diff options
Diffstat (limited to 'src/plugins/Input/mad/decoder_mad.cpp')
| -rw-r--r-- | src/plugins/Input/mad/decoder_mad.cpp | 151 |
1 files changed, 99 insertions, 52 deletions
diff --git a/src/plugins/Input/mad/decoder_mad.cpp b/src/plugins/Input/mad/decoder_mad.cpp index d29781622..7c8cc8f1b 100644 --- a/src/plugins/Input/mad/decoder_mad.cpp +++ b/src/plugins/Input/mad/decoder_mad.cpp @@ -122,9 +122,15 @@ bool DecoderMAD::initialize() if (! findHeader()) { - qDebug("DecoderMAD: Cannot find a valid MPEG header."); + qDebug("DecoderMAD: Can't find a valid MPEG header."); return FALSE; } + mad_stream_buffer(&stream, (unsigned char *) input_buf, input_bytes); + stream.error = MAD_ERROR_NONE; + stream.error = MAD_ERROR_BUFLEN; + mad_frame_mute (&frame); + stream.next_frame = NULL; + stream.sync = 0; configure(freq, channels, 16, bitrate); inited = TRUE; @@ -221,78 +227,116 @@ fail: bool DecoderMAD::findHeader() { - bool result = false; + bool result = FALSE; int count = 0; + bool has_xing = FALSE; + bool is_vbr = FALSE; + mad_timer_t duration = mad_timer_zero; + struct mad_header header; + mad_header_init (&header); - while (1) + while (TRUE) { - if (input_bytes < globalBufferSize) + input_bytes = 0; + if (stream.error == MAD_ERROR_BUFLEN || !stream.buffer) { - int bytes = input()->read(input_buf + input_bytes, - globalBufferSize - input_bytes); - if (bytes <= 0) + size_t remaining = 0; + + if (!stream.next_frame) { - if (bytes == -1) - result = false; - ; - break; + remaining = stream.bufend - stream.next_frame; + memmove (input_buf, stream.next_frame, remaining); } - input_bytes += bytes; - } - mad_stream_buffer(&stream, (unsigned char *) input_buf, input_bytes); + input_bytes = input()->read(input_buf + remaining, globalBufferSize - remaining); - bool done = false; - while (! done) + if (input_bytes <= 0) + break; + + mad_stream_buffer(&stream, (unsigned char *) input_buf + remaining, input_bytes); + stream.error = MAD_ERROR_NONE; + } + + if (mad_header_decode(&header, &stream) == -1) { - if (mad_frame_decode(&frame, &stream) != -1) - done = true; - else if (!MAD_RECOVERABLE(stream.error)) + if (stream.error == MAD_ERROR_BUFLEN) + continue; + else if (MAD_RECOVERABLE(stream.error)) + continue; + else { - qWarning("DecoderMAD: Can't decode frame"); + qDebug ("DecoderMAD: Can't decode header: %s", mad_stream_errorstr(&stream)); break; } - - count++; } + result = TRUE; - findXingHeader(stream.anc_ptr, stream.anc_bitlen); - result = done; - if ((stream.error != MAD_ERROR_BUFLEN)) + if (input()->isSequential()) break; - input_bytes = &input_buf[input_bytes] - (char *) stream.next_frame; - memmove(input_buf, stream.next_frame, input_bytes); - } + count ++; + //try to detect xing header + if (count == 1) + { + frame.header = header; + if (mad_frame_decode(&frame, &stream) != -1 && + findXingHeader(stream.anc_ptr, stream.anc_bitlen)) + { + is_vbr = TRUE; - if (result && count) - { - freq = frame.header.samplerate; - channels = MAD_NCHANNELS(&frame.header); - bitrate = frame.header.bitrate / 1000; - calcLength(&frame.header); - } + qDebug ("DecoderMAD: Xing header detected"); - return result; -} + if (xing.flags & XING_FRAMES) + { + has_xing = TRUE; + count = xing.frames; + break; + } + } + } + //try to detect VBR + if (!is_vbr && !(count > 15)) + { + if (bitrate && header.bitrate != bitrate) + { + qDebug ("DecoderMAD: VBR detected"); + is_vbr = TRUE; + } + else + bitrate = header.bitrate; + } + else if (!is_vbr) + { + qDebug ("DecoderMAD: Fixed rate detected"); + break; + } + mad_timer_add (&duration, header.duration); + } -void DecoderMAD::calcLength(struct mad_header *header) -{ - if (! input() || input()->isSequential()) - return; + if (!result) + return FALSE; - totalTime = 0.; - if (xing.flags & XING_FRAMES) + if (!is_vbr) { - mad_timer_t timer; - - timer = header->duration; - mad_timer_multiply(&timer, xing.frames); - - totalTime = double(mad_timer_count(timer, MAD_UNITS_MILLISECONDS)) / 1000.; + double time = (input()->size() * 8.0) / (header.bitrate); + double timefrac = (double)time - ((long)(time)); + mad_timer_set(&duration, (long)time, (long)(timefrac*100), 100); + } + else if (has_xing) + { + mad_timer_multiply (&header.duration, count); + duration = header.duration; } - else if (header->bitrate > 0) - totalTime = input()->size() * 8 / header->bitrate; + + totalTime = mad_timer_count(duration, MAD_UNITS_SECONDS); + qDebug ("DecoderMAD: Total time: %ld", long(totalTime)); + freq = header.samplerate; + channels = MAD_NCHANNELS(&header); + bitrate = header.bitrate / 1000; + mad_header_finish(&header); + input()->seek(0); + input_bytes = 0; + return TRUE; } double DecoderMAD::lengthInSeconds() @@ -352,7 +396,7 @@ void DecoderMAD::flush(bool final) void DecoderMAD::run() { - int skip_frames = 0; + int skip_frames = 1; //skip first frame mutex()->lock(); if (! inited) @@ -429,6 +473,9 @@ void DecoderMAD::run() { if (mad_frame_decode(&frame, &stream) == -1) { + if (stream.error == MAD_ERROR_LOSTSYNC) + continue; + if (stream.error == MAD_ERROR_BUFLEN) break; |
