summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwm4 <nfxjfg@googlemail.com>2014-09-21 12:51:41 +0200
committerMichael Niedermayer <michaelni@gmx.at>2014-09-21 14:57:12 +0200
commit6c7f1155bb648eced8e5aa08b1fd490df2f8b325 (patch)
tree607abb626c790b71c3a55e0597fe501b21499240
parent36bf549b2706bd10014556a84a33ed6daf5d5373 (diff)
avformat/mp3dec: avoid early EOF with concatenated gapless mp3s
Consider a file created with something like: cat file1.mp3 file2.mp3 > result.mp3 Then if file2.mp3 has gapless information, result.mp3 would stop playing something in the middle. This happens because the gapless info directs the decoder to discard all samples after a certain position. To make matters worse, the gapless info of file2.mp3 will be used when playing the file1.mp3 part, because the gapless info is located at the end of the file. While handling concatenated gapless files correctly would be insane and a lot of effort (especially without scanning the whole file on opening), it's easy to prevent at least early EOF. Playback will happen to work, even if it's slightly broken. Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--libavformat/avformat.h9
-rw-r--r--libavformat/mp3dec.c6
-rw-r--r--libavformat/utils.c7
3 files changed, 16 insertions, 6 deletions
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 2370cb08da..78054debca 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -1036,7 +1036,14 @@ typedef struct AVStream {
* avoided for broken by design formats such as mp3 with ad-hoc gapless
* audio support.
*/
- int64_t end_discard_sample;
+ int64_t first_discard_sample;
+
+ /**
+ * The sample after last sample that is intended to be discarded after
+ * first_discard_sample. Works on frame boundaries only. Used to prevent
+ * early EOF if the gapless info is broken (considered concatenated mp3s).
+ */
+ int64_t last_discard_sample;
/**
* Number of internally decoded frames, used internally in libavformat, do not access
diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c
index 639c78d405..8745f209d3 100644
--- a/libavformat/mp3dec.c
+++ b/libavformat/mp3dec.c
@@ -219,8 +219,10 @@ static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st,
mp3->start_pad = v>>12;
mp3-> end_pad = v&4095;
st->skip_samples = mp3->start_pad + 528 + 1;
- if (mp3->frames)
- st->end_discard_sample = -mp3->end_pad + 528 + 1 + mp3->frames * (int64_t)spf;
+ if (mp3->frames) {
+ st->first_discard_sample = -mp3->end_pad + 528 + 1 + mp3->frames * (int64_t)spf;
+ st->last_discard_sample = mp3->frames * (int64_t)spf;
+ }
if (!st->start_time)
st->start_time = av_rescale_q(st->skip_samples,
(AVRational){1, c->sample_rate},
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 58533f88e9..e0e78a78f1 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -1358,13 +1358,14 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
if (ret >= 0) {
AVStream *st = s->streams[pkt->stream_index];
int discard_padding = 0;
- if (st->end_discard_sample && pkt->pts != AV_NOPTS_VALUE) {
+ if (st->first_discard_sample && pkt->pts != AV_NOPTS_VALUE) {
int64_t pts = pkt->pts - (is_relative(pkt->pts) ? RELATIVE_TS_BASE : 0);
int64_t sample = ts_to_samples(st, pts);
int duration = ts_to_samples(st, pkt->duration);
int64_t end_sample = sample + duration;
- if (duration > 0 && end_sample >= st->end_discard_sample)
- discard_padding = FFMIN(end_sample - st->end_discard_sample, duration);
+ if (duration > 0 && end_sample >= st->first_discard_sample &&
+ sample < st->last_discard_sample)
+ discard_padding = FFMIN(end_sample - st->first_discard_sample, duration);
}
if (st->skip_samples || discard_padding) {
uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);