/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 | | }; |