vf_setpts.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010 Stefano Sabatini
3  * Copyright (c) 2008 Victor Paesa
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
27 /* #define DEBUG */
28 
29 #include "libavutil/eval.h"
30 #include "libavutil/mathematics.h"
31 #include "avfilter.h"
32 
33 static const char *var_names[] = {
34  "E",
35  "INTERLACED",
36  "N",
37  "PHI",
38  "PI",
39  "POS",
40  "PREV_INPTS",
41  "PREV_OUTPTS",
42  "PTS",
43  "STARTPTS",
44  "TB",
45  NULL
46 };
47 
48 enum var_name {
61 };
62 
63 typedef struct {
65  double var_values[VAR_VARS_NB];
67 
68 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
69 {
70  SetPTSContext *setpts = ctx->priv;
71  int ret;
72 
73  if ((ret = av_expr_parse(&setpts->expr, args ? args : "PTS",
74  var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
75  av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", args);
76  return ret;
77  }
78 
79  setpts->var_values[VAR_E ] = M_E;
80  setpts->var_values[VAR_N ] = 0.0;
81  setpts->var_values[VAR_PHI ] = M_PHI;
82  setpts->var_values[VAR_PI ] = M_PI;
83  setpts->var_values[VAR_PREV_INPTS ] = NAN;
84  setpts->var_values[VAR_PREV_OUTPTS] = NAN;
85  setpts->var_values[VAR_STARTPTS ] = NAN;
86  return 0;
87 }
88 
89 static int config_input(AVFilterLink *inlink)
90 {
91  SetPTSContext *setpts = inlink->dst->priv;
92 
93  setpts->var_values[VAR_TB] = av_q2d(inlink->time_base);
94 
95  av_log(inlink->src, AV_LOG_INFO, "TB:%f\n", setpts->var_values[VAR_TB]);
96  return 0;
97 }
98 
99 #define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
100 #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
101 
102 static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
103 {
104  SetPTSContext *setpts = inlink->dst->priv;
105  double d;
106  AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0);
107 
108  if (isnan(setpts->var_values[VAR_STARTPTS]))
109  setpts->var_values[VAR_STARTPTS] = TS2D(inpicref->pts);
110 
111  setpts->var_values[VAR_INTERLACED] = inpicref->video->interlaced;
112  setpts->var_values[VAR_PTS ] = TS2D(inpicref->pts);
113  setpts->var_values[VAR_POS ] = inpicref->pos == -1 ? NAN : inpicref->pos;
114 
115  d = av_expr_eval(setpts->expr, setpts->var_values, NULL);
116  outpicref->pts = D2TS(d);
117 
118 #ifdef DEBUG
119  av_log(inlink->dst, AV_LOG_DEBUG,
120  "n:%"PRId64" interlaced:%d pos:%"PRId64" pts:%"PRId64" t:%f -> pts:%"PRId64" t:%f\n",
121  (int64_t)setpts->var_values[VAR_N],
122  (int)setpts->var_values[VAR_INTERLACED],
123  inpicref ->pos,
124  inpicref ->pts, inpicref ->pts * av_q2d(inlink->time_base),
125  outpicref->pts, outpicref->pts * av_q2d(inlink->time_base));
126 #endif
127 
128  setpts->var_values[VAR_N] += 1.0;
129  setpts->var_values[VAR_PREV_INPTS ] = TS2D(inpicref ->pts);
130  setpts->var_values[VAR_PREV_OUTPTS] = TS2D(outpicref->pts);
131  avfilter_start_frame(inlink->dst->outputs[0], outpicref);
132 }
133 
134 static av_cold void uninit(AVFilterContext *ctx)
135 {
136  SetPTSContext *setpts = ctx->priv;
137  av_expr_free(setpts->expr);
138  setpts->expr = NULL;
139 }
140 
142  .name = "setpts",
143  .description = NULL_IF_CONFIG_SMALL("Set PTS for the output video frame."),
144  .init = init,
145  .uninit = uninit,
146 
147  .priv_size = sizeof(SetPTSContext),
148 
149  .inputs = (AVFilterPad[]) {{ .name = "default",
150  .type = AVMEDIA_TYPE_VIDEO,
151  .get_video_buffer = avfilter_null_get_video_buffer,
152  .config_props = config_input,
153  .start_frame = start_frame, },
154  { .name = NULL }},
155  .outputs = (AVFilterPad[]) {{ .name = "default",
156  .type = AVMEDIA_TYPE_VIDEO, },
157  { .name = NULL}},
158 };