Coverage Report

Created: 2026-04-01 07:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/bsf/setts.c
Line
Count
Source
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 {
58
    VAR_N,
59
    VAR_TS,
60
    VAR_POS,
61
    VAR_PREV_INPTS,
62
    VAR_PREV_INDTS,
63
    VAR_PREV_INDUR,
64
    VAR_PREV_OUTPTS,
65
    VAR_PREV_OUTDTS,
66
    VAR_PREV_OUTDUR,
67
    VAR_NEXT_PTS,
68
    VAR_NEXT_DTS,
69
    VAR_NEXT_DUR,
70
    VAR_PTS,
71
    VAR_DTS,
72
    VAR_DURATION,
73
    VAR_STARTPTS,
74
    VAR_STARTDTS,
75
    VAR_TB,
76
    VAR_TB_OUT,
77
    VAR_SR,
78
    VAR_NOPTS,
79
    VAR_VARS_NB
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
90
    AVRational time_base;
91
    int user_outtb;
92
    int prescale;
93
94
    int64_t frame_number;
95
96
    double var_values[VAR_VARS_NB];
97
98
    AVExpr *ts_expr;
99
    AVExpr *pts_expr;
100
    AVExpr *dts_expr;
101
    AVExpr *duration_expr;
102
103
    AVPacket *prev_inpkt;
104
    AVPacket *prev_outpkt;
105
    AVPacket *cur_pkt;
106
} SetTSContext;
107
108
static int setts_init(AVBSFContext *ctx)
109
399
{
110
399
    SetTSContext *s = ctx->priv_data;
111
399
    int ret;
112
113
399
    s->prev_inpkt = av_packet_alloc();
114
399
    s->prev_outpkt = av_packet_alloc();
115
399
    s->cur_pkt = av_packet_alloc();
116
399
    if (!s->prev_inpkt || !s->prev_outpkt || !s->cur_pkt)
117
0
        return AVERROR(ENOMEM);
118
119
399
    if ((ret = av_expr_parse(&s->ts_expr, s->ts_str,
120
399
                             var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
121
0
        av_log(ctx, AV_LOG_ERROR, "Error while parsing ts expression '%s'\n", s->ts_str);
122
0
        return ret;
123
0
    }
124
125
399
    if ((ret = av_expr_parse(&s->duration_expr, s->duration_str,
126
399
                             var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
127
0
        av_log(ctx, AV_LOG_ERROR, "Error while parsing duration expression '%s'\n", s->duration_str);
128
0
        return ret;
129
0
    }
130
131
399
    if (s->pts_str) {
132
0
        if ((ret = av_expr_parse(&s->pts_expr, s->pts_str,
133
0
                                 var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
134
0
            av_log(ctx, AV_LOG_ERROR, "Error while parsing pts expression '%s'\n", s->pts_str);
135
0
            return ret;
136
0
        }
137
0
    }
138
139
399
    if (s->dts_str) {
140
0
        if ((ret = av_expr_parse(&s->dts_expr, s->dts_str,
141
0
                                 var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
142
0
            av_log(ctx, AV_LOG_ERROR, "Error while parsing dts expression '%s'\n", s->dts_str);
143
0
            return ret;
144
0
        }
145
0
    }
146
147
399
    if (s->time_base.num > 0 && s->time_base.den > 0) {
148
0
        ctx->time_base_out = s->time_base;
149
0
        s->user_outtb = 1;
150
399
    } else if (s->time_base.num || !s->time_base.den) {
151
0
        av_log(ctx, AV_LOG_ERROR, "Invalid value %d/%d specified for output timebase\n", s->time_base.num, s->time_base.den);
152
0
        return AVERROR_INVALIDDATA;
153
0
    } else
154
399
        s->prescale = 0;
155
156
399
    s->frame_number= 0;
157
399
    s->var_values[VAR_STARTPTS] = AV_NOPTS_VALUE;
158
399
    s->var_values[VAR_STARTDTS] = AV_NOPTS_VALUE;
159
399
    s->var_values[VAR_NOPTS] = AV_NOPTS_VALUE;
160
399
    s->var_values[VAR_TB_OUT]= ctx->time_base_out.den ? av_q2d(ctx->time_base_out) : 0;
161
399
    s->var_values[VAR_SR]    = ctx->par_in->sample_rate;
162
163
399
    if (s->user_outtb && s->prescale)
164
0
        s->var_values[VAR_TB] = av_q2d(ctx->time_base_out);
165
399
    else
166
399
        s->var_values[VAR_TB] = ctx->time_base_in.den ? av_q2d(ctx->time_base_in) : 0;
167
168
399
    return 0;
169
399
}
170
171
103k
#define PRESCALED(x) ( s->prescale ? av_rescale_q(x, ctx->time_base_in, ctx->time_base_out) : x )
172
173
static int setts_filter(AVBSFContext *ctx, AVPacket *pkt)
174
17.7k
{
175
17.7k
    SetTSContext *s = ctx->priv_data;
176
17.7k
    int64_t new_ts, new_pts, new_dts, new_duration;
177
17.7k
    int ret;
178
179
17.7k
    ret = ff_bsf_get_packet_ref(ctx, pkt);
180
17.7k
    if (ret < 0 && (ret != AVERROR_EOF || !s->cur_pkt->data))
181
8.66k
        return ret;
182
183
9.06k
    if (!s->cur_pkt->data) {
184
399
         av_packet_move_ref(s->cur_pkt, pkt);
185
399
         return AVERROR(EAGAIN);
186
399
    }
187
188
8.66k
    if (s->var_values[VAR_STARTPTS] == AV_NOPTS_VALUE)
189
8.66k
        s->var_values[VAR_STARTPTS] = PRESCALED(s->cur_pkt->pts);
190
191
8.66k
    if (s->var_values[VAR_STARTDTS] == AV_NOPTS_VALUE)
192
8.66k
        s->var_values[VAR_STARTDTS] = PRESCALED(s->cur_pkt->dts);
193
194
8.66k
    s->var_values[VAR_N]           = s->frame_number++;
195
8.66k
    s->var_values[VAR_TS]          = PRESCALED(s->cur_pkt->dts);
196
8.66k
    s->var_values[VAR_POS]         = s->cur_pkt->pos;
197
8.66k
    s->var_values[VAR_PTS]         = PRESCALED(s->cur_pkt->pts);
198
8.66k
    s->var_values[VAR_DTS]         = PRESCALED(s->cur_pkt->dts);
199
8.66k
    s->var_values[VAR_DURATION]    = PRESCALED(s->cur_pkt->duration);
200
8.66k
    s->var_values[VAR_PREV_INPTS]  = PRESCALED(s->prev_inpkt->pts);
201
8.66k
    s->var_values[VAR_PREV_INDTS]  = PRESCALED(s->prev_inpkt->dts);
202
8.66k
    s->var_values[VAR_PREV_INDUR]  = PRESCALED(s->prev_inpkt->duration);
203
8.66k
    s->var_values[VAR_PREV_OUTPTS] = s->prev_outpkt->pts;
204
8.66k
    s->var_values[VAR_PREV_OUTDTS] = s->prev_outpkt->dts;
205
8.66k
    s->var_values[VAR_PREV_OUTDUR] = s->prev_outpkt->duration;
206
8.66k
    s->var_values[VAR_NEXT_PTS]    = PRESCALED(pkt->pts);
207
8.66k
    s->var_values[VAR_NEXT_DTS]    = PRESCALED(pkt->dts);
208
8.66k
    s->var_values[VAR_NEXT_DUR]    = PRESCALED(pkt->duration);
209
210
8.66k
    new_ts = llrint(av_expr_eval(s->ts_expr, s->var_values, NULL));
211
8.66k
    new_duration = llrint(av_expr_eval(s->duration_expr, s->var_values, NULL));
212
213
8.66k
    if (s->pts_str) {
214
0
        s->var_values[VAR_TS] = PRESCALED(s->cur_pkt->pts);
215
0
        new_pts = llrint(av_expr_eval(s->pts_expr, s->var_values, NULL));
216
8.66k
    } else {
217
8.66k
        new_pts = new_ts;
218
8.66k
    }
219
220
8.66k
    if (s->dts_str) {
221
0
        s->var_values[VAR_TS] = PRESCALED(s->cur_pkt->dts);
222
0
        new_dts = llrint(av_expr_eval(s->dts_expr, s->var_values, NULL));
223
8.66k
    } else {
224
8.66k
        new_dts = new_ts;
225
8.66k
    }
226
227
8.66k
    av_packet_unref(s->prev_inpkt);
228
8.66k
    av_packet_unref(s->prev_outpkt);
229
8.66k
    av_packet_move_ref(s->prev_inpkt, s->cur_pkt);
230
8.66k
    av_packet_move_ref(s->cur_pkt, pkt);
231
232
8.66k
    ret = av_packet_ref(pkt, s->prev_inpkt);
233
8.66k
    if (ret < 0)
234
0
        return ret;
235
236
8.66k
    if (s->user_outtb && !s->prescale) {
237
0
        new_pts = av_rescale_q(new_pts, ctx->time_base_in, ctx->time_base_out);
238
0
        new_dts = av_rescale_q(new_dts, ctx->time_base_in, ctx->time_base_out);
239
0
        new_duration = av_rescale_q(new_duration, ctx->time_base_in, ctx->time_base_out);
240
0
    }
241
242
8.66k
    pkt->pts = new_pts;
243
8.66k
    pkt->dts = new_dts;
244
8.66k
    pkt->duration = new_duration;
245
246
8.66k
    ret = av_packet_ref(s->prev_outpkt, pkt);
247
8.66k
    if (ret < 0)
248
0
        av_packet_unref(pkt);
249
250
8.66k
    return ret;
251
8.66k
}
252
253
static void setts_close(AVBSFContext *bsf)
254
399
{
255
399
    SetTSContext *s = bsf->priv_data;
256
257
399
    av_packet_free(&s->prev_inpkt);
258
399
    av_packet_free(&s->prev_outpkt);
259
399
    av_packet_free(&s->cur_pkt);
260
261
399
    av_expr_free(s->ts_expr);
262
399
    s->ts_expr = NULL;
263
399
    av_expr_free(s->pts_expr);
264
399
    s->pts_expr = NULL;
265
399
    av_expr_free(s->dts_expr);
266
399
    s->dts_expr = NULL;
267
399
    av_expr_free(s->duration_expr);
268
    s->duration_expr = NULL;
269
399
}
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
291
const FFBitStreamFilter ff_setts_bsf = {
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
};