• (转)学习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
    ");
     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
    ");
     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
    ", 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
    ");
     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
    ");
     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
    ");
    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
    ", 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
    ", 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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ", 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>
    ", 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
    ",
    447                 stream_index);
    448         if (filter_ctx[stream_index].filter_graph) {
    449             av_log(NULL, AV_LOG_DEBUG, "Going to reencode&filter the frame
    ");
    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
    ");
    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
    ");
    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
    ");
    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
    ", av_err2str(ret));
    522     return ret ? 1 : 0;
    523 }
  • 相关阅读:
    我的家庭保险方案推荐
    如何修改Total Commander配件文件的位置
    豆瓣统计-2015
    RESTful API接口设计规范
    正则表达式中 的$1,$2与实际应用
    查询排序:order by case when理解、在order By子句中使用case语句的理解
    架构设计:BFF和Serverless简介
    移动端1px细线解决方案总结
    SpringMVC中实体类属性is开头的字段返回JSON时自动去掉is开头的问题
    详解JS面向对象的三大特征之多态
  • 原文地址:https://www.cnblogs.com/jiu0821/p/10247080.html
Copyright © 2020-2023  润新知