当前位置: 首页 > 知识库问答 >
问题:

如何使用H264编解码器编写带有libavcodec for MP4文件的avc1 atom

子车俊材
2023-03-14
av_write_frame(outputFormatCtx, &pkt);

这是我到目前为止的努力,在从返回的编码器缓冲区解析SP和pps之后。(在memcping到sps和pps之前,我删除了前导的0x0000001 nal分隔符)。

 if ((sps) && (pps)) {
          //length of extradata is 6 bytes + 2 bytes for spslen + sps + 1 byte number of pps + 2 bytes for ppslen + pps

          uint32_t extradata_len = 8 + spslen + 1 + 2 + ppslen;
          outputStream->codecpar->extradata = (uint8_t*)av_mallocz(extradata_len);

          outputStream->codecpar->extradata_size = extradata_len;

          //start writing avcc extradata
          outputStream->codecpar->extradata[0] = 0x01;      //version
          outputStream->codecpar->extradata[1] = sps[1];    //profile
          outputStream->codecpar->extradata[2] = sps[2];    //comatibility
          outputStream->codecpar->extradata[3] = sps[3];    //level
          outputStream->codecpar->extradata[4] = 0xFC | 3;  // reserved (6 bits), NALU length size - 1 (2 bits) which is 3
          outputStream->codecpar->extradata[5] = 0xE0 | 1;  // reserved (3 bits), num of SPS (5 bits) which is 1 sps

          //write sps length
          memcpy(&outputStream->codecpar->extradata[6],&spslen,2);

          //Check to see if written correctly
          uint16_t *cspslen=(uint16_t *)&outputStream->codecpar->extradata[6];
          fprintf(stderr,"SPS length Wrote %d and read %d \n",spslen,*cspslen);


          //Write the actual sps
          int i = 0;
          for (i=0; i<spslen; i++) {
            outputStream->codecpar->extradata[8 + i] = sps[i];
          }

          for (size_t i = 0; i != outputStream->codecpar->extradata_size; ++i)
                fprintf(stderr, "\\%02x", (unsigned char)outputStream->codecpar->extradata[i]);
                fprintf(stderr,"\n");

          //Number of pps
          outputStream->codecpar->extradata[8 + spslen] = 0x01;

          //Size of pps
          memcpy(&outputStream->codecpar->extradata[8+spslen+1],&ppslen,2);

          for (size_t i = 0; i != outputStream->codecpar->extradata_size; ++i)
                fprintf(stderr, "\\%02x", (unsigned char)outputStream->codecpar->extradata[i]);
                fprintf(stderr,"\n");

          //Check to see if written correctly
          uint16_t *cppslen=(uint16_t *)&outputStream->codecpar->extradata[+8+spslen+1];
          fprintf(stderr,"PPS length Wrote %d and read %d \n",ppslen,*cppslen);


          //Write actual PPS
          for (i=0; i<ppslen; i++) {
           outputStream->codecpar->extradata[8 + spslen + 1 + 2 + i] = pps[i];
          }

          //Output the extradata to check
          for (size_t i = 0; i != outputStream->codecpar->extradata_size; ++i)
                fprintf(stderr, "\\%02x", (unsigned char)outputStream->codecpar->extradata[i]);
                fprintf(stderr,"\n");


          //Access the outputFormatCtx internal AVCodecContext and copy the codecpar to it
          AVCodecContext *avctx= outputFormatCtx->streams[0]->codec;

          fprintf(stderr,"Extradata size output stream sps pps %d\n",outputStream->codecpar->extradata_size);
          if(avcodec_parameters_to_context(avctx, outputStream->codecpar) < 0 ){
             fprintf(stderr,"Error avcodec_parameters_to_context");

          }

          //Check to see if extradata was actually transferred to OutputformatCtx internal AVCodecContext
          fprintf(stderr,"Extradata size after sps pps %d\n",avctx->extradata_size);



          //Write the MP4 header
          if(avformat_write_header(outputFormatCtx , NULL) < 0){
            fprintf(stderr,"Error avformat_write_header");
            ret = 1;
          } else {
            extradata_written=true;
            fprintf(stderr,"EXTRADATA written\n");
          }    
       } 

生成的视频文件将不播放。该extradata实际上存储在MP4文件的尾部部分,而不是AVC1的MP4头中的位置。因此它是由libavcodec编写的,但很可能是由avformat_write_trailer编写的。

我将在这里发布PPS和SPS信息以及最终的extradata字节字符串,以防在形成extradata时出错。

下面是硬件编码器的缓冲区,其前缀为nal分隔符的sps和pps

\00\00\00\01\27\64\00\28\AC\2B\40\A0\CD\00\F1\22\6A\00\00\00\01\28\EE\04\F2\C0

以下是13字节SPS:

27640028ac2b40a0cd00f1226a

下面是5字节PPS:

28ee04f2c0

下面是最后一个extradata字节字符串,它是29个字节长。我希望我写的PPS和SPS大小正确。

\01\64\00\28\FF\E1\0D\00\27\64\00\28\AC\2B\40\A0\CD\00\F1\22\6A\01\05\00\28\EE\04\F2\C0

我对编码器的后继帧进行了相同的转换,从NAL分隔符0x0000001转换为4字节NAL大小,并将它们按顺序保存到文件中,然后编写拖车。

知道错在哪里吗?我怎样才能写的引渡到它的适当位置在MP4头?

谢谢,克里斯

共有1个答案

鱼意远
2023-03-14

我发现了问题所在。raspberry pi是小endpoint,所以我假设我必须用小endpoint写sps长度和pps长度以及每个NALU大小。它们需要用大端语来写。在我做了更改之后,mp4info和mplayer中显示的avcc atom现在可以回放视频了。不必访问outputformatctx内部avcodeccontext并修改它。

这篇文章很有帮助:

H.264流的序列/图像参数集的可能位置

 类似资料:
  • 我们有一个Android应用程序,把视频编码成H264。在所有以前试用过的Android设备上,这个编码为基线配置文件,这是我需要的。 联想Yoga10的编解码器是omx.mtk.video.encoder.avc。这将视频编码为高轮廓,这给接收设备带来了问题。

  • The Python Imaging Library uses a plug-in model which allows you to add your own decoders to the library, without any changes to the library itself. Such plug-ins usually have names like XxxImagePlugi

  • 我正在尝试用Android6.0的MediaCodec将h264编码成实时低延迟的流。有大约6帧的延迟从编码器,我想知道如何减少 零件代码为: 编码器以320×480 60 fps的速度由屏幕表面馈入,通过dequeueOutputBuffer()输出流数据。大约有6个帧的数据没有被dequeueOutputBuffer()及时返回到编码器。换句话说,当馈送第n帧时,编码器输出第(N-6)帧的数据

  • 这是本问题的后续问题。 这是我的代码: 我的问题-我的实现对于呈现由解码的H264流是否可以?或者我需要做EGL设置或其他什么? 提前道谢!

  • 以下是我的问题: 什么是? 格式是不明确的,因为它可以是属于家族的任何格式,例如、、和,对吗? 如果我想把这些数据从Image的三个平面写到MediaCodec中,我需要转换成什么样的格式?YUV420、NV21、NV12、……? 格式也不明确,因为它可以是属于家族的任何格式,对吗?如果我将MediaCodec对象的选项设置为,那么是什么格式(YUV420P,yuv420sp...)是否应该向Me

  • 问题内容: 我有一些要发送到我的应用程序中的芹菜任务的对象。这些对象显然无法使用默认json库进行json序列化。有没有一种方法可以使celery使用自定义JSON / 对这些对象进行序列化/反序列化? 问题答案: 这里有些晚,但是您应该能够通过在kombu序列化程序注册表中注册自定义编码器和解码器,如docs中所示: http [//docs.celeryproject.org/en/lates