Browse code

Merge commit '7295b7373862ee54903b33d6ef3335531dfa93ad'

* commit '7295b7373862ee54903b33d6ef3335531dfa93ad':
dashenc: add webm support

Merged-by: Rodger Combs <rodger.combs@gmail.com>

Rodger Combs authored on 2017/09/27 02:13:09
Showing 2 changed files
... ...
@@ -61,6 +61,7 @@ typedef struct OutputStream {
61 61
     AVFormatContext *ctx;
62 62
     int ctx_inited, as_idx;
63 63
     AVIOContext *out;
64
+    char format_name[8];
64 65
     int packets_written;
65 66
     char initfile[1024];
66 67
     int64_t init_start_pos, pos;
... ...
@@ -101,12 +102,32 @@ typedef struct DASHContext {
101 101
     const char *utc_timing_url;
102 102
 } DASHContext;
103 103
 
104
-// RFC 6381
104
+static struct codec_string {
105
+    int id;
106
+    const char *str;
107
+} codecs[] = {
108
+    { AV_CODEC_ID_VP8, "vp8" },
109
+    { AV_CODEC_ID_VP9, "vp9" },
110
+    { AV_CODEC_ID_VORBIS, "vorbis" },
111
+    { AV_CODEC_ID_OPUS, "opus" },
112
+    { 0, NULL }
113
+};
114
+
105 115
 static void set_codec_str(AVFormatContext *s, AVCodecParameters *par,
106 116
                           char *str, int size)
107 117
 {
108 118
     const AVCodecTag *tags[2] = { NULL, NULL };
109 119
     uint32_t tag;
120
+    int i;
121
+
122
+    // common Webm codecs are not part of RFC 6381
123
+    for (i = 0; codecs[i].id; i++)
124
+        if (codecs[i].id == par->codec_id) {
125
+            av_strlcpy(str, codecs[i].str, size);
126
+            return;
127
+        }
128
+
129
+    // for codecs part of RFC 6381
110 130
     if (par->codec_type == AVMEDIA_TYPE_VIDEO)
111 131
         tags[0] = ff_codec_movvideo_tags;
112 132
     else if (par->codec_type == AVMEDIA_TYPE_AUDIO)
... ...
@@ -189,6 +210,21 @@ static int flush_dynbuf(OutputStream *os, int *range_length)
189 189
     return avio_open_dyn_buf(&os->ctx->pb);
190 190
 }
191 191
 
192
+static int flush_init_segment(AVFormatContext *s, OutputStream *os)
193
+{
194
+    DASHContext *c = s->priv_data;
195
+    int ret, range_length;
196
+
197
+    ret = flush_dynbuf(os, &range_length);
198
+    if (ret < 0)
199
+        return ret;
200
+
201
+    os->pos = os->init_range_length = range_length;
202
+    if (!c->single_file)
203
+        ff_format_io_close(s, &os->out);
204
+    return 0;
205
+}
206
+
192 207
 static void dash_free(AVFormatContext *s)
193 208
 {
194 209
     DASHContext *c = s->priv_data;
... ...
@@ -376,14 +412,14 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind
376 376
 
377 377
         if (as->media_type == AVMEDIA_TYPE_VIDEO) {
378 378
             AVStream *st = s->streams[i];
379
-            avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/mp4\" codecs=\"%s\"%s width=\"%d\" height=\"%d\"",
380
-                i, os->codec_str, os->bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
379
+            avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s width=\"%d\" height=\"%d\"",
380
+                i, os->format_name, os->codec_str, os->bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
381 381
             if (st->avg_frame_rate.num)
382 382
                 avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den);
383 383
             avio_printf(out, ">\n");
384 384
         } else {
385
-            avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/mp4\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n",
386
-                i, os->codec_str, os->bandwidth_str, s->streams[i]->codecpar->sample_rate);
385
+            avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/%s\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n",
386
+                i, os->format_name, os->codec_str, os->bandwidth_str, s->streams[i]->codecpar->sample_rate);
387 387
             avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n",
388 388
                 s->streams[i]->codecpar->channels);
389 389
         }
... ...
@@ -628,11 +664,18 @@ static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const ch
628 628
     return 0;
629 629
 }
630 630
 
631
+static int dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
632
+{
633
+    char valuestr[22];
634
+    snprintf(valuestr, sizeof(valuestr), "%"PRId64, value);
635
+    flags &= ~AV_DICT_DONT_STRDUP_VAL;
636
+    return av_dict_set(pm, key, valuestr, flags);
637
+}
638
+
631 639
 static int dash_init(AVFormatContext *s)
632 640
 {
633 641
     DASHContext *c = s->priv_data;
634 642
     int ret = 0, i;
635
-    AVOutputFormat *oformat;
636 643
     char *ptr;
637 644
     char basename[1024];
638 645
 
... ...
@@ -656,10 +699,6 @@ static int dash_init(AVFormatContext *s)
656 656
     if (ptr)
657 657
         *ptr = '\0';
658 658
 
659
-    oformat = av_guess_format("mp4", NULL, NULL);
660
-    if (!oformat)
661
-        return AVERROR_MUXER_NOT_FOUND;
662
-
663 659
     c->streams = av_mallocz(sizeof(*c->streams) * s->nb_streams);
664 660
     if (!c->streams)
665 661
         return AVERROR(ENOMEM);
... ...
@@ -694,8 +733,22 @@ static int dash_init(AVFormatContext *s)
694 694
         ctx = avformat_alloc_context();
695 695
         if (!ctx)
696 696
             return AVERROR(ENOMEM);
697
+
698
+        // choose muxer based on codec: webm for VP8/9 and opus, mp4 otherwise
699
+        // note: os->format_name is also used as part of the mimetype of the
700
+        //       representation, e.g. video/<format_name>
701
+        if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VP8 ||
702
+            s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VP9 ||
703
+            s->streams[i]->codecpar->codec_id == AV_CODEC_ID_OPUS ||
704
+            s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VORBIS) {
705
+            snprintf(os->format_name, sizeof(os->format_name), "webm");
706
+        } else {
707
+            snprintf(os->format_name, sizeof(os->format_name), "mp4");
708
+        }
709
+        ctx->oformat = av_guess_format(os->format_name, NULL, NULL);
710
+        if (!ctx->oformat)
711
+            return AVERROR_MUXER_NOT_FOUND;
697 712
         os->ctx = ctx;
698
-        ctx->oformat = oformat;
699 713
         ctx->interrupt_callback = s->interrupt_callback;
700 714
         ctx->opaque             = s->opaque;
701 715
         ctx->io_close           = s->io_close;
... ...
@@ -726,8 +779,13 @@ static int dash_init(AVFormatContext *s)
726 726
             return ret;
727 727
         os->init_start_pos = 0;
728 728
 
729
-        av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
730
-        if ((ret = avformat_init_output(ctx, &opts)) < 0)
729
+        if (!strcmp(os->format_name, "mp4")) {
730
+            av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
731
+        } else {
732
+            dict_set_int(&opts, "cluster_time_limit", c->min_seg_duration / 1000, 0);
733
+            dict_set_int(&opts, "cluster_size_limit", 5 * 1024 * 1024, 0); // set a large cluster size limit
734
+        }
735
+        if ((ret = avformat_write_header(ctx, &opts)) < 0)
731 736
             return ret;
732 737
         os->ctx_inited = 1;
733 738
         avio_flush(ctx->pb);
... ...
@@ -735,6 +793,13 @@ static int dash_init(AVFormatContext *s)
735 735
 
736 736
         av_log(s, AV_LOG_VERBOSE, "Representation %d init segment will be written to: %s\n", i, filename);
737 737
 
738
+        // Flush init segment
739
+        // except for mp4, since delay_moov is set and the init segment
740
+        // is then flushed after the first packets
741
+        if (strcmp(os->format_name, "mp4")) {
742
+            flush_init_segment(s, os);
743
+        }
744
+
738 745
         s->streams[i]->time_base = st->time_base;
739 746
         // If the muxer wants to shift timestamps, request to have them shifted
740 747
         // already before being handed to this muxer, so we don't have mismatches
... ...
@@ -907,12 +972,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream)
907 907
         }
908 908
 
909 909
         if (!os->init_range_length) {
910
-            ret = flush_dynbuf(os, &range_length);
911
-            if (ret < 0)
912
-                break;
913
-            os->pos = os->init_range_length = range_length;
914
-            if (!c->single_file)
915
-                ff_format_io_close(s, &os->out);
910
+            flush_init_segment(s, os);
916 911
         }
917 912
 
918 913
         if (!c->single_file) {
... ...
@@ -922,7 +982,8 @@ static int dash_flush(AVFormatContext *s, int final, int stream)
922 922
             ret = s->io_open(s, &os->out, temp_path, AVIO_FLAG_WRITE, NULL);
923 923
             if (ret < 0)
924 924
                 break;
925
-            write_styp(os->ctx->pb);
925
+            if (!strcmp(os->format_name, "mp4"))
926
+                write_styp(os->ctx->pb);
926 927
         } else {
927 928
             snprintf(full_path, sizeof(full_path), "%s%s", c->dirname, os->initfile);
928 929
         }
... ...
@@ -33,7 +33,7 @@
33 33
 // Also please add any ticket numbers that you believe might be affected here
34 34
 #define LIBAVFORMAT_VERSION_MAJOR  57
35 35
 #define LIBAVFORMAT_VERSION_MINOR  82
36
-#define LIBAVFORMAT_VERSION_MICRO 101
36
+#define LIBAVFORMAT_VERSION_MICRO 102
37 37
 
38 38
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
39 39
                                                LIBAVFORMAT_VERSION_MINOR, \