[FFmpeg-cvslog] lavf/dashenc: Add DASH segment type auto and make it the default

Andrey Semashev git at videolan.org
Wed Nov 21 14:40:45 EET 2018


ffmpeg | branch: master | Andrey Semashev <andrey.semashev at gmail.com> | Sat Nov 17 20:40:50 2018 +0300| [322e53f8aebb50cab0c3138c04b950f95fc455e5] | committer: Karthick J

lavf/dashenc: Add DASH segment type auto and make it the default

This commit restores the ability to create DASH streams with codecs
that require different containers that was lost after commit
2efdbf7367989cf9d296c25fa3d2aff8d6e25fdd. It adds a new "auto" value for
the dash_segment_type option and makes it the default. When in this mode,
the segment format will be chosen based on the codec used in the stream:
webm for Vorbis, Opus, VP8 or VP9, mp4 otherwise.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=322e53f8aebb50cab0c3138c04b950f95fc455e5
---

 doc/muxers.texi       |  7 +++--
 libavformat/dashenc.c | 72 ++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 59 insertions(+), 20 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 62f4091e31..2fed5cf3d4 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -289,10 +289,13 @@ Set container format (mp4/webm) options using a @code{:} separated list of
 key=value parameters. Values containing @code{:} special characters must be
 escaped.
 
- at item dash_segment_type @var{dash_segment_type}
+ at item -dash_segment_type @var{dash_segment_type}
 Possible values:
+ at item auto
+If this flag is set, the dash segment files format will be selected based on the stream codec. This is the default mode.
+
 @item mp4
-If this flag is set, the dash segment files will be in in ISOBMFF format. This is the default format.
+If this flag is set, the dash segment files will be in in ISOBMFF format.
 
 @item webm
 If this flag is set, the dash segment files will be in in WebM format.
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index d151921175..0af7b85c5f 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -49,7 +49,8 @@
 #include "dash.h"
 
 typedef enum {
-    SEGMENT_TYPE_MP4 = 0,
+    SEGMENT_TYPE_AUTO = 0,
+    SEGMENT_TYPE_MP4,
     SEGMENT_TYPE_WEBM,
     SEGMENT_TYPE_NB
 } SegmentType;
@@ -84,6 +85,8 @@ typedef struct OutputStream {
     int64_t first_pts, start_pts, max_pts;
     int64_t last_dts, last_pts;
     int bit_rate;
+    SegmentType segment_type;  /* segment type selected for this particular stream */
+    const char *format_name;
 
     char codec_str[100];
     int written_len;
@@ -131,8 +134,7 @@ typedef struct DASHContext {
     int64_t timeout;
     int index_correction;
     char *format_options_str;
-    SegmentType segment_type;
-    const char *format_name;
+    SegmentType segment_type_option;  /* segment type as specified in options */
 } DASHContext;
 
 static struct codec_string {
@@ -151,6 +153,7 @@ static struct format_string {
     SegmentType segment_type;
     const char *str;
 } formats[] = {
+    { SEGMENT_TYPE_AUTO, "auto" },
     { SEGMENT_TYPE_MP4, "mp4" },
     { SEGMENT_TYPE_WEBM, "webm" },
     { 0, NULL }
@@ -197,6 +200,38 @@ static const char *get_format_str(SegmentType segment_type) {
     return NULL;
 }
 
+static inline SegmentType select_segment_type(SegmentType segment_type, AVCodecID codec_id)
+{
+    if (segment_type == SEGMENT_TYPE_AUTO) {
+        if (codec_id == AV_CODEC_ID_OPUS || codec_id == AV_CODEC_ID_VORBIS ||
+            codec_id == AV_CODEC_ID_VP8 || codec_id == AV_CODEC_ID_VP9) {
+            segment_type = SEGMENT_TYPE_WEBM;
+        } else {
+            segment_type = SEGMENT_TYPE_MP4;
+        }
+    }
+
+    return segment_type;
+}
+
+static int init_segment_types(AVFormatContext *s)
+{
+    DASHContext *c = s->priv_data;
+    for (int i = 0; i < s->nb_streams; ++i) {
+        OutputStream *os = &c->streams[i];
+        SegmentType segment_type = select_segment_type(
+            c->segment_type_option, s->streams[i]->codecpar->codec_id);
+        os->segment_type = segment_type;
+        os->format_name = get_format_str(segment_type);
+        if (!os->format_name) {
+            av_log(s, AV_LOG_ERROR, "Could not select DASH segment type for stream %d\n", i);
+            return AVERROR_MUXER_NOT_FOUND;
+        }
+    }
+
+    return 0;
+}
+
 static int check_file_extension(const char *filename, const char *extension) {
     char *dot;
     if (!filename || !extension)
@@ -622,13 +657,13 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind
         if (as->media_type == AVMEDIA_TYPE_VIDEO) {
             AVStream *st = s->streams[i];
             avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s width=\"%d\" height=\"%d\"",
-                i, c->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
+                i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
             if (st->avg_frame_rate.num)
                 avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den);
             avio_printf(out, ">\n");
         } else {
             avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/%s\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n",
-                i, c->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate);
+                i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate);
             avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n",
                 s->streams[i]->codecpar->channels);
         }
@@ -993,6 +1028,9 @@ static int dash_init(AVFormatContext *s)
     if ((ret = parse_adaptation_sets(s)) < 0)
         return ret;
 
+    if ((ret = init_segment_types(s)) < 0)
+        return ret;
+
     for (i = 0; i < s->nb_streams; i++) {
         OutputStream *os = &c->streams[i];
         AdaptationSet *as = &c->as[os->as_idx - 1];
@@ -1018,13 +1056,10 @@ static int dash_init(AVFormatContext *s)
         if (!ctx)
             return AVERROR(ENOMEM);
 
-        c->format_name = get_format_str(c->segment_type);
-        if (!c->format_name)
-            return AVERROR_MUXER_NOT_FOUND;
-        if (c->segment_type == SEGMENT_TYPE_WEBM) {
-            if ((!c->single_file && check_file_extension(c->init_seg_name, c->format_name) != 0) ||
-                (!c->single_file && check_file_extension(c->media_seg_name, c->format_name) != 0) ||
-                (c->single_file && check_file_extension(c->single_file_name, c->format_name) != 0)) {
+        if (os->segment_type == SEGMENT_TYPE_WEBM) {
+            if ((!c->single_file && check_file_extension(c->init_seg_name, os->format_name) != 0) ||
+                (!c->single_file && check_file_extension(c->media_seg_name, os->format_name) != 0) ||
+                (c->single_file && check_file_extension(c->single_file_name, os->format_name) != 0)) {
                 av_log(s, AV_LOG_WARNING,
                        "One or many segment file names doesn't end with .webm. "
                        "Override -init_seg_name and/or -media_seg_name and/or "
@@ -1032,7 +1067,7 @@ static int dash_init(AVFormatContext *s)
             }
         }
 
-        ctx->oformat = av_guess_format(c->format_name, NULL, NULL);
+        ctx->oformat = av_guess_format(os->format_name, NULL, NULL);
         if (!ctx->oformat)
             return AVERROR_MUXER_NOT_FOUND;
         os->ctx = ctx;
@@ -1076,7 +1111,7 @@ static int dash_init(AVFormatContext *s)
                 return ret;
         }
 
-        if (c->segment_type == SEGMENT_TYPE_MP4) {
+        if (os->segment_type == SEGMENT_TYPE_MP4) {
             if (c->streaming)
                 av_dict_set(&opts, "movflags", "frag_every_frame+dash+delay_moov+global_sidx", 0);
             else
@@ -1141,7 +1176,7 @@ static int dash_write_header(AVFormatContext *s)
         // Flush init segment
         // Only for WebM segment, since for mp4 delay_moov is set and
         // the init segment is thus flushed after the first packets.
-        if (c->segment_type == SEGMENT_TYPE_WEBM &&
+        if (os->segment_type == SEGMENT_TYPE_WEBM &&
             (ret = flush_init_segment(s, os)) < 0)
             return ret;
     }
@@ -1312,7 +1347,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream)
         }
 
         if (!c->single_file) {
-            if (c->segment_type == SEGMENT_TYPE_MP4 && !os->written_len)
+            if (os->segment_type == SEGMENT_TYPE_MP4 && !os->written_len)
                 write_styp(os->ctx->pb);
         } else {
             snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, os->initfile);
@@ -1502,7 +1537,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
     }
 
     //write out the data immediately in streaming mode
-    if (c->streaming && c->segment_type == SEGMENT_TYPE_MP4) {
+    if (c->streaming && os->segment_type == SEGMENT_TYPE_MP4) {
         int len = 0;
         uint8_t *buf = NULL;
         if (!os->written_len)
@@ -1598,7 +1633,8 @@ static const AVOption options[] = {
     { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E },
     { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
     { "format_options","set list of options for the container format (mp4/webm) used for dash", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0, E},
-    { "dash_segment_type", "set dash segment files type", OFFSET(segment_type), AV_OPT_TYPE_INT, {.i64 = SEGMENT_TYPE_MP4 }, 0, SEGMENT_TYPE_NB - 1, E, "segment_type"},
+    { "dash_segment_type", "set dash segment files type", OFFSET(segment_type_option), AV_OPT_TYPE_INT, {.i64 = SEGMENT_TYPE_AUTO }, 0, SEGMENT_TYPE_NB - 1, E, "segment_type"},
+    { "auto", "select segment file format based on codec", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_AUTO }, 0, UINT_MAX,   E, "segment_type"},
     { "mp4", "make segment file in ISOBMFF format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_MP4 }, 0, UINT_MAX,   E, "segment_type"},
     { "webm", "make segment file in WebM format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_WEBM }, 0, UINT_MAX,   E, "segment_type"},
     { NULL },



More information about the ffmpeg-cvslog mailing list