#include "libavutil/intreadwrite.h"
#include "avformat.h"
+#include "internal.h"
#include "apetag.h"
/* The earliest and latest file formats supported by this library */
} else {
for (i = 0; i < ape_ctx->seektablelength / sizeof(uint32_t); i++) {
if (i < ape_ctx->totalframes - 1) {
- av_log(s, AV_LOG_DEBUG, "%8d %d (%d bytes)\n", i, ape_ctx->seektable[i], ape_ctx->seektable[i + 1] - ape_ctx->seektable[i]);
+ av_log(s, AV_LOG_DEBUG, "%8d %"PRIu32" (%"PRIu32" bytes)\n",
+ i, ape_ctx->seektable[i],
+ ape_ctx->seektable[i + 1] - ape_ctx->seektable[i]);
} else {
- av_log(s, AV_LOG_DEBUG, "%8d %d\n", i, ape_ctx->seektable[i]);
+ av_log(s, AV_LOG_DEBUG, "%8d %"PRIu32"\n", i, ape_ctx->seektable[i]);
}
}
}
#endif
}
-static int ape_read_header(AVFormatContext * s, AVFormatParameters * ap)
+static int ape_read_header(AVFormatContext * s)
{
AVIOContext *pb = s->pb;
APEContext *ape = s->priv_data;
AVStream *st;
uint32_t tag;
int i;
- int total_blocks;
- int64_t pts;
+ int total_blocks, final_size = 0;
+ int64_t pts, file_size;
/* Skip any leading junk such as id3v2 tags */
ape->junklength = avio_tell(pb);
ape->fileversion = avio_rl16(pb);
if (ape->fileversion < APE_MIN_VERSION || ape->fileversion > APE_MAX_VERSION) {
- av_log(s, AV_LOG_ERROR, "Unsupported file version - %"PRId16".%02"PRId16"\n",
+ av_log(s, AV_LOG_ERROR, "Unsupported file version - %d.%02d\n",
ape->fileversion / 1000, (ape->fileversion % 1000) / 10);
return -1;
}
return -1;
}
if (ape->seektablelength && (ape->seektablelength / sizeof(*ape->seektable)) < ape->totalframes) {
- av_log(s, AV_LOG_ERROR, "Number of seek entries is less than number of frames: %ld vs. %"PRIu32"\n",
+ av_log(s, AV_LOG_ERROR,
+ "Number of seek entries is less than number of frames: %zu vs. %"PRIu32"\n",
ape->seektablelength / sizeof(*ape->seektable), ape->totalframes);
return AVERROR_INVALIDDATA;
}
if (ape->seektablelength > 0) {
ape->seektable = av_malloc(ape->seektablelength);
+ if (!ape->seektable)
+ return AVERROR(ENOMEM);
for (i = 0; i < ape->seektablelength / sizeof(uint32_t); i++)
ape->seektable[i] = avio_rl32(pb);
}
ape->frames[i - 1].size = ape->frames[i].pos - ape->frames[i - 1].pos;
ape->frames[i].skip = (ape->frames[i].pos - ape->frames[0].pos) & 3;
}
- ape->frames[ape->totalframes - 1].size = ape->finalframeblocks * 4;
ape->frames[ape->totalframes - 1].nblocks = ape->finalframeblocks;
+ /* calculate final packet size from total file size, if available */
+ file_size = avio_size(pb);
+ if (file_size > 0) {
+ final_size = file_size - ape->frames[ape->totalframes - 1].pos -
+ ape->wavtaillength;
+ final_size -= final_size & 3;
+ }
+ if (file_size <= 0 || final_size <= 0)
+ final_size = ape->finalframeblocks * 8;
+ ape->frames[ape->totalframes - 1].size = final_size;
for (i = 0; i < ape->totalframes; i++) {
if(ape->frames[i].skip){
ape_dumpinfo(s, ape);
- /* try to read APE tags */
- if (pb->seekable) {
- ff_ape_parse_tag(s);
- avio_seek(pb, 0, SEEK_SET);
- }
-
av_log(s, AV_LOG_DEBUG, "Decoding file - v%d.%02d, compression level %"PRIu16"\n",
ape->fileversion / 1000, (ape->fileversion % 1000) / 10,
ape->compressiontype);
/* now we are ready: build format streams */
- st = av_new_stream(s, 0);
+ st = avformat_new_stream(s, NULL);
if (!st)
return -1;
st->codec->channels = ape->channels;
st->codec->sample_rate = ape->samplerate;
st->codec->bits_per_coded_sample = ape->bps;
- st->codec->frame_size = MAC_SUBFRAME_SIZE;
st->nb_frames = ape->totalframes;
st->start_time = 0;
st->duration = total_blocks / MAC_SUBFRAME_SIZE;
- av_set_pts_info(st, 64, MAC_SUBFRAME_SIZE, ape->samplerate);
+ avpriv_set_pts_info(st, 64, MAC_SUBFRAME_SIZE, ape->samplerate);
st->codec->extradata = av_malloc(APE_EXTRADATA_SIZE);
st->codec->extradata_size = APE_EXTRADATA_SIZE;
pts += ape->blocksperframe / MAC_SUBFRAME_SIZE;
}
+ /* try to read APE tags */
+ if (pb->seekable) {
+ ff_ape_parse_tag(s);
+ avio_seek(pb, 0, SEEK_SET);
+ }
+
return 0;
}
uint32_t extra_size = 8;
if (s->pb->eof_reached)
- return AVERROR(EIO);
- if (ape->currentframe > ape->totalframes)
- return AVERROR(EIO);
+ return AVERROR_EOF;
+ if (ape->currentframe >= ape->totalframes)
+ return AVERROR_EOF;
- avio_seek (s->pb, ape->frames[ape->currentframe].pos, SEEK_SET);
+ if (avio_seek(s->pb, ape->frames[ape->currentframe].pos, SEEK_SET) < 0)
+ return AVERROR(EIO);
/* Calculate how many blocks there are in this frame */
if (ape->currentframe == (ape->totalframes - 1))
else
nblocks = ape->blocksperframe;
+ if (ape->frames[ape->currentframe].size <= 0 ||
+ ape->frames[ape->currentframe].size > INT_MAX - extra_size) {
+ av_log(s, AV_LOG_ERROR, "invalid packet size: %d\n",
+ ape->frames[ape->currentframe].size);
+ ape->currentframe++;
+ return AVERROR(EIO);
+ }
+
if (av_new_packet(pkt, ape->frames[ape->currentframe].size + extra_size) < 0)
return AVERROR(ENOMEM);
if (index < 0)
return -1;
+ if (avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET) < 0)
+ return -1;
ape->currentframe = index;
return 0;
}
AVInputFormat ff_ape_demuxer = {
- "ape",
- NULL_IF_CONFIG_SMALL("Monkey's Audio"),
- sizeof(APEContext),
- ape_probe,
- ape_read_header,
- ape_read_packet,
- ape_read_close,
- ape_read_seek,
- .extensions = "ape,apl,mac"
+ .name = "ape",
+ .long_name = NULL_IF_CONFIG_SMALL("Monkey's Audio"),
+ .priv_data_size = sizeof(APEContext),
+ .read_probe = ape_probe,
+ .read_header = ape_read_header,
+ .read_packet = ape_read_packet,
+ .read_close = ape_read_close,
+ .read_seek = ape_read_seek,
+ .extensions = "ape,apl,mac",
};