*/
#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);
#define FRAME_HEADER_SIZE 17
// Fix Me! FRAME_HEADER_SIZE may be different.
-static const GUID index_guid = {
+static const ff_asf_guid index_guid = {
0x90, 0x08, 0x00, 0x33, 0xb1, 0xe5, 0xcf, 0x11, 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb
};
-static const GUID stream_bitrate_guid = { /* (http://get.to/sdp) */
+static const ff_asf_guid stream_bitrate_guid = { /* (http://get.to/sdp) */
0xce, 0x75, 0xf8, 0x7b, 0x8d, 0x46, 0xd1, 0x11, 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2
};
/**********************************/
#ifdef DEBUG
#define PRINT_IF_GUID(g,cmp) \
-if (!memcmp(g, &cmp, sizeof(GUID))) \
+if (!guidcmp(g, &cmp)) \
dprintf(NULL, "(GUID: %s) ", #cmp)
-static void print_guid(const GUID *g)
+static void print_guid(const ff_asf_guid *g)
{
int i;
PRINT_IF_GUID(g, ff_asf_header);
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++)
#define print_guid(g)
#endif
-static void get_guid(ByteIOContext *s, GUID *g)
+static int guidcmp(const void *g1, const void *g2)
+{
+ return memcmp(g1, g2, sizeof(ff_asf_guid));
+}
+
+static void get_guid(ByteIOContext *s, ff_asf_guid *g)
{
assert(sizeof(*g) == 16);
get_buffer(s, *g, sizeof(*g));
static int asf_probe(AVProbeData *pd)
{
/* check file header */
- if (!memcmp(pd->buf, &ff_asf_header, sizeof(GUID)))
+ if (!guidcmp(pd->buf, &ff_asf_header))
return AVPROBE_SCORE_MAX;
else
return 0;
url_fskip(s->pb, len);
return;
}
- if (strncmp(key, "WM/", 3))
+ if (!strncmp(key, "WM/", 3))
key += 3;
av_metadata_set(&s->metadata, key, value);
}
static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
ASFContext *asf = s->priv_data;
- GUID g;
+ ff_asf_guid g;
ByteIOContext *pb = s->pb;
AVStream *st;
ASFStream *asf_st;
memset(bitrate, 0, sizeof(bitrate));
get_guid(pb, &g);
- if (memcmp(&g, &ff_asf_header, sizeof(GUID)))
+ if (guidcmp(&g, &ff_asf_header))
return -1;
get_le64(pb);
get_le32(pb);
dprintf(s, "%08"PRIx64": ", url_ftell(pb) - 24);
print_guid(&g);
dprintf(s, " size=0x%"PRIx64"\n", gsize);
- if (!memcmp(&g, &ff_asf_data_header, sizeof(GUID))) {
+ if (!guidcmp(&g, &ff_asf_data_header)) {
asf->data_object_offset = url_ftell(pb);
// if not streaming, gsize is not unlimited (how?), and there is enough space in the file..
if (!(asf->hdr.flags & 0x01) && gsize >= 100) {
}
if (gsize < 24)
return -1;
- if (!memcmp(&g, &ff_asf_file_header, sizeof(GUID))) {
+ if (!guidcmp(&g, &ff_asf_file_header)) {
get_guid(pb, &asf->hdr.guid);
asf->hdr.file_size = get_le64(pb);
asf->hdr.create_time = get_le64(pb);
asf->hdr.max_pktsize = get_le32(pb);
asf->hdr.max_bitrate = get_le32(pb);
asf->packet_size = asf->hdr.max_pktsize;
- } else if (!memcmp(&g, &ff_asf_stream_header, sizeof(GUID))) {
+ } else if (!guidcmp(&g, &ff_asf_stream_header)) {
enum CodecType type;
int type_specific_size, sizeX;
uint64_t total_size;
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;
get_guid(pb, &g);
test_for_ext_stream_audio = 0;
- if (!memcmp(&g, &ff_asf_audio_stream, sizeof(GUID))) {
+ if (!guidcmp(&g, &ff_asf_audio_stream)) {
type = CODEC_TYPE_AUDIO;
- } else if (!memcmp(&g, &ff_asf_video_stream, sizeof(GUID))) {
+ } else if (!guidcmp(&g, &ff_asf_video_stream)) {
type = CODEC_TYPE_VIDEO;
- } else if (!memcmp(&g, &ff_asf_command_stream, sizeof(GUID))) {
+ } else if (!guidcmp(&g, &ff_asf_command_stream)) {
type = CODEC_TYPE_DATA;
- } else if (!memcmp(&g, &ff_asf_ext_stream_embed_stream_header, sizeof(GUID))) {
+ } else if (!guidcmp(&g, &ff_asf_ext_stream_embed_stream_header)) {
test_for_ext_stream_audio = 1;
type = CODEC_TYPE_UNKNOWN;
} else {
if (test_for_ext_stream_audio) {
get_guid(pb, &g);
- if (!memcmp(&g, &ff_asf_ext_stream_audio_stream, sizeof(GUID))) {
+ if (!guidcmp(&g, &ff_asf_ext_stream_audio_stream)) {
type = CODEC_TYPE_AUDIO;
is_dvr_ms_audio=1;
get_guid(pb, &g);
}
pos2 = url_ftell(pb);
url_fskip(pb, gsize - (pos2 - pos1 + 24));
- } else if (!memcmp(&g, &ff_asf_comment_header, sizeof(GUID))) {
+ } else if (!guidcmp(&g, &ff_asf_comment_header)) {
int len1, len2, len3, len4, len5;
len1 = get_le16(pb);
get_tag(s, "copyright", 0, len3);
get_tag(s, "comment" , 0, len4);
url_fskip(pb, len5);
- } else if (!memcmp(&g, &stream_bitrate_guid, sizeof(GUID))) {
+ } else if (!guidcmp(&g, &stream_bitrate_guid)) {
int stream_count = get_le16(pb);
int j;
// 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 (!memcmp(&g, &ff_asf_extended_content_header, sizeof(GUID))) {
+ } 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;
desc_count = get_le16(pb);
value_len = get_le16(pb);
get_tag(s, name, value_type, value_len);
}
- } else if (!memcmp(&g, &ff_asf_metadata_header, sizeof(GUID))) {
+ } else if (!guidcmp(&g, &ff_asf_metadata_header)) {
int n, stream_num, name_len, value_len, value_type, value_num;
n = get_le16(pb);
else if(!strcmp(name, "AspectRatioY")) dar[stream_num].den= value_num;
}
}
- } else if (!memcmp(&g, &ff_asf_ext_stream_header, sizeof(GUID))) {
+ } 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;
- int64_t pos_ex_st;
- pos_ex_st = url_ftell(pb);
+ unsigned int stream_languageid_index;
get_le64(pb); // starttime
get_le64(pb); // endtime
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
// there could be a optional stream properties object to follow
// if so the next iteration will pick it up
- } else if (!memcmp(&g, &ff_asf_head1_guid, sizeof(GUID))) {
+ } else if (!guidcmp(&g, &ff_asf_head1_guid)) {
int v1, v2;
get_guid(pb, &g);
v1 = get_le32(pb);
v2 = get_le16(pb);
#if 0
- } else if (!memcmp(&g, &ff_asf_codec_comment_header, sizeof(GUID))) {
+ } else if (!guidcmp(&g, &ff_asf_codec_comment_header)) {
int len, v1, n, num;
char str[256], *q;
char tag[16];
&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);
+ }
+ }
}
}
ASFStream *asf_st = 0;
for (;;) {
if(url_feof(pb))
- return AVERROR(EIO);
+ return AVERROR_EOF;
if (asf->packet_size_left < FRAME_HEADER_SIZE
|| asf->packet_segments < 1) {
//asf->packet_size_left <= asf->packet_padsize) {
asf->packet_pos= url_ftell(pb);
if (asf->data_object_size != (uint64_t)-1 &&
(asf->packet_pos - asf->data_object_offset >= asf->data_object_size))
- return AVERROR(EIO); /* Do not exceed the size of the data object */
+ return AVERROR_EOF; /* Do not exceed the size of the data object */
return 1;
}
if (asf->packet_time_start == 0) {
static void asf_build_simple_index(AVFormatContext *s, int stream_index)
{
- GUID g;
+ ff_asf_guid g;
ASFContext *asf = s->priv_data;
- int64_t gsize, itime;
- int64_t pos, current_pos, index_pts;
+ int64_t current_pos= url_ftell(s->pb);
int i;
- int pct,ict;
-
- current_pos = url_ftell(s->pb);
url_fseek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET);
get_guid(s->pb, &g);
- if (!memcmp(&g, &index_guid, sizeof(GUID))) {
- gsize = get_le64(s->pb);
+ if (!guidcmp(&g, &index_guid)) {
+ int64_t itime;
+ int pct, ict;
+ int64_t av_unused gsize= get_le64(s->pb);
get_guid(s->pb, &g);
itime=get_le64(s->pb);
pct=get_le32(s->pb);
for (i=0;i<ict;i++){
int pktnum=get_le32(s->pb);
int pktct =get_le16(s->pb);
- av_log(s, AV_LOG_DEBUG, "pktnum:%d, pktct:%d\n", pktnum, pktct);
-
- pos=s->data_offset + asf->packet_size*(int64_t)pktnum;
- index_pts=av_rescale(itime, i, 10000);
+ int64_t pos = s->data_offset + asf->packet_size*(int64_t)pktnum;
+ int64_t index_pts= av_rescale(itime, i, 10000);
+ av_log(s, AV_LOG_DEBUG, "pktnum:%d, pktct:%d\n", pktnum, pktct);
av_add_index_entry(s->streams[stream_index], pos, index_pts, asf->packet_size, 0, AVINDEX_KEYFRAME);
}
asf->index_read= 1;
/* find the position */
pos = st->index_entries[index].pos;
- pts = st->index_entries[index].timestamp;
// various attempts to find key frame have failed so far
// asf_reset_header(s);