RK3588-MPP解碼詳解

2023-11-21 12:01:34

一. 簡介

二. 環境介紹

  • 硬體環境: ArmSoM-W3 RK3588開發板

  • 軟體版本: OS:ArmSoM-W3 Debian11

三. 解碼器資料流介面

3.1 decode_put_packet

在這裡插入圖片描述

輸入碼流的形式:分幀與不分幀 MPP 的輸入都是沒有封裝資訊的裸碼流,裸碼流輸入有兩種形式:

  1. 不分幀 這種方式是已經按幀分段的資料,即每一包輸入給 decode_put_packet 函數的 MppPacket 資料都已經包含完整的一幀,不多也不少。在這種情況下,MPP 可以直接按包處理碼流,是 MPP 的預設執行情況。

  2. 分幀 按長度讀取的資料,這樣的資料無法判斷一包 MppPacket 資料是否是完整的一幀,需要 MPP 內部進行分幀處理。MPP 也可以支援這種形式的輸入,但需要在 mpp_init 之前,通過 control 介面的 MPP_DEC_SET_PARSER_SPLIT_MODE 命令,MPP 內的 need_split 標誌開啟。

      // NOTE: decoder split mode need to be set before init
        // 按幀輸入碼流
        RK_U32 need_split   = 1;
        mpi_cmd = MPP_DEC_SET_PARSER_SPLIT_MODE;
        param = &need_split;
        ret = mpi->control(ctx, mpi_cmd, param);
        if (MPP_OK != ret) {
            mpp_err("mpi->control failed\n");
            deInit(&packet, &frame, ctx, buf, data);
        }

     

    這樣,呼叫 decode_put_packet 輸入的 MppPacket 就會被 MPP 重新分幀,進入到情況一的處理。

<font color="red" size="3">如果這兩種情況出現了混用,會出現碼流解碼出錯的問題。

  • 分幀方式處理效率高,但需要輸入碼流之前先進行解析與分幀;

  • 不分幀方式使用簡單,但效率會受影響。

  • 在 mpi_dec_test 的測試用例中,使用的是方式不分幀的方式。在瑞芯微的 Android SDK 中,使用的是分幀的方式。使用者可以根據自己的應用場景和平臺條件進行選擇

 

3.2 decode_get_frame

在這裡插入圖片描述

3.3 給解碼器提供足夠大小的儲存畫素資料的記憶體空間

解碼器在解碼時,需要為輸出影象獲取儲存畫素資料的記憶體空間,使用者需要給解碼器提供足夠大小,這個空間大小的需求,會在 MPP 解碼器內部根據不同的晶片平臺以及不同的視訊格式需求進行計算,計算後的記憶體空間需求會通過MppFrame 的成員變數 buf_size 提供給使用者。使用者需要按 buf_size的大小進行記憶體分配,即可滿足解碼器的要求。

RK_U32 buf_size = mpp_frame_get_buf_size(frame);
​
ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24);
if (ret) 
{
    mpp_err("%p limit buffer group failed ret %d\n", ctx, ret);
    break;
}

 

3.4 輸出影象的變寬高資訊(Info change)

當碼流的寬高,格式,畫素位深等資訊發生變化時,需要反饋給使用者,使用者需要更新解碼器使用的 記憶體池,把新的記憶體更新給解碼器。這裡涉及到解碼記憶體分配與使用模式。 影象記憶體分配以及互動模式:

模式一:純內部分配模式 模式二:半內部分配模式 模式三:純外部分配模式: 直接使用外部顯示用的記憶體,容易實現零拷貝。

模式一:純內部分配模式

影象記憶體直接從 MPP 解碼器內部分配,記憶體由解碼器直接分配,使用者得到解碼器輸出影象,在使用 完成之後直接釋放。 在這種方式下,使用者不需要呼叫解碼器 control 介面的 MPP_DEC_SET_EXT_BUF_GROUP 命令,只 需要在解碼器上報 info change 時直接呼叫 control 介面的 MPP_DEC_SET_INFO_CHANGE_READY 命令即可。解碼器會自動在內部進行記憶體分配,使用者需要把獲取到的每幀資料直接釋放。

模式二:半內部分配模式

使用者需要根據get_frame返回的MppFrame的buf_size 來建立 MppBufferGroup,並通過 control 介面的 MPP_DEC_SET_EXT_BUF_GROUP 設定給解碼器。使用者可以通過 mpp_buffer_group_limit_config 介面來限制解碼器的記憶體使用量。

模式三:純外部分配模式

這種模式通過建立空的 external 模式的 MppBufferGroup,從使用者那裡匯入外部分配器分析的記憶體塊 檔案控制程式碼(一般是 dmabuf/ion/drm)。在 Android 平臺上,Mediaserver 通過 gralloc 從 SurfaceFlinger 獲取顯示用記憶體,把 gralloc 得到的檔案控制程式碼提交(commit)到 MppBufferGroup 裡,再把 MppBufferGroup 通過 control 介面 MPP_DEC_SET_EXT_BUF_GROUP 命令設定給解碼器,然後 MPP 解碼器將回圈使用 gralloc 得到的記憶體空間。