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 <michael@niedermayer.cc>
Signed-off-by: Marton Balint <cus@passwd.hu>
This commit is contained in:
Marton Balint 2016-02-03 03:42:50 +01:00
parent 0464767301
commit 79e4293613
3 changed files with 74 additions and 4 deletions

View File

@ -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" },

View File

@ -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[];

View File

@ -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);