/*
- * ASF compatible decoder.
+ * ASF compatible demuxer
* Copyright (c) 2000, 2001 Fabrice Bellard.
*
- * This library is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
#include "riff.h"
#include "mpegaudio.h"
#include "asf.h"
+#include "common.h"
#undef NDEBUG
#include <assert.h>
static void get_str16_nolen(ByteIOContext *pb, int len, char *buf, int buf_size)
{
- int c;
- char *q;
-
- q = buf;
- while (len > 0) {
- c = get_le16(pb);
- if ((q - buf) < buf_size - 1)
- *q++ = c;
- len-=2;
+ char* q = buf;
+ len /= 2;
+ while (len--) {
+ uint8_t tmp;
+ PUT_UTF8(get_le16(pb), tmp, if (q - buf < buf_size - 1) *q++ = tmp;)
}
*q = '\0';
}
get_guid(pb, &g);
gsize = get_le64(pb);
#ifdef DEBUG
- printf("%08Lx: ", url_ftell(pb) - 24);
+ printf("%08"PRIx64": ", url_ftell(pb) - 24);
print_guid(&g);
- printf(" size=0x%Lx\n", gsize);
+ printf(" size=0x%"PRIx64"\n", gsize);
#endif
if (gsize < 24)
goto fail;
asf->packet_size = asf->hdr.max_pktsize;
asf->nb_packets = asf->hdr.packets_count;
} else if (!memcmp(&g, &stream_header, sizeof(GUID))) {
- int type, total_size, type_specific_size, sizeX;
+ int type, type_specific_size, sizeX;
+ uint64_t total_size;
unsigned int tag1;
int64_t pos1, pos2;
int test_for_ext_stream_audio;
pos2 = url_ftell(pb);
url_fskip(pb, gsize - (pos2 - pos1 + 24));
} else if (!memcmp(&g, &data_header, sizeof(GUID))) {
+ asf->data_object_offset = url_ftell(pb);
+ if (gsize != (uint64_t)-1 && gsize >= 24) {
+ asf->data_object_size = gsize - 24;
+ } else {
+ asf->data_object_size = (uint64_t)-1;
+ }
break;
} else if (!memcmp(&g, &comment_header, sizeof(GUID))) {
int len1, len2, len3, len4, len5;
desc_count = get_le16(pb);
for(i=0;i<desc_count;i++)
{
- int name_len,value_type,value_len,value_num = 0;
+ int name_len,value_type,value_len;
+ uint64_t value_num = 0;
char *name, *value;
name_len = get_le16(pb);
- name = (char *)av_mallocz(name_len);
- get_str16_nolen(pb, name_len, name, name_len);
+ name = (char *)av_malloc(name_len * 2);
+ get_str16_nolen(pb, name_len, name, name_len * 2);
value_type = get_le16(pb);
value_len = get_le16(pb);
if ((value_type == 0) || (value_type == 1)) // unicode or byte
{
- value = (char *)av_mallocz(value_len);
- get_str16_nolen(pb, value_len, value, value_len);
+ value = (char *)av_malloc(value_len * 2);
+ get_str16_nolen(pb, value_len, value,
+ value_len * 2);
if (strcmp(name,"WM/AlbumTitle")==0) { pstrcpy(s->album, sizeof(s->album), value); }
av_free(value);
}
rsize+=2;
/* }else{
if (!url_feof(pb))
- printf("ff asf bad header %x at:%lld\n", c, url_ftell(pb));
+ printf("ff asf bad header %x at:%"PRId64"\n", c, url_ftell(pb));
return AVERROR_IO;*/
}
DO_2BITS(asf->packet_flags >> 1, padsize, 0); // sequence ignored
DO_2BITS(asf->packet_flags >> 3, padsize, 0); // padding length
+ //the following checks prevent overflows and infinite loops
+ if(packet_length >= (1U<<29)){
+ av_log(s, AV_LOG_ERROR, "invalid packet_length %d at:%"PRId64"\n", packet_length, url_ftell(pb));
+ return 0; // FIXME this should be -1
+ }
+ if(padsize >= (1U<<29)){
+ av_log(s, AV_LOG_ERROR, "invalid padsize %d at:%"PRId64"\n", padsize, url_ftell(pb));
+ return 0; // FIXME this should be -1
+ }
+
asf->packet_timestamp = get_le32(pb);
get_le16(pb); /* duration */
// rsize has at least 11 bytes which have to be present
|| asf->packet_segments < 1) {
//asf->packet_size_left <= asf->packet_padsize) {
int ret = asf->packet_size_left + asf->packet_padsize;
- //printf("PacketLeftSize:%d Pad:%d Pos:%Ld\n", asf->packet_size_left, asf->packet_padsize, url_ftell(pb));
+ //printf("PacketLeftSize:%d Pad:%d Pos:%"PRId64"\n", asf->packet_size_left, asf->packet_padsize, url_ftell(pb));
if((url_ftell(&s->pb) + ret - s->data_offset) % asf->packet_size)
ret += asf->packet_size - ((url_ftell(&s->pb) + ret - s->data_offset) % asf->packet_size);
+ assert(ret>=0);
/* fail safe */
url_fskip(pb, ret);
asf->packet_pos= url_ftell(&s->pb);
+ if (asf->data_object_size != (uint64_t)-1 &&
+ (asf->packet_pos - asf->data_object_offset >= asf->data_object_size))
+ return AVERROR_IO; /* Do not exceed the size of the data object */
ret = asf_get_packet(s);
//printf("READ ASF PACKET %d r:%d c:%d\n", ret, asf->packet_size_left, pc++);
if (ret < 0 || url_feof(pb))
/* return packet */
if (asf_st->ds_span > 1) {
/* packet descrambling */
- char* newdata = av_malloc(asf_st->pkt.size);
+ uint8_t *newdata = av_malloc(asf_st->pkt.size);
if (newdata) {
int offset = 0;
while (offset < asf_st->pkt.size) {
assert((asf_st->packet_pos - s->data_offset) % asf->packet_size == 0);
pos= asf_st->packet_pos;
- av_add_index_entry(s->streams[i], pos, pkt->size, pts, pos - start_pos[i] + 1, AVINDEX_KEYFRAME);
+ av_add_index_entry(s->streams[i], pos, pts, pkt->size, pos - start_pos[i] + 1, AVINDEX_KEYFRAME);
start_pos[i]= asf_st->packet_pos + 1;
if(pkt->stream_index == stream_index)
}
*ppos= pos;
-//printf("found keyframe at %Ld stream %d stamp:%Ld\n", *ppos, stream_index, pts);
+//printf("found keyframe at %"PRId64" stream %d stamp:%"PRId64"\n", *ppos, stream_index, pts);
return pts;
}
+static void asf_build_simple_index(AVFormatContext *s, int stream_index)
+{
+ GUID g;
+ ASFContext *asf = s->priv_data;
+ int64_t gsize, itime;
+ int64_t pos, current_pos, index_pts;
+ 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);
+ get_guid(&s->pb, &g);
+ itime=get_le64(&s->pb);
+ pct=get_le32(&s->pb);
+ ict=get_le32(&s->pb);
+ av_log(NULL, AV_LOG_DEBUG, "itime:0x%"PRIx64", pct:%d, ict:%d\n",itime,pct,ict);
+
+ for (i=0;i<ict;i++){
+ int pktnum=get_le32(&s->pb);
+ int pktct =get_le16(&s->pb);
+ av_log(NULL, 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);
+
+ av_add_index_entry(s->streams[stream_index], pos, index_pts, asf->packet_size, 0, AVINDEX_KEYFRAME);
+ }
+ asf->index_read= 1;
+ }
+ url_fseek(&s->pb, current_pos, SEEK_SET);
+}
+
static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags)
{
ASFContext *asf = s->priv_data;
+ AVStream *st = s->streams[stream_index];
+ int64_t pos;
+ int index;
if (asf->packet_size <= 0)
return -1;
- if(av_seek_frame_binary(s, stream_index, pts, flags)<0)
- return -1;
-
+ if (!asf->index_read)
+ asf_build_simple_index(s, stream_index);
+
+ if(!(asf->index_read && st->index_entries)){
+ if(av_seek_frame_binary(s, stream_index, pts, flags)<0)
+ return -1;
+ }else{
+ index= av_index_search_timestamp(st, pts, flags);
+ if(index<0)
+ return -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);
+ // url_fseek(&s->pb, pos, SEEK_SET);
+ // key_pos = pos;
+ // for(i=0;i<16;i++){
+ // pos = url_ftell(&s->pb);
+ // if (av_read_frame(s, &pkt) < 0){
+ // av_log(s, AV_LOG_INFO, "seek failed\n");
+ // return -1;
+ // }
+ // asf_st = s->streams[stream_index]->priv_data;
+ // pos += st->parser->frame_offset;
+ //
+ // if (pkt.size > b) {
+ // b = pkt.size;
+ // key_pos = pos;
+ // }
+ //
+ // av_free_packet(&pkt);
+ // }
+
+ /* do the seek */
+ av_log(NULL, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos);
+ url_fseek(&s->pb, pos, SEEK_SET);
+ }
asf_reset_header(s);
return 0;
}