(轉)MP4文件兩種格式AVC1和H264的區別及利用FFMPEG demux為h264碼流事項


出自:http://www.mworkbox.com/wp/work/314.html

2013-05-04

MP4的視頻H264封裝有2種格式:h264和avc1,對於這個細節,很容易被忽略。筆者也是在改編LIVE555流媒體時,增加mp4文件類型支持時遇到了該問題。

(一)首先,從原理上了解一下這2種格式的區別:
AVC1 描述:H.264 bitstream without start codes.一般通過ffmpeg轉碼生成的視頻,是不帶起始碼0×00000001的。
H264 描述:H.264 bitstream with start codes.一般對於一下HDVD等電影的壓制格式,是帶有起始碼0×00000001的。
來源文檔:http://msdn.microsoft.com/zh-cn/library/dd757808(v=vs.85).aspx
(二)其次,通過VLC播放器,可以查看到具體的格式。打開視頻后,通過菜單【工具】/【編解碼信息】可以查看到【編解碼器】具體格式,舉例如下,編解碼器信息:
編碼: H264 – MPEG-4 AVC (part 10) (avc1)
編碼: H264 – MPEG-4 AVC (part 10) (h264)

(三)最后,分享一下ffmpeg demux MP4文件后,轉換視頻流為live555可直接使用的h264 ES流的經驗和方法:
針對(avc1),av_read_frame后,取前四個字節為長度,把前四字節直接替換為0×00,0×00,0×00,0×01即可,但注意每個frame可以有多個NAUL:

  AVPacket pkt ;
    AVPacket* packet &pkt;
    av_init_packet(packet);
    av_read_frame(ctx, packet);
    
    
    if(packet->stream_index == 0)
    {//is video stream
    
       const char start_code[4000};
            if(is_avc_ || memcmp(start_code, packet->data4!= 0)
            {//is avc1 code, have no start code of H264
                int len 0;
                uint8_t *p = packet->data;

                is_avc_ = True;
                do 
                {//add start_code for each NAL, one frame may have multi NALs.
                    len = ntohl(*((long*)p));
                    memcpy(p, start_code4);

                    p += 4;
                    p += len;
                    if(p >= packet->data + packet->size)
                    {
                        break;
                    }
                while (1);
            }
        }

對於另外一種格式,(h264), 則直接對每個packet調用av_bitstream_filter_filter處理每個packet即可:

  bsfc_  = av_bitstream_filter_init("h264_mp4toannexb");
  
   if(pkt->stream_index == 0)
   {//is video stream
    
      AVBitStreamFilterContext* bsfc = bsfc_;
        int a;
        while (bsfc{
            AVPacket new_pkt *pkt;
            a = av_bitstream_filter_filter(bsfc, encode_ctx_, NULL,
                &new_pkt.data&new_pkt.size,
                pkt->data, pkt->size,
                pkt->flags & AV_PKT_FLAG_KEY);
            if(a == && new_pkt.data != pkt->data && new_pkt.destruct{
                uint8_t *t (uint8_t*)(new_pkt.size + FF_INPUT_BUFFER_PADDING_SIZE)//the new should be a subset of the old so cannot overflow
                if(t{
                    memcpy(t, new_pkt.data, new_pkt.size);
                    memset(t + new_pkt.size0, FF_INPUT_BUFFER_PADDING_SIZE);
                    new_pkt.data = t;
                    a 1;
                else
                    a = AVERROR(ENOMEM);
            }
            if (a && pkt->data != new_pkt.data{
                av_free_packet(pkt);
                new_pkt.destruct = av_destruct_packet;
            else if (a 0{
                envir(<< "!!!!!!!!!!av_bitstream_filter_filter failed" << ",res=" << a << "\n";
            }
            *pkt = new_pkt;
    
            bsfc = bsfc->next;
        }
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM