• (转)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 << " ";
                }
                *pkt = new_pkt;
        
                bsfc = bsfc->next;
            }
        }
  • 相关阅读:
    在数组中的两个数字如果前面一个数字大于后面的数字, 则这两个数字组成一个逆序对。 输入一个数组,求出这个数组中的逆序对的总数
    输入一个正整数数组,把数组里所有数字拼接起来排成一个数。打印能拼接出所有数字中最小的一个
    输入一个整型数组,数组里有正数,也有负数。求所有子数组的和的最大值
    数组中有一个数字出现的次数超过数组长度的一半
    输入一个字符串,打印出该字符串中字符的所有排列
    输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表
    输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径
    判断某数组是否是某二叉搜索树的后序遍历的结果
    栈的压人、弹出序列
    Valid Number
  • 原文地址:https://www.cnblogs.com/lihaiping/p/5284600.html
Copyright © 2020-2023  润新知