zoukankan      html  css  js  c++  java
  • (转)学习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 }
  • 相关阅读:
    jquery 实现 html5 placeholder 兼容password密码框
    php返回json的结果
    使用PHP读取远程文件
    Sharepoint 自定义字段
    Sharepoint 中新增 aspx页面,并在页面中新增web part
    【转】Sharepoint 2010 配置我的站点及BLOG
    JS 实现 Div 向上浮动
    UserProfile同步配置
    【转】Import User Profile Photos from Active Directory into SharePoint 2010
    Sharepoint 2010 SP1升级后 FIMSynchronizationService 服务无法开启
  • 原文地址:https://www.cnblogs.com/jiu0821/p/10247080.html
Copyright © 2011-2022 走看看