Ticket #1425: 0001-lavf-segment-add-reset_timestamps-option.patch

File 0001-lavf-segment-add-reset_timestamps-option.patch, 6.5 KB (added by Stefano Sabatini, 14 years ago)

Patch which adds the reset_timestamps segment option

  • doc/muxers.texi

    From 07fec85d814e9aa2f61a25ece9eb3cc5e2483b10 Mon Sep 17 00:00:00 2001
    From: Stefano Sabatini <stefasab@gmail.com>
    Date: Thu, 29 Nov 2012 13:45:50 +0100
    Subject: [PATCH] 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 from 0.
    
    It is meant to address trac ticket #1425.
    ---
     doc/muxers.texi       |    7 +++++++
     libavformat/segment.c |   56 +++++++++++++++++++++++++++++++++++++++++++++++--
     2 files changed, 61 insertions(+), 2 deletions(-)
    
    diff --git a/doc/muxers.texi b/doc/muxers.texi
    index 1c8f93b..be22298 100644
    a b the specified time and the time set by @var{force_key_frames}.  
    588588@item segment_times @var{times}
    589589Specify a list of split points. @var{times} contains a list of comma
    590590separated duration specifications, in increasing order.
     591
    591592@item segment_wrap @var{limit}
    592593Wrap around segment index once it reaches @var{limit}.
     594
     595@item reset_timestamps @var{1|0}
     596Reset timestamps at the begin of each segment, so that each segment
     597will start with near-zero timestamps. It is meant to ease the playback
     598of the generated segments. May not work with some combinations of
     599muxers/codecs. It is set to @code{0} by default.
    593600@end table
    594601
    595602Some examples follow.
  • libavformat/segment.c

    diff --git a/libavformat/segment.c b/libavformat/segment.c
    index 1ad410e..7c8eb28 100644
    a b  
    3535#include "libavutil/avstring.h"
    3636#include "libavutil/parseutils.h"
    3737#include "libavutil/mathematics.h"
     38#include "libavutil/timestamp.h"
    3839
    3940typedef enum {
    4041    LIST_TYPE_UNDEFINED = -1,
    typedef enum {  
    4950#define SEGMENT_LIST_FLAG_CACHE 1
    5051#define SEGMENT_LIST_FLAG_LIVE  2
    5152
     53struct stream_timestamps {
     54    int64_t last_out_pts, last_out_dts, start_pts, start_dts;
     55};
     56
    5257typedef struct {
    5358    const AVClass *class;  /**< Class for private options. */
    5459    int segment_idx;       ///< index of the segment file to write, starting from 0
    typedef struct {  
    7277    int64_t time_delta;
    7378    int  individual_header_trailer; /**< Set by a private option. */
    7479    int  write_header_trailer; /**< Set by a private option. */
     80
     81    int reset_timestamps;  ///< reset timestamps at the begin of each segment
     82    struct stream_timestamps *timestamps;
     83    int nb_timestamps;
    7584    int has_video;
    7685    double start_time, end_time;
    7786} SegmentContext;
    static int segment_start(AVFormatContext *s, int write_header)  
    131140{
    132141    SegmentContext *seg = s->priv_data;
    133142    AVFormatContext *oc = seg->avf;
    134     int err = 0;
     143    int err = 0, i;
    135144
    136145    if (write_header) {
    137146        avformat_free_context(oc);
    static int segment_start(AVFormatContext *s, int write_header)  
    163172        if ((err = avformat_write_header(oc, NULL)) < 0)
    164173            return err;
    165174    }
     175    if (seg->reset_timestamps)
     176        for (i = 0; i < seg->nb_timestamps; i++)
     177             seg->timestamps[i].start_pts = seg->timestamps[i].start_dts = AV_NOPTS_VALUE;
    166178
    167179    return 0;
    168180}
    static int seg_write_header(AVFormatContext *s)  
    379391    if (seg->list_type == LIST_TYPE_EXT)
    380392        av_log(s, AV_LOG_WARNING, "'ext' list type option is deprecated in favor of 'csv'\n");
    381393
    382     for (i = 0; i < s->nb_streams; i++)
     394    seg->timestamps = av_malloc(sizeof(*seg->timestamps) * s->nb_streams);
     395    if (!seg->timestamps) {
     396        ret = AVERROR(ENOMEM);
     397        goto fail;
     398    }
     399    seg->nb_timestamps = s->nb_streams;
     400
     401    for (i = 0; i < seg->nb_timestamps; i++) {
    383402        seg->has_video +=
    384403            (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO);
     404        seg->timestamps[i].last_out_pts = seg->timestamps[i].start_pts =
     405        seg->timestamps[i].last_out_dts = seg->timestamps[i].start_dts = AV_NOPTS_VALUE;
     406    }
    385407
    386408    if (seg->has_video > 1)
    387409        av_log(s, AV_LOG_WARNING,
    static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)  
    486508                              (double)(pkt->pts + pkt->duration) * av_q2d(st->time_base));
    487509    }
    488510
     511    if (seg->reset_timestamps) {
     512        struct stream_timestamps *ts = &seg->timestamps[pkt->stream_index];
     513
     514        /* compute initial timestamps */
     515        if (ts->start_pts == AV_NOPTS_VALUE)
     516            ts->start_pts = pkt->pts != AV_NOPTS_VALUE ? pkt->pts : ts->last_out_pts;
     517        if (ts->start_dts == AV_NOPTS_VALUE)
     518            ts->start_dts = pkt->dts != AV_NOPTS_VALUE ? pkt->dts : ts->last_out_dts;
     519
     520        av_log(s, AV_LOG_DEBUG, "start_pts:%s pts:%s start_dts:%s dts:%s",
     521               av_ts2str(ts->start_pts), av_ts2str(pkt->pts), av_ts2str(ts->start_dts), av_ts2str(pkt->dts));
     522
     523        /* compute last timestamps */
     524        if (pkt->pts != AV_NOPTS_VALUE)
     525            ts->last_out_pts = pkt->pts + (pkt->duration <= 0 ? 1 : pkt->duration);
     526        if (pkt->dts != AV_NOPTS_VALUE)
     527            ts->last_out_dts = pkt->dts + (pkt->duration <= 0 ? 1 : pkt->duration);
     528
     529        /* compute new timestamps */
     530        if (ts->start_pts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE)
     531            pkt->pts -= ts->start_pts;
     532        if (ts->start_dts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE)
     533            pkt->dts -= ts->start_dts;
     534
     535        av_log(s, AV_LOG_DEBUG, " -> pts:%s dts:%s\n", av_ts2str(pkt->pts), av_ts2str(pkt->dts));
     536    }
     537
    489538    ret = ff_write_chained(oc, pkt->stream_index, pkt, s);
    490539
    491540fail:
    fail:  
    518567
    519568    av_opt_free(seg);
    520569    av_freep(&seg->times);
     570    av_freep(&seg->timestamps);
    521571
    522572    avformat_free_context(oc);
    523573    return ret;
    static const AVOption options[] = {  
    544594    { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta_str), AV_OPT_TYPE_STRING, {.str = "0"}, 0, 0, E },
    545595    { "segment_times",     "set segment split time points",              OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL},  0, 0,       E },
    546596    { "segment_wrap",      "set number after which the index wraps",     OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
     597
    547598    { "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
    548599    { "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 },
     600    { "reset_timestamps", "reset timestamps at the begin of each segment", OFFSET(reset_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E },
    549601    { NULL },
    550602};
    551603