Originally committed as revision 18800 to svn://svn.ffmpeg.org/ffmpeg/trunk
Cyril Comparon authored on 2009/05/12 21:35:46... | ... |
@@ -18,7 +18,7 @@ OBJS-$(CONFIG_AMR_DEMUXER) += amr.o |
18 | 18 |
OBJS-$(CONFIG_AMR_MUXER) += amr.o |
19 | 19 |
OBJS-$(CONFIG_APC_DEMUXER) += apc.o |
20 | 20 |
OBJS-$(CONFIG_APE_DEMUXER) += ape.o |
21 |
-OBJS-$(CONFIG_ASF_DEMUXER) += asfdec.o asf.o asfcrypt.o riff.o |
|
21 |
+OBJS-$(CONFIG_ASF_DEMUXER) += asfdec.o asf.o asfcrypt.o riff.o avlanguage.o |
|
22 | 22 |
OBJS-$(CONFIG_ASF_MUXER) += asfenc.o asf.o riff.o |
23 | 23 |
OBJS-$(CONFIG_ASF_STREAM_MUXER) += asfenc.o asf.o riff.o |
24 | 24 |
OBJS-$(CONFIG_ASS_DEMUXER) += assdec.o |
... | ... |
@@ -112,6 +112,9 @@ const ff_asf_guid ff_asf_my_guid = { |
112 | 112 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
113 | 113 |
}; |
114 | 114 |
|
115 |
+const ff_asf_guid ff_asf_language_guid = { |
|
116 |
+ 0xa9, 0x46, 0x43, 0x7c, 0xe0, 0xef, 0xfc, 0x4b, 0xb2, 0x29, 0x39, 0x3e, 0xde, 0x41, 0x5c, 0x85 |
|
117 |
+}; |
|
115 | 118 |
|
116 | 119 |
const AVMetadataConv ff_asf_metadata_conv[] = { |
117 | 120 |
{ "AlbumArtist", "artist" }, |
... | ... |
@@ -42,6 +42,8 @@ typedef struct { |
42 | 42 |
|
43 | 43 |
int64_t packet_pos; |
44 | 44 |
|
45 |
+ uint16_t stream_language_index; |
|
46 |
+ |
|
45 | 47 |
} ASFStream; |
46 | 48 |
|
47 | 49 |
typedef uint8_t ff_asf_guid[16]; |
... | ... |
@@ -85,6 +87,7 @@ typedef struct { |
85 | 85 |
int asfid2avid[128]; ///< conversion table from asf ID 2 AVStream ID |
86 | 86 |
ASFStream streams[128]; ///< it's max number and it's not that big |
87 | 87 |
uint32_t stream_bitrates[128]; ///< max number of streams, bitrate for each (for streaming) |
88 |
+ char stream_languages[128][6]; ///< max number of streams, language for each (RFC1766, e.g. en-US) |
|
88 | 89 |
/* non streamed additonnal info */ |
89 | 90 |
uint64_t nb_packets; ///< how many packets are there in the file, invalid if broadcasting |
90 | 91 |
int64_t duration; ///< in 100ns units |
... | ... |
@@ -157,6 +160,7 @@ extern const ff_asf_guid ff_asf_ext_stream_embed_stream_header; |
157 | 157 |
extern const ff_asf_guid ff_asf_ext_stream_audio_stream; |
158 | 158 |
extern const ff_asf_guid ff_asf_metadata_header; |
159 | 159 |
extern const ff_asf_guid ff_asf_my_guid; |
160 |
+extern const ff_asf_guid ff_asf_language_guid; |
|
160 | 161 |
|
161 | 162 |
extern const AVMetadataConv ff_asf_metadata_conv[]; |
162 | 163 |
|
... | ... |
@@ -20,11 +20,13 @@ |
20 | 20 |
*/ |
21 | 21 |
|
22 | 22 |
#include "libavutil/common.h" |
23 |
+#include "libavutil/avstring.h" |
|
23 | 24 |
#include "libavcodec/mpegaudio.h" |
24 | 25 |
#include "avformat.h" |
25 | 26 |
#include "riff.h" |
26 | 27 |
#include "asf.h" |
27 | 28 |
#include "asfcrypt.h" |
29 |
+#include "avlanguage.h" |
|
28 | 30 |
|
29 | 31 |
void ff_mms_set_stream_selection(URLContext *h, AVFormatContext *format); |
30 | 32 |
|
... | ... |
@@ -76,6 +78,7 @@ static void print_guid(const ff_asf_guid *g) |
76 | 76 |
else PRINT_IF_GUID(g, ff_asf_ext_stream_audio_stream); |
77 | 77 |
else PRINT_IF_GUID(g, ff_asf_metadata_header); |
78 | 78 |
else PRINT_IF_GUID(g, stream_bitrate_guid); |
79 |
+ else PRINT_IF_GUID(g, ff_asf_language_guid); |
|
79 | 80 |
else |
80 | 81 |
dprintf(NULL, "(GUID: unknown) "); |
81 | 82 |
for(i=0;i<16;i++) |
... | ... |
@@ -238,6 +241,8 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) |
238 | 238 |
st->priv_data = asf_st; |
239 | 239 |
start_time = asf->hdr.preroll; |
240 | 240 |
|
241 |
+ asf_st->stream_language_index = 128; // invalid stream index means no language info |
|
242 |
+ |
|
241 | 243 |
if(!(asf->hdr.flags & 0x01)) { // if we aren't streaming... |
242 | 244 |
st->duration = asf->hdr.send_time / |
243 | 245 |
(10000000 / 1000) - start_time; |
... | ... |
@@ -403,6 +408,16 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) |
403 | 403 |
// av_log(s, AV_LOG_ERROR, "flags: 0x%x stream id %d, bitrate %d\n", flags, stream_id, bitrate); |
404 | 404 |
asf->stream_bitrates[stream_id]= bitrate; |
405 | 405 |
} |
406 |
+ } else if (!guidcmp(&g, &ff_asf_language_guid)) { |
|
407 |
+ int j; |
|
408 |
+ int stream_count = get_le16(pb); |
|
409 |
+ for(j = 0; j < stream_count; j++) { |
|
410 |
+ char lang[6]; |
|
411 |
+ unsigned int lang_len = get_byte(pb); |
|
412 |
+ get_str16_nolen(pb, lang_len, lang, sizeof(lang)); |
|
413 |
+ if (j < 128) |
|
414 |
+ av_strlcpy(asf->stream_languages[j], lang, sizeof(*asf->stream_languages)); |
|
415 |
+ } |
|
406 | 416 |
} else if (!guidcmp(&g, &ff_asf_extended_content_header)) { |
407 | 417 |
int desc_count, i; |
408 | 418 |
|
... | ... |
@@ -443,6 +458,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) |
443 | 443 |
} else if (!guidcmp(&g, &ff_asf_ext_stream_header)) { |
444 | 444 |
int ext_len, payload_ext_ct, stream_ct; |
445 | 445 |
uint32_t ext_d, leak_rate, stream_num; |
446 |
+ unsigned int stream_languageid_index; |
|
446 | 447 |
|
447 | 448 |
get_le64(pb); // starttime |
448 | 449 |
get_le64(pb); // endtime |
... | ... |
@@ -455,7 +471,11 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) |
455 | 455 |
get_le32(pb); // max-object-size |
456 | 456 |
get_le32(pb); // flags (reliable,seekable,no_cleanpoints?,resend-live-cleanpoints, rest of bits reserved) |
457 | 457 |
stream_num = get_le16(pb); // stream-num |
458 |
- get_le16(pb); // stream-language-id-index |
|
458 |
+ |
|
459 |
+ stream_languageid_index = get_le16(pb); // stream-language-id-index |
|
460 |
+ if (stream_num < 128) |
|
461 |
+ asf->streams[stream_num].stream_language_index = stream_languageid_index; |
|
462 |
+ |
|
459 | 463 |
get_le64(pb); // avg frametime in 100ns units |
460 | 464 |
stream_ct = get_le16(pb); //stream-name-count |
461 | 465 |
payload_ext_ct = get_le16(pb); //payload-extension-system-count |
... | ... |
@@ -535,6 +555,17 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) |
535 | 535 |
&st->sample_aspect_ratio.den, |
536 | 536 |
dar[i].num, dar[i].den, INT_MAX); |
537 | 537 |
//av_log(s, AV_LOG_ERROR, "dar %d:%d sar=%d:%d\n", dar[i].num, dar[i].den, st->sample_aspect_ratio.num, st->sample_aspect_ratio.den); |
538 |
+ |
|
539 |
+ // copy and convert language codes to the frontend |
|
540 |
+ if (asf->streams[i].stream_language_index < 128) { |
|
541 |
+ const char *rfc1766 = asf->stream_languages[asf->streams[i].stream_language_index]; |
|
542 |
+ if (rfc1766 && strlen(rfc1766) > 1) { |
|
543 |
+ const char primary_tag[3] = { rfc1766[0], rfc1766[1], '\0' }; // ignore country code if any |
|
544 |
+ const char *iso6392 = av_convert_lang_to(primary_tag, AV_LANG_ISO639_2_BIBL); |
|
545 |
+ if (iso6392) |
|
546 |
+ av_metadata_set(&st->metadata, "language", iso6392); |
|
547 |
+ } |
|
548 |
+ } |
|
538 | 549 |
} |
539 | 550 |
} |
540 | 551 |
|