本例子是由FFEMPG的doc/example例子transcode.c修改而來,可以根據需求任意轉換音視頻的編碼。
原來的例子的作用更類似於remux,並沒有實現轉碼的功能,只是實現了格式轉換,比如ts轉avi等。並不能實現音視頻編碼格式的轉換,比如將h264轉為mpeg2。
FFMPEG轉碼的實現有多種方式:
一種方式是:流解複用->視頻+音頻流->解碼->YUV/PCM等->視音頻編碼->重建的音視頻流->複用->流
另一種方式依賴AVFilter,這一部分在另外的幾篇文章中解釋怎麼用。雖然AVFilter學習起來可能比較困難,但是在實際的編程應用中,依靠AVFilter做轉碼效率比第一種方式高,並且解碼的CPU和時間消耗也少的多。所以,還是建議好好學習這部分的,畢竟我一直覺得FFMPEG的強項就是解碼和轉碼。
本例子是視頻mpeg2轉h264,音頻mpegaudio轉g711。
[cpp] view plain copy print ? /* * based on FFMPEG transcode.c * modified by tongli */ #include <stdio.h> #include "snprintf.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/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 open input file\n"); return ret; } if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot find stream 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;