From 79e42936137a535a8bac8ff3174c3658ce52a482 Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Wed, 3 Feb 2016 03:42:50 +0100 Subject: lavf/asfenc: add support for storing languages Checked compatiblity with VLC, Windows Media Player 12 and Windows Media ASF Viewer 9 series. Reviewed-by: Michael Niedermayer Signed-off-by: Marton Balint --- libavformat/asf.c | 4 +++ libavformat/asf.h | 1 + libavformat/asfenc.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/libavformat/asf.c b/libavformat/asf.c index 80d24dbf43..455ca4d826 100644 --- a/libavformat/asf.c +++ b/libavformat/asf.c @@ -143,6 +143,10 @@ const ff_asf_guid ff_asf_digital_signature = { 0xfc, 0xb3, 0x11, 0x22, 0x23, 0xbd, 0xd2, 0x11, 0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e }; +const ff_asf_guid ff_asf_extended_stream_properties_object = { + 0xcb, 0xa5, 0xe6, 0x14, 0x72, 0xc6, 0x32, 0x43, 0x83, 0x99, 0xa9, 0x69, 0x52, 0x06, 0x5b, 0x5a +}; + /* List of official tags at http://msdn.microsoft.com/en-us/library/dd743066(VS.85).aspx */ const AVMetadataConv ff_asf_metadata_conv[] = { { "WM/AlbumArtist", "album_artist" }, diff --git a/libavformat/asf.h b/libavformat/asf.h index f98fc46edc..1070293b77 100644 --- a/libavformat/asf.h +++ b/libavformat/asf.h @@ -101,6 +101,7 @@ extern const ff_asf_guid ff_asf_language_guid; extern const ff_asf_guid ff_asf_content_encryption; extern const ff_asf_guid ff_asf_ext_content_encryption; extern const ff_asf_guid ff_asf_digital_signature; +extern const ff_asf_guid ff_asf_extended_stream_properties_object; extern const AVMetadataConv ff_asf_metadata_conv[]; diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c index 6932c11250..e2aa2e00ba 100644 --- a/libavformat/asfenc.c +++ b/libavformat/asfenc.c @@ -23,6 +23,7 @@ #include "libavutil/dict.h" #include "libavutil/mathematics.h" #include "avformat.h" +#include "avlanguage.h" #include "avio_internal.h" #include "internal.h" #include "riff.h" @@ -220,6 +221,8 @@ typedef struct ASFContext { uint32_t seqno; int is_streamed; ASFStream streams[128]; ///< it's max number and it's not that big + const char *languages[128]; + int nb_languages; /* non streamed additonnal info */ uint64_t nb_packets; ///< how many packets are there in the file, invalid if broadcasting int64_t duration; ///< in 100ns units @@ -403,6 +406,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, bit_rate = 0; for (n = 0; n < s->nb_streams; n++) { + AVDictionaryEntry *entry; enc = s->streams[n]->codec; avpriv_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ @@ -412,6 +416,27 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, && enc->sample_aspect_ratio.num > 0 && enc->sample_aspect_ratio.den > 0) has_aspect_ratio++; + + entry = av_dict_get(s->streams[n]->metadata, "language", NULL, 0); + if (entry) { + const char *iso6391lang = av_convert_lang_to(entry->value, AV_LANG_ISO639_1); + if (iso6391lang) { + int i; + for (i = 0; i < asf->nb_languages; i++) { + if (!strcmp(asf->languages[i], iso6391lang)) { + asf->streams[n].stream_language_index = i; + break; + } + } + if (i >= asf->nb_languages) { + asf->languages[asf->nb_languages] = iso6391lang; + asf->streams[n].stream_language_index = asf->nb_languages; + asf->nb_languages++; + } + } + } else { + asf->streams[n].stream_language_index = 128; + } } if (asf->is_streamed) { @@ -441,13 +466,48 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, avio_wl32(pb, bit_rate ? bit_rate : -1); /* Maximum data rate in bps */ end_header(pb, hpos); - /* unknown headers */ + /* header_extension */ hpos = put_header(pb, &ff_asf_head1_guid); ff_put_guid(pb, &ff_asf_head2_guid); avio_wl16(pb, 6); + avio_wl32(pb, 0); /* length, to be filled later */ + if (asf->nb_languages) { + int64_t hpos2; + int i; + + hpos2 = put_header(pb, &ff_asf_language_guid); + avio_wl16(pb, asf->nb_languages); + for (i = 0; i < asf->nb_languages; i++) { + avio_w8(pb, 6); + avio_put_str16le(pb, asf->languages[i]); + } + end_header(pb, hpos2); + + for (n = 0; n < s->nb_streams; n++) { + int64_t es_pos; + if (asf->streams[n].stream_language_index > 127) + continue; + es_pos = put_header(pb, &ff_asf_extended_stream_properties_object); + avio_wl64(pb, 0); /* start time */ + avio_wl64(pb, 0); /* end time */ + avio_wl32(pb, s->streams[n]->codec->bit_rate); /* data bitrate bps */ + avio_wl32(pb, 5000); /* buffer size ms */ + avio_wl32(pb, 0); /* initial buffer fullness */ + avio_wl32(pb, s->streams[n]->codec->bit_rate); /* peak data bitrate */ + avio_wl32(pb, 5000); /* maximum buffer size ms */ + avio_wl32(pb, 0); /* max initial buffer fullness */ + avio_wl32(pb, 0); /* max object size */ + avio_wl32(pb, (!asf->is_streamed && pb->seekable) << 1); /* flags - seekable */ + avio_wl16(pb, n + 1); /* stream number */ + avio_wl16(pb, asf->streams[n].stream_language_index); /* language id index */ + avio_wl64(pb, 0); /* avg time per frame */ + avio_wl16(pb, 0); /* stream name count */ + avio_wl16(pb, 0); /* payload extension system count */ + end_header(pb, es_pos); + } + } if (has_aspect_ratio) { int64_t hpos2; - avio_wl32(pb, 26 + has_aspect_ratio * 84); hpos2 = put_header(pb, &ff_asf_metadata_header); avio_wl16(pb, 2 * has_aspect_ratio); for (n = 0; n < s->nb_streams; n++) { @@ -475,8 +535,13 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, } } end_header(pb, hpos2); - } else { - avio_wl32(pb, 0); + } + { + int64_t pos1; + pos1 = avio_tell(pb); + avio_seek(pb, hpos + 42, SEEK_SET); + avio_wl32(pb, pos1 - hpos - 46); + avio_seek(pb, pos1, SEEK_SET); } end_header(pb, hpos); -- cgit v1.2.3