mpp icon indicating copy to clipboard operation
mpp copied to clipboard

使用mpi_enc_test,去除代码内Hello world hahaha和SEI字段后,编码结果里PPS丢失

Open imxys opened this issue 3 years ago • 10 comments

环境: RK3399 使用旧版本的mpp库(并非是字符串配置编码参数,是用结构体配置) 使用原本mpi_enc_test时可以正常编码,header_mode为MPP_ENC_HEADER_MODE_EACH_IDR 测试命令 mpi_enc_test -t 7 -w 1920 -h 1080 -o /tmp/enc.h264

其内部NALU结构如下: 图片 在代码内去除如下两处

    /* optional */
    p->sei_mode = MPP_ENC_SEI_MODE_ONE_FRAME;
    ret = mpi->control(ctx, MPP_ENC_SET_SEI_CFG, &p->sei_mode);
    if (ret) {
        mpp_err("mpi control enc set sei cfg failed ret %d\n", ret);
        goto RET;
    }
        MppEncUserData user_data;
        char *str = "Hello world hahahaha lalalala\n";

        {
            MppMeta meta = mpp_frame_get_meta(frame);

            if ((p->frame_count & 2) == 0) {
                user_data.pdata = str;
                user_data.len = strlen(str) + 1;
                mpp_meta_set_ptr(meta, KEY_USER_DATA, &user_data);
            }

            if (p->osd_enable) {
                /* gen and cfg osd plt */
                mpi_enc_gen_osd_data(&p->osd_data, p->osd_idx_buf, p->frame_count);
                mpp_meta_set_ptr(meta, KEY_OSD_DATA, (void*)&p->osd_data);
            }
        }

注释上述代码后,编码视频仍然可播放(因为mpi_enc_test程序在一开始就获取了一次SPS和PPS写入文件) 但是其IDR帧内单元结构少了PPS,其内容变为如下: 图片

跟踪旧版mpp库内部 mpp_enc_v2.cpp:mpp_enc_thread()

     TASK_REENCODE:
         // 15. restore and process dpb
@@ -733,6 +797,14 @@ void *mpp_enc_thread(void *data)
         }
         frm->reencode = 0;
 
+        ptr = (char*) mpp_packet_get_pos(packet);
+        pktlen = mpp_packet_get_length(packet);
+        buflen = 0;
+        for (int i = 0; i < (pktlen > 30 ? 30 : pktlen); i++) {
+            buflen += snprintf(buf + buflen, sizeof(buf) - buflen, "%02x ", ptr[i]);
+        }
+        mpp_log("%s reencode: siz:%d data: [%s]", __func__, pktlen, buf);
+
         // check for header adding
         mpp_assert(hal_task->length == mpp_packet_get_length(packet));
 
@@ -780,6 +852,14 @@ void *mpp_enc_thread(void *data)
         /* setup output packet and meta data */
         mpp_packet_set_length(packet, hal_task->length);
 
+        ptr = (char*) mpp_packet_get_pos(packet);
+        pktlen = mpp_packet_get_length(packet);
+        buflen = 0;
+        for (int i = 0; i < (pktlen > 30 ? 30 : pktlen); i++) {
+            buflen += snprintf(buf + buflen, sizeof(buf) - buflen, "%02x ", ptr[i]);
+        }
+        mpp_log("%s TASK_DONE: siz:%d data: [%s]", __func__, pktlen, buf);
+
         {
             MppMeta meta = mpp_packet_get_meta(packet);

添加打印后,看编码日志大概是会在这个位置出现异常

mpp[26620]: mpp_enc_v2: mpp_enc_thread reencode: siz:24 data: [00 00 00 01 67 64 00 28 ac 1a d0 0f 00 44 bc a8 00 00 00 01 68 ce 3c 80 ]
mpp[26620]: mpp_enc_v2: mpp_enc_thread TASK_DONE: siz:121700 data: [00 00 00 01 67 64 00 28 ac 1a d0 0f 00 44 bc a8 00 00 00 01 25 b8 00 04 3f e5 ca 44 5f a8 ]

这两条日志打印之前的代码是hal相关的调用(mpp_enc_hal_start)等,我看不到源码

我尚未确认最新的mpp库是否有此问题,先发出来麻烦看一下是什么原因,谢谢!

imxys avatar Nov 29 '21 14:11 imxys

hal 代码里用的是函数指针,找一下都 hal 里不同硬件的实现,都可以看到代码

HermanChen avatar Nov 30 '21 00:11 HermanChen

hal 代码里用的是函数指针,找一下都 hal 里不同硬件的实现,都可以看到代码

您好,代码在哪里?我没看到hal,只能搜到头文件

imxys avatar Nov 30 '21 01:11 imxys

您好,我又确认了一下正常的h264编码结果,其内部SEI实际上有时候正常, 图片 有时候缺少了7个字节,SEI 0x05类型没有正常以0x80结尾 图片

imxys avatar Nov 30 '21 06:11 imxys

hal 代码里用的是函数指针,找一下都 hal 里不同硬件的实现,都可以看到代码

@HermanChen hello,请问有什么相关的指导么?我目前觉得就是交给hal那边编码的时候,生成的结果的位置比预想的生成位置往前了几个字节……

imxys avatar Dec 02 '21 03:12 imxys

@HermanChen 您好,问题基本上解决了

  1. hal代码找到了,是我搜索没搜清楚;没弄错的话代码应该是hal_h264e_vepu2_v2.c
  2. 本issue的问题没有具体定位什么原因,这个情况只有在1080P编码、High Profile情况下才出现,720P或者是Base Profile情况下正常;最后我把我 rk3399 原有SDK内库换成 github这边的mpp库最新提交就解决了问题。
  3. 此外我获取SPS、PPS方法使用的是MPP_ENC_GET_HDR_SYNC造成的问题,demo里用的MPP_ENC_GET_EXTRA_INFO,我把这个改掉之后,会在1080P、High Profile的编码情况下,产生 SPS后面跟上IDR帧的情况。也没有确认原因。MPP_ENC_GET_EXTRA_INFO还是mpp的文档里说不要用我才换的MPP_ENC_GET_HDR_SYNC;目前可能只好继续用原来的方法。

该问题梳理总结如上,您确认后可以关闭此issue了。

imxys avatar Dec 10 '21 13:12 imxys

使用 MPP_ENC_GET_HDR_SYNC 和 MPP_ENC_GET_EXTRA_INFO 两种的接口参数是有不同的,但是效果应该是一样的…… 需要注意的是,这两个接口需要在所有的参数配置都完成之后再调用,才能得到正确的结果。

HermanChen avatar Dec 13 '21 00:12 HermanChen

怀疑问题根本原因是这样的: MPP_ENC_GET_EXTRA_INFO 得到的是内部数据的 packet 结构信息,在编码器配置更新之后,里面的内容也给更新了,再去拷贝数据是正常的。 MPP_ENC_GET_HDR_SYNC 是在接口调用时刻就进行拷贝,把当时参数条件下生成的不正常的头就拷贝出现,等编码器配置完成完成之后,拷贝出来的数据就和真正编码器内部的数据不一致了。

HermanChen avatar Dec 13 '21 00:12 HermanChen

怀疑问题根本原因是这样的: MPP_ENC_GET_EXTRA_INFO 得到的是内部数据的 packet 结构信息,在编码器配置更新之后,里面的内容也给更新了,再去拷贝数据是正常的。 MPP_ENC_GET_HDR_SYNC 是在接口调用时刻就进行拷贝,把当时参数条件下生成的不正常的头就拷贝出现,等编码器配置完成完成之后,拷贝出来的数据就和真正编码器内部的数据不一致了。

您这个说法我有个疑问,因为在MPP_ENC_HEADER_MODE_EACH_IDR情况下,每次编码到I帧都需要复制一次SPS PPS吧? 然后好像我mpp库换成github上的是没什么问题的样子

imxys avatar Dec 13 '21 16:12 imxys

新的mpp库里编码出来一定带有两段SEI,这两段SEI都是完整的

imxys avatar Dec 13 '21 16:12 imxys

怀疑问题根本原因是这样的: MPP_ENC_GET_EXTRA_INFO 得到的是内部数据的 packet 结构信息,在编码器配置更新之后,里面的内容也给更新了,再去拷贝数据是正常的。 MPP_ENC_GET_HDR_SYNC 是在接口调用时刻就进行拷贝,把当时参数条件下生成的不正常的头就拷贝出现,等编码器配置完成完成之后,拷贝出来的数据就和真正编码器内部的数据不一致了。

您这个说法我有个疑问,因为在MPP_ENC_HEADER_MODE_EACH_IDR情况下,每次编码到I帧都需要复制一次SPS PPS吧? 然后好像我mpp库换成github上的是没什么问题的样子

是的,开起来就每次编码都带 SPS/PPS 输出

新的mpp库里编码出来一定带有两段SEI,这两段SEI都是完整的

嗯,是用来保存码控信息的

HermanChen avatar Dec 14 '21 00:12 HermanChen