FFmpeg
setts.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 Paul B Mahol
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * Change the PTS/DTS timestamps.
24  */
25 
26 #include "libavutil/opt.h"
27 #include "libavutil/eval.h"
28 
29 #include "bsf.h"
30 #include "bsf_internal.h"
31 
32 static const char *const var_names[] = {
33  "N", ///< frame number (starting at zero)
34  "TS",
35  "POS", ///< original position in the file of the frame
36  "PREV_INPTS", ///< previous input PTS
37  "PREV_INDTS", ///< previous input DTS
38  "PREV_INDURATION", ///< previous input duration
39  "PREV_OUTPTS", ///< previous output PTS
40  "PREV_OUTDTS", ///< previous output DTS
41  "PREV_OUTDURATION", ///< previous output duration
42  "NEXT_PTS", ///< next input PTS
43  "NEXT_DTS", ///< next input DTS
44  "NEXT_DURATION", ///< next input duration
45  "PTS", ///< original PTS in the file of the frame
46  "DTS", ///< original DTS in the file of the frame
47  "DURATION", ///< original duration in the file of the frame
48  "STARTPTS", ///< PTS at start of movie
49  "STARTDTS", ///< DTS at start of movie
50  "TB", ///< input timebase of the stream
51  "TB_OUT", ///< output timebase of the stream
52  "SR", ///< sample rate of the stream
53  "NOPTS", ///< The AV_NOPTS_VALUE constant
54  NULL
55 };
56 
57 enum var_name {
80 };
81 
82 typedef struct SetTSContext {
83  const AVClass *class;
84 
85  char *ts_str;
86  char *pts_str;
87  char *dts_str;
88  char *duration_str;
89 
92  int prescale;
93 
95 
97 
102 
106 } SetTSContext;
107 
109 {
111  int ret;
112 
113  s->prev_inpkt = av_packet_alloc();
114  s->prev_outpkt = av_packet_alloc();
115  s->cur_pkt = av_packet_alloc();
116  if (!s->prev_inpkt || !s->prev_outpkt || !s->cur_pkt)
117  return AVERROR(ENOMEM);
118 
119  if ((ret = av_expr_parse(&s->ts_expr, s->ts_str,
120  var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
121  av_log(ctx, AV_LOG_ERROR, "Error while parsing ts expression '%s'\n", s->ts_str);
122  return ret;
123  }
124 
125  if ((ret = av_expr_parse(&s->duration_expr, s->duration_str,
126  var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
127  av_log(ctx, AV_LOG_ERROR, "Error while parsing duration expression '%s'\n", s->duration_str);
128  return ret;
129  }
130 
131  if (s->pts_str) {
132  if ((ret = av_expr_parse(&s->pts_expr, s->pts_str,
133  var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
134  av_log(ctx, AV_LOG_ERROR, "Error while parsing pts expression '%s'\n", s->pts_str);
135  return ret;
136  }
137  }
138 
139  if (s->dts_str) {
140  if ((ret = av_expr_parse(&s->dts_expr, s->dts_str,
141  var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
142  av_log(ctx, AV_LOG_ERROR, "Error while parsing dts expression '%s'\n", s->dts_str);
143  return ret;
144  }
145  }
146 
147  if (s->time_base.num > 0 && s->time_base.den > 0) {
148  ctx->time_base_out = s->time_base;
149  s->user_outtb = 1;
150  } else if (s->time_base.num || !s->time_base.den) {
151  av_log(ctx, AV_LOG_ERROR, "Invalid value %d/%d specified for output timebase\n", s->time_base.num, s->time_base.den);
152  return AVERROR_INVALIDDATA;
153  } else
154  s->prescale = 0;
155 
156  s->frame_number= 0;
157  s->var_values[VAR_STARTPTS] = AV_NOPTS_VALUE;
158  s->var_values[VAR_STARTDTS] = AV_NOPTS_VALUE;
159  s->var_values[VAR_NOPTS] = AV_NOPTS_VALUE;
160  s->var_values[VAR_TB_OUT]= ctx->time_base_out.den ? av_q2d(ctx->time_base_out) : 0;
161  s->var_values[VAR_SR] = ctx->par_in->sample_rate;
162 
163  if (s->user_outtb && s->prescale)
164  s->var_values[VAR_TB] = av_q2d(ctx->time_base_out);
165  else
166  s->var_values[VAR_TB] = ctx->time_base_in.den ? av_q2d(ctx->time_base_in) : 0;
167 
168  return 0;
169 }
170 
171 #define PRESCALED(x) ( s->prescale ? av_rescale_q(x, ctx->time_base_in, ctx->time_base_out) : x )
172 
174 {
176  int64_t new_ts, new_pts, new_dts, new_duration;
177  int ret;
178 
180  if (ret < 0 && (ret != AVERROR_EOF || !s->cur_pkt->data))
181  return ret;
182 
183  if (!s->cur_pkt->data) {
184  av_packet_move_ref(s->cur_pkt, pkt);
185  return AVERROR(EAGAIN);
186  }
187 
188  if (s->var_values[VAR_STARTPTS] == AV_NOPTS_VALUE)
189  s->var_values[VAR_STARTPTS] = PRESCALED(s->cur_pkt->pts);
190 
191  if (s->var_values[VAR_STARTDTS] == AV_NOPTS_VALUE)
192  s->var_values[VAR_STARTDTS] = PRESCALED(s->cur_pkt->dts);
193 
194  s->var_values[VAR_N] = s->frame_number++;
195  s->var_values[VAR_TS] = PRESCALED(s->cur_pkt->dts);
196  s->var_values[VAR_POS] = s->cur_pkt->pos;
197  s->var_values[VAR_PTS] = PRESCALED(s->cur_pkt->pts);
198  s->var_values[VAR_DTS] = PRESCALED(s->cur_pkt->dts);
199  s->var_values[VAR_DURATION] = PRESCALED(s->cur_pkt->duration);
200  s->var_values[VAR_PREV_INPTS] = PRESCALED(s->prev_inpkt->pts);
201  s->var_values[VAR_PREV_INDTS] = PRESCALED(s->prev_inpkt->dts);
202  s->var_values[VAR_PREV_INDUR] = PRESCALED(s->prev_inpkt->duration);
203  s->var_values[VAR_PREV_OUTPTS] = s->prev_outpkt->pts;
204  s->var_values[VAR_PREV_OUTDTS] = s->prev_outpkt->dts;
205  s->var_values[VAR_PREV_OUTDUR] = s->prev_outpkt->duration;
206  s->var_values[VAR_NEXT_PTS] = PRESCALED(pkt->pts);
207  s->var_values[VAR_NEXT_DTS] = PRESCALED(pkt->dts);
208  s->var_values[VAR_NEXT_DUR] = PRESCALED(pkt->duration);
209 
210  new_ts = llrint(av_expr_eval(s->ts_expr, s->var_values, NULL));
211  new_duration = llrint(av_expr_eval(s->duration_expr, s->var_values, NULL));
212 
213  if (s->pts_str) {
214  s->var_values[VAR_TS] = PRESCALED(s->cur_pkt->pts);
215  new_pts = llrint(av_expr_eval(s->pts_expr, s->var_values, NULL));
216  } else {
217  new_pts = new_ts;
218  }
219 
220  if (s->dts_str) {
221  s->var_values[VAR_TS] = PRESCALED(s->cur_pkt->dts);
222  new_dts = llrint(av_expr_eval(s->dts_expr, s->var_values, NULL));
223  } else {
224  new_dts = new_ts;
225  }
226 
227  av_packet_unref(s->prev_inpkt);
228  av_packet_unref(s->prev_outpkt);
229  av_packet_move_ref(s->prev_inpkt, s->cur_pkt);
230  av_packet_move_ref(s->cur_pkt, pkt);
231 
232  ret = av_packet_ref(pkt, s->prev_inpkt);
233  if (ret < 0)
234  return ret;
235 
236  if (s->user_outtb && !s->prescale) {
237  new_pts = av_rescale_q(new_pts, ctx->time_base_in, ctx->time_base_out);
238  new_dts = av_rescale_q(new_dts, ctx->time_base_in, ctx->time_base_out);
239  new_duration = av_rescale_q(new_duration, ctx->time_base_in, ctx->time_base_out);
240  }
241 
242  pkt->pts = new_pts;
243  pkt->dts = new_dts;
244  pkt->duration = new_duration;
245 
246  ret = av_packet_ref(s->prev_outpkt, pkt);
247  if (ret < 0)
249 
250  return ret;
251 }
252 
253 static void setts_close(AVBSFContext *bsf)
254 {
255  SetTSContext *s = bsf->priv_data;
256 
257  av_packet_free(&s->prev_inpkt);
258  av_packet_free(&s->prev_outpkt);
259  av_packet_free(&s->cur_pkt);
260 
261  av_expr_free(s->ts_expr);
262  s->ts_expr = NULL;
263  av_expr_free(s->pts_expr);
264  s->pts_expr = NULL;
265  av_expr_free(s->dts_expr);
266  s->dts_expr = NULL;
267  av_expr_free(s->duration_expr);
268  s->duration_expr = NULL;
269 }
270 
271 #define OFFSET(x) offsetof(SetTSContext, x)
272 #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_SUBTITLE_PARAM|AV_OPT_FLAG_BSF_PARAM)
273 
274 static const AVOption options[] = {
275  { "ts", "set expression for packet PTS and DTS", OFFSET(ts_str), AV_OPT_TYPE_STRING, {.str="TS"}, 0, 0, FLAGS },
276  { "pts", "set expression for packet PTS", OFFSET(pts_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
277  { "dts", "set expression for packet DTS", OFFSET(dts_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
278  { "duration", "set expression for packet duration", OFFSET(duration_str), AV_OPT_TYPE_STRING, {.str="DURATION"}, 0, 0, FLAGS },
279  { "time_base", "set output timebase", OFFSET(time_base), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS },
280  { "prescale", "convert to output timebase before evaluation", OFFSET(prescale), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
281  { NULL },
282 };
283 
284 static const AVClass setts_class = {
285  .class_name = "setts_bsf",
286  .item_name = av_default_item_name,
287  .option = options,
288  .version = LIBAVUTIL_VERSION_INT,
289 };
290 
292  .p.name = "setts",
293  .p.priv_class = &setts_class,
294  .priv_data_size = sizeof(SetTSContext),
295  .init = setts_init,
296  .close = setts_close,
297  .filter = setts_filter,
298 };
SetTSContext::cur_pkt
AVPacket * cur_pkt
Definition: setts.c:105
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: packet.c:432
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
VAR_TB_OUT
@ VAR_TB_OUT
Definition: setts.c:76
bsf_internal.h
opt.h
var_name
var_name
Definition: noise.c:46
VAR_PREV_OUTPTS
@ VAR_PREV_OUTPTS
Definition: setts.c:64
VAR_NEXT_DUR
@ VAR_NEXT_DUR
Definition: setts.c:69
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
AVBitStreamFilter::name
const char * name
Definition: bsf.h:112
int64_t
long long int64_t
Definition: coverity.c:34
setts_init
static int setts_init(AVBSFContext *ctx)
Definition: setts.c:108
SetTSContext::duration_expr
AVExpr * duration_expr
Definition: setts.c:101
AVOption
AVOption.
Definition: opt.h:429
SetTSContext::var_values
double var_values[VAR_VARS_NB]
Definition: setts.c:96
options
static const AVOption options[]
Definition: setts.c:274
VAR_DURATION
@ VAR_DURATION
Definition: setts.c:72
filter
void(* filter)(uint8_t *src, int stride, int qscale)
Definition: h263dsp.c:29
AVPacket::duration
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:606
AV_OPT_TYPE_RATIONAL
@ AV_OPT_TYPE_RATIONAL
Underlying C type is AVRational.
Definition: opt.h:280
SetTSContext::user_outtb
int user_outtb
Definition: setts.c:91
av_packet_free
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: packet.c:74
AVBSFContext
The bitstream filter state.
Definition: bsf.h:68
av_expr_parse
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
Definition: eval.c:710
var_names
static const char *const var_names[]
Definition: setts.c:32
close
static av_cold void close(AVCodecParserContext *s)
Definition: apv_parser.c:197
VAR_PREV_OUTDTS
@ VAR_PREV_OUTDTS
Definition: setts.c:65
bsf.h
SetTSContext::duration_str
char * duration_str
Definition: setts.c:88
VAR_DTS
@ VAR_DTS
Definition: setts.c:71
VAR_NEXT_DTS
@ VAR_NEXT_DTS
Definition: setts.c:68
VAR_POS
@ VAR_POS
Definition: setts.c:60
SetTSContext::ts_expr
AVExpr * ts_expr
Definition: setts.c:98
VAR_NEXT_PTS
@ VAR_NEXT_PTS
Definition: setts.c:67
VAR_STARTDTS
@ VAR_STARTDTS
Definition: setts.c:74
av_expr_free
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:358
SetTSContext::time_base
AVRational time_base
Definition: setts.c:90
VAR_STARTPTS
@ VAR_STARTPTS
Definition: setts.c:73
pkt
AVPacket * pkt
Definition: movenc.c:60
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
setts_class
static const AVClass setts_class
Definition: setts.c:284
s
#define s(width, name)
Definition: cbs_vp9.c:198
av_q2d
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
ctx
AVFormatContext * ctx
Definition: movenc.c:49
av_expr_eval
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:792
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
VAR_TS
@ VAR_TS
Definition: setts.c:59
VAR_TB
@ VAR_TB
Definition: setts.c:75
AVExpr
Definition: eval.c:158
setts_filter
static int setts_filter(AVBSFContext *ctx, AVPacket *pkt)
Definition: setts.c:173
VAR_PREV_INDUR
@ VAR_PREV_INDUR
Definition: setts.c:63
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
SetTSContext
Definition: setts.c:82
prescale
static const FLOAT prescale[64]
Definition: faanidct.c:40
NULL
#define NULL
Definition: coverity.c:32
setts_close
static void setts_close(AVBSFContext *bsf)
Definition: setts.c:253
ts_str
static void ts_str(char buffer[60], int64_t ts, AVRational base)
Definition: seek.c:47
FFBitStreamFilter
Definition: bsf_internal.h:27
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:242
options
Definition: swscale.c:43
SetTSContext::frame_number
int64_t frame_number
Definition: setts.c:94
av_packet_ref
int av_packet_ref(AVPacket *dst, const AVPacket *src)
Setup a new reference to the data described by a given packet.
Definition: packet.c:440
av_packet_move_ref
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
Move every field in src to dst and reset src.
Definition: packet.c:489
SetTSContext::pts_expr
AVExpr * pts_expr
Definition: setts.c:99
FFBitStreamFilter::p
AVBitStreamFilter p
The public AVBitStreamFilter.
Definition: bsf_internal.h:31
eval.h
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:550
ff_setts_bsf
const FFBitStreamFilter ff_setts_bsf
Definition: setts.c:291
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:247
SetTSContext::prev_outpkt
AVPacket * prev_outpkt
Definition: setts.c:104
AVPacket::dts
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed.
Definition: packet.h:587
SetTSContext::prev_inpkt
AVPacket * prev_inpkt
Definition: setts.c:103
av_packet_alloc
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: packet.c:63
VAR_N
@ VAR_N
Definition: setts.c:58
SetTSContext::dts_expr
AVExpr * dts_expr
Definition: setts.c:100
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:581
PRESCALED
#define PRESCALED(x)
Definition: setts.c:171
VAR_PREV_INDTS
@ VAR_PREV_INDTS
Definition: setts.c:62
VAR_PREV_OUTDUR
@ VAR_PREV_OUTDUR
Definition: setts.c:66
AVBSFContext::priv_data
void * priv_data
Opaque filter-specific private data.
Definition: bsf.h:83
ret
ret
Definition: filter_design.txt:187
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:81
SetTSContext::prescale
int prescale
Definition: setts.c:92
VAR_PTS
@ VAR_PTS
Definition: setts.c:70
VAR_NOPTS
@ VAR_NOPTS
Definition: setts.c:78
SetTSContext::ts_str
char * ts_str
Definition: setts.c:85
SetTSContext::pts_str
char * pts_str
Definition: setts.c:86
VAR_VARS_NB
@ VAR_VARS_NB
Definition: setts.c:79
SetTSContext::dts_str
char * dts_str
Definition: setts.c:87
llrint
#define llrint(x)
Definition: libm.h:396
AVPacket
This structure stores compressed data.
Definition: packet.h:565
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
ff_bsf_get_packet_ref
int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt)
Called by bitstream filters to get packet for filtering.
Definition: bsf.c:256
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:276
OFFSET
#define OFFSET(x)
Definition: setts.c:271
AVFormatContext::priv_data
void * priv_data
Format private data.
Definition: avformat.h:1292
VAR_PREV_INPTS
@ VAR_PREV_INPTS
Definition: setts.c:61
FLAGS
#define FLAGS
Definition: setts.c:272
VAR_SR
@ VAR_SR
Definition: setts.c:77