aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/Input
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/Input')
-rw-r--r--src/plugins/Input/mad/decoder_mad.cpp151
-rw-r--r--src/plugins/Input/mad/decoder_mad.h49
2 files changed, 119 insertions, 81 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;
diff --git a/src/plugins/Input/mad/decoder_mad.h b/src/plugins/Input/mad/decoder_mad.h
index 313af2e0f..f37016657 100644
--- a/src/plugins/Input/mad/decoder_mad.h
+++ b/src/plugins/Input/mad/decoder_mad.h
@@ -12,7 +12,8 @@ class DecoderMAD;
#include <qmmp/decoder.h>
#include "decodermadfactory.h"
-extern "C" {
+extern "C"
+{
#include <mad.h>
}
@@ -20,8 +21,8 @@ extern "C" {
class DecoderMAD : public Decoder
{
public:
- DecoderMAD(QObject *parent = 0, DecoderFactory *d = 0,
- QIODevice *i = 0, Output *o = 0);
+ DecoderMAD(QObject *parent = 0, DecoderFactory *d = 0,
+ QIODevice *i = 0, Output *o = 0);
virtual ~DecoderMAD();
// standard decoder API
@@ -30,17 +31,6 @@ public:
void seek(double);
void stop();
- // Equalizer
- //bool isEQSupported() const { return TRUE; }
- //void setEQEnabled(bool);
- //void setEQ(const EqPreset &);
-
- static const int maxDecodeRetries;
- static const int maxFrameSize;
- static const int maxFrameCheck;
- static const int initialFrameSize;
-
-
private:
// thread run function
void run();
@@ -53,12 +43,11 @@ private:
void deinit();
bool findHeader();
bool findXingHeader(struct mad_bitptr, unsigned int);
- void calcLength(struct mad_header *);
-
bool inited, user_stop, done, finish, derror, eof, useeq;
double totalTime, seekTime;
int channels;
- long bitrate, freq, len;
+ unsigned long bitrate;
+ long freq, len;
unsigned int bks;
mad_fixed_t eqbands[32];
@@ -71,19 +60,21 @@ private:
unsigned long output_bytes, output_at, output_size;
// MAD decoder
- struct {
- int flags;
- unsigned long frames;
- unsigned long bytes;
- unsigned char toc[100];
- long scale;
+ struct
+ {
+ int flags;
+ unsigned long frames;
+ unsigned long bytes;
+ unsigned char toc[100];
+ long scale;
} xing;
- enum {
- XING_FRAMES = 0x0001,
- XING_BYTES = 0x0002,
- XING_TOC = 0x0004,
- XING_SCALE = 0x0008
+ enum
+ {
+ XING_FRAMES = 0x0001,
+ XING_BYTES = 0x0002,
+ XING_TOC = 0x0004,
+ XING_SCALE = 0x0008
};
struct mad_stream stream;
@@ -92,4 +83,4 @@ private:
};
-#endif // __decoder_mad_h
+#endif // DECODER_MAD_H