参考雷老师:
音视频分离demuxer简化版,里面详细描述了SPS/PPS的操作: http://blog.youkuaiyun.com/leixiaohua1020/article/details/39767055
音视频流分离demuxer: http://blog.youkuaiyun.com/leixiaohua1020/article/details/39802819
音视频流复用muxer: http://blog.youkuaiyun.com/leixiaohua1020/article/details/39802913
一 音视频分离需要注意
》纯音频分离:pkt写入文件的话,单独解码播放,需要增加adts信息(音频stream/pkt 都需要为解码器增加额外的包头参数信息),
ADTS AAC
| ||||||
ADTS_header | AAC ES | ADTS_header | AAC ES |
...
| ADTS_header | AAC ES |
ADTS参考: http://blog.youkuaiyun.com/tx3344/article/details/7414543
》纯视频分离:pkt写入文件的话,单独解码播放,需要增加pps,sps信息(视频stream/pkt 都需要为解码器增加额外的包头参数信息),
SDP中的H.264的SPS和PPS串,包含了初始化H.264解码器所需要的信息参数,包括编码所用的profile,level,图像的宽和高,deblock滤波器等。
SPS和PPS信息存储在AVCodecContext结构体的extradata中。需要使用ffmpeg中名称为“h264_mp4toannexb”的bitstream filter处理。流的第一NALU是SPS->PPS->IDR
SPS/PPS介绍参考:http://www.rosoo.net/a/201110/15236.html
http://blog.youkuaiyun.com/sunnylgz/article/details/7680262
SPS/PPS ffmpeg操作: http://blog.youkuaiyun.com/leixiaohua1020/article/details/39767055
》1分2,解码器上下文复制API挺有用,avcodec_copy_context
》muxer/demuxer基本上就是基于pkt进行操作而非frame。
》获取文件中某路流的解码和格式信息API挺好用:
获取文件视频流pcodeCtx,pfmtCtx指针。
/* select the video stream */
ret = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
if (ret < 0) {
printf( "Cannot find a video stream in the input file\n");
return ret;
}
video_stream_index = ret;
pCodecCtx = pFormatCtx->streams[video_stream_index]->codec;
/* init the video decoder */
if ((ret = avcodec_open2(pCodecCtx, dec, NULL)) < 0) {
printf( "Cannot open video decoder\n");
return ret;
}
二 音视频分离简化版小结
mkv分离出mp3,h264
音视频文件分离出单独的音,视频文件:直接用av_read_frame读取包,根据stream_index写入fwrite到对应文件;其中视频加入了pps/sps 通过API:av_bitstream_filter_filter,可以单独播放;mp3文件没有加ADTS应该是播放不了的,以后下下雷老师代码调测下。
三 音视频分离小结
mkv分离出mp3,h264
整体思路是通过打开muxer文件,获取codecCtx后,复制2份-->avio_open创建2个mp3,h264文件--》创建2个stream,avformat_new_stream()---》判断av_read_frame后的pkt进行交叉文件写入av_interleaved_write_frame(ofmt_ctx),这里简洁的技巧是,写入前,ofmt_ctx根据ofmt_ctx_v/ofmt_ctx_a动态更新参数。完成1 mkv >分2,stream mp3/h24 >合1 write_frame的流程。
avformat_open_input():打开输入文件。
avcodec_copy_context():赋值AVCodecContext的参数。
avformat_alloc_output_context2():初始化输出文件。
avio_open():打开输出文件。
avformat_write_header():写入文件头。
av_read_frame():从输入文件读取一个AVPacket。
av_interleaved_write_frame():写入一个AVPacket到输出文件。
av_write_trailer():写入文件尾。
四 音视频复用小结
mp3,h264合并成mkv,
参考三,针对PKT操作,用的API差不多,特别的API有
int av_compare_ts ( int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b )
针对其返回值比较当前a,v的timestamp是否大于小于0;来读取本次audio pkt或者video pkt;
整体思路是,
打开2输入文件--》获取pFmtCtx,pCodecCtx
--》新建2路流avformat_new_stream --》 写ofmtCtx文件头
--》循环开始:根据av_compare_ts读pkt
--》av_bitstream_filter_filter(h264bsfc/aacbsfc,xx),音视频同步后
--》av_interleaved_write_frame,循环结束
--》av_write_trailer(ofmt_ctx);