保存音频包:
直接输出解复用之后的的音频数据码流。只需要在每次调用av_read_frame()之后将得到的音频的AVPacket存为本地文件即可。
但在分离AAC码流的时候,直接存储AVPacket后的文件可能是不能播放的。
分离H.264码流的时候,直接存储AVPacket后的文件可能是不能播放的。
复用格式是FLV,MP4等,直接存储后的文件是不能播放的。
因为FLV,MP4这些属于“特殊容器”。经过仔细对比后发现,调用av_read_frame()后得到的AVPacket里面的内容是AAC纯数据,就是那种不包含ADTS文件头的AAC数据。(存储AAC数据的AVPacket的data字段中的数据是不包含7字节ADTS文件头的数据)因此如果想要得到可以播放的AAC文件,需要在每个AVPacket前面加上7字节ADTS文件头。
demux分离时,h264需要h264_mp4toannexb,音频aac好像没有用到
mux时,h264也需要h264_mp4toannexb,aac用到aac_adtstoasc
mux时对于某些封装格式(例如MP4/FLV/MKV等)中的AAC,需要用到名称为“aac_adtstoasc”的bitstream filter。
============================================================
保存视频包:
分离某些封装格式(例如MP4/FLV/MKV等)中的H.264的时候,需要首先写入SPS和PPS
例如flv格式时,从av_read_frame中读出的包也是不包含video tag header的裸视频数据。
FLV,MP4这些“特殊容器”,需要经过以下2步处理才能得到可播放的H.264码流:
1.第一次存储AVPacket之前需要在前面加上H.264的SPS和PPS。这些信息存储在AVCodecContext的extradata里面。
并且需要使用FFMPEG中的名为"h264_mp4toannexb"的bitstream filter 进行处理。
然后将处理后的extradata存入文件
具体代码如下:
代码片段A
  1. unsigned char *dummy=NULL;   //输入的指针
  2. int dummy_len;
  3. AVBitStreamFilterContext* bsfc =  av_bitstream_filter_init("h264_mp4toannexb");
  4. av_bitstream_filter_filter(bsfc, pCodecCtx, NULL, &dummy, &dummy_len, NULL, 0, 0);
  5. fwrite(pCodecCtx->extradata,pCodecCtx-->extradata_size,1,fp);
  6. av_bitstream_filter_close(bsfc);
  7. free(dummy);
2.通过查看FFMPEG源代码发现,AVPacket中的数据起始处没有分隔符(0x00000001), 也不是0x65、0x67、0x68、0x41等字节,所以可以肯定AVPacket不是标准的nalu。其实,AVPacket前4个字表示的是nalu的长度,从第5个字节开始才是nalu的数据。所以直接将AVPacket前4个字节替换为0x00000001即可得到标准的nalu数据。
具体代码如下:
代码片段B
  1. char nal_start[]={0,0,0,1};
  2. fwrite(nal_start,4,1,fp);
  3. fwrite(pkt->data+4,pkt->size-4,1,fp);
  4. fclose(fp);
  1. char nal_start[]={0,0,0,1};
  2. memcpy(packet->data,nal_start,4);
经过以上两步处理之后,我们就得到了可以正常播放的H.264码流
====================================================
其它处理方式:
(1)使用bitstream filter处理每个AVPacket(简单)
把每个AVPacket中的数据(data字段)经过bitstream filter“过滤”一遍。关键函数是av_bitstream_filter_filter()。示例代码如下。
  1. AVBitStreamFilterContext* h264bsfc =  av_bitstream_filter_init("h264_mp4toannexb");
  2. while(av_read_frame(ifmt_ctx, &pkt)>=0){
  3. if(pkt.stream_index==videoindex){
  4. av_bitstream_filter_filter(h264bsfc, ifmt_ctx->streams[videoindex]->codec, NULL, &pkt.data, &pkt.size, pkt.data, pkt.size, 0);
  5. fwrite(pkt.data,1,pkt.size,fp_video);
  6. //...
  7. }
  8. av_free_packet(&pkt);
  9. }
  10. av_bitstream_filter_close(h264bsfc);
代码中,把av_bitstream_filter_filter()的输入数据和输出数据(分别对应第4,5,6,7个参数)都设置成AVPacket的data字段就可以了。
经过上述代码处理之后,AVPacket中的数据有如下变化:
*每个AVPacket的data添加了H.264的NALU的起始码{0,0,0,1}
*每个IDR帧数据前面添加了SPS和PPS
(2)手工添加SPS,PPS(稍微复杂)
将AVCodecContext的extradata数据经过bitstream filter处理之后得到SPS、PPS,拷贝至每个IDR帧之前。“代码片段A”示例了写入SPS、PPS的过程。
然后修改AVPacket的data。把前4个字节改为起始码。参见:代码片段B
参考:
视音频分离器(demuxer):ts->h264+aac 利用av_interleaved_write_frame
视音频复用器(muxer):h264+aac->mkv,用到av_interleaved_write_frame

mux复用 demux解复用的更多相关文章

  1. 【DSP开发】【VS开发】MUX和DEMUX的含义

    MUX和DEMUX Mux 是 Multiplex 的缩写,意为"多路传输",其实就是"混流"."封装"的意思,与"合成" ...

  2. C++的精髓——代码复用、接口复用

    C++的精髓——代码复用.接口复用 在另一篇文章中提到C++三大特点的核心概括,也写在这里吧.封装:信息隐藏继承:代码复用多态:面向对象C++并不是面向对象,它包容多种编程思想,如面向过程,面向对象, ...

  3. 解复用-mpeg2

    http://blog.csdn.net/yipie/article/details/7612226 数字高清晰度电视(High Definition Television)简称HDTV,是继黑白电视 ...

  4. tmux 终端复用详解

    tmux是什么 我们在linux服务器上的工作一般都是通过一个远程的终端连接软件连接到远端系统进行操作,例如使用xshell或者SecureCRT工具通过ssh进行远程连接.在使用过程中,如果要做比较 ...

  5. React事件处理函数的bind复用和name复用

    一.bind复用 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset=&qu ...

  6. FFmpeg封装格式处理2-解复用例程

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10506642.html FFmpeg封装格式处理相关内容分为如下几篇文章: [1]. F ...

  7. 机顶盒demux的工作原理

    在机顶盒中demux部分相对来说是比较复杂的部分,对于机顶盒软件开发的新手来说通常在这里会遇到一些困难,今天特意研究了一下驱动层代码,有一点自己的理解,因此写下来记录一下学习过程. 机顶盒中数据是如何 ...

  8. Android ijkplayer详解使用教程

    1.认识ijkplayer 最近公司准备开发一款视频播放及直播的应用,找了许多开源的框架,大部分都是基于ffmpeg开发的.最开始准备用Vitamio框架开发的,相关的文章也比较丰富,结果对于非个人移 ...

  9. VLC说明

    一.简介 vlc的全名是Video Lan Client,是一个开源的.跨平台的视频播放器.VLC支持大量的音视频传输.封装和编码格式,完整的功能特性列表可以在这里获得http://www.video ...

随机推荐

  1. Google Maps API V3 之 路线服务

    Google官方教程: Google 地图 API V3 使用入门 Google 地图 API V3 针对移动设备进行开发 Google 地图 API V3 之事件 Google 地图 API V3 ...

  2. 【转】Java enum的用法详解

    用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法. p ...

  3. 在 Github 上找「好东西」的方法

    使用 Github 的站内搜索,搜索: Awesome + 你的关键字

  4. [译] 你该知道的javascript作用域 (javascript scope)(转)

    javascript有一些对于初学者甚至是有经验的开发者都难以理解的概念. 这个部分是针对那些听到 : 作用域, 闭包, this, 命名空间, 函数作用域, 函数作用域, 全局作用域, 变量作用域( ...

  5. Java_Array数组1

    package org.array.demo; /** * 数组可以看成一组相同属性的元素的集合 * 1.静态声明 * 静态声明的格式: * 数组类型[] 标识 = new 数组类型[数组长度]; * ...

  6. VC调试闪退解决办法

    在VC2010调试或执行EXE文件时,程序运行结束后自动退出了,想看到打印 可以采用几种方法: 1.按ctrl+F5只执行不调试 2.在cmd中手动调用 而不是直接点 3.加入getchar  #in ...

  7. mysql数据库 中文乱码

    看到一篇很好的文章,转录于此 中文乱码似乎是程序编写中永恒的一个话题和难点,就比如MySQL存取中文乱码,但我想做任何事情,都要有个思路才行,有了思路才知道如何去解决问题,否则,即使一时解决了问题,但 ...

  8. PHP错误处理函数set_error_handler()的用法

    定义和用法 set_error_handler() 函数设置用户自定义的错误处理函数. 该函数用于创建运行时期间的用户自己的错误处理方法. 该函数会返回旧的错误处理程序,若失败,则返回 null. 语 ...

  9. PHP定时备份MySQL,mysqldump语法大全

    几个常用操作: 1.备份 # 只导出表结构 d:/PHP/xampp/mysql/bin/mysqldump -h127.0.0.1 -P3306 -uroot -p123456 snsgou_sns ...

  10. TCP/IP三次握手和HTTP过程

    1.TCP连接 手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接.TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在"无差别&qu ...