LCOV - code coverage report
Current view: top level - src/libavfilter - af_resample.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 163 0.0 %
Date: 2017-07-21 15:41:20 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /*
       2             :  * This file is part of FFmpeg.
       3             :  *
       4             :  * FFmpeg is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Lesser General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2.1 of the License, or (at your option) any later version.
       8             :  *
       9             :  * FFmpeg is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Lesser General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Lesser General Public
      15             :  * License along with FFmpeg; if not, write to the Free Software
      16             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      17             :  */
      18             : 
      19             : /**
      20             :  * @file
      21             :  * sample format and channel layout conversion audio filter
      22             :  */
      23             : 
      24             : #include "libavutil/avassert.h"
      25             : #include "libavutil/avstring.h"
      26             : #include "libavutil/common.h"
      27             : #include "libavutil/dict.h"
      28             : #include "libavutil/mathematics.h"
      29             : #include "libavutil/opt.h"
      30             : 
      31             : #include "libavresample/avresample.h"
      32             : 
      33             : #include "audio.h"
      34             : #include "avfilter.h"
      35             : #include "formats.h"
      36             : #include "internal.h"
      37             : 
      38             : typedef struct ResampleContext {
      39             :     const AVClass *class;
      40             :     AVAudioResampleContext *avr;
      41             :     AVDictionary *options;
      42             : 
      43             :     int resampling;
      44             :     int64_t next_pts;
      45             :     int64_t next_in_pts;
      46             : 
      47             :     /* set by filter_frame() to signal an output frame to request_frame() */
      48             :     int got_output;
      49             : } ResampleContext;
      50             : 
      51           0 : static av_cold int init(AVFilterContext *ctx, AVDictionary **opts)
      52             : {
      53           0 :     ResampleContext *s = ctx->priv;
      54           0 :     const AVClass *avr_class = avresample_get_class();
      55           0 :     AVDictionaryEntry *e = NULL;
      56             : 
      57           0 :     while ((e = av_dict_get(*opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
      58           0 :         if (av_opt_find(&avr_class, e->key, NULL, 0,
      59             :                         AV_OPT_SEARCH_FAKE_OBJ | AV_OPT_SEARCH_CHILDREN))
      60           0 :             av_dict_set(&s->options, e->key, e->value, 0);
      61             :     }
      62             : 
      63           0 :     e = NULL;
      64           0 :     while ((e = av_dict_get(s->options, "", e, AV_DICT_IGNORE_SUFFIX)))
      65           0 :         av_dict_set(opts, e->key, NULL, 0);
      66             : 
      67             :     /* do not allow the user to override basic format options */
      68           0 :     av_dict_set(&s->options,  "in_channel_layout", NULL, 0);
      69           0 :     av_dict_set(&s->options, "out_channel_layout", NULL, 0);
      70           0 :     av_dict_set(&s->options,  "in_sample_fmt",     NULL, 0);
      71           0 :     av_dict_set(&s->options, "out_sample_fmt",     NULL, 0);
      72           0 :     av_dict_set(&s->options,  "in_sample_rate",    NULL, 0);
      73           0 :     av_dict_set(&s->options, "out_sample_rate",    NULL, 0);
      74             : 
      75           0 :     return 0;
      76             : }
      77             : 
      78           0 : static av_cold void uninit(AVFilterContext *ctx)
      79             : {
      80           0 :     ResampleContext *s = ctx->priv;
      81             : 
      82           0 :     if (s->avr) {
      83           0 :         avresample_close(s->avr);
      84           0 :         avresample_free(&s->avr);
      85             :     }
      86           0 :     av_dict_free(&s->options);
      87           0 : }
      88             : 
      89           0 : static int query_formats(AVFilterContext *ctx)
      90             : {
      91           0 :     AVFilterLink *inlink  = ctx->inputs[0];
      92           0 :     AVFilterLink *outlink = ctx->outputs[0];
      93             :     AVFilterFormats *in_formats, *out_formats, *in_samplerates, *out_samplerates;
      94             :     AVFilterChannelLayouts *in_layouts, *out_layouts;
      95             :     int ret;
      96             : 
      97           0 :     if (!(in_formats      = ff_all_formats         (AVMEDIA_TYPE_AUDIO)) ||
      98           0 :         !(out_formats     = ff_all_formats         (AVMEDIA_TYPE_AUDIO)) ||
      99           0 :         !(in_samplerates  = ff_all_samplerates     (                  )) ||
     100           0 :         !(out_samplerates = ff_all_samplerates     (                  )) ||
     101           0 :         !(in_layouts      = ff_all_channel_layouts (                  )) ||
     102             :         !(out_layouts     = ff_all_channel_layouts (                  )))
     103           0 :         return AVERROR(ENOMEM);
     104             : 
     105           0 :     if ((ret = ff_formats_ref         (in_formats,      &inlink->out_formats        )) < 0 ||
     106           0 :         (ret = ff_formats_ref         (out_formats,     &outlink->in_formats        )) < 0 ||
     107           0 :         (ret = ff_formats_ref         (in_samplerates,  &inlink->out_samplerates    )) < 0 ||
     108           0 :         (ret = ff_formats_ref         (out_samplerates, &outlink->in_samplerates    )) < 0 ||
     109           0 :         (ret = ff_channel_layouts_ref (in_layouts,      &inlink->out_channel_layouts)) < 0 ||
     110           0 :         (ret = ff_channel_layouts_ref (out_layouts,     &outlink->in_channel_layouts)) < 0)
     111           0 :         return ret;
     112             : 
     113           0 :     return 0;
     114             : }
     115             : 
     116           0 : static int config_output(AVFilterLink *outlink)
     117             : {
     118           0 :     AVFilterContext *ctx = outlink->src;
     119           0 :     AVFilterLink *inlink = ctx->inputs[0];
     120           0 :     ResampleContext   *s = ctx->priv;
     121             :     char buf1[64], buf2[64];
     122             :     int ret;
     123             : 
     124             :     int64_t resampling_forced;
     125             : 
     126           0 :     if (s->avr) {
     127           0 :         avresample_close(s->avr);
     128           0 :         avresample_free(&s->avr);
     129             :     }
     130             : 
     131           0 :     if (inlink->channel_layout == outlink->channel_layout &&
     132           0 :         inlink->sample_rate    == outlink->sample_rate    &&
     133           0 :         (inlink->format        == outlink->format ||
     134           0 :         (av_get_channel_layout_nb_channels(inlink->channel_layout)  == 1 &&
     135           0 :          av_get_channel_layout_nb_channels(outlink->channel_layout) == 1 &&
     136           0 :          av_get_planar_sample_fmt(inlink->format) ==
     137           0 :          av_get_planar_sample_fmt(outlink->format))))
     138           0 :         return 0;
     139             : 
     140           0 :     if (!(s->avr = avresample_alloc_context()))
     141           0 :         return AVERROR(ENOMEM);
     142             : 
     143           0 :     if (s->options) {
     144             :         int ret;
     145           0 :         AVDictionaryEntry *e = NULL;
     146           0 :         while ((e = av_dict_get(s->options, "", e, AV_DICT_IGNORE_SUFFIX)))
     147           0 :             av_log(ctx, AV_LOG_VERBOSE, "lavr option: %s=%s\n", e->key, e->value);
     148             : 
     149           0 :         ret = av_opt_set_dict(s->avr, &s->options);
     150           0 :         if (ret < 0)
     151           0 :             return ret;
     152             :     }
     153             : 
     154           0 :     av_opt_set_int(s->avr,  "in_channel_layout", inlink ->channel_layout, 0);
     155           0 :     av_opt_set_int(s->avr, "out_channel_layout", outlink->channel_layout, 0);
     156           0 :     av_opt_set_int(s->avr,  "in_sample_fmt",     inlink ->format,         0);
     157           0 :     av_opt_set_int(s->avr, "out_sample_fmt",     outlink->format,         0);
     158           0 :     av_opt_set_int(s->avr,  "in_sample_rate",    inlink ->sample_rate,    0);
     159           0 :     av_opt_set_int(s->avr, "out_sample_rate",    outlink->sample_rate,    0);
     160             : 
     161           0 :     if ((ret = avresample_open(s->avr)) < 0)
     162           0 :         return ret;
     163             : 
     164           0 :     av_opt_get_int(s->avr, "force_resampling", 0, &resampling_forced);
     165           0 :     s->resampling = resampling_forced || (inlink->sample_rate != outlink->sample_rate);
     166             : 
     167           0 :     if (s->resampling) {
     168           0 :         outlink->time_base = (AVRational){ 1, outlink->sample_rate };
     169           0 :         s->next_pts        = AV_NOPTS_VALUE;
     170           0 :         s->next_in_pts     = AV_NOPTS_VALUE;
     171             :     } else
     172           0 :         outlink->time_base = inlink->time_base;
     173             : 
     174           0 :     av_get_channel_layout_string(buf1, sizeof(buf1),
     175             :                                  -1, inlink ->channel_layout);
     176           0 :     av_get_channel_layout_string(buf2, sizeof(buf2),
     177             :                                  -1, outlink->channel_layout);
     178           0 :     av_log(ctx, AV_LOG_VERBOSE,
     179             :            "fmt:%s srate:%d cl:%s -> fmt:%s srate:%d cl:%s\n",
     180           0 :            av_get_sample_fmt_name(inlink ->format), inlink ->sample_rate, buf1,
     181           0 :            av_get_sample_fmt_name(outlink->format), outlink->sample_rate, buf2);
     182             : 
     183           0 :     return 0;
     184             : }
     185             : 
     186           0 : static int request_frame(AVFilterLink *outlink)
     187             : {
     188           0 :     AVFilterContext *ctx = outlink->src;
     189           0 :     ResampleContext   *s = ctx->priv;
     190           0 :     int ret = 0;
     191             : 
     192           0 :     s->got_output = 0;
     193           0 :     while (ret >= 0 && !s->got_output)
     194           0 :         ret = ff_request_frame(ctx->inputs[0]);
     195             : 
     196             :     /* flush the lavr delay buffer */
     197           0 :     if (ret == AVERROR_EOF && s->avr) {
     198             :         AVFrame *frame;
     199           0 :         int nb_samples = avresample_get_out_samples(s->avr, 0);
     200             : 
     201           0 :         if (!nb_samples)
     202           0 :             return ret;
     203             : 
     204           0 :         frame = ff_get_audio_buffer(outlink, nb_samples);
     205           0 :         if (!frame)
     206           0 :             return AVERROR(ENOMEM);
     207             : 
     208           0 :         ret = avresample_convert(s->avr, frame->extended_data,
     209           0 :                                  frame->linesize[0], nb_samples,
     210             :                                  NULL, 0, 0);
     211           0 :         if (ret <= 0) {
     212           0 :             av_frame_free(&frame);
     213           0 :             return (ret == 0) ? AVERROR_EOF : ret;
     214             :         }
     215             : 
     216           0 :         frame->nb_samples = ret;
     217           0 :         frame->pts = s->next_pts;
     218           0 :         return ff_filter_frame(outlink, frame);
     219             :     }
     220           0 :     return ret;
     221             : }
     222             : 
     223           0 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     224             : {
     225           0 :     AVFilterContext  *ctx = inlink->dst;
     226           0 :     ResampleContext    *s = ctx->priv;
     227           0 :     AVFilterLink *outlink = ctx->outputs[0];
     228             :     int ret;
     229             : 
     230           0 :     if (s->avr) {
     231             :         AVFrame *out;
     232             :         int delay, nb_samples;
     233             : 
     234             :         /* maximum possible samples lavr can output */
     235           0 :         delay      = avresample_get_delay(s->avr);
     236           0 :         nb_samples = avresample_get_out_samples(s->avr, in->nb_samples);
     237             : 
     238           0 :         out = ff_get_audio_buffer(outlink, nb_samples);
     239           0 :         if (!out) {
     240           0 :             ret = AVERROR(ENOMEM);
     241           0 :             goto fail;
     242             :         }
     243             : 
     244           0 :         ret = avresample_convert(s->avr, out->extended_data, out->linesize[0],
     245           0 :                                  nb_samples, in->extended_data, in->linesize[0],
     246           0 :                                  in->nb_samples);
     247           0 :         if (ret <= 0) {
     248           0 :             av_frame_free(&out);
     249           0 :             if (ret < 0)
     250           0 :                 goto fail;
     251             :         }
     252             : 
     253           0 :         av_assert0(!avresample_available(s->avr));
     254             : 
     255           0 :         if (s->resampling && s->next_pts == AV_NOPTS_VALUE) {
     256           0 :             if (in->pts == AV_NOPTS_VALUE) {
     257           0 :                 av_log(ctx, AV_LOG_WARNING, "First timestamp is missing, "
     258             :                        "assuming 0.\n");
     259           0 :                 s->next_pts = 0;
     260             :             } else
     261           0 :                 s->next_pts = av_rescale_q(in->pts, inlink->time_base,
     262             :                                            outlink->time_base);
     263             :         }
     264             : 
     265           0 :         if (ret > 0) {
     266           0 :             out->nb_samples = ret;
     267             : 
     268           0 :             ret = av_frame_copy_props(out, in);
     269           0 :             if (ret < 0) {
     270           0 :                 av_frame_free(&out);
     271           0 :                 goto fail;
     272             :             }
     273             : 
     274           0 :             if (s->resampling) {
     275           0 :                 out->sample_rate = outlink->sample_rate;
     276             :                 /* Only convert in->pts if there is a discontinuous jump.
     277             :                    This ensures that out->pts tracks the number of samples actually
     278             :                    output by the resampler in the absence of such a jump.
     279             :                    Otherwise, the rounding in av_rescale_q() and av_rescale()
     280             :                    causes off-by-1 errors. */
     281           0 :                 if (in->pts != AV_NOPTS_VALUE && in->pts != s->next_in_pts) {
     282           0 :                     out->pts = av_rescale_q(in->pts, inlink->time_base,
     283           0 :                                                 outlink->time_base) -
     284           0 :                                    av_rescale(delay, outlink->sample_rate,
     285           0 :                                               inlink->sample_rate);
     286             :                 } else
     287           0 :                     out->pts = s->next_pts;
     288             : 
     289           0 :                 s->next_pts = out->pts + out->nb_samples;
     290           0 :                 s->next_in_pts = in->pts + in->nb_samples;
     291             :             } else
     292           0 :                 out->pts = in->pts;
     293             : 
     294           0 :             ret = ff_filter_frame(outlink, out);
     295           0 :             s->got_output = 1;
     296             :         }
     297             : 
     298           0 : fail:
     299           0 :         av_frame_free(&in);
     300             :     } else {
     301           0 :         in->format = outlink->format;
     302           0 :         ret = ff_filter_frame(outlink, in);
     303           0 :         s->got_output = 1;
     304             :     }
     305             : 
     306           0 :     return ret;
     307             : }
     308             : 
     309           0 : static const AVClass *resample_child_class_next(const AVClass *prev)
     310             : {
     311           0 :     return prev ? NULL : avresample_get_class();
     312             : }
     313             : 
     314           0 : static void *resample_child_next(void *obj, void *prev)
     315             : {
     316           0 :     ResampleContext *s = obj;
     317           0 :     return prev ? NULL : s->avr;
     318             : }
     319             : 
     320             : static const AVClass resample_class = {
     321             :     .class_name       = "resample",
     322             :     .item_name        = av_default_item_name,
     323             :     .version          = LIBAVUTIL_VERSION_INT,
     324             :     .child_class_next = resample_child_class_next,
     325             :     .child_next       = resample_child_next,
     326             : };
     327             : 
     328             : static const AVFilterPad avfilter_af_resample_inputs[] = {
     329             :     {
     330             :         .name          = "default",
     331             :         .type          = AVMEDIA_TYPE_AUDIO,
     332             :         .filter_frame  = filter_frame,
     333             :     },
     334             :     { NULL }
     335             : };
     336             : 
     337             : static const AVFilterPad avfilter_af_resample_outputs[] = {
     338             :     {
     339             :         .name          = "default",
     340             :         .type          = AVMEDIA_TYPE_AUDIO,
     341             :         .config_props  = config_output,
     342             :         .request_frame = request_frame
     343             :     },
     344             :     { NULL }
     345             : };
     346             : 
     347             : AVFilter ff_af_resample = {
     348             :     .name          = "resample",
     349             :     .description   = NULL_IF_CONFIG_SMALL("Audio resampling and conversion."),
     350             :     .priv_size     = sizeof(ResampleContext),
     351             :     .priv_class    = &resample_class,
     352             :     .init_dict     = init,
     353             :     .uninit        = uninit,
     354             :     .query_formats = query_formats,
     355             :     .inputs        = avfilter_af_resample_inputs,
     356             :     .outputs       = avfilter_af_resample_outputs,
     357             : };

Generated by: LCOV version 1.13