分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
=====================================================
最简单的基于FFmpeg的封装格式处理系列文章列表:
最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)
最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)
最简单的基于FFmpeg的封装格式处理:视音频复用器(muxer)
最简单的基于FFMPEG的封装格式处理:封装格式转换(remuxer)
=====================================================
简介
打算记录一下基于FFmpeg的封装格式处理方面的例子。包括了视音频分离,复用,封装格式转换。这是第2篇。
本文记录一个基于FFmpeg的视音频分离器(Simplest FFmpeg demuxer)。视音频分离器(Demuxer)即是将封装格式数据(例如MKV)中的视频压缩数据(例如H.264)和音频压缩数据(例如AAC)分离开。如图所示。在这个过程中并不涉及到编码和解码。
前一篇文章中,记录一个简单版的视音频分离器。相比于前一篇文中的分离器,本篇文章记录的分离器复杂了很多。相比于简单版的分离器,学习的难度大了一些。但是该分离器可以很好地处理FFmpeg支持的各种格式(例如分离AAC音频流),拥有更好的实用性。
流程图
程序的流程如下图所示。从流程图中可以看出,一共初始化了3个AVFormatContext,其中1个用于输入,另外2个分别用于视频输出和音频输出。3个AVFormatContext初始化之后,通过avcodec_copy_context()函数可以将输入视频/音频的参数拷贝至输出视频/音频的AVCodecContext结构体。最后,通过av_read_frame()获取AVPacket,根据AVPacket类型的不同,分别使用av_interleaved_write_frame()写入不同的输出文件中即可。
PS:对于某些封装格式(例如MP4/FLV/MKV等)中的H.264,需要用到名称为“h264_mp4toannexb”的bitstream filter。这一点在前一篇文章《最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)》中,已经有过详细叙述,这里不再重复。
简单介绍一下流程中各个重要函数的意义:
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():写入文件尾。
代码
下面贴上代码:
/** * 最简单的基于FFmpeg的视音频分离器 * Simplest FFmpeg Demuxer * * 雷霄骅 Lei Xiaohua * leixiaohua1020@126.com * 中国传媒大学/数字电视技术 * Communication University of China / Digital TV Technology * http://blog.csdn.net/leixiaohua1020 * * 本程序可以将封装格式中的视频码流数据和音频码流数据分离出来。 * 在该例子中, 将MPEG2TS的文件分离得到H.264视频码流文件和AAC * 音频码流文件。 * * This software split a media file (in Container such as * MKV, FLV, AVI...) to video and audio bitstream. * In this example, it demux a MPEG2TS file to H.264 bitstream * and AAC bitstream. */#include <stdio.h>#define __STDC_CONSTANT_MACROS#ifdef _WIN32//Windowsextern "C"{
#include "libavformat/avformat.h"};#else//Linux...#ifdef __cplusplusextern "C"{
#endif#include <libavformat/avformat.h>#ifdef __cplusplus};#endif#endif/*FIX: H.264 in some container format (FLV, MP4, MKV etc.) need "h264_mp4toannexb" bitstream filter (BSF) *Add SPS,PPS in front of IDR frame *Add start code ("0,0,0,1") in front of NALUH.264 in some container (MPEG2TS) don't need this BSF.*///'1': Use H.264 Bitstream Filter #define USE_H264BSF 0int main(int argc, char* argv[]){ AVOutputFormat *ofmt_a = NULL,*ofmt_v = NULL; //(Input AVFormatContext and Output AVFormatContext) AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx_a = NULL, *ofmt_ctx_v = NULL; AVPacket pkt; int ret, i; int videoindex=-1,audioindex=-1; int frame_index=0; const char *in_filename = "cuc_ieschool.ts";//Input file URL //char *in_filename = "cuc_ieschool.mkv"; const char *out_filename_v = "cuc_ieschool.h264";//Output file URL //char *out_filename_a = "cuc_ieschool.mp3"; const char *out_filename_a = "cuc_ieschool.aac"; av_register_all(); //Input if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) { printf( "Could not open input file."); goto end; } if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) { printf( "Failed to retrieve input stream information"); goto end; } //Output avformat_alloc_output_context2(&ofmt_ctx_v, NULL, NULL, out_filename_v); if (!ofmt_ctx_v) { printf( "Could not create output context\n"); ret = AVERROR_UNKNOWN; goto end; } ofmt_v = ofmt_ctx_v->