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

File 0001-lavf-segment-add-reset_timestamps-option.patch, 6.5 KB (added by saste, 4 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