最简单的基于FFMPEG的转码程序 [转]

本文介绍一个简单的基于FFmpeg的转码器。它可以将一种视频格式(包括封转格式和编码格式)转换为另一种视频格式。转码器在视音频编解码处理的 程序中,属于一个比较复杂的东西。因为它结合了视频的解码和编码。一个视频播放器,一般只包含解码功能;一个视频编码工具,一般只包含编码功能;而一个视 频转码器,则需要先对视频进行解码,然后再对视频进行编码,因而相当于解码器和编码器的结合。下图例举了一个视频的转码流程。输入视频的封装格式是 FLV,视频编码标准是H.264,音频编码标准是AAC;输出视频的封装格式是AVI,视频编码标准是MPEG2,音频编码标准是MP3。从流程中可以 看出,首先从输入视频中分离出视频码流和音频压缩码流,然后分别将视频码流和音频码流进行解码,获取到非压缩的像素数据/音频采样数据,接着将非压缩的像 素数据/音频采样数据重新进行编码,获得重新编码后的视频码流和音频码流,最后将视频码流和音频码流重新封装成一个文件。

本文介绍的视频转码器正是使用FFMPEG类库从编程的角度实现了上述流程。该例子是从FFmpeg的例子改编的,平台是VC2010,类库版本是2014.5.6。

流程图(2014.9.29更新)

下面附两张使用FFmpeg转码视频的流程图。图中使用浅绿色标出了视频的编码、解码函数。从代码中可以看出,使用了AVFilter的不少东西,因此建议先学习AVFilter的内容后再看这个转码器的源代码。

PS:实际上,转码器不是一定依赖AVFilter的。因此打算有时间对这个转码器进行进一步的简化,使学习的人无需AVFilter的基础也可以理解转码器。

简单介绍一下流程中各个函数的意义:
open_input_file():打开输入文件,并初始化相关的结构体。
open_output_file():打开输出文件,并初始化相关的结构体。
init_filters():初始化AVFilter相关的结构体。
av_read_frame():从输入文件中读取一个AVPacket。
avcodec_decode_video2():解码一个视频AVPacket(存储H.264等压缩码流数据)为AVFrame(存储YUV等非压缩的像素数据)。
avcodec_decode_video4():解码一个音频AVPacket(存储MP3等压缩码流数据)为AVFrame(存储PCM采样数据)。
filter_encode_write_frame():编码一个AVFrame。
flush_encoder():输入文件读取完毕后,输出编码器中剩余的AVPacket。

以上函数中open_input_file(),open_output_file(),init_filters()中的函数在其他文章中都有所叙述,在这里不再重复:

open_input_file()可参考:100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)

open_output_file()可参考:最简单的基于FFMPEG的视频编码器(YUV编码为H.264)

init_filters()可参考:最简单的基于FFmpeg的AVfilter例子(水印叠加)

在这里介绍一下其中编码的函数filter_encode_write_frame()。filter_encode_write_frame()函数的流程如下图所示,它完成了视频/音频的编码功能。

PS:视频和音频的编码流程中除了编码函数avcodec_encode_video2()和avcodec_encode_audio2()不一样之外,其他部分几乎完全一样。

简单介绍一下filter_encode_write_frame()中各个函数的意义:

av_buffersrc_add_frame():将解码后的AVFrame加入Filtergraph。

av_buffersink_get_buffer_ref():从Filtergraph中取一个AVFrame。

avcodec_encode_video2():编码一个视频AVFrame为AVPacket。

avcodec_encode_audio2():编码一个音频AVFrame为AVPacket。

av_interleaved_write_frame():将编码后的AVPacket写入文件。

代码

贴上代码

[cpp] view plaincopy

  1. /*
  2. *最简单的基于FFmpeg的转码器
  3. *Simplest FFmpeg Transcoder
  4. *
  5. *雷霄骅 Lei Xiaohua
  6. *[email protected]
  7. *中国传媒大学/数字电视技术
  8. *Communication University of China / DigitalTV Technology
  9. *http://blog.csdn.net/leixiaohua1020
  10. *
  11. *本程序实现了视频格式之间的转换。是一个最简单的视频转码程序。
  12. *
  13. */
  14. #include "stdafx.h"
  15. extern "C"
  16. {
  17. #include "libavcodec/avcodec.h"
  18. #include "libavformat/avformat.h"
  19. #include "libavfilter/avfiltergraph.h"
  20. #include "libavfilter/avcodec.h"
  21. #include "libavfilter/buffersink.h"
  22. #include "libavfilter/buffersrc.h"
  23. #include "libavutil/avutil.h"
  24. #include "libavutil/opt.h"
  25. #include "libavutil/pixdesc.h"
  26. };
  27. static AVFormatContext *ifmt_ctx;
  28. static AVFormatContext *ofmt_ctx;
  29. typedef struct FilteringContext{
  30. AVFilterContext*buffersink_ctx;
  31. AVFilterContext*buffersrc_ctx;
  32. AVFilterGraph*filter_graph;
  33. } FilteringContext;
  34. static FilteringContext *filter_ctx;
  35. static int open_input_file(const char *filename)
  36. {
  37. int ret;
  38. unsigned int i;
  39. ifmt_ctx =NULL;
  40. if ((ret = avformat_open_input(&ifmt_ctx,filename, NULL, NULL)) < 0) {
  41. av_log(NULL, AV_LOG_ERROR, "Cannot openinput file\n");
  42. return ret;
  43. }
  44. if ((ret = avformat_find_stream_info(ifmt_ctx, NULL))< 0) {
  45. av_log(NULL, AV_LOG_ERROR, "Cannot findstream information\n");
  46. return ret;
  47. }
  48. for (i = 0; i < ifmt_ctx->nb_streams; i++) {
  49. AVStream*stream;
  50. AVCodecContext *codec_ctx;
  51. stream =ifmt_ctx->streams[i];
  52. codec_ctx =stream->codec;
  53. /* Reencode video & audio and remux subtitles etc. */
  54. if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO
  55. ||codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
  56. /* Open decoder */
  57. ret =avcodec_open2(codec_ctx,
  58. avcodec_find_decoder(codec_ctx->codec_id), NULL);
  59. if (ret < 0) {
  60. av_log(NULL, AV_LOG_ERROR, "Failed toopen decoder for stream #%u\n", i);
  61. return ret;
  62. }
  63. }
  64. }
  65. av_dump_format(ifmt_ctx, 0, filename, 0);
  66. return 0;
  67. }
  68. static int open_output_file(const char *filename)
  69. {
  70. AVStream*out_stream;
  71. AVStream*in_stream;
  72. AVCodecContext*dec_ctx, *enc_ctx;
  73. AVCodec*encoder;
  74. int ret;
  75. unsigned int i;
  76. ofmt_ctx =NULL;
  77. avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename);
  78. if (!ofmt_ctx) {
  79. av_log(NULL, AV_LOG_ERROR, "Could notcreate output context\n");
  80. return AVERROR_UNKNOWN;
  81. }
  82. for (i = 0; i < ifmt_ctx->nb_streams; i++) {
  83. out_stream= avformat_new_stream(ofmt_ctx, NULL);
  84. if (!out_stream) {
  85. av_log(NULL, AV_LOG_ERROR, "Failedallocating output stream\n");
  86. return AVERROR_UNKNOWN;
  87. }
  88. in_stream =ifmt_ctx->streams[i];
  89. dec_ctx =in_stream->codec;
  90. enc_ctx =out_stream->codec;
  91. if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO
  92. ||dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
  93. /* in this example, we choose transcoding to same codec */
  94. encoder= avcodec_find_encoder(dec_ctx->codec_id);
  95. /* In this example, we transcode to same properties(picture size,
  96. * sample rate etc.). These properties can be changed for output
  97. * streams easily using filters */
  98. if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
  99. enc_ctx->height = dec_ctx->height;
  100. enc_ctx->width = dec_ctx->width;
  101. enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;
  102. /* take first format from list of supported formats */
  103. enc_ctx->pix_fmt = encoder->pix_fmts[0];
  104. /* video time_base can be set to whatever is handy andsupported by encoder */
  105. enc_ctx->time_base = dec_ctx->time_base;
  106. } else {
  107. enc_ctx->sample_rate = dec_ctx->sample_rate;
  108. enc_ctx->channel_layout = dec_ctx->channel_layout;
  109. enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
  110. /* take first format from list of supported formats */
  111. enc_ctx->sample_fmt = encoder->sample_fmts[0];
  112. AVRationaltime_base={1, enc_ctx->sample_rate};
  113. enc_ctx->time_base = time_base;
  114. }
  115. /* Third parameter can be used to pass settings to encoder*/
  116. ret =avcodec_open2(enc_ctx, encoder, NULL);
  117. if (ret < 0) {
  118. av_log(NULL, AV_LOG_ERROR, "Cannot openvideo encoder for stream #%u\n", i);
  119. return ret;
  120. }
  121. } else if(dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN) {
  122. av_log(NULL, AV_LOG_FATAL, "Elementarystream #%d is of unknown type, cannot proceed\n", i);
  123. return AVERROR_INVALIDDATA;
  124. } else {
  125. /* if this stream must be remuxed */
  126. ret =avcodec_copy_context(ofmt_ctx->streams[i]->codec,
  127. ifmt_ctx->streams[i]->codec);
  128. if (ret < 0) {
  129. av_log(NULL, AV_LOG_ERROR, "Copyingstream context failed\n");
  130. return ret;
  131. }
  132. }
  133. if (ofmt_ctx->oformat->flags &AVFMT_GLOBALHEADER)
  134. enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
  135. }
  136. av_dump_format(ofmt_ctx, 0, filename, 1);
  137. if (!(ofmt_ctx->oformat->flags &AVFMT_NOFILE)) {
  138. ret =avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);
  139. if (ret < 0) {
  140. av_log(NULL, AV_LOG_ERROR, "Could notopen output file ‘%s‘", filename);
  141. return ret;
  142. }
  143. }
  144. /* init muxer, write output file header */
  145. ret =avformat_write_header(ofmt_ctx, NULL);
  146. if (ret < 0) {
  147. av_log(NULL,AV_LOG_ERROR, "Error occurred when openingoutput file\n");
  148. return ret;
  149. }
  150. return 0;
  151. }
  152. static intinit_filter(FilteringContext* fctx, AVCodecContext *dec_ctx,
  153. AVCodecContext *enc_ctx, const char *filter_spec)
  154. {
  155. char args[512];
  156. int ret = 0;
  157. AVFilter*buffersrc = NULL;
  158. AVFilter*buffersink = NULL;
  159. AVFilterContext*buffersrc_ctx = NULL;
  160. AVFilterContext*buffersink_ctx = NULL;
  161. AVFilterInOut*outputs = avfilter_inout_alloc();
  162. AVFilterInOut*inputs  = avfilter_inout_alloc();
  163. AVFilterGraph*filter_graph = avfilter_graph_alloc();
  164. if (!outputs || !inputs || !filter_graph) {
  165. ret =AVERROR(ENOMEM);
  166. goto end;
  167. }
  168. if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
  169. buffersrc =avfilter_get_by_name("buffer");
  170. buffersink= avfilter_get_by_name("buffersink");
  171. if (!buffersrc || !buffersink) {
  172. av_log(NULL, AV_LOG_ERROR, "filteringsource or sink element not found\n");
  173. ret = AVERROR_UNKNOWN;
  174. goto end;
  175. }
  176. _snprintf(args, sizeof(args),
  177. "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
  178. dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
  179. dec_ctx->time_base.num,dec_ctx->time_base.den,
  180. dec_ctx->sample_aspect_ratio.num,
  181. dec_ctx->sample_aspect_ratio.den);
  182. ret =avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
  183. args, NULL, filter_graph);
  184. if (ret < 0) {
  185. av_log(NULL, AV_LOG_ERROR, "Cannotcreate buffer source\n");
  186. goto end;
  187. }
  188. ret =avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
  189. NULL, NULL, filter_graph);
  190. if (ret < 0) {
  191. av_log(NULL, AV_LOG_ERROR, "Cannotcreate buffer sink\n");
  192. goto end;
  193. }
  194. ret =av_opt_set_bin(buffersink_ctx, "pix_fmts",
  195. (uint8_t*)&enc_ctx->pix_fmt, sizeof(enc_ctx->pix_fmt),
  196. AV_OPT_SEARCH_CHILDREN);
  197. if (ret < 0) {
  198. av_log(NULL, AV_LOG_ERROR, "Cannot setoutput pixel format\n");
  199. goto end;
  200. }
  201. } else if(dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
  202. buffersrc = avfilter_get_by_name("abuffer");
  203. buffersink= avfilter_get_by_name("abuffersink");
  204. if (!buffersrc || !buffersink) {
  205. av_log(NULL, AV_LOG_ERROR, "filteringsource or sink element not found\n");
  206. ret =AVERROR_UNKNOWN;
  207. goto end;
  208. }
  209. if (!dec_ctx->channel_layout)
  210. dec_ctx->channel_layout =
  211. av_get_default_channel_layout(dec_ctx->channels);
  212. _snprintf(args, sizeof(args),
  213. "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
  214. dec_ctx->time_base.num, dec_ctx->time_base.den,dec_ctx->sample_rate,
  215. av_get_sample_fmt_name(dec_ctx->sample_fmt),
  216. dec_ctx->channel_layout);
  217. ret =avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
  218. args, NULL, filter_graph);
  219. if (ret < 0) {
  220. av_log(NULL, AV_LOG_ERROR, "Cannotcreate audio buffer source\n");
  221. goto end;
  222. }
  223. ret =avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
  224. NULL, NULL, filter_graph);
  225. if (ret < 0) {
  226. av_log(NULL, AV_LOG_ERROR, "Cannotcreate audio buffer sink\n");
  227. goto end;
  228. }
  229. ret = av_opt_set_bin(buffersink_ctx, "sample_fmts",
  230. (uint8_t*)&enc_ctx->sample_fmt, sizeof(enc_ctx->sample_fmt),
  231. AV_OPT_SEARCH_CHILDREN);
  232. if (ret < 0) {
  233. av_log(NULL, AV_LOG_ERROR, "Cannot setoutput sample format\n");
  234. goto end;
  235. }
  236. ret =av_opt_set_bin(buffersink_ctx, "channel_layouts",
  237. (uint8_t*)&enc_ctx->channel_layout,
  238. sizeof(enc_ctx->channel_layout),AV_OPT_SEARCH_CHILDREN);
  239. if (ret < 0) {
  240. av_log(NULL, AV_LOG_ERROR, "Cannot setoutput channel layout\n");
  241. goto end;
  242. }
  243. ret =av_opt_set_bin(buffersink_ctx, "sample_rates",
  244. (uint8_t*)&enc_ctx->sample_rate, sizeof(enc_ctx->sample_rate),
  245. AV_OPT_SEARCH_CHILDREN);
  246. if (ret < 0) {
  247. av_log(NULL, AV_LOG_ERROR, "Cannot setoutput sample rate\n");
  248. goto end;
  249. }
  250. } else {
  251. ret =AVERROR_UNKNOWN;
  252. goto end;
  253. }
  254. /* Endpoints for the filter graph. */
  255. outputs->name       =av_strdup("in");
  256. outputs->filter_ctx = buffersrc_ctx;
  257. outputs->pad_idx    = 0;
  258. outputs->next       = NULL;
  259. inputs->name       = av_strdup("out");
  260. inputs->filter_ctx = buffersink_ctx;
  261. inputs->pad_idx    = 0;
  262. inputs->next       = NULL;
  263. if (!outputs->name || !inputs->name) {
  264. ret =AVERROR(ENOMEM);
  265. goto end;
  266. }
  267. if ((ret = avfilter_graph_parse_ptr(filter_graph,filter_spec,
  268. &inputs, &outputs, NULL)) < 0)
  269. goto end;
  270. if ((ret = avfilter_graph_config(filter_graph, NULL))< 0)
  271. goto end;
  272. /* Fill FilteringContext */
  273. fctx->buffersrc_ctx = buffersrc_ctx;
  274. fctx->buffersink_ctx = buffersink_ctx;
  275. fctx->filter_graph= filter_graph;
  276. end:
  277. avfilter_inout_free(&inputs);
  278. avfilter_inout_free(&outputs);
  279. return ret;
  280. }
  281. static int init_filters(void)
  282. {
  283. const char*filter_spec;
  284. unsigned int i;
  285. int ret;
  286. filter_ctx =(FilteringContext *)av_malloc_array(ifmt_ctx->nb_streams, sizeof(*filter_ctx));
  287. if (!filter_ctx)
  288. return AVERROR(ENOMEM);
  289. for (i = 0; i < ifmt_ctx->nb_streams; i++) {
  290. filter_ctx[i].buffersrc_ctx  =NULL;
  291. filter_ctx[i].buffersink_ctx= NULL;
  292. filter_ctx[i].filter_graph   =NULL;
  293. if(!(ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO
  294. ||ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO))
  295. continue;
  296. if (ifmt_ctx->streams[i]->codec->codec_type== AVMEDIA_TYPE_VIDEO)
  297. filter_spec = "null"; /* passthrough (dummy) filter for video */
  298. else
  299. filter_spec = "anull"; /* passthrough (dummy) filter for audio */
  300. ret =init_filter(&filter_ctx[i], ifmt_ctx->streams[i]->codec,
  301. ofmt_ctx->streams[i]->codec, filter_spec);
  302. if (ret)
  303. return ret;
  304. }
  305. return 0;
  306. }
  307. static intencode_write_frame(AVFrame *filt_frame, unsignedint stream_index, int*got_frame) {
  308. int ret;
  309. int got_frame_local;
  310. AVPacketenc_pkt;
  311. int (*enc_func)(AVCodecContext *, AVPacket *, const AVFrame *, int*) =
  312. (ifmt_ctx->streams[stream_index]->codec->codec_type ==
  313. AVMEDIA_TYPE_VIDEO) ? avcodec_encode_video2 : avcodec_encode_audio2;
  314. if (!got_frame)
  315. got_frame =&got_frame_local;
  316. av_log(NULL,AV_LOG_INFO, "Encoding frame\n");
  317. /* encode filtered frame */
  318. enc_pkt.data =NULL;
  319. enc_pkt.size =0;
  320. av_init_packet(&enc_pkt);
  321. ret =enc_func(ofmt_ctx->streams[stream_index]->codec, &enc_pkt,
  322. filt_frame, got_frame);
  323. av_frame_free(&filt_frame);
  324. if (ret < 0)
  325. return ret;
  326. if (!(*got_frame))
  327. return 0;
  328. /* prepare packet for muxing */
  329. enc_pkt.stream_index = stream_index;
  330. enc_pkt.dts =av_rescale_q_rnd(enc_pkt.dts,
  331. ofmt_ctx->streams[stream_index]->codec->time_base,
  332. ofmt_ctx->streams[stream_index]->time_base,
  333. (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  334. enc_pkt.pts =av_rescale_q_rnd(enc_pkt.pts,
  335. ofmt_ctx->streams[stream_index]->codec->time_base,
  336. ofmt_ctx->streams[stream_index]->time_base,
  337. (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  338. enc_pkt.duration = av_rescale_q(enc_pkt.duration,
  339. ofmt_ctx->streams[stream_index]->codec->time_base,
  340. ofmt_ctx->streams[stream_index]->time_base);
  341. av_log(NULL,AV_LOG_DEBUG, "Muxing frame\n");
  342. /* mux encoded frame */
  343. ret =av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
  344. return ret;
  345. }
  346. static intfilter_encode_write_frame(AVFrame *frame, unsignedint stream_index)
  347. {
  348. int ret;
  349. AVFrame*filt_frame;
  350. av_log(NULL,AV_LOG_INFO, "Pushing decoded frame tofilters\n");
  351. /* push the decoded frame into the filtergraph */
  352. ret =av_buffersrc_add_frame_flags(filter_ctx[stream_index].buffersrc_ctx,
  353. frame,0);
  354. if (ret < 0) {
  355. av_log(NULL, AV_LOG_ERROR, "Error whilefeeding the filtergraph\n");
  356. return ret;
  357. }
  358. /* pull filtered frames from the filtergraph */
  359. while (1) {
  360. filt_frame= av_frame_alloc();
  361. if (!filt_frame) {
  362. ret =AVERROR(ENOMEM);
  363. break;
  364. }
  365. av_log(NULL, AV_LOG_INFO, "Pullingfiltered frame from filters\n");
  366. ret =av_buffersink_get_frame(filter_ctx[stream_index].buffersink_ctx,
  367. filt_frame);
  368. if (ret < 0) {
  369. /* if nomore frames for output - returns AVERROR(EAGAIN)
  370. * if flushed and no more frames for output - returns AVERROR_EOF
  371. * rewrite retcode to 0 to show it as normal procedure completion
  372. */
  373. if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
  374. ret= 0;
  375. av_frame_free(&filt_frame);
  376. break;
  377. }
  378. filt_frame->pict_type = AV_PICTURE_TYPE_NONE;
  379. ret =encode_write_frame(filt_frame, stream_index, NULL);
  380. if (ret < 0)
  381. break;
  382. }
  383. return ret;
  384. }
  385. static int flush_encoder(unsigned intstream_index)
  386. {
  387. int ret;
  388. int got_frame;
  389. if(!(ofmt_ctx->streams[stream_index]->codec->codec->capabilities&
  390. CODEC_CAP_DELAY))
  391. return 0;
  392. while (1) {
  393. av_log(NULL, AV_LOG_INFO, "Flushingstream #%u encoder\n", stream_index);
  394. ret =encode_write_frame(NULL, stream_index, &got_frame);
  395. if (ret < 0)
  396. break;
  397. if (!got_frame)
  398. return 0;
  399. }
  400. return ret;
  401. }
  402. int_tmain(int argc, _TCHAR* argv[])
  403. {
  404. int ret;
  405. AVPacketpacket;
  406. AVFrame *frame= NULL;
  407. enum AVMediaType type;
  408. unsigned intstream_index;
  409. unsigned int i;
  410. int got_frame;
  411. int (*dec_func)(AVCodecContext *, AVFrame *, int *, const AVPacket*);
  412. if (argc != 3) {
  413. av_log(NULL, AV_LOG_ERROR, "Usage: %s<input file> <output file>\n", argv[0]);
  414. return 1;
  415. }
  416. av_register_all();
  417. avfilter_register_all();
  418. if ((ret = open_input_file(argv[1])) < 0)
  419. goto end;
  420. if ((ret = open_output_file(argv[2])) < 0)
  421. goto end;
  422. if ((ret = init_filters()) < 0)
  423. goto end;
  424. /* read all packets */
  425. while (1) {
  426. if ((ret= av_read_frame(ifmt_ctx, &packet)) < 0)
  427. break;
  428. stream_index = packet.stream_index;
  429. type =ifmt_ctx->streams[packet.stream_index]->codec->codec_type;
  430. av_log(NULL, AV_LOG_DEBUG, "Demuxergave frame of stream_index %u\n",
  431. stream_index);
  432. if (filter_ctx[stream_index].filter_graph) {
  433. av_log(NULL, AV_LOG_DEBUG, "Going toreencode&filter the frame\n");
  434. frame =av_frame_alloc();
  435. if (!frame) {
  436. ret = AVERROR(ENOMEM);
  437. break;
  438. }
  439. packet.dts = av_rescale_q_rnd(packet.dts,
  440. ifmt_ctx->streams[stream_index]->time_base,
  441. ifmt_ctx->streams[stream_index]->codec->time_base,
  442. (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  443. packet.pts = av_rescale_q_rnd(packet.pts,
  444. ifmt_ctx->streams[stream_index]->time_base,
  445. ifmt_ctx->streams[stream_index]->codec->time_base,
  446. (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  447. dec_func = (type == AVMEDIA_TYPE_VIDEO) ? avcodec_decode_video2 :
  448. avcodec_decode_audio4;
  449. ret =dec_func(ifmt_ctx->streams[stream_index]->codec, frame,
  450. &got_frame, &packet);
  451. if (ret < 0) {
  452. av_frame_free(&frame);
  453. av_log(NULL, AV_LOG_ERROR, "Decodingfailed\n");
  454. break;
  455. }
  456. if (got_frame) {
  457. frame->pts = av_frame_get_best_effort_timestamp(frame);
  458. ret= filter_encode_write_frame(frame, stream_index);
  459. av_frame_free(&frame);
  460. if (ret< 0)
  461. goto end;
  462. } else {
  463. av_frame_free(&frame);
  464. }
  465. } else {
  466. /* remux this frame without reencoding */
  467. packet.dts = av_rescale_q_rnd(packet.dts,
  468. ifmt_ctx->streams[stream_index]->time_base,
  469. ofmt_ctx->streams[stream_index]->time_base,
  470. (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  471. packet.pts = av_rescale_q_rnd(packet.pts,
  472. ifmt_ctx->streams[stream_index]->time_base,
  473. ofmt_ctx->streams[stream_index]->time_base,
  474. (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  475. ret =av_interleaved_write_frame(ofmt_ctx, &packet);
  476. if (ret < 0)
  477. goto end;
  478. }
  479. av_free_packet(&packet);
  480. }
  481. /* flush filters and encoders */
  482. for (i = 0; i < ifmt_ctx->nb_streams; i++) {
  483. /* flush filter */
  484. if (!filter_ctx[i].filter_graph)
  485. continue;
  486. ret =filter_encode_write_frame(NULL, i);
  487. if (ret < 0) {
  488. av_log(NULL, AV_LOG_ERROR, "Flushingfilter failed\n");
  489. goto end;
  490. }
  491. /* flush encoder */
  492. ret = flush_encoder(i);
  493. if (ret < 0) {
  494. av_log(NULL, AV_LOG_ERROR, "Flushingencoder failed\n");
  495. goto end;
  496. }
  497. }
  498. av_write_trailer(ofmt_ctx);
  499. end:
  500. av_free_packet(&packet);
  501. av_frame_free(&frame);
  502. for (i = 0; i < ifmt_ctx->nb_streams; i++) {
  503. avcodec_close(ifmt_ctx->streams[i]->codec);
  504. if (ofmt_ctx && ofmt_ctx->nb_streams >i && ofmt_ctx->streams[i] &&ofmt_ctx->streams[i]->codec)
  505. avcodec_close(ofmt_ctx->streams[i]->codec);
  506. if(filter_ctx && filter_ctx[i].filter_graph)
  507. avfilter_graph_free(&filter_ctx[i].filter_graph);
  508. }
  509. av_free(filter_ctx);
  510. avformat_close_input(&ifmt_ctx);
  511. if (ofmt_ctx &&!(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
  512. avio_close(ofmt_ctx->pb);
  513. avformat_free_context(ofmt_ctx);
  514. if (ret < 0)
  515. av_log(NULL, AV_LOG_ERROR, "Erroroccurred\n");
  516. return (ret? 1:0);
  517. }

程序运行截图:

默认情况下运行程序,会将“cuc_ieschool.ts”转换为“cuc_ieschool.avi”。调试的时候,可以修改“配置属性->调试->命令参数”中的参数,即可改变转码的输入输出文件。

工程下载地址(VC2010):http://download.csdn.net/detail/leixiaohua1020/7394649

时间: 2024-10-12 07:45:17

最简单的基于FFMPEG的转码程序 [转]的相关文章

最简单的基于FFMPEG的转码程序 [转] —— 分析

模块:  libavcodec    - 编码解码器         libavdevice   - 输入输出设备的支持         libavfilter   - 视音频滤镜支持         libavformat   - 视音频等格式的解析         libavutil     - 工具库         libpostproc   - 后期效果处理         libswscale    - 图像颜色.尺寸转换 1. 主函数分析: int_tmain(int argc, 

最简单的基于FFMPEG的转码程序

本文介绍一个简单的基于FFmpeg的转码器.转码器在视音频编解码处理的程序中,属于一个比较复杂的东西.因为它结合了视频的解码和编码.一个视频播放器,一般只包含解码功能:一个视频编码工具,一般只包含编码功能:而一个视频转码器,则需要先对视频进行解码,然后再对视频进行编码,因而相当于解码器和编码器的结合.下图例举了一个视频的转码流程.输入视频的封装格式是FLV,视频编码标准是H.264,音频编码标准是AAC:输出视频的封装格式是AVI,视频编码标准是MPEG2,音频编码标准是MP3.从流程中可以看出

最简单的基于FFMPEG的转码程序分析 +ffmpga代码简析(转 +总结)

模块:  libavcodec    - 编码解码器         libavdevice   - 输入输出设备的支持         libavfilter   - 视音频滤镜支持         libavformat   - 视音频等格式的解析         libavutil     - 工具库         libpostproc   - 后期效果处理         libswscale    - 图像颜色.尺寸转换 1. ffmpga代码简析 1.1 av_log() av_

最简单的基于FFmpeg的内存读写的例子:内存转码器

上篇文章记录了一个基于FFmpeg的内存播放器,可以使用FFmpeg读取并播放内存中的数据.这篇文章记录一个基于FFmpeg的内存转码器.该转码器可以使用FFmpeg读取内存中的数据,转码为H.264之后再将数据输出到内存.关于如何从内存读取数据,以及如何将数据输出到内存,可以参考文章: ffmpeg 从内存中读取数据(或将数据输出到内存) FFmpeg读写内存的关键点有2个:1.       初始化自定义的AVIOContext,指定自定义的回调函数.2.       自己写回调函数.注意函数

最简单的基于FFmpeg的内存读写的例子:内存播放器

打算记录两个最简单的FFmpeg进行内存读写的例子.之前的所有有关FFmpeg的例子都是对文件进行操作的.例如<100行代码实现最简单的基于FFMPEG+SDL的视频播放器>播放的是一个视频的文件.而<最简单的基于FFMPEG的转码程序>也是将一个视频文件转换为另一个视频文件.<最简单的基于FFmpeg的视频编码器(YUV编码为H.264)>也是最后编码得到一个H.264视频文件.实际上,并不是所有视频的编码,解码都是针对文件进行处理的.有的时候需要的解码的视频数据在一

(转)最简单的基于FFmpeg的内存读写的例子:内存播放器

ffmpeg内存播放解码 目录(?)[+] ===================================================== 最简单的基于FFmpeg的内存读写的例子系列文章列表: 最简单的基于FFmpeg的内存读写的例子:内存播放器 最简单的基于FFmpeg的内存读写的例子:内存转码器 ===================================================== 打算记录两个最简单的FFmpeg进行内存读写的例子.之前的所有有关FFmpe

最简单的基于FFmpeg的移动端例子:Android 转码器

本文记录一个安卓平台下基于FFmpeg的视频转码器.该转码器实际上移植自ffmpeg工程中的ffmpeg.c源代码.有关ffmpeg.c的源代码可以参考文章<ffmpeg.c函数结构简单分析(画图)>,在这里就不重复记录了. 源代码 项目的目录结构如图所示.Java源代码位于src目录,而C代码位于jni目录. Android程序Java端代码位于src\com\leixiaohua1020\sffmpegandroidtranscoder\MainActivity.java,如下所示. /*

最简单的基于FFmpeg的移动端样例:IOS 视频转码器

===================================================== 最简单的基于FFmpeg的移动端样例系列文章列表: 最简单的基于FFmpeg的移动端样例:Android HelloWorld 最简单的基于FFmpeg的移动端样例:Android 视频解码器 最简单的基于FFmpeg的移动端样例:Android 视频解码器-单个库版 最简单的基于FFmpeg的移动端样例:Android 推流器 最简单的基于FFmpeg的移动端样例:Android 视频转

最简单的基于FFmpeg的移动端例子:IOS 视频转码器

本文记录iOS平台下基于FFmpeg的视频转码器.该转码器实际上移植自ffmpeg工程中的ffmpeg.c源代码.有关ffmpeg.c的源代码可以参考文章<ffmpeg.c函数结构简单分析(画图)>,在这里就不重复记录了. 源代码 项目的目录结构如图所示. 下列C语言文件拷贝自FFmpeg源代码: cmdutils.ccmdutils.hcmdutils_common_opts.hconfig.hffmpeg.hffmpeg_filter.cffmpeg_opt.c 此外在编译ffmpeg.c