1. 程式人生 > >FFMPEG實現的轉碼程序

FFMPEG實現的轉碼程序

enc yuv sso oba avstream med ext lin repl

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

源代碼下載:

csdn工程:http://download.csdn.NET/detail/rootusers/8425619

from:http://blog.csdn.net/rootusers/article/details/43488827

FFMPEG實現的轉碼程序