本文主要分析mp4封装的h265/h264,copy转hls,红色为自己添加的注释。

动态添加此filter
    for (i = 0; i < nb_output_streams; i++) {
        ost = output_streams[i];
        if(ost->st->codec->codec_type  == AVMEDIA_TYPE_VIDEO && ost->st->codec->codec_id == AV_CODEC_ID_H264)
        {
           AVBitStreamFilterContext * avFilter = av_bitstream_filter_init("h264_mp4toannexb");
           ost->bitstream_filters = avFilter;
        }else if(ost->st->codec->codec_type  == AVMEDIA_TYPE_VIDEO && ost->st->codec->codec_id == AV_CODEC_ID_HEVC)
        {
           AVBitStreamFilterContext * avFilter = av_bitstream_filter_init("hevc_mp4toannexb");
           ost->bitstream_filters = avFilter;
        }

}

hevc->hls

如果不加 -bsf:v hevc_mp4toannex,就会报如下错误:

原因如下:

check_hevc_startcode会发现没有00000001字段。

相关代码有:hevc_mp4toannexb_bsf.c

前缀(vps,sps,pps)例子如下:

typedef structHEVCBSFContext {

uint8_t length_size;

int     extradata_parsed;

}HEVCBSFContext;

static inthevc_extradata_to_annexb(AVBSFContext *ctx)

{

GetByteContext gb;

int length_size, num_arrays, i, j;

int ret = 0;

uint8_t *new_extradata = NULL;

size_t  new_extradata_size = 0;

bytestream2_init(&gb,ctx->par_in->extradata, ctx->par_in->extradata_size);

bytestream2_skip(&gb, 21);

//跳过21个字节

length_size =(bytestream2_get_byte(&gb) & 3) + 1;

//第22个字节(0x03)后两位加上1。

num_arrays = bytestream2_get_byte(&gb);

//第23个字节(0x03)

for (i = 0; i < num_arrays; i++) {

int type =bytestream2_get_byte(&gb) & 0x3f;

//对应0x20,0x21,0x22

int cnt = bytestream2_get_be16(&gb);

//对应0x00 0x01, 0x00 0x01, 0x00 0x01,

if (!(type == NAL_VPS || type ==NAL_SPS || type == NAL_PPS ||

type == NAL_SEI_PREFIX || type ==NAL_SEI_SUFFIX || type == 0)) {

av_log(ctx, AV_LOG_ERROR,"Invalid NAL unit type in extradata: %d\n",

type);

ret = AVERROR_INVALIDDATA;

goto fail;

}

for (j = 0; j < cnt; j++) {

int nalu_len =bytestream2_get_be16(&gb);

//对应0x00 0x17(0x40~0x59),0x00 0x27(0x42~0x40),0x00 0x07(0x44~0x20)

if (4 +AV_INPUT_BUFFER_PADDING_SIZE + nalu_len > SIZE_MAX - new_extradata_size) {

ret = AVERROR_INVALIDDATA;

goto fail;

}

ret =av_reallocp(&new_extradata, new_extradata_size + nalu_len + 4 +AV_INPUT_BUFFER_PADDING_SIZE);

if (ret < 0)

goto fail;

AV_WB32(new_extradata +new_extradata_size, 1);

// addthe startcode,也就是00 00 00 01

bytestream2_get_buffer(&gb,new_extradata + new_extradata_size + 4, nalu_len);

new_extradata_size += 4 + nalu_len;

memset(new_extradata + new_extradata_size,0, AV_INPUT_BUFFER_PADDING_SIZE);

}

}

av_freep(&ctx->par_out->extradata);

ctx->par_out->extradata      = new_extradata;

ctx->par_out->extradata_size =new_extradata_size;

//得到新的字符串,长度。

if (!new_extradata_size)

av_log(ctx, AV_LOG_WARNING, "Noparameter sets in the extradata\n");

return length_size;

fail:

av_freep(&new_extradata);

return ret;

}

static inthevc_mp4toannexb_init(AVBSFContext *ctx)

{

...

}

//对于每一帧,都会进入hevc_mp4toannexb_filter函数,如下:

static inthevc_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out)

{

HEVCBSFContext *s = ctx->priv_data;

AVPacket *in;

GetByteContext gb;

int got_irap = 0;

int i, ret = 0;

ret = ff_bsf_get_packet(ctx, &in);

if (ret < 0)

return ret;

if (!s->extradata_parsed) {

av_packet_move_ref(out, in);

av_packet_free(&in);

return 0;

}

bytestream2_init(&gb, in->data,in->size);

while (bytestream2_get_bytes_left(&gb)){

uint32_t nalu_size = 0;

int     nalu_type;

int is_irap, add_extradata, extra_size,prev_size;

for (i = 0; i < s->length_size;i++)

nalu_size = (nalu_size << 8)| bytestream2_get_byte(&gb);

//前4位表示数据大小。

nalu_type =(bytestream2_peek_byte(&gb) >> 1) & 0x3f;

//对应0x26

/* prepend extradata to IRAP frames */

is_irap       = nalu_type >= 16 &&nalu_type <= 23;

//帧类型在16到23之间,都会被强插入vps等前缀。

add_extradata = is_irap &&!got_irap;

extra_size    = add_extradata *ctx->par_out->extradata_size;

got_irap     |= is_irap;

if (SIZE_MAX - nalu_size < 4 ||

SIZE_MAX - 4 - nalu_size <extra_size) {

ret = AVERROR_INVALIDDATA;

goto fail;

}

prev_size = out->size;

ret = av_grow_packet(out, 4 + nalu_size+ extra_size);

if (ret < 0)

goto fail;

if (add_extradata)

memcpy(out->data + prev_size,ctx->par_out->extradata, extra_size);

//插入vps等前缀。

AV_WB32(out->data + prev_size +extra_size, 1);

// add thestartcode,也就是00 00 00 01

bytestream2_get_buffer(&gb,out->data + prev_size + 4 + extra_size, nalu_size);

//拷贝帧数据。

}

ret = av_packet_copy_props(out, in);

if (ret < 0)

goto fail;

fail:

if (ret < 0)

av_packet_unref(out);

av_packet_free(&in);

return ret;

}

...

h264->hls

解析mp4的块,得到sps,pps总数据,在h264_mp4toannexb_filter中去除头,得到sps,pps(只做一次),然后在每个关键帧前插sps,pps数据。

hevc_mp4toannexb_bsf.c/h264_mp4toannexb_bsf.c相关推荐

  1. WebRTC-集成qsv硬解码实现

    1.Window下QSV硬解码配置 在libavcodec/codec_list.c下添加 &ff_h264_qsv_decoder, 在ffmpeg_generate.gni下加入 &quo ...

  2. FFmpeg源代码简单分析:configure

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  3. H264 帧、pps 、sps

    H264帧 对于H.264而言,每帧的界定符为00 00 00 01 或者00 00 01. 例如下面是一个H264的文件片段 00 00 00 01 67 42 C0 28 DA 01 E0 08 ...

  4. FFmpeg封装格式处理:视音频复用器(muxer)不同格式中数据有无bsf的差异-- Filter bitstream_filter实现格式转换:h264_mp4toannexb

    视音频复用器:从输入文件中挑出需要的视频/音频流,再合并放到一个文件中 不同封装格式中的数据存放方式不同,其差异需要一个av_bitstream_filter_filter(AVBitStreamFi ...

  5. Android多媒体开发(2)————使用Android NKD编译原版FFmpeg

    /******************************************************************************************** * auth ...

  6. Win7下利用MinGW和Android NDK编译ffmpeg0.10(neon优化)

    不久之前萌生了移植ffmpeg到android平台上的冲动,然后就开始搞.网上搜了个遍,着实费了不少工夫.因此把成果列出来供同道中人参考. 本文主要参考了Scott Wong 兄的在 Windows ...

  7. win 7下ffmpeg平台和Android联合编译ndk rc7和ffmpeg harmony(最后还是改为r5)

    恩..前面弄好了ndk和cgwin之后开始进行FFmepeg的搭建..前面的图都没了啊啊 参考http://www.cnblogs.com/scottwong/archive/2011/06/26/2 ...

  8. 阿里云服务器编译ffmpeg

    1.在usr文件夹中创建jason文件夹 cd /usr :进入usr文件夹 mkdir jason: 创建jason文件夹 2.上传ffmpeg文件到阿里云 3.解压ffmpeg压缩包 4.编译.s ...

  9. 应用角度理解H264码流

    应用角度理解H264码流 前言 1.NAL 2.SPS.PPS 2.1 SPS 2.2 PPS 3.Slice&MB 3.1.Slice 3.2.MB 4.RTP负载 5.AUD 6.文献 前 ...

最新文章

  1. 今天终于搞懂了:为什么 Java 的 main 方法必须是 public static void?
  2. 数据结构之【数组和广义表】复习题
  3. Python列表List
  4. 踩内存是什么意思啊_面试|搬了这么久的砖,居然还不知道什么“踩内存”
  5. Java中如何引用文档对象模型_在JAVA中使用文档对象模型DOM经验小结
  6. 前端学习(3059):vue+element今日头条管理-优化文章状态
  7. LeetCode算法入门- Remove Duplicates from Sorted Array -day21
  8. mongoTemplate.aggregate() 聚合查询,关联查询
  9. linux音频声卡 pulseaudio服务
  10. 毕业设计——如何画系统功能结构图?
  11. 在修改redis配置文件的情况下启动redis需指定配置文件
  12. Django3.0入门教程【四】:Django常用命令
  13. 1079:计算分数加减表达式的值
  14. 英语的计算机求职回信,2020年计算机英文求职信范文模板
  15. Git, Gitlab使用文档
  16. 南京信息工程大学计算机与科学专业,2019南京信息工程大学专业排名
  17. 十五、圣礼是蒙恩的凭藉
  18. 基于协同过滤算法的电影推荐系统设计(二) - ALS算法详解
  19. 计算机三级数据库技术 第14章 数据仓库与数据挖掘
  20. javaScript和html的区别与联系

热门文章

  1. 当一个查询语句同时出现了where,group by,having,order by的时候,执行顺序和编写顺序
  2. 预失真算法matlab实现,2013-全国研究生数学建模B题-seleh模型预失真MATLAB仿真代码...
  3. java中EQ、NE、GT、GE、LT、LE分别代表含义
  4. 百度谷歌必应搜狗知乎 可切换搜索框的实现
  5. nfs服务共享目录的创建
  6. 常见的嵌入式微处理器(Micro Processor Unit,MPU)
  7. php显示照片墙,照片墙(css动态效果)
  8. 实习时候的亚子==(四)
  9. Linux 视频剪辑与录音
  10. SYN6288中文语音合成 程序