summaryrefslogtreecommitdiff
path: root/libavformat/mp3dec.c
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2013-07-07 13:15:32 +0200
committerMichael Niedermayer <michaelni@gmx.at>2013-07-08 17:12:51 +0200
commite096283ea55bc36a637b47329e19ddb26fb1440b (patch)
treea642c79c1e40de93973164b50796527ed332e2fa /libavformat/mp3dec.c
parent6150bec3f873ec3777496ac6a184d4b1190d6f16 (diff)
mp3dec: detect CBR and use CBR axiom to seek
This should also work reasonable with truncated and growing mp3s. Fixes Ticket2590 Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat/mp3dec.c')
-rw-r--r--libavformat/mp3dec.c29
1 files changed, 23 insertions, 6 deletions
diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c
index d2f35d0725..c9973c5142 100644
--- a/libavformat/mp3dec.c
+++ b/libavformat/mp3dec.c
@@ -39,10 +39,12 @@
typedef struct {
AVClass *class;
int64_t filesize;
+ int64_t header_filesize;
int xing_toc;
int start_pad;
int end_pad;
int usetoc;
+ int is_cbr;
} MP3DecContext;
/* mp3 read */
@@ -190,6 +192,9 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
if (size && frames && !is_cbr)
st->codec->bit_rate = av_rescale(size, 8 * c.sample_rate, frames * (int64_t)spf);
+ mp3->is_cbr = is_cbr;
+ mp3->header_filesize = size;
+
return 0;
}
@@ -279,21 +284,33 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
int flags)
{
MP3DecContext *mp3 = s->priv_data;
- AVIndexEntry *ie;
+ AVIndexEntry *ie, ie1;
AVStream *st = s->streams[0];
int64_t ret = av_index_search_timestamp(st, timestamp, flags);
int i, j;
- if (!mp3->xing_toc) {
+ if (mp3->is_cbr && st->duration > 0 && mp3->header_filesize > s->data_offset) {
+ int64_t filesize = avio_size(s->pb);
+ int64_t duration;
+ if (filesize <= s->data_offset)
+ filesize = mp3->header_filesize;
+ filesize -= s->data_offset;
+ duration = av_rescale(st->duration, filesize, mp3->header_filesize - s->data_offset);
+ ie = &ie1;
+ timestamp = av_clip64(timestamp, 0, duration);
+ ie->timestamp = timestamp;
+ ie->pos = av_rescale(timestamp, filesize, duration) + s->data_offset;
+ } else if (mp3->xing_toc) {
+ if (ret < 0)
+ return ret;
+
+ ie = &st->index_entries[ret];
+ } else {
st->skip_samples = timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0;
return -1;
}
- if (ret < 0)
- return ret;
-
- ie = &st->index_entries[ret];
ret = avio_seek(s->pb, ie->pos, SEEK_SET);
if (ret < 0)
return ret;