[09/14] dashenc: Add an option for writing segments starting at an index other than one

Message ID 1419862828-30060-9-git-send-email-martin@martin.st
State New
Headers show

Commit Message

Martin Storsjö Dec. 29, 2014, 2:20 p.m.
Based on patches by Rodger Combs.
---
 libavformat/dashenc.c | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

Comments

Derek Buitenhuis Dec. 29, 2014, 5 p.m. | #1
On 12/29/2014 2:20 PM, Martin Storsjö wrote:
> Based on patches by Rodger Combs.
> ---
>  libavformat/dashenc.c | 24 +++++++++++++++++++-----
>  1 file changed, 19 insertions(+), 5 deletions(-)

LGTM, I think.

- Derek

Patch

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 5afc40b..a76acf2 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -93,6 +93,7 @@  typedef struct DASHContext {
     const char *single_file_name;
     const char *init_seg_name;
     const char *media_seg_name;
+    int start_segment;
 } DASHContext;
 
 static int dash_write(void *opaque, uint8_t *buf, int buf_size)
@@ -195,10 +196,10 @@  static void dash_free(AVFormatContext *s)
 
 static void output_segment_list(OutputStream *os, AVIOContext *out, DASHContext *c)
 {
-    int i, start_index = 0, start_number = 1;
+    int i, start_index = 0, start_number = c->start_segment;
     if (c->window_size) {
         start_index  = FFMAX(os->nb_segments   - c->window_size, 0);
-        start_number = FFMAX(os->segment_index - c->window_size, 1);
+        start_number = FFMAX(os->segment_index - c->window_size, c->start_segment);
     }
 
     if (c->use_template) {
@@ -206,7 +207,7 @@  static void output_segment_list(OutputStream *os, AVIOContext *out, DASHContext
         avio_printf(out, "\t\t\t\t<SegmentTemplate timescale=\"%d\" ", timescale);
         if (!c->use_timeline)
             avio_printf(out, "duration=\"%"PRId64"\" ", c->last_duration);
-        avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? start_number : 1);
+        avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? start_number : c->start_segment);
         if (c->use_timeline) {
             int64_t cur_time = 0;
             avio_printf(out, "\t\t\t\t\t<SegmentTimeline>\n");
@@ -541,6 +542,13 @@  static int dash_write_header(AVFormatContext *s)
     if (c->single_file)
         c->use_template = 0;
 
+    /* If starting at a later segment than the first, don't shift
+     * timestamps back to zero, just make them nonnegative. The fragment
+     * timestamp offset written in the tfdt atoms assume that the stream
+     * starts (in the fragments that haven't been written) at dts=0. */
+    if (c->start_segment > 1 && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO)
+        s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE;
+
     av_strlcpy(c->dirname, s->filename, sizeof(c->dirname));
     ptr = strrchr(c->dirname, '/');
     if (ptr) {
@@ -626,7 +634,11 @@  static int dash_write_header(AVFormatContext *s)
             goto fail;
         os->init_start_pos = 0;
 
-        av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
+        if (c->start_segment > 1) {
+            av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov+frag_discont", 0);
+        } else {
+            av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
+        }
         if ((ret = avformat_write_header(ctx, &opts)) < 0) {
              goto fail;
         }
@@ -649,7 +661,7 @@  static int dash_write_header(AVFormatContext *s)
         set_codec_str(s, os->ctx->streams[0]->codec, os->codec_str, sizeof(os->codec_str));
         os->first_dts = AV_NOPTS_VALUE;
         os->end_dts = AV_NOPTS_VALUE;
-        os->segment_index = 1;
+        os->segment_index = c->start_segment;
     }
 
     if (!c->has_video && c->min_seg_duration <= 0) {
@@ -765,6 +777,7 @@  static int dash_flush(AVFormatContext *s, int final, int stream)
                 ffurl_close(os->out);
                 os->out = NULL;
             }
+            av_opt_set_int(os->ctx, "fragment_index", os->segment_index, AV_OPT_SEARCH_CHILDREN);
         }
 
         start_pos = avio_tell(os->ctx->pb);
@@ -929,6 +942,7 @@  static const AVOption options[] = {
     { "single_file_name", "DASH-templated name to be used for baseURL. Implies storing all segments in one file, accessed using byte ranges", OFFSET(single_file_name), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
     { "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.m4s"}, 0, 0, E },
     { "media_seg_name", "DASH-templated name to used for the media segments", OFFSET(media_seg_name), AV_OPT_TYPE_STRING, {.str = "chunk-stream$RepresentationID$-$Number%05d$.m4s"}, 0, 0, E },
+    { "start_segment", "Segment number of the first segment", OFFSET(start_segment), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, E },
     { NULL },
 };