Browse code

lavf/segment: add reset_timestamps option

The new options reset the timestamps at each new segment, so that the
generated segments will have timestamps starting close to 0.

It is meant to address trac ticket #1425.

Stefano Sabatini authored on 2012/11/29 21:45:50
Showing 3 changed files
... ...
@@ -598,8 +598,15 @@ the specified time and the time set by @var{force_key_frames}.
598 598
 @item segment_times @var{times}
599 599
 Specify a list of split points. @var{times} contains a list of comma
600 600
 separated duration specifications, in increasing order.
601
+
601 602
 @item segment_wrap @var{limit}
602 603
 Wrap around segment index once it reaches @var{limit}.
604
+
605
+@item reset_timestamps @var{1|0}
606
+Reset timestamps at the begin of each segment, so that each segment
607
+will start with near-zero timestamps. It is meant to ease the playback
608
+of the generated segments. May not work with some combinations of
609
+muxers/codecs. It is set to @code{0} by default.
603 610
 @end table
604 611
 
605 612
 Some examples follow.
... ...
@@ -34,6 +34,7 @@
34 34
 #include "libavutil/avstring.h"
35 35
 #include "libavutil/parseutils.h"
36 36
 #include "libavutil/mathematics.h"
37
+#include "libavutil/timestamp.h"
37 38
 
38 39
 typedef enum {
39 40
     LIST_TYPE_UNDEFINED = -1,
... ...
@@ -71,8 +72,11 @@ typedef struct {
71 71
     int64_t time_delta;
72 72
     int  individual_header_trailer; /**< Set by a private option. */
73 73
     int  write_header_trailer; /**< Set by a private option. */
74
+
75
+    int reset_timestamps;  ///< reset timestamps at the begin of each segment
74 76
     int has_video;
75 77
     double start_time, end_time;
78
+    int64_t start_pts, start_dts;
76 79
 } SegmentContext;
77 80
 
78 81
 static void print_csv_escaped_str(AVIOContext *ctx, const char *str)
... ...
@@ -467,6 +471,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
467 467
 
468 468
     /* if the segment has video, start a new segment *only* with a key video frame */
469 469
     if ((st->codec->codec_type == AVMEDIA_TYPE_VIDEO || !seg->has_video) &&
470
+        pkt->pts != AV_NOPTS_VALUE &&
470 471
         av_compare_ts(pkt->pts, st->time_base,
471 472
                       end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0 &&
472 473
         pkt->flags & AV_PKT_FLAG_KEY) {
... ...
@@ -485,11 +490,29 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
485 485
         oc = seg->avf;
486 486
 
487 487
         seg->start_time = (double)pkt->pts * av_q2d(st->time_base);
488
+        seg->start_pts = av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q);
489
+        seg->start_dts = pkt->dts != AV_NOPTS_VALUE ?
490
+            av_rescale_q(pkt->dts, st->time_base, AV_TIME_BASE_Q) : seg->start_pts;
488 491
     } else if (pkt->pts != AV_NOPTS_VALUE) {
489 492
         seg->end_time = FFMAX(seg->end_time,
490 493
                               (double)(pkt->pts + pkt->duration) * av_q2d(st->time_base));
491 494
     }
492 495
 
496
+    if (seg->reset_timestamps) {
497
+        av_log(s, AV_LOG_DEBUG, "start_pts:%s pts:%s start_dts:%s dts:%s",
498
+               av_ts2timestr(seg->start_pts, &AV_TIME_BASE_Q), av_ts2timestr(pkt->pts, &st->time_base),
499
+               av_ts2timestr(seg->start_dts, &AV_TIME_BASE_Q), av_ts2timestr(pkt->dts, &st->time_base));
500
+
501
+        /* compute new timestamps */
502
+        if (pkt->pts != AV_NOPTS_VALUE)
503
+            pkt->pts -= av_rescale_q(seg->start_pts, AV_TIME_BASE_Q, st->time_base);
504
+        if (pkt->dts != AV_NOPTS_VALUE)
505
+            pkt->dts -= av_rescale_q(seg->start_dts, AV_TIME_BASE_Q, st->time_base);
506
+
507
+        av_log(s, AV_LOG_DEBUG, " -> pts:%s dts:%s\n",
508
+               av_ts2timestr(pkt->pts, &st->time_base), av_ts2timestr(pkt->dts, &st->time_base));
509
+    }
510
+
493 511
     ret = ff_write_chained(oc, pkt->stream_index, pkt, s);
494 512
 
495 513
 fail:
... ...
@@ -548,8 +571,10 @@ static const AVOption options[] = {
548 548
     { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta_str), AV_OPT_TYPE_STRING, {.str = "0"}, 0, 0, E },
549 549
     { "segment_times",     "set segment split time points",              OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL},  0, 0,       E },
550 550
     { "segment_wrap",      "set number after which the index wraps",     OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
551
+
551 552
     { "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
552 553
     { "write_header_trailer", "write a header to the first segment and a trailer to the last one", OFFSET(write_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
554
+    { "reset_timestamps", "reset timestamps at the begin of each segment", OFFSET(reset_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E },
553 555
     { NULL },
554 556
 };
555 557
 
... ...
@@ -31,7 +31,7 @@
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR 54
33 33
 #define LIBAVFORMAT_VERSION_MINOR 49
34
-#define LIBAVFORMAT_VERSION_MICRO 100
34
+#define LIBAVFORMAT_VERSION_MICRO 101
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
37 37
                                                LIBAVFORMAT_VERSION_MINOR, \