# HG changeset patch # User benoit # Date 1242131746 0 # Node ID c090f960fc8ad28837f56e0c35fc0ca0c5c2cebb # Parent a88b316427275b1b6e1d05c226743d562b075785 Per-stream language-tags extraction in asfdec. Patch by Cyril Comparon: gmail(name, surname); Original thread: Suggestion for a centralized language-tag facility in libavformat Date: 04/10/2009 07:33 PM diff -r a88b31642727 -r c090f960fc8a Makefile --- a/Makefile Mon May 11 04:35:15 2009 +0000 +++ b/Makefile Tue May 12 12:35:46 2009 +0000 @@ -18,7 +18,7 @@ OBJS-$(CONFIG_AMR_MUXER) += amr.o OBJS-$(CONFIG_APC_DEMUXER) += apc.o OBJS-$(CONFIG_APE_DEMUXER) += ape.o -OBJS-$(CONFIG_ASF_DEMUXER) += asfdec.o asf.o asfcrypt.o riff.o +OBJS-$(CONFIG_ASF_DEMUXER) += asfdec.o asf.o asfcrypt.o riff.o avlanguage.o OBJS-$(CONFIG_ASF_MUXER) += asfenc.o asf.o riff.o OBJS-$(CONFIG_ASF_STREAM_MUXER) += asfenc.o asf.o riff.o OBJS-$(CONFIG_ASS_DEMUXER) += assdec.o diff -r a88b31642727 -r c090f960fc8a asf.c --- a/asf.c Mon May 11 04:35:15 2009 +0000 +++ b/asf.c Tue May 12 12:35:46 2009 +0000 @@ -112,6 +112,9 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +const ff_asf_guid ff_asf_language_guid = { + 0xa9, 0x46, 0x43, 0x7c, 0xe0, 0xef, 0xfc, 0x4b, 0xb2, 0x29, 0x39, 0x3e, 0xde, 0x41, 0x5c, 0x85 +}; const AVMetadataConv ff_asf_metadata_conv[] = { { "AlbumArtist", "artist" }, diff -r a88b31642727 -r c090f960fc8a asf.h --- a/asf.h Mon May 11 04:35:15 2009 +0000 +++ b/asf.h Tue May 12 12:35:46 2009 +0000 @@ -42,6 +42,8 @@ int64_t packet_pos; + uint16_t stream_language_index; + } ASFStream; typedef uint8_t ff_asf_guid[16]; @@ -85,6 +87,7 @@ int asfid2avid[128]; ///< conversion table from asf ID 2 AVStream ID ASFStream streams[128]; ///< it's max number and it's not that big uint32_t stream_bitrates[128]; ///< max number of streams, bitrate for each (for streaming) + char stream_languages[128][6]; ///< max number of streams, language for each (RFC1766, e.g. en-US) /* 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 @@ -157,6 +160,7 @@ extern const ff_asf_guid ff_asf_ext_stream_audio_stream; extern const ff_asf_guid ff_asf_metadata_header; extern const ff_asf_guid ff_asf_my_guid; +extern const ff_asf_guid ff_asf_language_guid; extern const AVMetadataConv ff_asf_metadata_conv[]; diff -r a88b31642727 -r c090f960fc8a asfdec.c --- a/asfdec.c Mon May 11 04:35:15 2009 +0000 +++ b/asfdec.c Tue May 12 12:35:46 2009 +0000 @@ -20,11 +20,13 @@ */ #include "libavutil/common.h" +#include "libavutil/avstring.h" #include "libavcodec/mpegaudio.h" #include "avformat.h" #include "riff.h" #include "asf.h" #include "asfcrypt.h" +#include "avlanguage.h" void ff_mms_set_stream_selection(URLContext *h, AVFormatContext *format); @@ -76,6 +78,7 @@ else PRINT_IF_GUID(g, ff_asf_ext_stream_audio_stream); else PRINT_IF_GUID(g, ff_asf_metadata_header); else PRINT_IF_GUID(g, stream_bitrate_guid); + else PRINT_IF_GUID(g, ff_asf_language_guid); else dprintf(NULL, "(GUID: unknown) "); for(i=0;i<16;i++) @@ -238,6 +241,8 @@ st->priv_data = asf_st; start_time = asf->hdr.preroll; + asf_st->stream_language_index = 128; // invalid stream index means no language info + if(!(asf->hdr.flags & 0x01)) { // if we aren't streaming... st->duration = asf->hdr.send_time / (10000000 / 1000) - start_time; @@ -403,6 +408,16 @@ // av_log(s, AV_LOG_ERROR, "flags: 0x%x stream id %d, bitrate %d\n", flags, stream_id, bitrate); asf->stream_bitrates[stream_id]= bitrate; } + } else if (!guidcmp(&g, &ff_asf_language_guid)) { + int j; + int stream_count = get_le16(pb); + for(j = 0; j < stream_count; j++) { + char lang[6]; + unsigned int lang_len = get_byte(pb); + get_str16_nolen(pb, lang_len, lang, sizeof(lang)); + if (j < 128) + av_strlcpy(asf->stream_languages[j], lang, sizeof(*asf->stream_languages)); + } } else if (!guidcmp(&g, &ff_asf_extended_content_header)) { int desc_count, i; @@ -443,6 +458,7 @@ } else if (!guidcmp(&g, &ff_asf_ext_stream_header)) { int ext_len, payload_ext_ct, stream_ct; uint32_t ext_d, leak_rate, stream_num; + unsigned int stream_languageid_index; get_le64(pb); // starttime get_le64(pb); // endtime @@ -455,7 +471,11 @@ get_le32(pb); // max-object-size get_le32(pb); // flags (reliable,seekable,no_cleanpoints?,resend-live-cleanpoints, rest of bits reserved) stream_num = get_le16(pb); // stream-num - get_le16(pb); // stream-language-id-index + + stream_languageid_index = get_le16(pb); // stream-language-id-index + if (stream_num < 128) + asf->streams[stream_num].stream_language_index = stream_languageid_index; + get_le64(pb); // avg frametime in 100ns units stream_ct = get_le16(pb); //stream-name-count payload_ext_ct = get_le16(pb); //payload-extension-system-count @@ -535,6 +555,17 @@ &st->sample_aspect_ratio.den, dar[i].num, dar[i].den, INT_MAX); //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); + + // copy and convert language codes to the frontend + if (asf->streams[i].stream_language_index < 128) { + const char *rfc1766 = asf->stream_languages[asf->streams[i].stream_language_index]; + if (rfc1766 && strlen(rfc1766) > 1) { + const char primary_tag[3] = { rfc1766[0], rfc1766[1], '\0' }; // ignore country code if any + const char *iso6392 = av_convert_lang_to(primary_tag, AV_LANG_ISO639_2_BIBL); + if (iso6392) + av_metadata_set(&st->metadata, "language", iso6392); + } + } } }