FFmpeg
Loading...
Searching...
No Matches
packetsync.c
Go to the documentation of this file.
1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19/**
20 * @file
21 * Packet sync API. Heavily based on libavfilter/framesync.c by Nicolas George
22 */
23
24#include "libavutil/avassert.h"
25#include "libavutil/mem.h"
26#include "libavutil/opt.h"
27
28#include "libavcodec/bsf.h"
29#include "filters.h"
30#include "packetsync.h"
31
32#define OFFSET(member) offsetof(FFPacketSync, member)
33#define FLAGS (AV_OPT_FLAG_BSF_PARAM|AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
34
35static const char *packetsync_name(void *ptr)
36{
37 return "packetsync";
38}
39
40static const AVOption packetsync_options[] = {
41 { "eof_action", "Action to take when encountering EOF from secondary input ",
42 OFFSET(opt_eof_action), AV_OPT_TYPE_INT, { .i64 = EOF_ACTION_PASS },
43 EOF_ACTION_ENDALL, EOF_ACTION_PASS, .flags = FLAGS, .unit = "eof_action" },
44 { "endall", "End both streams.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_ENDALL }, .flags = FLAGS, .unit = "eof_action" },
45 { "pass", "Pass through the main input.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_PASS }, .flags = FLAGS, .unit = "eof_action" },
46 { "ts_sync_mode", "How strictly to sync streams based on secondary input timestamps",
47 OFFSET(opt_ts_sync_mode), AV_OPT_TYPE_INT, { .i64 = TS_DEFAULT },
48 TS_DEFAULT, TS_NEAREST, .flags = FLAGS, .unit = "ts_sync_mode" },
49 { "default", "Packet from secondary input with the nearest lower or equal timestamp to the primary input packet",
50 0, AV_OPT_TYPE_CONST, { .i64 = TS_DEFAULT }, .flags = FLAGS, .unit = "ts_sync_mode" },
51 { "nearest", "Packet from secondary input with the absolute nearest timestamp to the primary input packet",
52 0, AV_OPT_TYPE_CONST, { .i64 = TS_NEAREST }, .flags = FLAGS, .unit = "ts_sync_mode" },
53 { NULL }
54};
56 .version = LIBAVUTIL_VERSION_INT,
57 .class_name = "packetsync",
58 .item_name = packetsync_name,
60 .option = packetsync_options,
61 .parent_log_context_offset = OFFSET(parent),
62};
63
65{
66 const AVClass *c = *iter ? NULL : &ff_packetsync_class;
67 *iter = (void *)(uintptr_t)c;
68 return c;
69}
70
71enum {
75};
76
78
80{
81 if (fs->class)
82 return;
83 fs->class = &ff_packetsync_class;
85}
86
88{
89 /* For filters with several outputs, we will not be able to assume which
90 output is relevant for ff_outlink_packet_wanted() and
91 ff_bsf_link_set_in_status(). To be designed when needed. */
92 av_assert0(parent->nb_outputs == 1);
93
95 fs->parent = parent;
96 fs->nb_in = nb_in;
97
98 fs->in = av_calloc(nb_in, sizeof(*fs->in));
99 if (!fs->in) {
100 fs->nb_in = 0;
101 return AVERROR(ENOMEM);
102 }
103
104 return 0;
105}
106
108{
109 fs->eof = 1;
110 fs->pkt_ready = 0;
111 ff_bsf_link_set_in_status(fs->parent->outputs[0], AVERROR_EOF, pts);
112}
113
115{
116 unsigned i, level = 0;
117
118 for (i = 0; i < fs->nb_in; i++)
119 if (fs->in[i].state != STATE_EOF)
120 level = FFMAX(level, fs->in[i].sync);
121 av_assert0(level <= fs->sync_level);
122 if (level < fs->sync_level)
123 av_log(fs, AV_LOG_VERBOSE, "Sync level %u\n", level);
124 if (fs->opt_ts_sync_mode > TS_DEFAULT) {
125 for (i = 0; i < fs->nb_in; i++) {
126 if (fs->in[i].sync < level)
127 fs->in[i].ts_mode = fs->opt_ts_sync_mode;
128 else
129 fs->in[i].ts_mode = TS_DEFAULT;
130 }
131 }
132 if (level)
133 fs->sync_level = level;
134 else
135 packetsync_eof(fs, eof_pts);
136}
137
139{
140 unsigned i;
141
142 for (i = 1; i < fs->nb_in; i++) {
143 fs->in[i].after = EXT_NULL;
144 fs->in[i].sync = 0;
145 }
146 if (fs->opt_eof_action == EOF_ACTION_ENDALL) {
147 for (i = 0; i < fs->nb_in; i++)
148 fs->in[i].after = EXT_STOP;
149 }
150
151 if (!fs->time_base.num) {
152 for (i = 0; i < fs->nb_in; i++) {
153 if (fs->in[i].sync) {
154 if (fs->time_base.num) {
155 fs->time_base = av_gcd_q(fs->time_base, fs->in[i].time_base,
157 } else {
158 fs->time_base = fs->in[i].time_base;
159 }
160 }
161 }
162 if (!fs->time_base.num) {
163 av_log(fs, AV_LOG_ERROR, "Impossible to set time base\n");
164 return AVERROR(EINVAL);
165 }
166 av_log(fs, AV_LOG_VERBOSE, "Selected %d/%d time base\n",
167 fs->time_base.num, fs->time_base.den);
168 }
169
170 for (i = 0; i < fs->nb_in; i++)
171 fs->in[i].pts = fs->in[i].pts_next = AV_NOPTS_VALUE;
172 fs->sync_level = UINT_MAX;
174
175 return 0;
176}
177
179{
180 unsigned i;
181 int64_t pts;
182 int ret;
183
184 while (!(fs->pkt_ready || fs->eof)) {
185 ret = consume_from_fifos(fs);
186 if (ret <= 0)
187 return ret;
188
189 pts = INT64_MAX;
190 for (i = 0; i < fs->nb_in; i++)
191 if (fs->in[i].have_next && fs->in[i].pts_next < pts)
192 pts = fs->in[i].pts_next;
193 if (pts == INT64_MAX) {
195 break;
196 }
197 for (i = 0; i < fs->nb_in; i++) {
198 if (fs->in[i].pts_next == pts ||
199 (fs->in[i].ts_mode == TS_NEAREST &&
200 fs->in[i].have_next &&
201 fs->in[i].pts_next != INT64_MAX && fs->in[i].pts != AV_NOPTS_VALUE &&
202 fs->in[i].pts_next - pts < pts - fs->in[i].pts)) {
203 av_packet_free(&fs->in[i].pkt);
204 fs->in[i].pkt = fs->in[i].pkt_next;
205 fs->in[i].pts = fs->in[i].pts_next;
206 fs->in[i].pkt_next = NULL;
207 fs->in[i].pts_next = AV_NOPTS_VALUE;
208 fs->in[i].have_next = 0;
209 fs->in[i].state = fs->in[i].pkt ? STATE_RUN : STATE_EOF;
210 if (fs->in[i].sync == fs->sync_level && fs->in[i].pkt)
211 fs->pkt_ready = 1;
212 if (fs->in[i].state == STATE_EOF &&
213 fs->in[i].after == EXT_STOP)
215 }
216 }
217 if (fs->pkt_ready)
218 for (i = 0; i < fs->nb_in; i++)
219 if ((fs->in[i].state == STATE_BOF &&
220 fs->in[i].before == EXT_STOP))
221 fs->pkt_ready = 0;
222 fs->pts = pts;
223 }
224 return 0;
225}
226
228 int64_t pts)
229{
230 return pts + 1;
231}
232
234{
235 int64_t pts;
236
237 av_assert0(!fs->in[in].have_next);
239 pts = av_rescale_q_rnd(pkt->pts, fs->in[in].time_base, fs->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
240 pkt->pts = pts;
241 fs->in[in].pkt_next = pkt;
242 fs->in[in].pts_next = pts;
243 fs->in[in].have_next = 1;
244}
245
246static void packetsync_inject_status(FFPacketSync *fs, unsigned in, int status, int64_t eof_pts)
247{
248 av_assert0(!fs->in[in].have_next);
249 fs->in[in].sync = 0;
251 fs->in[in].pkt_next = NULL;
252 fs->in[in].pts_next = fs->in[in].state != STATE_RUN
253 ? INT64_MAX : packetsync_pts_extrapolate(fs, in, fs->in[in].pts);
254 fs->in[in].have_next = 1;
255}
256
258 unsigned get)
259{
260 AVPacket *pkt;
261 unsigned need_copy = 0, i;
262 int64_t pts_next;
263
264 if (!fs->in[in].pkt) {
265 *rpkt = NULL;
266 return 0;
267 }
268 pkt = fs->in[in].pkt;
269 if (get) {
270 /* Find out if we need to copy the packet: is there another sync
271 stream, and do we know if its current packet will outlast this one? */
272 pts_next = fs->in[in].have_next ? fs->in[in].pts_next : INT64_MAX;
273 for (i = 0; i < fs->nb_in && !need_copy; i++)
274 if (i != in && fs->in[i].sync &&
275 (!fs->in[i].have_next || fs->in[i].pts_next < pts_next))
276 need_copy = 1;
277 if (need_copy) {
278 if (!(pkt = av_packet_clone(pkt)))
279 return AVERROR(ENOMEM);
280 } else {
281 fs->in[in].pkt = NULL;
282 }
283 fs->pkt_ready = 0;
284 }
285 *rpkt = pkt;
286 return 0;
287}
288
290{
291 unsigned i;
292
293 for (i = 0; i < fs->nb_in; i++) {
294 av_packet_free(&fs->in[i].pkt);
295 av_packet_free(&fs->in[i].pkt_next);
296 }
297
298 av_freep(&fs->in);
299}
300
302{
304 AVPacket *pkt = NULL;
305 int64_t pts;
306 unsigned i, nb_active, nb_miss;
307 int ret, status;
308
309 nb_active = nb_miss = 0;
310 for (i = 0; i < fs->nb_in; i++) {
311 if (fs->in[i].have_next || fs->in[i].state == STATE_EOF)
312 continue;
313 nb_active++;
314 ret = ff_bsf_inlink_consume_packet(ctx->inputs[i], &pkt);
315 if (ret < 0)
316 return ret;
317 if (ret) {
320 } else {
321 ret = ff_bsf_inlink_acknowledge_status(ctx->inputs[i], &status, &pts);
322 if (ret > 0) {
323 packetsync_inject_status(fs, i, status, pts);
324 } else if (!ret) {
325 nb_miss++;
326 }
327 }
328 }
329 if (nb_miss) {
330 if (nb_miss == nb_active && !ff_bsf_outlink_packet_wanted(ctx->outputs[0]))
332 for (i = 0; i < fs->nb_in; i++)
333 if (!fs->in[i].have_next && fs->in[i].state != STATE_EOF)
335 return 0;
336 }
337 return 1;
338}
339
341{
343 int ret;
344
345 ret = ff_bsf_outlink_get_status(ctx->outputs[0]);
346 if (ret) {
347 unsigned i;
348 for (i = 0; i < ctx->nb_inputs; i++)
349 ff_bsf_inlink_set_status(ctx->inputs[i], ret);
350 return 0;
351 }
352
353 ret = packetsync_advance(fs);
354 if (ret < 0)
355 return ret;
356 if (fs->eof || !fs->pkt_ready)
357 return 0;
358 ret = fs->on_event(fs);
359 if (ret < 0)
360 return ret;
361 fs->pkt_ready = 0;
362
363 return 0;
364}
365
367{
368 int ret;
369
370 ret = ff_packetsync_init(fs, parent, 2);
371 if (ret < 0)
372 return ret;
373 fs->in[0].time_base = parent->inputs[0]->time_base;
374 fs->in[1].time_base = parent->inputs[1]->time_base;
375 fs->in[0].sync = 2;
376 fs->in[0].before = EXT_STOP;
377 fs->in[0].after = EXT_STOP;
378 fs->in[1].sync = 1;
379 fs->in[1].before = EXT_NULL;
380 fs->in[1].after = EXT_NULL;
381 return 0;
382}
383
385{
387 AVPacket *mainpic = NULL, *secondpic = NULL;
388 int ret;
389
390 if ((ret = ff_packetsync_get_packet(fs, 0, &mainpic, 1)) < 0 ||
391 (ret = ff_packetsync_get_packet(fs, 1, &secondpic, 0)) < 0) {
392 av_packet_free(&mainpic);
393 return ret;
394 }
395 av_assert0(mainpic);
396 mainpic->pts = av_rescale_q(fs->pts, fs->time_base, ctx->outputs[0]->time_base);
397 *f0 = mainpic;
398 *f1 = secondpic;
399 return 0;
400}
401
403{
404 int ret;
405
406 ret = ff_packetsync_dualinput_get(fs, f0, f1);
407 if (ret < 0)
408 return ret;
409 ret = av_packet_make_writable(*f0);
410 if (ret < 0) {
411 av_packet_free(f0);
412 *f1 = NULL;
413 return ret;
414 }
415 return 0;
416}
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
int ff_bsf_inlink_acknowledge_status(AVBitStreamFilterLink *link, int *rstatus, int64_t *rpts)
int ff_bsf_inlink_consume_packet(AVBitStreamFilterLink *link, AVPacket **rpkt)
int ff_bsf_outlink_packet_wanted(AVBitStreamFilterLink *link)
int ff_bsf_outlink_get_status(AVBitStreamFilterLink *link)
void ff_bsf_link_set_in_status(AVBitStreamFilterLink *link, int status, int64_t pts)
void ff_bsf_inlink_set_status(AVBitStreamFilterLink *link, int status)
void ff_bsf_inlink_request_packet(AVBitStreamFilterLink *link)
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define fs(width, name, subs,...)
Definition cbs_vp9.c:200
#define FLAGS
Definition cmdutils.c:598
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static AVPacket * pkt
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition packet.c:74
AVPacket * av_packet_clone(const AVPacket *src)
Create a new packet that references the same data as src.
Definition packet.c:478
int av_packet_make_writable(AVPacket *pkt)
Create a writable reference for the data described by a given packet, avoiding data copy if possible.
Definition packet.c:516
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
AVRational av_gcd_q(AVRational a, AVRational b, int max_den, AVRational def)
Return the best rational so that a and b are multiple of it.
Definition rational.c:188
int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, enum AVRounding rnd)
Rescale a 64-bit integer by 2 rational numbers with specified rounding.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AV_ROUND_PASS_MINMAX
Flag telling rescaling functions to pass INT64_MIN/MAX through unchanged, avoiding special cases for ...
@ AV_ROUND_NEAR_INF
Round to nearest and halfway cases away from zero.
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
#define AV_TIME_BASE
Internal time base represented as integer.
Definition avutil.h:253
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition avutil.h:263
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
void av_opt_set_defaults(void *s)
Set the values of all AVOption fields to their default values.
Definition opt.c:1756
#define FFERROR_BSF_NOT_READY
Special return code when activate() did not do anything.
Definition filters.h:32
@ AV_CLASS_CATEGORY_BITSTREAM_FILTER
Definition log.h:37
#define FFMAX(a, b)
Definition macros.h:47
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
AVOptions.
void ff_packetsync_uninit(FFPacketSync *fs)
Free all memory currently allocated.
Definition packetsync.c:289
static int consume_from_fifos(FFPacketSync *fs)
Definition packetsync.c:301
int ff_packetsync_init_dualinput(FFPacketSync *fs, AVBitStreamFilterContext *parent)
Initialize a packet sync structure for dualinput.
Definition packetsync.c:366
int ff_packetsync_configure(FFPacketSync *fs)
Configure a packet sync structure.
Definition packetsync.c:138
const AVClass * ff_packetsync_child_class_iterate(void **iter)
Definition packetsync.c:64
static const AVOption packetsync_options[]
Definition packetsync.c:40
static int64_t packetsync_pts_extrapolate(FFPacketSync *fs, unsigned in, int64_t pts)
Definition packetsync.c:227
static const char * packetsync_name(void *ptr)
Definition packetsync.c:35
const AVClass ff_packetsync_class
Definition packetsync.c:55
@ STATE_BOF
Definition packetsync.c:72
@ STATE_EOF
Definition packetsync.c:74
@ STATE_RUN
Definition packetsync.c:73
static int packetsync_advance(FFPacketSync *fs)
Definition packetsync.c:178
int ff_packetsync_activate(FFPacketSync *fs)
Examine the packets in the filter's input and try to produce output.
Definition packetsync.c:340
int ff_packetsync_get_packet(FFPacketSync *fs, unsigned in, AVPacket **rpkt, unsigned get)
Get the current packet in an input.
Definition packetsync.c:257
int ff_packetsync_init(FFPacketSync *fs, AVBitStreamFilterContext *parent, unsigned nb_in)
Initialize a packet sync structure.
Definition packetsync.c:87
int ff_packetsync_dualinput_get(FFPacketSync *fs, AVPacket **f0, AVPacket **f1)
Definition packetsync.c:384
int ff_packetsync_dualinput_get_writable(FFPacketSync *fs, AVPacket **f0, AVPacket **f1)
Same as ff_packetsync_dualinput_get(), but make sure that f0 is writable.
Definition packetsync.c:402
#define OFFSET(member)
Definition packetsync.c:32
void ff_packetsync_preinit(FFPacketSync *fs)
Pre-initialize a packet sync structure.
Definition packetsync.c:79
static void packetsync_inject_status(FFPacketSync *fs, unsigned in, int status, int64_t eof_pts)
Definition packetsync.c:246
static void packetsync_inject_packet(FFPacketSync *fs, unsigned in, AVPacket *pkt)
Definition packetsync.c:233
static void packetsync_sync_level_update(FFPacketSync *fs, int64_t eof_pts)
Definition packetsync.c:114
static void packetsync_eof(FFPacketSync *fs, int64_t pts)
Definition packetsync.c:107
@ TS_DEFAULT
Sync to packets from secondary input with the nearest, lower or equal timestamp to the packet event o...
Definition packetsync.h:82
@ TS_NEAREST
Sync to packets from secondary input with the absolute nearest timestamp to the packet event one.
Definition packetsync.h:88
@ EOF_ACTION_PASS
Definition packetsync.h:31
@ EOF_ACTION_ENDALL
Definition packetsync.h:30
@ EXT_STOP
Completely stop all streams with this one.
Definition packetsync.h:62
@ EXT_NULL
Ignore this stream and continue processing the other ones.
Definition packetsync.h:67
static void get(const uint8_t *pixels, int stride, int16_t *block)
An instance of a filter.
Definition bsf.h:347
unsigned nb_outputs
number of output pads
Definition bsf.h:369
AVBitStreamFilterLink ** inputs
array of pointers to input links
Definition bsf.h:364
Describe the class of an AVClass context structure.
Definition log.h:76
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition packet.h:596
Packet sync structure.
Definition packetsync.h:160
uint8_t level
Definition svq3.c:208
#define av_freep(p)
#define av_log(a,...)
static int64_t pts
static double c[64]