Commit 1e03d600 authored by Steven Liu's avatar Steven Liu

avformat/hlsenc: add var_stream_map LANGUAGE field string parameter

use a:0,agroup:aud_low,default:Yes,language:CHN a:1,agroup:aud_low,language:ENG
        a:2,agroup:aud_high,default:YesYes,language:CHN a:3,agroup:aud_high,language:ENG
        v:0,agroup:aud_low v:1,agroup:aud_high
        create master m3u8 list.

result:
EXTM3U
EXT-X-VERSION:3
EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_aud_low",NAME="audio_0",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="audio_2",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: 's avatarSteven Liu <lq@chinaffmpeg.org>
parent 6a25bb5a
...@@ -982,6 +982,22 @@ and they are mapped to the one video only variant streams with audio group name ...@@ -982,6 +982,22 @@ and they are mapped to the one video only variant streams with audio group name
By default, a single hls variant containing all the encoded streams is created. 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" \
-master_pl_name master.m3u8 \
http://example.com/live/out_%v.m3u8
@end example
This example creates two audio only and one video only variant streams. In
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.
By default, a single hls variant containing all the encoded streams is created.
@item cc_stream_map @item cc_stream_map
Map string which specifies different closed captions groups and their Map string which specifies different closed captions groups and their
attributes. The closed captions stream groups are separated by space. attributes. The closed captions stream groups are separated by space.
......
...@@ -998,7 +998,7 @@ static int write_manifest(AVFormatContext *s, int final) ...@@ -998,7 +998,7 @@ static int write_manifest(AVFormatContext *s, int final)
continue; continue;
get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); 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,
playlist_file, i, is_default); playlist_file, NULL, i, is_default);
max_audio_bitrate = FFMAX(st->codecpar->bit_rate + max_audio_bitrate = FFMAX(st->codecpar->bit_rate +
os->muxer_overhead, max_audio_bitrate); os->muxer_overhead, max_audio_bitrate);
if (!av_strnstr(audio_codec_str, os->codec_str, sizeof(audio_codec_str))) { if (!av_strnstr(audio_codec_str, os->codec_str, sizeof(audio_codec_str))) {
......
...@@ -154,6 +154,7 @@ typedef struct VariantStream { ...@@ -154,6 +154,7 @@ typedef struct VariantStream {
unsigned int nb_streams; unsigned int nb_streams;
int m3u8_created; /* status of media play-list creation */ int m3u8_created; /* status of media play-list creation */
int is_default; /* default status of audio group */ int is_default; /* default status of audio group */
char *language; /* audio lauguage name */
char *agroup; /* audio group name */ char *agroup; /* audio group name */
char *ccgroup; /* closed caption group name */ char *ccgroup; /* closed caption group name */
char *baseurl; char *baseurl;
...@@ -1261,7 +1262,7 @@ static int create_master_playlist(AVFormatContext *s, ...@@ -1261,7 +1262,7 @@ static int create_master_playlist(AVFormatContext *s,
goto fail; goto fail;
} }
ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name, 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, hls->has_default_key ? vs->is_default : 1);
av_freep(&m3u8_rel_name); av_freep(&m3u8_rel_name);
} }
...@@ -1829,7 +1830,7 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) ...@@ -1829,7 +1830,7 @@ static int parse_variant_stream_mapstring(AVFormatContext *s)
/** /**
* Expected format for var_stream_map string is as below: * Expected format for var_stream_map string is as below:
* "a:0,v:0 a:1,v:1" * "a:0,v:0 a:1,v:1"
* "a:0,agroup:a0,default:1 a:1,agroup:a1,defalut:0 v:0,agroup:a0 v:1,agroup:a1" * "a:0,agroup:a0,default:1,language:ENG a:1,agroup:a1,defalut:0 v:0,agroup:a0 v:1,agroup:a1"
* This string specifies how to group the audio, video and subtitle streams * This string specifies how to group the audio, video and subtitle streams
* into different variant streams. The variant stream groups are separated * into different variant streams. The variant stream groups are separated
* by space. * by space.
...@@ -1879,8 +1880,12 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) ...@@ -1879,8 +1880,12 @@ static int parse_variant_stream_mapstring(AVFormatContext *s)
nb_streams = 0; nb_streams = 0;
while (keyval = av_strtok(varstr, ",", &saveptr2)) { while (keyval = av_strtok(varstr, ",", &saveptr2)) {
varstr = NULL; varstr = NULL;
if (av_strstart(keyval, "language:", &val)) {
if (av_strstart(keyval, "default:", &val)) { vs->language = av_strdup(val);
if (!vs->language)
return AVERROR(ENOMEM);
continue;
} else if (av_strstart(keyval, "default:", &val)) {
vs->is_default = (!av_strncasecmp(val, "YES", strlen("YES")) || vs->is_default = (!av_strncasecmp(val, "YES", strlen("YES")) ||
(!av_strncasecmp(val, "1", strlen("1")))); (!av_strncasecmp(val, "1", strlen("1"))));
hls->has_default_key = 1; hls->has_default_key = 1;
...@@ -2392,6 +2397,7 @@ static void hls_free_variant_streams(struct HLSContext *hls) ...@@ -2392,6 +2397,7 @@ static void hls_free_variant_streams(struct HLSContext *hls)
av_freep(&vs->m3u8_name); av_freep(&vs->m3u8_name);
av_freep(&vs->streams); av_freep(&vs->streams);
av_freep(&vs->agroup); av_freep(&vs->agroup);
av_freep(&vs->language);
av_freep(&vs->ccgroup); av_freep(&vs->ccgroup);
av_freep(&vs->baseurl); av_freep(&vs->baseurl);
} }
...@@ -2843,6 +2849,7 @@ fail: ...@@ -2843,6 +2849,7 @@ fail:
av_freep(&vs->m3u8_name); av_freep(&vs->m3u8_name);
av_freep(&vs->vtt_m3u8_name); av_freep(&vs->vtt_m3u8_name);
av_freep(&vs->streams); av_freep(&vs->streams);
av_freep(&vs->language);
av_freep(&vs->agroup); av_freep(&vs->agroup);
av_freep(&vs->ccgroup); av_freep(&vs->ccgroup);
av_freep(&vs->baseurl); av_freep(&vs->baseurl);
......
...@@ -36,13 +36,16 @@ void ff_hls_write_playlist_version(AVIOContext *out, int version) { ...@@ -36,13 +36,16 @@ 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 *filename, int name_id, int is_default) { char *filename, char *language, int name_id, int is_default) {
if (!out || !agroup || !filename) if (!out || !agroup || !filename)
return; return;
avio_printf(out, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"", agroup); avio_printf(out, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"", agroup);
avio_printf(out, ",NAME=\"audio_%d\",DEFAULT=%s,URI=\"%s\"\n", name_id, avio_printf(out, ",NAME=\"audio_%d\",DEFAULT=%s,", name_id, is_default ? "YES" : "NO");
is_default ? "YES" : "NO", filename); if (language) {
avio_printf(out, "LANGUAGE=\"%s\",", language);
}
avio_printf(out, "URI=\"%s\"\n", filename);
} }
void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
......
...@@ -38,7 +38,7 @@ typedef enum { ...@@ -38,7 +38,7 @@ typedef enum {
void ff_hls_write_playlist_version(AVIOContext *out, int version); 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 *filename, int name_id, int is_default); char *filename, char *language, int name_id, int is_default);
void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
int bandwidth, char *filename, char *agroup, int bandwidth, char *filename, char *agroup,
char *codecs, char *ccgroup); char *codecs, char *ccgroup);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment