首页 > 代码库 > 最简单的基于FFMPEG的转码程序
最简单的基于FFMPEG的转码程序
本文介绍一个简单的基于FFmpeg的转码器。转码器在视音频编解码处理的程序中,属于一个比较复杂的东西。因为它结合了视频的解码和编码。一个视频播放器,一般只包含解码功能;一个视频编码工具,一般只包含编码功能;而一个视频转码器,则需要先对视频进行解码,然后再对视频进行编码,因而相当于解码器和编码器的结合。下图例举了一个视频的转码流程。输入视频的封装格式是FLV,视频编码标准是H.264,音频编码标准是AAC;输出视频的封装格式是AVI,视频编码标准是MPEG2,音频编码标准是MP3。从流程中可以看出,首先从输入视频中分离出视频码流和音频压缩码流,然后分别将视频码流和音频码流进行解码,获取到非压缩的像素数据/音频采样数据,接着将非压缩的像素数据/音频采样数据重新进行编码,获得重新编码后的视频码流和音频码流,最后将视频码流和音频码流重新封装成一个文件。
本文介绍的视频转码器正是使用FFMPEG类库从编程的角度实现了上述流程。
下面贴上代码,代码是从FFmpeg的例子改编的,平台是VC2010,类库版本是2014.5.6。
/* *最简单的基于FFmpeg的转码器 *Simplest FFmpeg Transcoder * *雷霄骅 Lei Xiaohua *leixiaohua1020@126.com *中国传媒大学/数字电视技术 *Communication University of China / DigitalTV Technology *http://blog.csdn.net/leixiaohua1020 * *本程序实现了视频格式之间的转换。是一个最简单的视频转码程序。 * */ #include "stdafx.h" extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavfilter/avfiltergraph.h" #include "libavfilter/avcodec.h" #include "libavfilter/buffersink.h" #include "libavfilter/buffersrc.h" #include "libavutil/avutil.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" }; static AVFormatContext *ifmt_ctx; static AVFormatContext *ofmt_ctx; typedef struct FilteringContext{ AVFilterContext*buffersink_ctx; AVFilterContext*buffersrc_ctx; AVFilterGraph*filter_graph; } FilteringContext; static FilteringContext *filter_ctx; static int open_input_file(const char *filename) { int ret; unsigned int i; ifmt_ctx =NULL; if ((ret = avformat_open_input(&ifmt_ctx,filename, NULL, NULL)) < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot openinput file\n"); return ret; } if ((ret = avformat_find_stream_info(ifmt_ctx, NULL))< 0) { av_log(NULL, AV_LOG_ERROR, "Cannot findstream information\n"); return ret; } for (i = 0; i < ifmt_ctx->nb_streams; i++) { AVStream*stream; AVCodecContext *codec_ctx; stream =ifmt_ctx->streams[i]; codec_ctx =stream->codec; /* Reencode video & audio and remux subtitles etc. */ if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { /* Open decoder */ ret =avcodec_open2(codec_ctx, avcodec_find_decoder(codec_ctx->codec_id), NULL); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Failed toopen decoder for stream #%u\n", i); return ret; } } } av_dump_format(ifmt_ctx, 0, filename, 0); return 0; } static int open_output_file(const char *filename) { AVStream*out_stream; AVStream*in_stream; AVCodecContext*dec_ctx, *enc_ctx; AVCodec*encoder; int ret; unsigned int i; ofmt_ctx =NULL; avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename); if (!ofmt_ctx) { av_log(NULL, AV_LOG_ERROR, "Could notcreate output context\n"); return AVERROR_UNKNOWN; } for (i = 0; i < ifmt_ctx->nb_streams; i++) { out_stream= avformat_new_stream(ofmt_ctx, NULL); if (!out_stream) { av_log(NULL, AV_LOG_ERROR, "Failedallocating output stream\n"); return AVERROR_UNKNOWN; } in_stream =ifmt_ctx->streams[i]; dec_ctx =in_stream->codec; enc_ctx =out_stream->codec; if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { /* in this example, we choose transcoding to same codec */ encoder= avcodec_find_encoder(dec_ctx->codec_id); /* In this example, we transcode to same properties(picture size, * sample rate etc.). These properties can be changed for output * streams easily using filters */ if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { enc_ctx->height = dec_ctx->height; enc_ctx->width = dec_ctx->width; enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio; /* take first format from list of supported formats */ enc_ctx->pix_fmt = encoder->pix_fmts[0]; /* video time_base can be set to whatever is handy andsupported by encoder */ enc_ctx->time_base = dec_ctx->time_base; } else { enc_ctx->sample_rate = dec_ctx->sample_rate; enc_ctx->channel_layout = dec_ctx->channel_layout; enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout); /* take first format from list of supported formats */ enc_ctx->sample_fmt = encoder->sample_fmts[0]; AVRationaltime_base={1, enc_ctx->sample_rate}; enc_ctx->time_base = time_base; } /* Third parameter can be used to pass settings to encoder*/ ret =avcodec_open2(enc_ctx, encoder, NULL); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot openvideo encoder for stream #%u\n", i); return ret; } } else if(dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN) { av_log(NULL, AV_LOG_FATAL, "Elementarystream #%d is of unknown type, cannot proceed\n", i); return AVERROR_INVALIDDATA; } else { /* if this stream must be remuxed */ ret =avcodec_copy_context(ofmt_ctx->streams[i]->codec, ifmt_ctx->streams[i]->codec); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Copyingstream context failed\n"); return ret; } } if (ofmt_ctx->oformat->flags &AVFMT_GLOBALHEADER) enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; } av_dump_format(ofmt_ctx, 0, filename, 1); if (!(ofmt_ctx->oformat->flags &AVFMT_NOFILE)) { ret =avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Could notopen output file '%s'", filename); return ret; } } /* init muxer, write output file header */ ret =avformat_write_header(ofmt_ctx, NULL); if (ret < 0) { av_log(NULL,AV_LOG_ERROR, "Error occurred when openingoutput file\n"); return ret; } return 0; } static intinit_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, AVCodecContext *enc_ctx, const char *filter_spec) { char args[512]; int ret = 0; AVFilter*buffersrc = http://www.mamicode.com/NULL;>程序运行截图:
默认情况下运行程序,会将“cuc_ieschool.ts”转换为“cuc_ieschool.avi”。调试的时候,可以修改“配置属性->调试->命令参数”中的参数,即可改变转码的输入输出文件。
工程下载地址(VC2010):http://download.csdn.net/detail/leixiaohua1020/7394649
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。