LCOV - code coverage report
Current view: top level - libavfilter - setpts.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 77 79 97.5 %
Date: 2017-12-16 21:16:39 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2010 Stefano Sabatini
       3             :  * Copyright (c) 2008 Victor Paesa
       4             :  *
       5             :  * This file is part of FFmpeg.
       6             :  *
       7             :  * FFmpeg is free software; you can redistribute it and/or
       8             :  * modify it under the terms of the GNU Lesser General Public
       9             :  * License as published by the Free Software Foundation; either
      10             :  * version 2.1 of the License, or (at your option) any later version.
      11             :  *
      12             :  * FFmpeg is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with FFmpeg; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : /**
      23             :  * @file
      24             :  * video presentation timestamp (PTS) modification filter
      25             :  */
      26             : 
      27             : #include <inttypes.h>
      28             : 
      29             : #include "libavutil/eval.h"
      30             : #include "libavutil/internal.h"
      31             : #include "libavutil/mathematics.h"
      32             : #include "libavutil/opt.h"
      33             : #include "libavutil/time.h"
      34             : #include "audio.h"
      35             : #include "avfilter.h"
      36             : #include "internal.h"
      37             : #include "video.h"
      38             : 
      39             : static const char *const var_names[] = {
      40             :     "FRAME_RATE",  ///< defined only for constant frame-rate video
      41             :     "INTERLACED",  ///< tell if the current frame is interlaced
      42             :     "N",           ///< frame / sample number (starting at zero)
      43             :     "NB_CONSUMED_SAMPLES", ///< number of samples consumed by the filter (only audio)
      44             :     "NB_SAMPLES",  ///< number of samples in the current frame (only audio)
      45             :     "POS",         ///< original position in the file of the frame
      46             :     "PREV_INPTS",  ///< previous  input PTS
      47             :     "PREV_INT",    ///< previous  input time in seconds
      48             :     "PREV_OUTPTS", ///< previous output PTS
      49             :     "PREV_OUTT",   ///< previous output time in seconds
      50             :     "PTS",         ///< original pts in the file of the frame
      51             :     "SAMPLE_RATE", ///< sample rate (only audio)
      52             :     "STARTPTS",    ///< PTS at start of movie
      53             :     "STARTT",      ///< time at start of movie
      54             :     "T",           ///< original time in the file of the frame
      55             :     "TB",          ///< timebase
      56             :     "RTCTIME",     ///< wallclock (RTC) time in micro seconds
      57             :     "RTCSTART",    ///< wallclock (RTC) time at the start of the movie in micro seconds
      58             :     "S",           //   Number of samples in the current frame
      59             :     "SR",          //   Audio sample rate
      60             :     NULL
      61             : };
      62             : 
      63             : enum var_name {
      64             :     VAR_FRAME_RATE,
      65             :     VAR_INTERLACED,
      66             :     VAR_N,
      67             :     VAR_NB_CONSUMED_SAMPLES,
      68             :     VAR_NB_SAMPLES,
      69             :     VAR_POS,
      70             :     VAR_PREV_INPTS,
      71             :     VAR_PREV_INT,
      72             :     VAR_PREV_OUTPTS,
      73             :     VAR_PREV_OUTT,
      74             :     VAR_PTS,
      75             :     VAR_SAMPLE_RATE,
      76             :     VAR_STARTPTS,
      77             :     VAR_STARTT,
      78             :     VAR_T,
      79             :     VAR_TB,
      80             :     VAR_RTCTIME,
      81             :     VAR_RTCSTART,
      82             :     VAR_S,
      83             :     VAR_SR,
      84             :     VAR_VARS_NB
      85             : };
      86             : 
      87             : typedef struct SetPTSContext {
      88             :     const AVClass *class;
      89             :     char *expr_str;
      90             :     AVExpr *expr;
      91             :     double var_values[VAR_VARS_NB];
      92             :     enum AVMediaType type;
      93             : } SetPTSContext;
      94             : 
      95          54 : static av_cold int init(AVFilterContext *ctx)
      96             : {
      97          54 :     SetPTSContext *setpts = ctx->priv;
      98             :     int ret;
      99             : 
     100          54 :     if ((ret = av_expr_parse(&setpts->expr, setpts->expr_str,
     101             :                              var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
     102           0 :         av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", setpts->expr_str);
     103           0 :         return ret;
     104             :     }
     105             : 
     106          54 :     setpts->var_values[VAR_N]           = 0.0;
     107          54 :     setpts->var_values[VAR_S]           = 0.0;
     108          54 :     setpts->var_values[VAR_PREV_INPTS]  = NAN;
     109          54 :     setpts->var_values[VAR_PREV_INT]    = NAN;
     110          54 :     setpts->var_values[VAR_PREV_OUTPTS] = NAN;
     111          54 :     setpts->var_values[VAR_PREV_OUTT]   = NAN;
     112          54 :     setpts->var_values[VAR_STARTPTS]    = NAN;
     113          54 :     setpts->var_values[VAR_STARTT]      = NAN;
     114          54 :     return 0;
     115             : }
     116             : 
     117          54 : static int config_input(AVFilterLink *inlink)
     118             : {
     119          54 :     AVFilterContext *ctx = inlink->dst;
     120          54 :     SetPTSContext *setpts = ctx->priv;
     121             : 
     122          54 :     setpts->type = inlink->type;
     123          54 :     setpts->var_values[VAR_TB] = av_q2d(inlink->time_base);
     124          54 :     setpts->var_values[VAR_RTCSTART] = av_gettime();
     125             : 
     126          54 :     setpts->var_values[VAR_SR] =
     127          54 :     setpts->var_values[VAR_SAMPLE_RATE] =
     128          54 :         setpts->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN;
     129             : 
     130         109 :     setpts->var_values[VAR_FRAME_RATE] = inlink->frame_rate.num &&
     131           1 :                                          inlink->frame_rate.den ?
     132          55 :                                             av_q2d(inlink->frame_rate) : NAN;
     133             : 
     134          54 :     av_log(inlink->src, AV_LOG_VERBOSE, "TB:%f FRAME_RATE:%f SAMPLE_RATE:%f\n",
     135             :            setpts->var_values[VAR_TB],
     136             :            setpts->var_values[VAR_FRAME_RATE],
     137             :            setpts->var_values[VAR_SAMPLE_RATE]);
     138          54 :     return 0;
     139             : }
     140             : 
     141             : #define D2TS(d)  (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
     142             : #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
     143             : #define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)*av_q2d(tb))
     144             : 
     145             : #define BUF_SIZE 64
     146             : 
     147        5526 : static inline char *double2int64str(char *buf, double v)
     148             : {
     149        5526 :     if (isnan(v)) snprintf(buf, BUF_SIZE, "nan");
     150        4712 :     else          snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)v);
     151        5526 :     return buf;
     152             : }
     153             : 
     154             : #define d2istr(v) double2int64str((char[BUF_SIZE]){0}, v)
     155             : 
     156        1842 : static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     157             : {
     158        1842 :     SetPTSContext *setpts = inlink->dst->priv;
     159        1842 :     int64_t in_pts = frame->pts;
     160             :     double d;
     161             : 
     162        1842 :     if (isnan(setpts->var_values[VAR_STARTPTS])) {
     163          54 :         setpts->var_values[VAR_STARTPTS] = TS2D(frame->pts);
     164          54 :         setpts->var_values[VAR_STARTT  ] = TS2T(frame->pts, inlink->time_base);
     165             :     }
     166        1842 :     setpts->var_values[VAR_PTS       ] = TS2D(frame->pts);
     167        1842 :     setpts->var_values[VAR_T         ] = TS2T(frame->pts, inlink->time_base);
     168        1842 :     setpts->var_values[VAR_POS       ] = frame->pkt_pos == -1 ? NAN : frame->pkt_pos;
     169        1842 :     setpts->var_values[VAR_RTCTIME   ] = av_gettime();
     170             : 
     171        1842 :     if (inlink->type == AVMEDIA_TYPE_VIDEO) {
     172          50 :         setpts->var_values[VAR_INTERLACED] = frame->interlaced_frame;
     173        1792 :     } else if (inlink->type == AVMEDIA_TYPE_AUDIO) {
     174        1792 :         setpts->var_values[VAR_S] = frame->nb_samples;
     175        1792 :         setpts->var_values[VAR_NB_SAMPLES] = frame->nb_samples;
     176             :     }
     177             : 
     178        1842 :     d = av_expr_eval(setpts->expr, setpts->var_values, NULL);
     179        1842 :     frame->pts = D2TS(d);
     180             : 
     181        7368 :     av_log(inlink->dst, AV_LOG_TRACE,
     182             :             "N:%"PRId64" PTS:%s T:%f POS:%s",
     183        1842 :             (int64_t)setpts->var_values[VAR_N],
     184        1842 :             d2istr(setpts->var_values[VAR_PTS]),
     185             :             setpts->var_values[VAR_T],
     186        1842 :             d2istr(setpts->var_values[VAR_POS]));
     187        1842 :     switch (inlink->type) {
     188          50 :     case AVMEDIA_TYPE_VIDEO:
     189          50 :         av_log(inlink->dst, AV_LOG_TRACE, " INTERLACED:%"PRId64,
     190          50 :                 (int64_t)setpts->var_values[VAR_INTERLACED]);
     191          50 :         break;
     192        1792 :     case AVMEDIA_TYPE_AUDIO:
     193        3584 :         av_log(inlink->dst, AV_LOG_TRACE, " NB_SAMPLES:%"PRId64" NB_CONSUMED_SAMPLES:%"PRId64,
     194        1792 :                 (int64_t)setpts->var_values[VAR_NB_SAMPLES],
     195        1792 :                 (int64_t)setpts->var_values[VAR_NB_CONSUMED_SAMPLES]);
     196        1792 :         break;
     197             :     }
     198        1842 :     av_log(inlink->dst, AV_LOG_TRACE, " -> PTS:%s T:%f\n", d2istr(d), TS2T(d, inlink->time_base));
     199             : 
     200        1842 :     if (inlink->type == AVMEDIA_TYPE_VIDEO) {
     201          50 :         setpts->var_values[VAR_N] += 1.0;
     202             :     } else {
     203        1792 :         setpts->var_values[VAR_N] += frame->nb_samples;
     204             :     }
     205             : 
     206        1842 :     setpts->var_values[VAR_PREV_INPTS ] = TS2D(in_pts);
     207        1842 :     setpts->var_values[VAR_PREV_INT   ] = TS2T(in_pts, inlink->time_base);
     208        1842 :     setpts->var_values[VAR_PREV_OUTPTS] = TS2D(frame->pts);
     209        1842 :     setpts->var_values[VAR_PREV_OUTT]   = TS2T(frame->pts, inlink->time_base);
     210        1842 :     if (setpts->type == AVMEDIA_TYPE_AUDIO) {
     211        1792 :         setpts->var_values[VAR_NB_CONSUMED_SAMPLES] += frame->nb_samples;
     212             :     }
     213        1842 :     return ff_filter_frame(inlink->dst->outputs[0], frame);
     214             : }
     215             : 
     216          54 : static av_cold void uninit(AVFilterContext *ctx)
     217             : {
     218          54 :     SetPTSContext *setpts = ctx->priv;
     219          54 :     av_expr_free(setpts->expr);
     220          54 :     setpts->expr = NULL;
     221          54 : }
     222             : 
     223             : #define OFFSET(x) offsetof(SetPTSContext, x)
     224             : #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
     225             : static const AVOption options[] = {
     226             :     { "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = FLAGS },
     227             :     { NULL }
     228             : };
     229             : 
     230             : #if CONFIG_SETPTS_FILTER
     231             : #define setpts_options options
     232             : AVFILTER_DEFINE_CLASS(setpts);
     233             : 
     234             : static const AVFilterPad avfilter_vf_setpts_inputs[] = {
     235             :     {
     236             :         .name         = "default",
     237             :         .type         = AVMEDIA_TYPE_VIDEO,
     238             :         .config_props = config_input,
     239             :         .filter_frame = filter_frame,
     240             :     },
     241             :     { NULL }
     242             : };
     243             : 
     244             : static const AVFilterPad avfilter_vf_setpts_outputs[] = {
     245             :     {
     246             :         .name = "default",
     247             :         .type = AVMEDIA_TYPE_VIDEO,
     248             :     },
     249             :     { NULL }
     250             : };
     251             : 
     252             : AVFilter ff_vf_setpts = {
     253             :     .name      = "setpts",
     254             :     .description = NULL_IF_CONFIG_SMALL("Set PTS for the output video frame."),
     255             :     .init      = init,
     256             :     .uninit    = uninit,
     257             : 
     258             :     .priv_size = sizeof(SetPTSContext),
     259             :     .priv_class = &setpts_class,
     260             : 
     261             :     .inputs    = avfilter_vf_setpts_inputs,
     262             :     .outputs   = avfilter_vf_setpts_outputs,
     263             : };
     264             : #endif /* CONFIG_SETPTS_FILTER */
     265             : 
     266             : #if CONFIG_ASETPTS_FILTER
     267             : 
     268             : #define asetpts_options options
     269             : AVFILTER_DEFINE_CLASS(asetpts);
     270             : 
     271             : static const AVFilterPad asetpts_inputs[] = {
     272             :     {
     273             :         .name         = "default",
     274             :         .type         = AVMEDIA_TYPE_AUDIO,
     275             :         .config_props = config_input,
     276             :         .filter_frame = filter_frame,
     277             :     },
     278             :     { NULL }
     279             : };
     280             : 
     281             : static const AVFilterPad asetpts_outputs[] = {
     282             :     {
     283             :         .name = "default",
     284             :         .type = AVMEDIA_TYPE_AUDIO,
     285             :     },
     286             :     { NULL }
     287             : };
     288             : 
     289             : AVFilter ff_af_asetpts = {
     290             :     .name        = "asetpts",
     291             :     .description = NULL_IF_CONFIG_SMALL("Set PTS for the output audio frame."),
     292             :     .init        = init,
     293             :     .uninit      = uninit,
     294             :     .priv_size   = sizeof(SetPTSContext),
     295             :     .priv_class  = &asetpts_class,
     296             :     .inputs      = asetpts_inputs,
     297             :     .outputs     = asetpts_outputs,
     298             : };
     299             : #endif /* CONFIG_ASETPTS_FILTER */

Generated by: LCOV version 1.13