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

Zenon Mousmoulas zmousm at noc.grnet.gr
Thu Mar 28 09:01:20 EET 2019


March 21, 2019 4:37 PM, "Zenon Mousmoulas" <zmousm at 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 at 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.


More information about the ffmpeg-devel mailing list