|
|
|
@ -184,6 +184,213 @@ finish: |
|
|
|
|
url_fseek(s->pb, off + len, SEEK_SET); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int asf_read_file_properties(AVFormatContext *s, int64_t size) |
|
|
|
|
{ |
|
|
|
|
ASFContext *asf = s->priv_data; |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
|
|
|
|
|
ff_get_guid(pb, &asf->hdr.guid); |
|
|
|
|
asf->hdr.file_size = get_le64(pb); |
|
|
|
|
asf->hdr.create_time = get_le64(pb); |
|
|
|
|
get_le64(pb); /* number of packets */ |
|
|
|
|
asf->hdr.play_time = get_le64(pb); |
|
|
|
|
asf->hdr.send_time = get_le64(pb); |
|
|
|
|
asf->hdr.preroll = get_le32(pb); |
|
|
|
|
asf->hdr.ignore = get_le32(pb); |
|
|
|
|
asf->hdr.flags = get_le32(pb); |
|
|
|
|
asf->hdr.min_pktsize = get_le32(pb); |
|
|
|
|
asf->hdr.max_pktsize = get_le32(pb); |
|
|
|
|
asf->hdr.max_bitrate = get_le32(pb); |
|
|
|
|
s->packet_size = asf->hdr.max_pktsize; |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int asf_read_ext_stream_properties(AVFormatContext *s, int64_t size) |
|
|
|
|
{ |
|
|
|
|
ASFContext *asf = s->priv_data; |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
ff_asf_guid g; |
|
|
|
|
int ext_len, payload_ext_ct, stream_ct, i; |
|
|
|
|
uint32_t ext_d, leak_rate, stream_num; |
|
|
|
|
unsigned int stream_languageid_index; |
|
|
|
|
|
|
|
|
|
get_le64(pb); // starttime
|
|
|
|
|
get_le64(pb); // endtime
|
|
|
|
|
leak_rate = get_le32(pb); // leak-datarate
|
|
|
|
|
get_le32(pb); // bucket-datasize
|
|
|
|
|
get_le32(pb); // init-bucket-fullness
|
|
|
|
|
get_le32(pb); // alt-leak-datarate
|
|
|
|
|
get_le32(pb); // alt-bucket-datasize
|
|
|
|
|
get_le32(pb); // alt-init-bucket-fullness
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
if (stream_num < 128) |
|
|
|
|
asf->stream_bitrates[stream_num] = leak_rate; |
|
|
|
|
|
|
|
|
|
for (i=0; i<stream_ct; i++){ |
|
|
|
|
get_le16(pb); |
|
|
|
|
ext_len = get_le16(pb); |
|
|
|
|
url_fseek(pb, ext_len, SEEK_CUR); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (i=0; i<payload_ext_ct; i++){ |
|
|
|
|
ff_get_guid(pb, &g); |
|
|
|
|
ext_d=get_le16(pb); |
|
|
|
|
ext_len=get_le32(pb); |
|
|
|
|
url_fseek(pb, ext_len, SEEK_CUR); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int asf_read_content_desc(AVFormatContext *s, int64_t size) |
|
|
|
|
{ |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
int len1, len2, len3, len4, len5; |
|
|
|
|
|
|
|
|
|
len1 = get_le16(pb); |
|
|
|
|
len2 = get_le16(pb); |
|
|
|
|
len3 = get_le16(pb); |
|
|
|
|
len4 = get_le16(pb); |
|
|
|
|
len5 = get_le16(pb); |
|
|
|
|
get_tag(s, "title" , 0, len1); |
|
|
|
|
get_tag(s, "author" , 0, len2); |
|
|
|
|
get_tag(s, "copyright", 0, len3); |
|
|
|
|
get_tag(s, "comment" , 0, len4); |
|
|
|
|
url_fskip(pb, len5); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int asf_read_ext_content_desc(AVFormatContext *s, int64_t size) |
|
|
|
|
{ |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
ASFContext *asf = s->priv_data; |
|
|
|
|
int desc_count, i, ret; |
|
|
|
|
|
|
|
|
|
desc_count = get_le16(pb); |
|
|
|
|
for(i=0;i<desc_count;i++) { |
|
|
|
|
int name_len,value_type,value_len; |
|
|
|
|
char name[1024]; |
|
|
|
|
|
|
|
|
|
name_len = get_le16(pb); |
|
|
|
|
if (name_len%2) // must be even, broken lavf versions wrote len-1
|
|
|
|
|
name_len += 1; |
|
|
|
|
if ((ret = avio_get_str16le(pb, name_len, name, sizeof(name))) < name_len) |
|
|
|
|
url_fskip(pb, name_len - ret); |
|
|
|
|
value_type = get_le16(pb); |
|
|
|
|
value_len = get_le16(pb); |
|
|
|
|
if (!value_type && value_len%2) |
|
|
|
|
value_len += 1; |
|
|
|
|
/**
|
|
|
|
|
* My sample has that stream set to 0 maybe that mean the container. |
|
|
|
|
* Asf stream count start at 1. I am using 0 to the container value since it's unused |
|
|
|
|
*/ |
|
|
|
|
if (!strcmp(name, "AspectRatioX")){ |
|
|
|
|
asf->dar[0].num= get_value(s->pb, value_type); |
|
|
|
|
} else if(!strcmp(name, "AspectRatioY")){ |
|
|
|
|
asf->dar[0].den= get_value(s->pb, value_type); |
|
|
|
|
} else |
|
|
|
|
get_tag(s, name, value_type, value_len); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int asf_read_language_list(AVFormatContext *s, int64_t size) |
|
|
|
|
{ |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
ASFContext *asf = s->priv_data; |
|
|
|
|
int j, ret; |
|
|
|
|
int stream_count = get_le16(pb); |
|
|
|
|
for(j = 0; j < stream_count; j++) { |
|
|
|
|
char lang[6]; |
|
|
|
|
unsigned int lang_len = get_byte(pb); |
|
|
|
|
if ((ret = avio_get_str16le(pb, lang_len, lang, sizeof(lang))) < lang_len) |
|
|
|
|
url_fskip(pb, lang_len - ret); |
|
|
|
|
if (j < 128) |
|
|
|
|
av_strlcpy(asf->stream_languages[j], lang, sizeof(*asf->stream_languages)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int asf_read_metadata(AVFormatContext *s, int64_t size) |
|
|
|
|
{ |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
ASFContext *asf = s->priv_data; |
|
|
|
|
int n, stream_num, name_len, value_len, value_type, value_num; |
|
|
|
|
int ret, i; |
|
|
|
|
n = get_le16(pb); |
|
|
|
|
|
|
|
|
|
for(i=0;i<n;i++) { |
|
|
|
|
char name[1024]; |
|
|
|
|
|
|
|
|
|
get_le16(pb); //lang_list_index
|
|
|
|
|
stream_num= get_le16(pb); |
|
|
|
|
name_len= get_le16(pb); |
|
|
|
|
value_type= get_le16(pb); |
|
|
|
|
value_len= get_le32(pb); |
|
|
|
|
|
|
|
|
|
if ((ret = avio_get_str16le(pb, name_len, name, sizeof(name))) < name_len) |
|
|
|
|
url_fskip(pb, name_len - ret); |
|
|
|
|
//av_log(s, AV_LOG_ERROR, "%d %d %d %d %d <%s>\n", i, stream_num, name_len, value_type, value_len, name);
|
|
|
|
|
value_num= get_le16(pb);//we should use get_value() here but it does not work 2 is le16 here but le32 elsewhere
|
|
|
|
|
url_fskip(pb, value_len - 2); |
|
|
|
|
|
|
|
|
|
if(stream_num<128){ |
|
|
|
|
if (!strcmp(name, "AspectRatioX")) asf->dar[stream_num].num= value_num; |
|
|
|
|
else if(!strcmp(name, "AspectRatioY")) asf->dar[stream_num].den= value_num; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int asf_read_marker(AVFormatContext *s, int64_t size) |
|
|
|
|
{ |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
int i, count, name_len, ret; |
|
|
|
|
char name[1024]; |
|
|
|
|
|
|
|
|
|
get_le64(pb); // reserved 16 bytes
|
|
|
|
|
get_le64(pb); // ...
|
|
|
|
|
count = get_le32(pb); // markers count
|
|
|
|
|
get_le16(pb); // reserved 2 bytes
|
|
|
|
|
name_len = get_le16(pb); // name length
|
|
|
|
|
for(i=0;i<name_len;i++){ |
|
|
|
|
get_byte(pb); // skip the name
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for(i=0;i<count;i++){ |
|
|
|
|
int64_t pres_time; |
|
|
|
|
int name_len; |
|
|
|
|
|
|
|
|
|
get_le64(pb); // offset, 8 bytes
|
|
|
|
|
pres_time = get_le64(pb); // presentation time
|
|
|
|
|
get_le16(pb); // entry length
|
|
|
|
|
get_le32(pb); // send time
|
|
|
|
|
get_le32(pb); // flags
|
|
|
|
|
name_len = get_le32(pb); // name length
|
|
|
|
|
if ((ret = avio_get_str16le(pb, name_len * 2, name, sizeof(name))) < name_len) |
|
|
|
|
url_fskip(pb, name_len - ret); |
|
|
|
|
ff_new_chapter(s, i, (AVRational){1, 10000000}, pres_time, AV_NOPTS_VALUE, name ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) |
|
|
|
|
{ |
|
|
|
|
ASFContext *asf = s->priv_data; |
|
|
|
@ -204,7 +411,6 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) |
|
|
|
|
memset(&asf->asfid2avid, -1, sizeof(asf->asfid2avid)); |
|
|
|
|
for(;;) { |
|
|
|
|
uint64_t gpos= url_ftell(pb); |
|
|
|
|
int ret; |
|
|
|
|
ff_get_guid(pb, &g); |
|
|
|
|
gsize = get_le64(pb); |
|
|
|
|
av_dlog(s, "%08"PRIx64": ", gpos); |
|
|
|
@ -223,19 +429,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) |
|
|
|
|
if (gsize < 24) |
|
|
|
|
return -1; |
|
|
|
|
if (!ff_guidcmp(&g, &ff_asf_file_header)) { |
|
|
|
|
ff_get_guid(pb, &asf->hdr.guid); |
|
|
|
|
asf->hdr.file_size = get_le64(pb); |
|
|
|
|
asf->hdr.create_time = get_le64(pb); |
|
|
|
|
get_le64(pb); /* number of packets */ |
|
|
|
|
asf->hdr.play_time = get_le64(pb); |
|
|
|
|
asf->hdr.send_time = get_le64(pb); |
|
|
|
|
asf->hdr.preroll = get_le32(pb); |
|
|
|
|
asf->hdr.ignore = get_le32(pb); |
|
|
|
|
asf->hdr.flags = get_le32(pb); |
|
|
|
|
asf->hdr.min_pktsize = get_le32(pb); |
|
|
|
|
asf->hdr.max_pktsize = get_le32(pb); |
|
|
|
|
asf->hdr.max_bitrate = get_le32(pb); |
|
|
|
|
s->packet_size = asf->hdr.max_pktsize; |
|
|
|
|
asf_read_file_properties(s, gsize); |
|
|
|
|
} else if (!ff_guidcmp(&g, &ff_asf_stream_header)) { |
|
|
|
|
enum AVMediaType type; |
|
|
|
|
int type_specific_size, sizeX; |
|
|
|
@ -413,121 +607,15 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) |
|
|
|
|
pos2 = url_ftell(pb); |
|
|
|
|
url_fskip(pb, gsize - (pos2 - pos1 + 24)); |
|
|
|
|
} else if (!ff_guidcmp(&g, &ff_asf_comment_header)) { |
|
|
|
|
int len1, len2, len3, len4, len5; |
|
|
|
|
|
|
|
|
|
len1 = get_le16(pb); |
|
|
|
|
len2 = get_le16(pb); |
|
|
|
|
len3 = get_le16(pb); |
|
|
|
|
len4 = get_le16(pb); |
|
|
|
|
len5 = get_le16(pb); |
|
|
|
|
get_tag(s, "title" , 0, len1); |
|
|
|
|
get_tag(s, "author" , 0, len2); |
|
|
|
|
get_tag(s, "copyright", 0, len3); |
|
|
|
|
get_tag(s, "comment" , 0, len4); |
|
|
|
|
url_fskip(pb, len5); |
|
|
|
|
asf_read_content_desc(s, gsize); |
|
|
|
|
} else if (!ff_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); |
|
|
|
|
if ((ret = avio_get_str16le(pb, lang_len, lang, sizeof(lang))) < lang_len) |
|
|
|
|
url_fskip(pb, lang_len - ret); |
|
|
|
|
if (j < 128) |
|
|
|
|
av_strlcpy(asf->stream_languages[j], lang, sizeof(*asf->stream_languages)); |
|
|
|
|
} |
|
|
|
|
asf_read_language_list(s, gsize); |
|
|
|
|
} else if (!ff_guidcmp(&g, &ff_asf_extended_content_header)) { |
|
|
|
|
int desc_count, i; |
|
|
|
|
|
|
|
|
|
desc_count = get_le16(pb); |
|
|
|
|
for(i=0;i<desc_count;i++) { |
|
|
|
|
int name_len,value_type,value_len; |
|
|
|
|
char name[1024]; |
|
|
|
|
|
|
|
|
|
name_len = get_le16(pb); |
|
|
|
|
if (name_len%2) // must be even, broken lavf versions wrote len-1
|
|
|
|
|
name_len += 1; |
|
|
|
|
if ((ret = avio_get_str16le(pb, name_len, name, sizeof(name))) < name_len) |
|
|
|
|
url_fskip(pb, name_len - ret); |
|
|
|
|
value_type = get_le16(pb); |
|
|
|
|
value_len = get_le16(pb); |
|
|
|
|
if (!value_type && value_len%2) |
|
|
|
|
value_len += 1; |
|
|
|
|
/**
|
|
|
|
|
* My sample has that stream set to 0 maybe that mean the container. |
|
|
|
|
* Asf stream count start at 1. I am using 0 to the container value since it's unused |
|
|
|
|
*/ |
|
|
|
|
if (!strcmp(name, "AspectRatioX")){ |
|
|
|
|
asf->dar[0].num= get_value(s->pb, value_type); |
|
|
|
|
} else if(!strcmp(name, "AspectRatioY")){ |
|
|
|
|
asf->dar[0].den= get_value(s->pb, value_type); |
|
|
|
|
} else |
|
|
|
|
get_tag(s, name, value_type, value_len); |
|
|
|
|
} |
|
|
|
|
asf_read_ext_content_desc(s, gsize); |
|
|
|
|
} else if (!ff_guidcmp(&g, &ff_asf_metadata_header)) { |
|
|
|
|
int n, stream_num, name_len, value_len, value_type, value_num; |
|
|
|
|
n = get_le16(pb); |
|
|
|
|
|
|
|
|
|
for(i=0;i<n;i++) { |
|
|
|
|
char name[1024]; |
|
|
|
|
|
|
|
|
|
get_le16(pb); //lang_list_index
|
|
|
|
|
stream_num= get_le16(pb); |
|
|
|
|
name_len= get_le16(pb); |
|
|
|
|
value_type= get_le16(pb); |
|
|
|
|
value_len= get_le32(pb); |
|
|
|
|
|
|
|
|
|
if ((ret = avio_get_str16le(pb, name_len, name, sizeof(name))) < name_len) |
|
|
|
|
url_fskip(pb, name_len - ret); |
|
|
|
|
//av_log(s, AV_LOG_ERROR, "%d %d %d %d %d <%s>\n", i, stream_num, name_len, value_type, value_len, name);
|
|
|
|
|
value_num= get_le16(pb);//we should use get_value() here but it does not work 2 is le16 here but le32 elsewhere
|
|
|
|
|
url_fskip(pb, value_len - 2); |
|
|
|
|
|
|
|
|
|
if(stream_num<128){ |
|
|
|
|
if (!strcmp(name, "AspectRatioX")) asf->dar[stream_num].num= value_num; |
|
|
|
|
else if(!strcmp(name, "AspectRatioY")) asf->dar[stream_num].den= value_num; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
asf_read_metadata(s, gsize); |
|
|
|
|
} else if (!ff_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
|
|
|
|
|
leak_rate = get_le32(pb); // leak-datarate
|
|
|
|
|
get_le32(pb); // bucket-datasize
|
|
|
|
|
get_le32(pb); // init-bucket-fullness
|
|
|
|
|
get_le32(pb); // alt-leak-datarate
|
|
|
|
|
get_le32(pb); // alt-bucket-datasize
|
|
|
|
|
get_le32(pb); // alt-init-bucket-fullness
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
if (stream_num < 128) |
|
|
|
|
asf->stream_bitrates[stream_num] = leak_rate; |
|
|
|
|
|
|
|
|
|
for (i=0; i<stream_ct; i++){ |
|
|
|
|
get_le16(pb); |
|
|
|
|
ext_len = get_le16(pb); |
|
|
|
|
url_fseek(pb, ext_len, SEEK_CUR); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (i=0; i<payload_ext_ct; i++){ |
|
|
|
|
ff_get_guid(pb, &g); |
|
|
|
|
ext_d=get_le16(pb); |
|
|
|
|
ext_len=get_le32(pb); |
|
|
|
|
url_fseek(pb, ext_len, SEEK_CUR); |
|
|
|
|
} |
|
|
|
|
asf_read_ext_stream_properties(s, gsize); |
|
|
|
|
|
|
|
|
|
// there could be a optional stream properties object to follow
|
|
|
|
|
// if so the next iteration will pick it up
|
|
|
|
@ -539,32 +627,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) |
|
|
|
|
v2 = get_le16(pb); |
|
|
|
|
continue; |
|
|
|
|
} else if (!ff_guidcmp(&g, &ff_asf_marker_header)) { |
|
|
|
|
int i, count, name_len; |
|
|
|
|
char name[1024]; |
|
|
|
|
|
|
|
|
|
get_le64(pb); // reserved 16 bytes
|
|
|
|
|
get_le64(pb); // ...
|
|
|
|
|
count = get_le32(pb); // markers count
|
|
|
|
|
get_le16(pb); // reserved 2 bytes
|
|
|
|
|
name_len = get_le16(pb); // name length
|
|
|
|
|
for(i=0;i<name_len;i++){ |
|
|
|
|
get_byte(pb); // skip the name
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for(i=0;i<count;i++){ |
|
|
|
|
int64_t pres_time; |
|
|
|
|
int name_len; |
|
|
|
|
|
|
|
|
|
get_le64(pb); // offset, 8 bytes
|
|
|
|
|
pres_time = get_le64(pb); // presentation time
|
|
|
|
|
get_le16(pb); // entry length
|
|
|
|
|
get_le32(pb); // send time
|
|
|
|
|
get_le32(pb); // flags
|
|
|
|
|
name_len = get_le32(pb); // name length
|
|
|
|
|
if ((ret = avio_get_str16le(pb, name_len * 2, name, sizeof(name))) < name_len) |
|
|
|
|
url_fskip(pb, name_len - ret); |
|
|
|
|
ff_new_chapter(s, i, (AVRational){1, 10000000}, pres_time, AV_NOPTS_VALUE, name ); |
|
|
|
|
} |
|
|
|
|
asf_read_marker(s, gsize); |
|
|
|
|
} else if (url_feof(pb)) { |
|
|
|
|
return -1; |
|
|
|
|
} else { |
|
|
|
|