(转)学习ffmpeg官方示例transcoding.c遇到的问题和解决方法

转自:https://blog.csdn.net/w_z_z_1991/article/details/53002416

 Top

最近学习ffmpeg,官网提供的示例代码transcoding.c演示了编解码和滤波器的使用,不过第一步的编译运行测试就卡了好久,今天终于找到了原因了,赶紧记录一下,我相信和我遇到同样问题的人不在少数,所以希望能为大家提供一篇有效的解决方案,减轻入门时的痛苦。

把官网示例拷一份在本地,以相同的名字命名为transcoding.c, 因为官网的这个示例,用的是ffmpeg2.x的API,因为我也不太熟悉ffmpeg,用ffmpeg3.x编译时,提示了我几个API过时的问题,所以我装回了ffmpeg2.8.6来编译这个示例。下面是我的编译命令:

gcc -I /usr/local/include/ -L /usr/local/lib -lavformat -lavfilter -lavutil -lswscale -lavcodec transcoding.c -o transcoding    

生成了名为transcoding的二进制可执行文件,我使用自己的一个测试视频运行它:

./transcoding test.mp4 output.mp4

运行结果如下:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 1
    compatible_brands: isomavc1
    creation_time   : 2016-01-10 07:17:18
    encoder         : FormatFactory : www.pcfreetime.com
  Duration: 00:01:41.49, start: 0.000000, bitrate: 863 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 856x480 [SAR 480:481 DAR 856:481], 744 kb/s, SAR 427:428 DAR 427:240, 24 fps, 24 tbr, 24k tbn, 48 tbc (default)
    Metadata:
      creation_time   : 2016-01-10 07:17:18
      handler_name    : video
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 116 kb/s (default)
    Metadata:
      creation_time   : 2016-01-10 07:17:18
      handler_name    : sound
[libx264 @ 0x7fe4ac851600] broken ffmpeg default settings detected
[libx264 @ 0x7fe4ac851600] use an encoding preset (e.g. -vpre medium)
[libx264 @ 0x7fe4ac851600] preset usage: -vpre <speed> -vpre <profile>
[libx264 @ 0x7fe4ac851600] speed presets are listed in x264 --help
[libx264 @ 0x7fe4ac851600] profile is optional; x264 defaults to high
Cannot open video encoder for stream #0
Error occurred: Generic error in an external library

#issue 1 - [libx264 @ 0x7fe4ac851600] broken ffmpeg default settings detected

这个错误及其下面的信息告诉我们,在打开输出文件的视频编码器时出现了错误,这通常是由于编码器参数设置不当造成的。通过搜索,发现了这篇文章对这个问题解释的比较清楚: 
http://blog.csdn.net/cffishappy/article/details/7680097

解决方法:

transcoding.c中的open_output_file函数中,修改的部分如下(只增加了13-17行):

 1 if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
 2                 enc_ctx->height = dec_ctx->height;
 3                 enc_ctx->width = dec_ctx->width;
 4                 enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;
 5                 /* take first format from list of supported formats */
 6                 if (encoder->pix_fmts)
 7                     enc_ctx->pix_fmt = encoder->pix_fmts[0];
 8                 else
 9                     enc_ctx->pix_fmt = dec_ctx->pix_fmt;
10                 /* video time_base can be set to whatever is handy and supported by encoder */
11                 enc_ctx->time_base = dec_ctx->time_base;
12 
13                 enc_ctx->me_range = 16; 
14                 enc_ctx->max_qdiff = 4;
15                 enc_ctx->qmin = 10; 
16                 enc_ctx->qmax = 51; 
17                 enc_ctx->qcompress = 0.6;
18 
19             } else {
20                 enc_ctx->sample_rate = dec_ctx->sample_rate;
21                 enc_ctx->channel_layout = dec_ctx->channel_layout;
22                 enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
23                 /* take first format from list of supported formats */
24                 enc_ctx->sample_fmt = encoder->sample_fmts[0];
25                 enc_ctx->time_base = (AVRational){1, enc_ctx->sample_rate};
26             }   

之后,我们保存编译再次运行结果如下:

 1 ...
 2 Encoding frame
 3 Pulling filtered frame from filters
 4 Pushing decoded frame to filters
 5 Pulling filtered frame from filters
 6 Encoding frame
 7 [mp4 @ 0x7fbe86803e00] Malformed AAC bitstream detected: use the audio bitstream filter 'aac_adtstoasc' to fix it ('-bsf:a aac_adtstoasc' option with ffmpeg)
 8 [libx264 @ 0x7fbe86804400] frame I:1     Avg QP:45.67  size:  5439
 9 [libx264 @ 0x7fbe86804400] frame P:1     Avg QP:46.05  size:   174
10 [libx264 @ 0x7fbe86804400] mb I  I16..4: 71.7% 26.7%  1.5%
11 [libx264 @ 0x7fbe86804400] mb P  I16..4:  0.2%  0.0%  0.0%  P16..4:  5.2%  0.2%  0.0%  0.0%  0.0%    skip:94.4%
12 [libx264 @ 0x7fbe86804400] final ratefactor: 56.92
13 [libx264 @ 0x7fbe86804400] 8x8 transform intra:26.7%
14 [libx264 @ 0x7fbe86804400] coded y,uvDC,uvAC intra: 8.4% 33.3% 10.1% inter: 0.0% 0.1% 0.0%
15 [libx264 @ 0x7fbe86804400] i16 v,h,dc,p: 39% 34%  7% 19%
16 [libx264 @ 0x7fbe86804400] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu:  6% 15% 22% 10% 10%  7% 16%  5%  9%
17 [libx264 @ 0x7fbe86804400] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu:  8% 33% 12% 10%  8%  8% 15%  2%  4%
18 [libx264 @ 0x7fbe86804400] i8c dc,h,v,p: 70% 16% 11%  3%
19 [libx264 @ 0x7fbe86804400] Weighted P-Frames: Y:0.0% UV:0.0%
20 [libx264 @ 0x7fbe86804400] kb/s:538.85
21 [libfaac @ 0x7fbe862d2600] 4 frames left in the queue on closing
22 Error occurred: Operation not permitted

这次的视频编码可以打开并正常编码了,可是音频部分又出现了问题,关于这个问题的解答可以看这个文章: 
http://www.tuicool.com/articles/NNNVv2z

#issue2 - [mp4 @ 0x7fbe86803e00] Malformed AAC bitstream detected

这个问题在网上搜了好久,stackoverflow中提供了一种方法,可以使程序正常运行,但处理结果中只有音频被保留, 这显然不是我想要的。

其实,只需要调整一下代码顺序就可以了。知道真相的我眼泪掉下来。

解决方法

还是在transcoding.c中的open_output_file函数中,只是把for循环尾部的那句代码:

1 if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
2                 enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; 

提前到for循环中整个if判断结构的前面就行了,因为我们在打开编码器前,没有设置编码器上下文中enc_ctx->flags这个参数,所以把这句提前了就解决问题了。如下:

 1             if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
 2                 enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
 3 
 4             if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
 5                 enc_ctx->height = dec_ctx->height;
 6                 enc_ctx->width = dec_ctx->width;
 7                 enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;
 8                 /* take first format from list of supported formats */
 9                 if (encoder->pix_fmts)
10                     enc_ctx->pix_fmt = encoder->pix_fmts[0];
11                 else
12                     enc_ctx->pix_fmt = dec_ctx->pix_fmt;
13                 /* video time_base can be set to whatever is handy and supported by encoder */
14                 enc_ctx->time_base = dec_ctx->time_base;
15 
16                 enc_ctx->me_range = 16;
17                 enc_ctx->max_qdiff = 4;
18                 enc_ctx->qmin = 10;
19                 enc_ctx->qmax = 51;
20                 enc_ctx->qcompress = 0.6;
21 
22             } else {
23                 enc_ctx->sample_rate = dec_ctx->sample_rate;
24                 enc_ctx->channel_layout = dec_ctx->channel_layout;
25                 enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
26                 /* take first format from list of supported formats */
27                 enc_ctx->sample_fmt = encoder->sample_fmts[0];
28                 enc_ctx->time_base = (AVRational){1, enc_ctx->sample_rate};
29             }

#issue3 - 处理后的结果比原视频模糊

在经过以上两个问题的解决后,编译通过是没有问题了,不过你可能会不满意输出视频的质量,觉得它比原视频模糊了许多,这时我们可以调节\#issue1中的代码:

1 enc_ctx->qmax = 51; 

把这个参数改小点,可以减小编码时的量化间隔,提高编码视频的质量,不过你可能因此加长整个编码的时间。

例如我将其改为:

1 enc_ctx->qmax = 30;

最后附上修改后的完整代码:

filename: transcoding.c

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

 

posted @ 2019-01-09 21:52  jiu~  阅读(2491)  评论(0编辑  收藏  举报