(转)学习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 }