FFmpeg
Loading...
Searching...
No Matches
trim.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
6 * License 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 GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include "libavutil/fifo.h"
21#include "libavutil/opt.h"
22#include "libavutil/timestamp.h"
23
24#include "libavcodec/bsf.h"
26
36
37/* The packet discriminant a bound is compared against; the indexes count consumed
38 * and exported packets. */
45
46/* An axis, a unit, and whether the value is relative; the duration types are
47 * the relative forms of pts and msec_pt. */
48static const struct {
50 int msec;
52} trim_types[] = {
53 [TRIM_PTS] = { AXIS_PTS, 0, 0 },
54 [TRIM_DTS] = { AXIS_DTS, 0, 0 },
55 [TRIM_PKT_INDEX] = { AXIS_INDEX, 0, 0 },
56 [TRIM_MSEC_PT] = { AXIS_PTS, 1, 0 },
57 [TRIM_MSEC_DT] = { AXIS_DTS, 1, 0 },
58 [TRIM_DUR_TS] = { AXIS_PTS, 0, 1 },
59 [TRIM_DUR_T_MSEC] = { AXIS_PTS, 1, 1 },
60};
61
62typedef struct TrimBound {
63 /* Resolved from the options, immutable once init returns. */
64 int active; ///< the option was set at all
66 int relative; ///< offset is measured from the reference packet
67 int64_t offset; ///< option value converted to axis units
68
69 /* Rebuilt from the fields above by every reset. */
70 int64_t value; ///< resolved bound, meaningful once pending is clear
71 int pending; ///< the reference packet has not been seen yet
72} TrimBound;
73
74typedef struct TrimContext {
75 const AVClass *class;
76
84
87
88 int audio; ///< trim through skip samples side data
89 int64_t pkt_idx; ///< packets consumed so far
90 int64_t out_idx; ///< packets exported so far
91 int64_t skip_carry; ///< samples of head skip left over by dropped packets
92 uint8_t skip_reason; ///< reason that head skip came with
93
96
97 AVFifo *preroll_fifo; ///< packets held since the last keyframe, NULL when off
98 AVPacket *pending; ///< in-range packet waiting for the preroll to drain
99 int preroll_full; ///< the group overflowed, so hold nothing until the next one
100
101 int64_t nb_exported; ///< packets that left the filter
102 int64_t last_pts; ///< the last of them, kept for the closing summary
106
107/* Bounds mix option values with stream values; either can overflow. */
109 const char *what)
110{
111 if ((delta > 0 && *acc > INT64_MAX - delta) ||
112 (delta < 0 && *acc < INT64_MIN - delta)) {
113 av_log(ctx, AV_LOG_ERROR, "%s is not representable\n", what);
114 return AVERROR(ERANGE);
115 }
116
117 *acc += delta;
118
119 return 0;
120}
121
123 enum TrimAxis axis)
124{
125 switch (axis) {
126 case AXIS_PTS: return pkt->pts;
127 case AXIS_DTS: return pkt->dts;
128 case AXIS_OUT_INDEX: return s->out_idx;
129 default: return s->pkt_idx;
130 }
131}
132
133/* The dts stands in for the pts, being monotonic and never above it. */
135{
136 return axis == AXIS_PTS ? AXIS_DTS : axis;
137}
138
139/* An index counts whole packets, so only time places a bound inside one. */
140static int axis_is_time(enum TrimAxis axis)
141{
142 return axis == AXIS_PTS || axis == AXIS_DTS;
143}
144
145/* Nothing converted here is ever negative, so a negative result is the
146 * INT64_MIN av_rescale_q reports for one it cannot represent. */
148 AVRational to, const char *what)
149{
150 int64_t converted = av_rescale_q(*value, from, to);
151
152 if (converted < 0) {
153 av_log(ctx, AV_LOG_ERROR, "%s is not representable\n", what);
154 return AVERROR(ERANGE);
155 }
156
157 *value = converted;
158
159 return 0;
160}
161
163 const char *what)
164{
165 return convert_checked(ctx, value, ctx->time_base_in,
166 (AVRational){ 1, ctx->par_in->sample_rate }, what);
167}
168
170 const char *what)
171{
172 return convert_checked(ctx, value, (AVRational){ 1, ctx->par_in->sample_rate },
173 ctx->time_base_in, what);
174}
175
176/* The samples a packet decodes to, zero where the codec does not give them. */
178{
179 return FFMAX(av_get_audio_frame_duration2(ctx->par_in, pkt->size), 0);
180}
181
182/* A skip reaching past a dropped packet only needs how much of itself that
183 * packet used up, which a duration still estimates closely enough. */
185{
186 int64_t nb_samples = packet_samples(ctx, pkt);
187
188 if (nb_samples > 0)
189 return nb_samples;
190
191 nb_samples = av_rescale_q(pkt->duration, ctx->time_base_in,
192 (AVRational){ 1, ctx->par_in->sample_rate });
193
194 return FFMAX(nb_samples, 0);
195}
196
197/* How far a packet reaches past its axis value. Audio reaches as far as the
198 * samples it decodes to, a duration also covering any gap after them; without
199 * them it reaches nowhere, so no bound can fall inside it. */
201 enum TrimAxis axis, int64_t *span)
202{
203 TrimContext *s = ctx->priv_data;
204
205 *span = 0;
206
207 if (!axis_is_time(axis))
208 return 0;
209
210 if (s->audio) {
211 *span = packet_samples(ctx, pkt);
212 return samples_to_time_base(ctx, span, "packet span");
213 }
214
215 *span = FFMAX(pkt->duration, 0);
216
217 return 0;
218}
219
220static int bound_init(AVBSFContext *ctx, TrimBound *b, int active,
221 int64_t value, int type, int rel, const char *name)
222{
223 b->active = active;
224 if (!active)
225 return 0;
226
227 b->axis = trim_types[type].axis;
228 b->relative = rel || trim_types[type].relative;
229
230 if (trim_types[type].relative && value < 0) {
231 av_log(ctx, AV_LOG_ERROR, "%s duration must not be negative\n", name);
232 return AVERROR(EINVAL);
233 }
234
235 if (trim_types[type].msec) {
236 int64_t ts = av_rescale_q(value, (AVRational){ 1, 1000 },
237 ctx->time_base_in);
238 if (ts == INT64_MIN) {
239 av_log(ctx, AV_LOG_ERROR, "%s of %"PRId64" ms is not representable "
240 "in the stream time base\n", name, value);
241 return AVERROR(ERANGE);
242 }
243 value = ts;
244 }
245
246 b->offset = value;
247
248 return 0;
249}
250
252{
253 b->value = b->offset;
254 b->pending = b->relative;
255}
256
258 const char *name)
259{
260 int ret = add_checked(ctx, &b->value, ref, name);
261
262 if (ret < 0)
263 return ret;
264
265 b->pending = 0;
266
267 return 0;
268}
269
270/* How much of the packet lies before the start bound, EAGAIN when all of it
271 * does. */
272static int trim_head(AVBSFContext *ctx, const AVPacket *pkt, int64_t *head)
273{
274 TrimContext *s = ctx->priv_data;
275 int64_t v, span;
276 int ret;
277
278 if (!s->start_bound.active)
279 return 0;
280
281 /* A packet without the discriminant a bound uses cannot be placed. */
282 v = packet_axis(s, pkt, s->start_bound.axis);
283 if (v == AV_NOPTS_VALUE)
284 return AVERROR(EAGAIN);
285
286 /* The start is measured from the first packet of the stream. */
287 if (s->start_bound.pending) {
288 ret = bound_resolve(ctx, &s->start_bound, v, "start bound");
289 if (ret < 0)
290 return ret;
291 }
292
293 if (v >= s->start_bound.value)
294 return 0;
295
296 ret = packet_span(ctx, pkt, s->start_bound.axis, &span);
297 if (ret < 0)
298 return ret;
299
300 if (!s->trim_packets || av_sat_add64(v, span) <= s->start_bound.value)
301 return AVERROR(EAGAIN);
302 *head = s->start_bound.value - v;
303
304 return 0;
305}
306
307/* How much of the packet lies past the end bound, measured from head, where it
308 * starts contributing. EAGAIN when none of it is inside, EOF once nothing later
309 * can be. */
310static int trim_tail(AVBSFContext *ctx, const AVPacket *pkt, int64_t head,
311 int64_t *tail)
312{
313 TrimContext *s = ctx->priv_data;
314 int64_t v;
315 int ret;
316
317 if (!s->end_bound.active)
318 return 0;
319
320 /* The end is measured from the first exported packet, at the point it is
321 * trimmed to. */
322 if (s->end_bound.pending) {
323 int64_t ref = packet_axis(s, pkt, s->end_bound.axis);
324
325 if (ref == AV_NOPTS_VALUE)
326 return AVERROR(EAGAIN);
327 if (axis_is_time(s->end_bound.axis)) {
328 ret = add_checked(ctx, &ref, head, "end anchor");
329 if (ret < 0)
330 return ret;
331 }
332 ret = bound_resolve(ctx, &s->end_bound, ref, "end bound");
333 if (ret < 0)
334 return ret;
335 }
336
337 /* Only a discriminant that cannot come back into range may end the stream. */
338 v = packet_axis(s, pkt, monotonic_axis(s->end_bound.axis));
339 if (v != AV_NOPTS_VALUE && v >= s->end_bound.value)
340 return AVERROR_EOF;
341
342 v = packet_axis(s, pkt, s->end_bound.axis);
343 if (v == AV_NOPTS_VALUE)
344 return AVERROR(EAGAIN);
345
346 /* Reordering can still bring in-range packets after this one. */
347 if (v >= s->end_bound.value)
348 return AVERROR(EAGAIN);
349
350 if (s->trim_packets) {
351 int64_t span, past;
352
353 ret = packet_span(ctx, pkt, s->end_bound.axis, &span);
354 if (ret < 0)
355 return ret;
356
357 past = av_sat_add64(v, span);
358 if (past > s->end_bound.value)
359 *tail = past - s->end_bound.value;
360 }
361
362 return 0;
363}
364
365/* Audio is trimmed in sample space through skip samples side data, leaving the
366 * timestamps untouched. */
367static int trim_audio(AVBSFContext *ctx, AVPacket *pkt, int64_t head, int keep)
368{
369 TrimContext *s = ctx->priv_data;
370 int64_t nb_samples = packet_samples(ctx, pkt);
371 int64_t tail = 0, anchor, input_head;
372 int trimming = head != 0;
373 uint8_t head_reason = 0, tail_reason = 0, input_reason;
374 size_t size;
376 &size);
377 int ret;
378
379 ret = time_base_to_samples(ctx, &head, "head trim");
380 if (ret < 0)
381 return ret;
382
383 /* A decoder replaces the skip it carries with any nonzero one a packet
384 * brings, whether larger or smaller, so resolve the incoming skip first. */
385 input_head = s->skip_carry;
386 input_reason = s->skip_reason;
387
388 if (side && size >= 8 && AV_RL32(side)) {
389 input_head = AV_RL32(side);
390 input_reason = size >= 10 ? AV_RL8(side + 8) : 0;
391 }
392
393 /* That skip and this filter's trim are offsets from the same boundary, so
394 * the larger wins and brings its own reason; the trim has none. */
395 if (input_head >= head) {
396 head = input_head;
397 head_reason = input_reason;
398 }
399
400 /* Only a trim of this filter collapses a packet; one already covered by its
401 * own skip is passed through. */
402 if (!keep || (trimming && nb_samples > 0 && head >= nb_samples))
403 goto drop;
404
405 /* A bound measured from this packet is anchored past its composed skip. */
406 anchor = head;
407 ret = samples_to_time_base(ctx, &anchor, "end anchor");
408 if (ret < 0)
409 return ret;
410
411 ret = trim_tail(ctx, pkt, anchor, &tail);
412 if (ret < 0) {
413 if (ret != AVERROR(EAGAIN))
414 return ret;
415 goto drop;
416 }
417
418 trimming |= tail != 0;
419 ret = time_base_to_samples(ctx, &tail, "tail trim");
420 if (ret < 0)
421 return ret;
422 if (side && size >= 8 && AV_RL32(side + 4) >= tail) {
423 tail = AV_RL32(side + 4);
424 tail_reason = size >= 10 ? AV_RL8(side + 9) : 0;
425 }
426
427 if (trimming && nb_samples > 0 && head >= nb_samples - tail)
428 goto drop;
429
430 /* The side data below carries any excess from here on. */
431 s->skip_carry = 0;
432 s->skip_reason = 0;
433
434 if (!head && !tail)
435 return 0;
436
437 if (head > UINT32_MAX || tail > UINT32_MAX) {
438 av_log(ctx, AV_LOG_ERROR, "skip samples count is not representable\n");
439 return AVERROR(ERANGE);
440 }
441
442 if (!side || size < 10) {
444 if (!side)
445 return AVERROR(ENOMEM);
446 }
447
448 AV_WL32(side, head);
449 AV_WL32(side + 4, tail);
450 AV_WL8 (side + 8, head_reason);
451 AV_WL8 (side + 9, tail_reason);
452
453 return 0;
454
455drop:
456 /* A decoder subtracts the samples of every frame it discards and carries
457 * the rest, so do the same across dropped packets. */
458 if (head > 0) {
459 int64_t consumed = packet_skip_consumed(ctx, pkt);
460
461 if (consumed <= 0) {
462 av_log(ctx, AV_LOG_ERROR, "cannot carry a %"PRId64" sample skip past "
463 "a dropped packet of unknown sample count\n", head);
464 return AVERROR(EINVAL);
465 }
466 s->skip_carry = FFMAX(head - consumed, 0);
467 s->skip_reason = s->skip_carry ? head_reason : 0;
468 }
469
470 return AVERROR(EAGAIN);
471}
472
473/* Everything but audio is trimmed on the timeline itself, which no side data
474 * can express. */
476{
477 int64_t tail = 0;
478 int ret;
479
480 ret = trim_tail(ctx, pkt, head, &tail);
481 if (ret < 0)
482 return ret;
483
484 if (!head && !tail)
485 return 0;
486
487 /* Bounds on different axes can select disjoint parts of one packet, and
488 * each trim is below the duration, so the subtraction cannot overflow. */
489 if (head >= pkt->duration - tail)
490 return AVERROR(EAGAIN);
491
492 if (pkt->pts != AV_NOPTS_VALUE) {
493 ret = add_checked(ctx, &pkt->pts, head, "packet pts");
494 if (ret < 0)
495 return ret;
496 }
497 if (pkt->dts != AV_NOPTS_VALUE) {
498 ret = add_checked(ctx, &pkt->dts, head, "packet dts");
499 if (ret < 0)
500 return ret;
501 }
502 pkt->duration -= head + tail;
503
504 return 0;
505}
506
508{
509 TrimContext *s = ctx->priv_data;
510 AVPacket *held;
511
512 while (s->preroll_fifo && av_fifo_read(s->preroll_fifo, &held, 1) >= 0)
513 av_packet_free(&held);
514}
515
516/* A held packet is decoded for the frames after it to reference and dropped
517 * before output, so the exported stream still begins at the bound. */
519{
520 TrimContext *s = ctx->priv_data;
521 AVPacket *held;
522
523 if (av_fifo_read(s->preroll_fifo, &held, 1) >= 0) {
524 av_packet_move_ref(pkt, held);
525 av_packet_free(&held);
526 pkt->flags |= AV_PKT_FLAG_DISCARD;
527 return;
528 }
529
530 av_packet_move_ref(pkt, s->pending);
531 av_packet_free(&s->pending);
532}
533
535{
536 TrimContext *s = ctx->priv_data;
537 AVPacket *held;
538 int ret;
539
540 if (s->preroll_full)
541 return AVERROR(EAGAIN);
542
543 held = av_packet_alloc();
544 if (!held)
545 return AVERROR(ENOMEM);
546
547 av_packet_move_ref(held, pkt);
548 ret = av_fifo_write(s->preroll_fifo, &held, 1);
549 if (ret < 0) {
550 av_packet_move_ref(pkt, held);
551 av_packet_free(&held);
552 if (ret != AVERROR(ENOSPC))
553 return ret;
554
555 /* A group too long to hold is dropped whole rather than exported as a
556 * fragment no decoder can start from. */
557 av_log(ctx, AV_LOG_WARNING, "preroll exceeds %d packets, the first "
558 "packets in range will not be decodable\n", s->preroll_size);
560 s->preroll_full = 1;
561 }
562
563 return AVERROR(EAGAIN);
564}
565
566static void log_exported_packet(AVBSFContext *ctx, const char *which,
567 int64_t idx, int64_t pts, int64_t dts, int key)
568{
569 av_log(ctx, AV_LOG_VERBOSE, "%s exported packet: output index %"PRId64", "
570 "pts %s, dts %s, keyframe %d\n", which, idx, av_ts2str(pts),
571 av_ts2str(dts), key);
572}
573
575{
576 TrimContext *s = ctx->priv_data;
577
578 s->last_pts = pkt->pts;
579 s->last_dts = pkt->dts;
580 s->last_key = !!(pkt->flags & AV_PKT_FLAG_KEY);
581
582 if (!s->nb_exported++)
583 log_exported_packet(ctx, "first", 0, s->last_pts, s->last_dts,
584 s->last_key);
585}
586
587/* Only the flush or close ending the stream can tell which packet was last. */
589{
590 TrimContext *s = ctx->priv_data;
591
592 if (s->nb_exported)
593 log_exported_packet(ctx, "last", s->nb_exported - 1, s->last_pts,
594 s->last_dts, s->last_key);
595 else if (s->pkt_idx)
596 av_log(ctx, AV_LOG_WARNING, "no packet was in range, the output is "
597 "empty\n");
598}
599
601{
602 TrimContext *s = ctx->priv_data;
603 int64_t head = 0;
604 int ret;
605
606 /* The preroll an in-range packet needs is exported ahead of it. */
607 if (s->pending) {
610 return 0;
611 }
612
614 if (ret < 0)
615 return ret;
616
617 /* Only the group the start bound falls in is worth keeping, so the window
618 * starts over at every keyframe. */
619 if (s->preroll_fifo && pkt->flags & AV_PKT_FLAG_KEY) {
621 s->preroll_full = 0;
622 }
623
624 ret = trim_head(ctx, pkt, &head);
625
626 /* A packet before the start still composes with the skip it carries, so the
627 * audio path runs on it too and is told the verdict instead. */
628 if (s->audio && (!ret || ret == AVERROR(EAGAIN)))
629 ret = trim_audio(ctx, pkt, head, !ret);
630 else if (!ret)
631 ret = trim_shift(ctx, pkt, head);
632 else if (ret == AVERROR(EAGAIN) && s->preroll_fifo)
633 ret = preroll_hold(ctx, pkt);
634
635 s->pkt_idx++;
636 if (ret < 0) {
638 return ret;
639 }
640
641 s->out_idx++;
642 if (s->preroll_fifo && av_fifo_can_read(s->preroll_fifo)) {
643 s->pending = av_packet_alloc();
644 if (!s->pending) {
646 return AVERROR(ENOMEM);
647 }
648 av_packet_move_ref(s->pending, pkt);
650 }
651
653
654 return 0;
655}
656
657/* Runtime state is derived from the options, so a flush restores it exactly. */
659{
660 TrimContext *s = ctx->priv_data;
661
662 bound_reset(&s->start_bound);
663 bound_reset(&s->end_bound);
664
665 s->pkt_idx = 0;
666 s->out_idx = 0;
667 s->nb_exported = 0;
668 s->skip_carry = 0;
669 s->skip_reason = 0;
670
672 av_packet_free(&s->pending);
673 s->preroll_full = 0;
674}
675
677{
680}
681
683{
684 TrimContext *s = ctx->priv_data;
685
688 av_packet_free(&s->pending);
689 av_fifo_freep2(&s->preroll_fifo);
690}
691
693{
694 TrimContext *s = ctx->priv_data;
695 int ret;
696
697 if (s->start == INT64_MIN && s->end == INT64_MAX) {
698 av_log(ctx, AV_LOG_ERROR, "At least one of start or end must be set\n");
699 return AVERROR(EINVAL);
700 }
701
702 ret = bound_init(ctx, &s->start_bound, s->start != INT64_MIN, s->start,
703 s->start_type, s->start_rel, "start");
704 if (ret < 0)
705 return ret;
706
707 ret = bound_init(ctx, &s->end_bound, s->end != INT64_MAX, s->end,
708 s->end_type, s->end_rel, "end");
709 if (ret < 0)
710 return ret;
711
712 /* A packet count measured from the first exported packet is a promise about
713 * the exported stream, so it is counted there. */
714 if (s->end_bound.axis == AXIS_INDEX && s->end_bound.relative)
715 s->end_bound.axis = AXIS_OUT_INDEX;
716
717 /* Shifting the timeline leaves the samples where they were, so audio with
718 * no sample space to be trimmed in cannot be trimmed at all. */
719 if (s->trim_packets && ctx->par_in->codec_type == AVMEDIA_TYPE_AUDIO) {
720 if (ctx->par_in->sample_rate <= 0 || ctx->time_base_in.num <= 0 ||
721 ctx->time_base_in.den <= 0) {
722 av_log(ctx, AV_LOG_ERROR, "audio is trimmed through skip samples "
723 "side data, which needs a sample rate and a time base\n");
724 return AVERROR(EINVAL);
725 }
726 s->audio = 1;
727 }
728
729 /* The window is bounded by a keyframe, which only video has. Audio needs a
730 * preroll counted in samples, which is not the one this would give. */
731 if (s->preroll && s->start_bound.active &&
732 ctx->par_in->codec_type == AVMEDIA_TYPE_VIDEO) {
733 s->preroll_fifo = av_fifo_alloc2(1, sizeof(AVPacket *),
735 if (!s->preroll_fifo)
736 return AVERROR(ENOMEM);
737 av_fifo_auto_grow_limit(s->preroll_fifo, s->preroll_size);
738 }
739
741
742 return 0;
743}
744
745#define OFFSET(x) offsetof(TrimContext, x)
746#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_BSF_PARAM)
747static const AVOption trim_options[] = {
748 { "start", "time or index marking the start of the accepted range", OFFSET(start),
749 AV_OPT_TYPE_INT64, { .i64 = INT64_MIN }, INT64_MIN, INT64_MAX, FLAGS },
750 { "start_type", "how to interpret start", OFFSET(start_type),
751 AV_OPT_TYPE_INT, { .i64 = TRIM_PTS }, 0, TRIM_MSEC_DT, FLAGS, .unit = "start_type" },
752 { "pts", "stream time base pts", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_PTS }, 0, 0, FLAGS, .unit = "start_type" },
753 { "dts", "stream time base dts", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_DTS }, 0, 0, FLAGS, .unit = "start_type" },
754 { "pkt_index", "packet index", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_PKT_INDEX }, 0, 0, FLAGS, .unit = "start_type" },
755 { "msec_pt", "milliseconds, matched against pts", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_MSEC_PT }, 0, 0, FLAGS, .unit = "start_type" },
756 { "msec_dt", "milliseconds, matched against dts", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_MSEC_DT }, 0, 0, FLAGS, .unit = "start_type" },
757 { "start_rel", "interpret start relative to the first packet of the stream", OFFSET(start_rel),
758 AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
759 { "end", "time or index marking the end of the accepted range", OFFSET(end),
760 AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS },
761 { "end_type", "how to interpret end", OFFSET(end_type),
762 AV_OPT_TYPE_INT, { .i64 = TRIM_PTS }, 0, TRIM_DUR_T_MSEC, FLAGS, .unit = "end_type" },
763 { "pts", "stream time base pts", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_PTS }, 0, 0, FLAGS, .unit = "end_type" },
764 { "dts", "stream time base dts", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_DTS }, 0, 0, FLAGS, .unit = "end_type" },
765 { "pkt_index", "packet index", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_PKT_INDEX }, 0, 0, FLAGS, .unit = "end_type" },
766 { "msec_pt", "milliseconds, matched against pts", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_MSEC_PT }, 0, 0, FLAGS, .unit = "end_type" },
767 { "msec_dt", "milliseconds, matched against dts", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_MSEC_DT }, 0, 0, FLAGS, .unit = "end_type" },
768 { "dur_ts", "duration in stream time base", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_DUR_TS }, 0, 0, FLAGS, .unit = "end_type" },
769 { "dur_t_msec", "duration in milliseconds", 0, AV_OPT_TYPE_CONST, { .i64 = TRIM_DUR_T_MSEC }, 0, 0, FLAGS, .unit = "end_type" },
770 { "end_rel", "interpret end relative to the first exported packet", OFFSET(end_rel),
771 AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
772 { "trim_packets", "trim packets straddling a boundary instead of exporting them "
773 "untouched or dropping them", OFFSET(trim_packets),
774 AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
775 { "preroll", "export the packets the first packet in range needs to be decodable, "
776 "flagged for the decoder to drop them after decoding", OFFSET(preroll),
777 AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
778 { "preroll_size", "maximum number of packets held for preroll", OFFSET(preroll_size),
779 AV_OPT_TYPE_INT, { .i64 = 300 }, 1, INT_MAX, FLAGS },
780 { NULL },
781};
782
783static const AVClass trim_class = {
784 .class_name = "trim",
785 .item_name = av_default_item_name,
786 .option = trim_options,
787 .version = LIBAVUTIL_VERSION_INT,
788};
789
791 .p.name = "trim",
792 .p.priv_class = &trim_class,
793 .priv_data_size = sizeof(TrimContext),
794 .init = trim_init,
795 .close = trim_close,
796 .flush = trim_flush,
798};
static AVFormatContext * ctx
static av_cold void close(AVCodecParserContext *s)
Definition apv_parser.c:197
const FFBitStreamFilter ff_trim_bsf
Definition trim.c:790
int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt)
Called by bitstream filters to get packet for filtering.
Definition bsf.c:254
#define s(width, name)
Definition cbs_vp9.c:198
#define FLAGS
Definition cmdutils.c:597
#define av_sat_add64
Definition common.h:139
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static AVPacket * pkt
void(* flush)(AVBSFContext *ctx)
Definition dts2pts.c:610
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
double value
Definition eval.c:102
const char * key
A generic FIFO API.
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
Definition opt.h:262
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
@ AV_PKT_DATA_SKIP_SAMPLES
Recommends skipping the specified number of samples.
Definition packet.h:153
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition packet.c:74
#define AV_PKT_FLAG_DISCARD
Flag is used to discard packets which are required to maintain valid decoder state but are not requir...
Definition packet.h:657
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition packet.c:434
uint8_t * av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, size_t size)
Allocate new information of a packet.
Definition packet.c:231
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition packet.h:650
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
Move every field in src to dst and reset src.
Definition packet.c:491
uint8_t * av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type, size_t *size)
Get side information from packet.
Definition packet.c:252
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition packet.c:63
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
AVFifo * av_fifo_alloc2(size_t nb_elems, size_t elem_size, unsigned int flags)
Allocate and initialize an AVFifo with a given element size.
Definition fifo.c:47
void av_fifo_freep2(AVFifo **f)
Free an AVFifo and reset pointer to NULL.
Definition fifo.c:286
#define AV_FIFO_FLAG_AUTO_GROW
Automatically resize the FIFO on writes, so that the data fits.
Definition fifo.h:63
size_t av_fifo_can_read(const AVFifo *f)
Definition fifo.c:87
int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems)
Write data into a FIFO.
Definition fifo.c:188
void av_fifo_auto_grow_limit(AVFifo *f, size_t max_elems)
Set the maximum size (in elements) to which the FIFO can be resized automatically.
Definition fifo.c:77
int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems)
Read data from a FIFO.
Definition fifo.c:240
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#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
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
cl_device_type type
#define b
Definition input.c:43
#define AV_WL8(p, d)
#define AV_RL8(x)
#define AV_WL32(p, v)
#define AV_RL32(p)
static void trim_report(AVBSFContext *ctx)
Definition trim.c:588
static void bound_reset(TrimBound *b)
Definition trim.c:251
static void log_exported_packet(AVBSFContext *ctx, const char *which, int64_t idx, int64_t pts, int64_t dts, int key)
Definition trim.c:566
static void trim_close(AVBSFContext *ctx)
Definition trim.c:682
int relative
Definition trim.c:51
static void trim_flush(AVBSFContext *ctx)
Definition trim.c:676
static int samples_to_time_base(AVBSFContext *ctx, int64_t *value, const char *what)
Definition trim.c:169
static int add_checked(AVBSFContext *ctx, int64_t *acc, int64_t delta, const char *what)
Definition trim.c:108
static int convert_checked(AVBSFContext *ctx, int64_t *value, AVRational from, AVRational to, const char *what)
Definition trim.c:147
TrimAxis
Definition trim.c:39
@ AXIS_PTS
Definition trim.c:40
@ AXIS_OUT_INDEX
Definition trim.c:43
@ AXIS_DTS
Definition trim.c:41
@ AXIS_INDEX
Definition trim.c:42
TrimType
Definition trim.c:27
@ TRIM_DUR_T_MSEC
Definition trim.c:34
@ TRIM_DUR_TS
Definition trim.c:33
@ TRIM_MSEC_PT
Definition trim.c:31
@ TRIM_PTS
Definition trim.c:28
@ TRIM_MSEC_DT
Definition trim.c:32
@ TRIM_PKT_INDEX
Definition trim.c:30
@ TRIM_DTS
Definition trim.c:29
static void preroll_export(AVBSFContext *ctx, AVPacket *pkt)
Definition trim.c:518
static int trim_audio(AVBSFContext *ctx, AVPacket *pkt, int64_t head, int keep)
Definition trim.c:367
static const struct @121072265223206255134261043041011175177273217055 trim_types[]
static int bound_resolve(AVBSFContext *ctx, TrimBound *b, int64_t ref, const char *name)
Definition trim.c:257
static int64_t packet_axis(const TrimContext *s, const AVPacket *pkt, enum TrimAxis axis)
Definition trim.c:122
static int bound_init(AVBSFContext *ctx, TrimBound *b, int active, int64_t value, int type, int rel, const char *name)
Definition trim.c:220
enum TrimAxis axis
Definition trim.c:49
static int packet_span(AVBSFContext *ctx, const AVPacket *pkt, enum TrimAxis axis, int64_t *span)
Definition trim.c:200
static void trim_reset(AVBSFContext *ctx)
Definition trim.c:658
static void packet_exported(AVBSFContext *ctx, const AVPacket *pkt)
Definition trim.c:574
static const AVClass trim_class
Definition trim.c:783
static int time_base_to_samples(AVBSFContext *ctx, int64_t *value, const char *what)
Definition trim.c:162
static enum TrimAxis monotonic_axis(enum TrimAxis axis)
Definition trim.c:134
static int trim_tail(AVBSFContext *ctx, const AVPacket *pkt, int64_t head, int64_t *tail)
Definition trim.c:310
static int trim_shift(AVBSFContext *ctx, AVPacket *pkt, int64_t head)
Definition trim.c:475
static const AVOption trim_options[]
Definition trim.c:747
#define OFFSET(x)
Definition trim.c:745
static int axis_is_time(enum TrimAxis axis)
Definition trim.c:140
int msec
Definition trim.c:50
static int trim_head(AVBSFContext *ctx, const AVPacket *pkt, int64_t *head)
Definition trim.c:272
static void preroll_clear(AVBSFContext *ctx)
Definition trim.c:507
static int trim_filter(AVBSFContext *ctx, AVPacket *pkt)
Definition trim.c:600
static int64_t packet_skip_consumed(AVBSFContext *ctx, const AVPacket *pkt)
Definition trim.c:184
static int trim_init(AVBSFContext *ctx)
Definition trim.c:692
static int preroll_hold(AVBSFContext *ctx, AVPacket *pkt)
Definition trim.c:534
static int64_t packet_samples(AVBSFContext *ctx, const AVPacket *pkt)
Definition trim.c:177
const char * from
Definition jacosubdec.c:64
int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes)
Definition utils.c:823
const char * to
Definition webvttdec.c:36
#define FFMAX(a, b)
Definition macros.h:47
AVOptions.
const char * name
Definition qsvenc.c:142
The bitstream filter state.
Definition bsf.h:68
Describe the class of an AVClass context structure.
Definition log.h:76
Definition fifo.c:35
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
Rational number (pair of numerator and denominator).
Definition rational.h:58
int relative
offset is measured from the reference packet
Definition trim.c:66
int active
the option was set at all
Definition trim.c:64
int64_t offset
option value converted to axis units
Definition trim.c:67
int pending
the reference packet has not been seen yet
Definition trim.c:71
int64_t value
resolved bound, meaningful once pending is clear
Definition trim.c:70
enum TrimAxis axis
Definition trim.c:65
int64_t pkt_idx
packets consumed so far
Definition trim.c:89
int end_type
Definition trim.c:80
TrimBound end_bound
Definition trim.c:86
int64_t nb_exported
packets that left the filter
Definition trim.c:101
int64_t out_idx
packets exported so far
Definition trim.c:90
int start_rel
Definition trim.c:81
int preroll
Definition trim.c:94
int audio
trim through skip samples side data
Definition trim.c:88
AVFifo * preroll_fifo
packets held since the last keyframe, NULL when off
Definition trim.c:97
int64_t start
Definition trim.c:77
int end_rel
Definition trim.c:82
TrimBound start_bound
Definition trim.c:85
int64_t last_pts
the last of them, kept for the closing summary
Definition trim.c:102
int preroll_size
Definition trim.c:95
int64_t end
Definition trim.c:78
int trim_packets
Definition trim.c:83
int start_type
Definition trim.c:79
int64_t skip_carry
samples of head skip left over by dropped packets
Definition trim.c:91
AVPacket * pending
in-range packet waiting for the preroll to drain
Definition trim.c:98
int64_t last_dts
Definition trim.c:103
int last_key
Definition trim.c:104
int preroll_full
the group overflowed, so hold nothing until the next one
Definition trim.c:99
uint8_t skip_reason
reason that head skip came with
Definition trim.c:92
#define av_log(a,...)
void(* filter)(uint8_t *src, ptrdiff_t stride, int qscale)
Definition h263dsp.c:29
static int ref[MAX_W *MAX_W]
timestamp utils, mostly useful for debugging/logging purposes
#define av_ts2str(ts)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition timestamp.h:54
static int64_t pts
int size
float delta