mux复用 demux解复用

简介: 保存音频包: 直接输出解复用之后的的音频数据码流。只需要在每次调用av_read_frame()之后将得到的音频的AVPacket存为本地文件即可。 但在分离AAC码流的时候,直接存储AVPacket后的文件可能是不能播放的。
保存音频包:
直接输出解复用之后的的音频数据码流。只需要在每次调用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


目录
相关文章
|
2月前
C 函数怎么实现复用
在 C 语言中,函数复用主要通过定义、调用、使用头文件、参数化及库的使用来实现。定义一个函数完成特定任务,并在需要的地方调用它,避免重复代码。将函数声明放在头文件中,供多个源文件包含,进一步提升复用性。参数化使函数能处理不同输入,增强灵活性。将常用函数编译成库,在多个项目中引用,提高代码可维护性和可读性。
|
6月前
模块功能复用和扩展性
模块功能复用和扩展性 模块功能复用和扩展性是软件工程中的重要概念,主要体现在设计和实现阶段。
93 1
|
缓存 JavaScript 网络架构
多路由复用页面组件问题
多路由复用页面组件问题
111 0
多路由复用页面组件问题
|
芯片
hk32(航顺)标准库使用spi3复用功能的问题
hk32(航顺)标准库使用spi3复用功能的问题
270 0
hk32(航顺)标准库使用spi3复用功能的问题
|
设计模式 Java Linux
I/O复用前世今生
之前总结了一篇文章《单服务器知识》[1],主要整理两方面的: 一是socket以及IO常识 二是单机高性能模式 你会一般不会出现socket连接IO相关知识结合,所以在学习IO的时候,总会有很多的背景知识,出现现在会很吃力,或者说不知道就在里面。 这是为什么呢?
127 0
I/O复用前世今生
|
存储 缓存 前端开发
一文概述:从状态复用到Hooks
React Hooks 是 React 16.8 推出的新特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性
333 0
一文概述:从状态复用到Hooks
分集和复用
分集和复用
127 0
|
算法 程序员 PHP
程序设计中的计算复用(Computational Reuse)
从斐波那契数列说起 我想几乎每一个程序员对斐波那契(Fibonacci)数列都不会陌生,在很多教科书或文章中涉及到递归或计算复杂性的地方都会将计算斐波那契数列的程序作为经典示例。如果现在让你以最快的速度用C#写出一个计算斐波那契数列第n个数的函数(不考虑参数小于1或结果溢出等异常情况),我不知你的程...
950 0
下一篇
无影云桌面