Hello, I've created a new version of the patch in which the second empty line was removed. I couldn't find any other feedback inline in your response, so that's all I changed.
Best regards, Philippe Symons Op di 13 nov. 2018 om 03:29 schreef Liu Steven <l...@chinaffmpeg.org>: > > > > 在 2018年11月13日,上午6:36,Philippe Symons <philippe.sym...@gmail.com> 写道: > > > > Hello everyone, > > > > This is my first patch to FFMpeg or any open-source project for that > > matter. In this patch, I've added the LANGUAGE attribute to the > > #EXT-X-MEDIA tag for for audio only variant streams for HLS streams. > > > > This attribute will be added to the output in > > avformats' ff_hls_write_audio_rendition() function, if the language code > > can be found in the metadata of the variant stream. > > > > The reason why I implemented this, was because I was working with a > player > > which needs this attribute to determine the language of the audio stream. > > After asking the question on StackOverflow ( > > > https://stackoverflow.com/questions/53205283/ffmpeg-hls-multiple-audio-languages-with-var-stream-map-ext-x-mediatype-doesn/53206492#53206492 > ), > > I noticed that it wasn't implemented. > > > > I've tested these changes with the following command: > > > > ffmpeg -re -i /home/philippe/Videos/example.ts -map 0:v -c:v copy -map > 0:a > > -c:a copy -f hls -hls_time 6 -hls_list_size 10 -hls_flags > > delete_segments+program_date_time -hls_segment_filename > > "/var/www/html/live/stream_%v_%d.ts" -var_stream_map "v:0,agroup:lang > > a:0,agroup:lang a:1,agroup:lang a:2,agroup:lang a: > > 3,agroup:lang" -master_pl_name master.m3u8 > /var/www/html/live/stream-%v.m3u8 > > > > Looking forward to your feedback. I hope it's okay. > > > > Signed-off-by: Philippe Symons <philippe.sym...@gmail.com> > --- > libavformat/dashenc.c | 2 +- > libavformat/hlsenc.c | 24 ++++++++++++++++++++++-- > libavformat/hlsplaylist.c | 6 +++++- > libavformat/hlsplaylist.h | 2 +- > 4 files changed, 29 insertions(+), 5 deletions(-) > > diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c > index f8b3d106d5..ca5ef01e3f 100644 > --- a/libavformat/dashenc.c > +++ b/libavformat/dashenc.c > @@ -897,7 +897,7 @@ static int write_manifest(AVFormatContext *s, int > final) > if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) > continue; > get_hls_playlist_name(playlist_file, sizeof(playlist_file), > NULL, i); > - ff_hls_write_audio_rendition(c->m3u8_out, (char *)audio_group, > + ff_hls_write_audio_rendition(c->m3u8_out, (char > *)audio_group, NULL, > playlist_file, i, is_default); > max_audio_bitrate = FFMAX(st->codecpar->bit_rate + > os->muxer_overhead, > max_audio_bitrate); > diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c > index e0048aa9d8..b31daa108e 100644 > --- a/libavformat/hlsenc.c > +++ b/libavformat/hlsenc.c > @@ -1205,7 +1205,6 @@ static int create_master_playlist(AVFormatContext *s, > } > > set_http_options(s, &options, hls); > - > ret = hlsenc_io_open(s, &hls->m3u8_out, hls->master_m3u8_url, > &options); > av_dict_free(&options); > if (ret < 0) { > @@ -1228,12 +1227,33 @@ static int create_master_playlist(AVFormatContext > *s, > > /* For audio only variant streams add #EXT-X-MEDIA tag with > attributes*/ > for (i = 0; i < hls->nb_varstreams; i++) { > + AVFormatContext* var_context; > + char* language = NULL; > + > vs = &(hls->var_streams[i]); > + var_context = vs->avf; > > if (vs->has_video || vs->has_subtitle || !vs->agroup) > continue; > > m3u8_name_size = strlen(vs->m3u8_name) + 1; > + > + /* > + * Try to obtain the language code of the audio stream. > + * -if available- it will be used to write the LANGUAGE > + * attribute in the #EXT-X-MEDIA tag > + */ > + if(var_context && var_context->nb_streams > 0) > + { > if (var_context && var_context->nb_streams > 0) { > + AVDictionary* meta_dict = vs->streams[0]->metadata; > + AVDictionaryEntry *langEntry = av_dict_get(meta_dict, > "language", NULL, 0); > + if(langEntry) > + { > if (langEntry) { > + language = langEntry->value; > + } > + } > + > + > > two empty line? > m3u8_rel_name = av_malloc(m3u8_name_size); > if (!m3u8_rel_name) { > ret = AVERROR(ENOMEM); > @@ -1247,7 +1267,7 @@ static int create_master_playlist(AVFormatContext *s, > goto fail; > } > > - ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, > m3u8_rel_name, 0, 1); > + ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, language, > m3u8_rel_name, 0, 1); > > av_freep(&m3u8_rel_name); > } > diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c > index efcbff0009..42c7cf5727 100644 > --- a/libavformat/hlsplaylist.c > +++ b/libavformat/hlsplaylist.c > @@ -35,12 +35,16 @@ void ff_hls_write_playlist_version(AVIOContext *out, > int version) { > avio_printf(out, "#EXT-X-VERSION:%d\n", version); > } > > -void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, > +void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, char* > language, > char *filename, int name_id, int > is_default) { > if (!out || !agroup || !filename) > return; > > avio_printf(out, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"", > agroup); > + > + if(language) > + avio_printf(out, ",LANGUAGE=\"%s\"", language); > + > avio_printf(out, ",NAME=\"audio_%d\",DEFAULT=%s,URI=\"%s\"\n", > name_id, > is_default ? "YES" : "NO", filename); > } > diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h > index 5054b01c8f..faf1ccdd02 100644 > --- a/libavformat/hlsplaylist.h > +++ b/libavformat/hlsplaylist.h > @@ -37,7 +37,7 @@ typedef enum { > } PlaylistType; > > void ff_hls_write_playlist_version(AVIOContext *out, int version); > -void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, > +void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, char* > language, > char *filename, int name_id, int > is_default); > void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, > int bandwidth, char *filename, char *agroup, > -- > 2.17.1 > > > > > > > > Best regards, > > > > Philippe Symons > > > <0001-HLS-Add-LANGUAGE-attribute-to-EXT-X-MEDIA-tag-for-au.patch>_______________________________________________ > > ffmpeg-devel mailing list > > ffmpeg-devel@ffmpeg.org > > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel >
From 8c3ff42994ef16f745b486b2e3e09c2040b2e3e0 Mon Sep 17 00:00:00 2001 From: Philippe Symons <philippe.sym...@gmail.com> Date: Wed, 14 Nov 2018 23:22:20 +0100 Subject: [PATCH] [HLS] Add LANGUAGE attribute to #EXT-X-MEDIA tag for audio-only variant streams. Signed-off-by: Philippe Symons <philippe.sym...@gmail.com> --- libavformat/dashenc.c | 2 +- libavformat/hlsenc.c | 23 +++++++++++++++++++++-- libavformat/hlsplaylist.c | 6 +++++- libavformat/hlsplaylist.h | 2 +- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index d151921175..17465c1917 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -898,7 +898,7 @@ static int write_manifest(AVFormatContext *s, int final) if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) continue; get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); - ff_hls_write_audio_rendition(c->m3u8_out, (char *)audio_group, + ff_hls_write_audio_rendition(c->m3u8_out, (char *)audio_group, NULL, playlist_file, i, is_default); max_audio_bitrate = FFMAX(st->codecpar->bit_rate + os->muxer_overhead, max_audio_bitrate); diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index e0048aa9d8..b1bd7b66ef 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -1205,7 +1205,6 @@ static int create_master_playlist(AVFormatContext *s, } set_http_options(s, &options, hls); - ret = hlsenc_io_open(s, &hls->m3u8_out, hls->master_m3u8_url, &options); av_dict_free(&options); if (ret < 0) { @@ -1228,12 +1227,32 @@ static int create_master_playlist(AVFormatContext *s, /* For audio only variant streams add #EXT-X-MEDIA tag with attributes*/ for (i = 0; i < hls->nb_varstreams; i++) { + AVFormatContext* var_context; + char* language = NULL; + vs = &(hls->var_streams[i]); + var_context = vs->avf; if (vs->has_video || vs->has_subtitle || !vs->agroup) continue; m3u8_name_size = strlen(vs->m3u8_name) + 1; + + /* + * Try to obtain the language code of the audio stream. + * -if available- it will be used to write the LANGUAGE + * attribute in the #EXT-X-MEDIA tag + */ + if(var_context && var_context->nb_streams > 0) + { + AVDictionary* meta_dict = vs->streams[0]->metadata; + AVDictionaryEntry *langEntry = av_dict_get(meta_dict, "language", NULL, 0); + if(langEntry) + { + language = langEntry->value; + } + } + m3u8_rel_name = av_malloc(m3u8_name_size); if (!m3u8_rel_name) { ret = AVERROR(ENOMEM); @@ -1247,7 +1266,7 @@ static int create_master_playlist(AVFormatContext *s, goto fail; } - ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name, 0, 1); + ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, language, m3u8_rel_name, 0, 1); av_freep(&m3u8_rel_name); } diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c index efcbff0009..42c7cf5727 100644 --- a/libavformat/hlsplaylist.c +++ b/libavformat/hlsplaylist.c @@ -35,12 +35,16 @@ void ff_hls_write_playlist_version(AVIOContext *out, int version) { avio_printf(out, "#EXT-X-VERSION:%d\n", version); } -void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, +void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, char* language, char *filename, int name_id, int is_default) { if (!out || !agroup || !filename) return; avio_printf(out, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"", agroup); + + if(language) + avio_printf(out, ",LANGUAGE=\"%s\"", language); + avio_printf(out, ",NAME=\"audio_%d\",DEFAULT=%s,URI=\"%s\"\n", name_id, is_default ? "YES" : "NO", filename); } diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h index 5054b01c8f..faf1ccdd02 100644 --- a/libavformat/hlsplaylist.h +++ b/libavformat/hlsplaylist.h @@ -37,7 +37,7 @@ typedef enum { } PlaylistType; void ff_hls_write_playlist_version(AVIOContext *out, int version); -void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, +void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, char* language, char *filename, int name_id, int is_default); void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, char *filename, char *agroup, -- 2.17.1
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel