diff mbox

[FFmpeg-devel] avformat/hlsenc: add var_stream_map NAME field string parameter

Message ID 20190321143727.AD98ED8023@mail.noc.grnet.gr
State New
Headers show

Commit Message

Zenon Mousmoulas March 21, 2019, 8:04 a.m. UTC
Use "a:0,agroup:aud_low,default:Yes,name:Chinese,language:CHN
     a:1,agroup:aud_low,language:ENG
     a:2,agroup:aud_high,default:Yes,name:Chinese,language:CHN
     a:3,agroup:aud_high,language:ENG
     v:0,agroup:aud_low v:1,agroup:aud_high"
to create master m3u8 list.

Result:

EXTM3U
EXT-X-VERSION:3
EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_aud_low",NAME="Chinese",DEFAULT=YES,LANGUAGE="CHN",URI="out_0.m3u8"
EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_aud_low",NAME="audio_1",DEFAULT=NO,LANGUAGE="ENG",URI="out_1.m3u8"
EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_aud_high",NAME="Chinese",DEFAULT=YES,LANGUAGE="CHN",URI="out_2.m3u8"
EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_aud_high",NAME="audio_3",DEFAULT=NO,LANGUAGE="ENG",URI="out_3.m3u8"
EXT-X-STREAM-INF:BANDWIDTH=1170400,RESOLUTION=640x480,CODECS="avc1.64001e,mp4a.40.2",AUDIO="group_aud_low"
out_4.m3u8
EXT-X-STREAM-INF:BANDWIDTH=3440800,RESOLUTION=640x480,CODECS="avc1.64001e,mp4a.40.2",AUDIO="group_aud_high"
out_5.m3u8

Signed-off-by: Zenon Mousmoulas <zmousm@noc.grnet.gr>
---
 doc/muxers.texi           |  6 ++++--
 libavformat/dashenc.c     |  2 +-
 libavformat/hlsenc.c      | 14 +++++++++++---
 libavformat/hlsplaylist.c |  6 ++++--
 libavformat/hlsplaylist.h |  2 +-
 5 files changed, 21 insertions(+), 9 deletions(-)

Comments

Zenon Mousmoulas March 28, 2019, 7:01 a.m. UTC | #1
March 21, 2019 4:37 PM, "Zenon Mousmoulas" <zmousm@noc.grnet.gr> wrote:

> Use "a:0,agroup:aud_low,default:Yes,name:Chinese,language:CHN
> a:1,agroup:aud_low,language:ENG
> a:2,agroup:aud_high,default:Yes,name:Chinese,language:CHN
> a:3,agroup:aud_high,language:ENG
> v:0,agroup:aud_low v:1,agroup:aud_high"
> to create master m3u8 list.
> 
> Result:
> 
> EXTM3U
> EXT-X-VERSION:3
> EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_aud_low",NAME="Chinese",DEFAULT=YES,LANGUAGE="CHN",URI="out_0
> m3u8"
> EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_aud_low",NAME="audio_1",DEFAULT=NO,LANGUAGE="ENG",URI="out_1.
> 3u8"
> EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_aud_high",NAME="Chinese",DEFAULT=YES,LANGUAGE="CHN",URI="out_
> .m3u8"
> EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_aud_high",NAME="audio_3",DEFAULT=NO,LANGUAGE="ENG",URI="out_3
> m3u8"
> EXT-X-STREAM-INF:BANDWIDTH=1170400,RESOLUTION=640x480,CODECS="avc1.64001e,mp4a.40.2",AUDIO="group_au
> _low"
> out_4.m3u8
> EXT-X-STREAM-INF:BANDWIDTH=3440800,RESOLUTION=640x480,CODECS="avc1.64001e,mp4a.40.2",AUDIO="group_au
> _high"
> out_5.m3u8
> 
> Signed-off-by: Zenon Mousmoulas <zmousm@noc.grnet.gr>
> ---
> doc/muxers.texi | 6 ++++--
> libavformat/dashenc.c | 2 +-
> libavformat/hlsenc.c | 14 +++++++++++---
> libavformat/hlsplaylist.c | 6 ++++--
> libavformat/hlsplaylist.h | 2 +-
> 5 files changed, 21 insertions(+), 9 deletions(-)
> 
> diff --git a/doc/muxers.texi b/doc/muxers.texi
> index aac7d94edf..57d1432827 100644
> --- a/doc/muxers.texi
> +++ b/doc/muxers.texi
> @@ -988,7 +988,7 @@ By default, a single hls variant containing all the encoded streams is created.
> @example
> ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k \
> -map 0:a -map 0:a -map 0:v -f hls \
> - -var_stream_map "a:0,agroup:aud_low,default:yes,language=ENG a:1,agroup:aud_low,language:CHN
> v:0,agroup:aud_low" \
> + -var_stream_map "a:0,agroup:aud_low,default:yes,name:English,language:ENG
> a:1,agroup:aud_low,language:CHN v:0,agroup:aud_low" \
> -master_pl_name master.m3u8 \
> http://example.com/live/out_%v.m3u8
> @end example
> @@ -997,7 +997,9 @@ addition to the #EXT-X-STREAM-INF tag for each variant stream in the master
> playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams
> and they are mapped to the one video only variant streams with audio group name
> 'aud_low', and the audio group have default stat is NO or YES, and one audio
> -have and language is named ENG, the other audio language is named CHN.
> +have and language is named ENG, the other audio language is named CHN. The first
> +audio is named English, overriding the default which is derived from the variant
> +stream index.
> 
> By default, a single hls variant containing all the encoded streams is created.
> 
> diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
> index 1b74bce060..06dc9f3143 100644
> --- a/libavformat/dashenc.c
> +++ b/libavformat/dashenc.c
> @@ -1016,7 +1016,7 @@ static int write_manifest(AVFormatContext *s, int final)
> continue;
> get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i);
> ff_hls_write_audio_rendition(c->m3u8_out, (char *)audio_group,
> - playlist_file, NULL, i, is_default);
> + playlist_file, NULL, i, NULL, is_default);
> max_audio_bitrate = FFMAX(st->codecpar->bit_rate +
> os->muxer_overhead, max_audio_bitrate);
> if (!av_strnstr(audio_codec_str, os->codec_str, sizeof(audio_codec_str))) {
> diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
> index 5f9a200c6e..813ac37368 100644
> --- a/libavformat/hlsenc.c
> +++ b/libavformat/hlsenc.c
> @@ -154,6 +154,7 @@ typedef struct VariantStream {
> unsigned int nb_streams;
> int m3u8_created; /* status of media play-list creation */
> int is_default; /* default status of audio group */
> + char *name; /* audio name */
> char *language; /* audio lauguage name */
> char *agroup; /* audio group name */
> char *ccgroup; /* closed caption group name */
> @@ -1262,7 +1263,9 @@ static int create_master_playlist(AVFormatContext *s,
> goto fail;
> }
> 
> - ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name, vs->language, i,
> hls->has_default_key ? vs->is_default : 1);
> + ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name,
> + vs->language, i, vs->name,
> + hls->has_default_key ? vs->is_default : 1);
> 
> av_freep(&m3u8_rel_name);
> }
> @@ -1830,7 +1833,7 @@ static int parse_variant_stream_mapstring(AVFormatContext *s)
> /**
> * Expected format for var_stream_map string is as below:
> * "a:0,v:0 a:1,v:1"
> - * "a:0,agroup:a0,default:1,language:ENG a:1,agroup:a1,defalut:0 v:0,agroup:a0 v:1,agroup:a1"
> + * "a:0,agroup:a0,default:1,name:English,language:ENG a:1,agroup:a1,default:0 v:0,agroup:a0
> v:1,agroup:a1"
> * This string specifies how to group the audio, video and subtitle streams
> * into different variant streams. The variant stream groups are separated
> * by space.
> @@ -1880,7 +1883,12 @@ static int parse_variant_stream_mapstring(AVFormatContext *s)
> nb_streams = 0;
> while (keyval = av_strtok(varstr, ",", &saveptr2)) {
> varstr = NULL;
> - if (av_strstart(keyval, "language:", &val)) {
> + if (av_strstart(keyval, "name:", &val)) {
> + vs->name = av_strdup(val);
> + if (!vs->name)
> + return AVERROR(ENOMEM);
> + continue;
> + } else if (av_strstart(keyval, "language:", &val)) {
> vs->language = av_strdup(val);
> if (!vs->language)
> return AVERROR(ENOMEM);
> diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c
> index 0537049a97..85b5668f22 100644
> --- a/libavformat/hlsplaylist.c
> +++ b/libavformat/hlsplaylist.c
> @@ -24,6 +24,7 @@
> #include <stdint.h>
> 
> #include "libavutil/time_internal.h"
> +#include "libavutil/avstring.h"
> 
> #include "avformat.h"
> #include "hlsplaylist.h"
> @@ -36,12 +37,13 @@ void ff_hls_write_playlist_version(AVIOContext *out, int version) {
> }
> 
> void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup,
> - char *filename, char *language, int name_id, int is_default) {
> + char *filename, char *language, int name_id, char *name, int is_default) {
> if (!out || !agroup || !filename)
> return;
> 
> avio_printf(out, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"", agroup);
> - avio_printf(out, ",NAME=\"audio_%d\",DEFAULT=%s,", name_id, is_default ? "YES" : "NO");
> + avio_printf(out, ",NAME=\"%s\",DEFAULT=%s,", name ? name : av_asprintf("audio_%d", name_id),
> + is_default ? "YES" : "NO");
> if (language) {
> avio_printf(out, "LANGUAGE=\"%s\",", language);
> }
> diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h
> index 54c93a3963..4a75e1fd74 100644
> --- a/libavformat/hlsplaylist.h
> +++ b/libavformat/hlsplaylist.h
> @@ -38,7 +38,7 @@ typedef enum {
> 
> void ff_hls_write_playlist_version(AVIOContext *out, int version);
> void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup,
> - char *filename, char *language, int name_id, int is_default);
> + char *filename, char *language, int name_id, char *name, int is_default);
> void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
> int bandwidth, char *filename, char *agroup,
> char *codecs, char *ccgroup);
> -- 
> 2.11.0

Ping.

This patch allows for setting a descriptive NAME in the HLS master playlist. NAME is required by the HLS spec, while LANGUAGE is not. Many HLS client implementations only support the former field, in which case the auto-generated "audio_%d" does not say much. Furthermore, a user-provided NAME can be more descriptive than what is afforded by a language code.

Regards,
Z.
diff mbox

Patch

diff --git a/doc/muxers.texi b/doc/muxers.texi
index aac7d94edf..57d1432827 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -988,7 +988,7 @@  By default, a single hls variant containing all the encoded streams is created.
 @example
 ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k \
   -map 0:a -map 0:a -map 0:v -f hls \
-  -var_stream_map "a:0,agroup:aud_low,default:yes,language=ENG a:1,agroup:aud_low,language:CHN v:0,agroup:aud_low" \
+  -var_stream_map "a:0,agroup:aud_low,default:yes,name:English,language:ENG a:1,agroup:aud_low,language:CHN v:0,agroup:aud_low" \
   -master_pl_name master.m3u8 \
   http://example.com/live/out_%v.m3u8
 @end example
@@ -997,7 +997,9 @@  addition to the #EXT-X-STREAM-INF tag for each variant stream in the master
 playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams
 and they are mapped to the one video only variant streams with audio group name
 'aud_low', and the audio group have default stat is NO or YES, and one audio
-have and language is named ENG, the other audio language is named CHN.
+have and language is named ENG, the other audio language is named CHN. The first
+audio is named English, overriding the default which is derived from the variant
+stream index.
 
 By default, a single hls variant containing all the encoded streams is created.
 
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 1b74bce060..06dc9f3143 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -1016,7 +1016,7 @@  static int write_manifest(AVFormatContext *s, int final)
                 continue;
             get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i);
             ff_hls_write_audio_rendition(c->m3u8_out, (char *)audio_group,
-                                         playlist_file, NULL, i, is_default);
+                                         playlist_file, NULL, i, NULL, is_default);
             max_audio_bitrate = FFMAX(st->codecpar->bit_rate +
                                       os->muxer_overhead, max_audio_bitrate);
             if (!av_strnstr(audio_codec_str, os->codec_str, sizeof(audio_codec_str))) {
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 5f9a200c6e..813ac37368 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -154,6 +154,7 @@  typedef struct VariantStream {
     unsigned int nb_streams;
     int m3u8_created; /* status of media play-list creation */
     int is_default; /* default status of audio group */
+    char *name; /* audio name */
     char *language; /* audio lauguage name */
     char *agroup; /* audio group name */
     char *ccgroup; /* closed caption group name */
@@ -1262,7 +1263,9 @@  static int create_master_playlist(AVFormatContext *s,
             goto fail;
         }
 
-        ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name, vs->language, i, hls->has_default_key ? vs->is_default : 1);
+        ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name,
+                                     vs->language, i, vs->name,
+                                     hls->has_default_key ? vs->is_default : 1);
 
         av_freep(&m3u8_rel_name);
     }
@@ -1830,7 +1833,7 @@  static int parse_variant_stream_mapstring(AVFormatContext *s)
     /**
      * Expected format for var_stream_map string is as below:
      * "a:0,v:0 a:1,v:1"
-     * "a:0,agroup:a0,default:1,language:ENG a:1,agroup:a1,defalut:0 v:0,agroup:a0  v:1,agroup:a1"
+     * "a:0,agroup:a0,default:1,name:English,language:ENG a:1,agroup:a1,default:0 v:0,agroup:a0  v:1,agroup:a1"
      * This string specifies how to group the audio, video and subtitle streams
      * into different variant streams. The variant stream groups are separated
      * by space.
@@ -1880,7 +1883,12 @@  static int parse_variant_stream_mapstring(AVFormatContext *s)
         nb_streams = 0;
         while (keyval = av_strtok(varstr, ",", &saveptr2)) {
             varstr = NULL;
-            if (av_strstart(keyval, "language:", &val)) {
+            if (av_strstart(keyval, "name:", &val)) {
+                vs->name = av_strdup(val);
+                if (!vs->name)
+                    return AVERROR(ENOMEM);
+                continue;
+            } else if (av_strstart(keyval, "language:", &val)) {
                 vs->language = av_strdup(val);
                 if (!vs->language)
                     return AVERROR(ENOMEM);
diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c
index 0537049a97..85b5668f22 100644
--- a/libavformat/hlsplaylist.c
+++ b/libavformat/hlsplaylist.c
@@ -24,6 +24,7 @@ 
 #include <stdint.h>
 
 #include "libavutil/time_internal.h"
+#include "libavutil/avstring.h"
 
 #include "avformat.h"
 #include "hlsplaylist.h"
@@ -36,12 +37,13 @@  void ff_hls_write_playlist_version(AVIOContext *out, int version) {
 }
 
 void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup,
-                                  char *filename, char *language, int name_id, int is_default) {
+                                  char *filename, char *language, int name_id, char *name, int is_default) {
     if (!out || !agroup || !filename)
         return;
 
     avio_printf(out, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"", agroup);
-    avio_printf(out, ",NAME=\"audio_%d\",DEFAULT=%s,", name_id, is_default ? "YES" : "NO");
+    avio_printf(out, ",NAME=\"%s\",DEFAULT=%s,", name ? name : av_asprintf("audio_%d", name_id),
+                is_default ? "YES" : "NO");
     if (language) {
         avio_printf(out, "LANGUAGE=\"%s\",", language);
     }
diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h
index 54c93a3963..4a75e1fd74 100644
--- a/libavformat/hlsplaylist.h
+++ b/libavformat/hlsplaylist.h
@@ -38,7 +38,7 @@  typedef enum {
 
 void ff_hls_write_playlist_version(AVIOContext *out, int version);
 void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup,
-                                  char *filename, char *language, int name_id, int is_default);
+                                  char *filename, char *language, int name_id, char *name, int is_default);
 void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
                               int bandwidth, char *filename, char *agroup,
                               char *codecs, char *ccgroup);