summaryrefslogtreecommitdiff
path: root/muggle-plugin/vdr_decoder_mp3.c
diff options
context:
space:
mode:
Diffstat (limited to 'muggle-plugin/vdr_decoder_mp3.c')
-rw-r--r--muggle-plugin/vdr_decoder_mp3.c464
1 files changed, 464 insertions, 0 deletions
diff --git a/muggle-plugin/vdr_decoder_mp3.c b/muggle-plugin/vdr_decoder_mp3.c
new file mode 100644
index 0000000..6569760
--- /dev/null
+++ b/muggle-plugin/vdr_decoder_mp3.c
@@ -0,0 +1,464 @@
+/*!
+ * \file vdr_decoder_mp3.h
+ * \brief An mp3 decoder for a VDR media plugin (muggle)
+ *
+ * \version $Revision: 1.2 $
+ * \date $Date$
+ * \author Ralf Klueber, Lars von Wedel, Andreas Kellner
+ * \author Responsible author: $Author$
+ *
+ * $Id$
+ *
+ * Adapted from
+ * MP3/MPlayer plugin to VDR (C++)
+ * (C) 2001,2002 Stefan Huelswitt <huels@iname.com>
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <cmath>
+#include <iostream>
+
+#include "vdr_config.h"
+#include "vdr_decoder_mp3.h"
+#include "vdr_stream.h"
+#include "vdr_setup.h"
+
+#include "mg_tools.h"
+#include "mg_content.h"
+
+#define d(x) x
+
+// ----------------------------------------------------------------
+
+int
+mgMadStream (struct mad_stream *stream, mgStream * str)
+{
+ unsigned char *data;
+ unsigned long len;
+ if (str->stream (data, len, stream->next_frame))
+ {
+ if (len > 0)
+ {
+ mad_stream_buffer (stream, data, len);
+ }
+ return len;
+ }
+ return -1;
+}
+
+
+// --- mgMP3Decoder -------------------------------------------------------------
+
+mgMP3Decoder::mgMP3Decoder (mgContentItem * item, bool preinit):mgDecoder
+(item)
+{
+ m_stream = 0;
+ m_isStream = false;
+
+ m_filename = item->getSourceFile ();
+
+ if (preinit)
+ {
+ m_stream = new mgStream (m_filename);
+ printf ("m_stream for %s\n", m_filename.c_str ());
+
+ }
+ m_madframe = 0;
+ m_madsynth = 0;
+
+ memset (&m_madstream, 0, sizeof (m_madstream));
+
+ init ();
+}
+
+
+mgMP3Decoder::~mgMP3Decoder ()
+{
+ clean ();
+ delete m_stream;
+}
+
+
+void
+mgMP3Decoder::init ()
+{
+ clean ();
+ mad_stream_init (&m_madstream);
+
+ m_madframe = new mad_frame;
+ mad_frame_init (m_madframe);
+
+ m_madsynth = new mad_synth;
+ mad_synth_init (m_madsynth);
+
+ mad_stream_options (&m_madstream, MAD_OPTION_IGNORECRC);
+
+ m_playtime = mad_timer_zero;
+ m_skiptime = mad_timer_zero;
+ m_framenum = m_framemax = 0;
+ m_frameinfo = 0;
+ m_mute = m_errcount = 0;
+}
+
+
+void
+mgMP3Decoder::clean ()
+{
+ m_playing = false;
+ if (m_madsynth)
+ {
+ mad_synth_finish (m_madsynth);
+ delete m_madsynth;
+ m_madsynth = 0;
+ }
+
+ if (m_madframe)
+ {
+ mad_frame_finish (m_madframe);
+ delete m_madframe;
+ m_madframe = 0;
+ }
+ mad_stream_finish (&m_madstream);
+}
+
+
+bool mgMP3Decoder::valid (void)
+{
+ bool
+ res = false;
+ if (tryLock ())
+ {
+ if (start ())
+ {
+ struct mgDecode *
+ dd;
+ int
+ count = 10;
+ do
+ {
+ dd = decode ();
+ if (dd->status == dsEof)
+ {
+ count = 0;
+ }
+ if (dd->status != dsPlay)
+ {
+ break;
+ }
+ }
+ while (--count);
+ if (!count)
+ {
+ res = true;
+ }
+ stop ();
+ }
+ unlock ();
+ }
+ return res;
+}
+
+
+mgPlayInfo *
+mgMP3Decoder::playInfo ()
+{
+ if (m_playing)
+ {
+ m_playinfo.m_index = mad_timer_count (m_playtime, MAD_UNITS_SECONDS);
+
+ return &m_playinfo;
+ }
+ return 0;
+}
+
+
+bool mgMP3Decoder::start ()
+{
+ lock (true);
+ init ();
+ m_playing = true;
+
+ if (m_stream->open (true))
+ {
+ if (!m_isStream)
+ {
+ m_stream->seek ();
+
+ printf
+ ("mgMP3Decoder::start: m_framemax not determined, rewinding disabled!!!\n");
+
+/* m_framemax = scan->Frames+20; // TODO
+
+ m_frameinfo = new struct FrameInfo[m_framemax];
+ if(!m_frameinfo)
+ {
+ printf( "mgMP3Decoder::start: no memory for frame index, rewinding disabled" );
+ }
+ */
+ }
+ unlock ();
+
+ printf ("mgMP3Decoder::start: true\n");
+ return true;
+ }
+ m_stream->close ();
+ clean ();
+ unlock ();
+ printf ("mgMP3Decoder::start: false");
+ return false;
+}
+
+
+bool mgMP3Decoder::stop (void)
+{
+ lock ();
+
+ if (m_playing)
+ {
+ m_stream->close ();
+ clean ();
+ }
+ unlock ();
+ return true;
+}
+
+
+struct mgDecode *
+mgMP3Decoder::done (eDecodeStatus status)
+{
+ m_ds.status = status;
+ m_ds.index = mad_timer_count (m_playtime, MAD_UNITS_MILLISECONDS);
+ m_ds.pcm = &m_madsynth->pcm;
+ unlock (); // release the lock from Decode()
+
+ return &m_ds;
+}
+
+
+eDecodeStatus mgMP3Decoder::decodeError (bool hdr)
+{
+ if (m_madstream.error == MAD_ERROR_BUFLEN
+ || m_madstream.error == MAD_ERROR_BUFPTR)
+ {
+ int
+ s = mgMadStream (&m_madstream, m_stream);
+ if (s < 0)
+ {
+ printf ("mgMP3Decoder::decodeError: dsError returned\n");
+ return dsError;
+ }
+ if (s == 0)
+ {
+ printf ("mgMP3Decoder::decodeError: dsEof returned\n");
+ return dsEof;
+ }
+ }
+ else if (!MAD_RECOVERABLE (m_madstream.error))
+ {
+ printf
+ ("mgMP3Decoder::decodeError: mad decode %sfailed, frame=%d: %s. Returning dsError\n",
+ hdr ? "hdr " : "", m_framenum, mad_stream_errorstr (&m_madstream));
+ return dsError;
+ }
+ else
+ {
+ m_errcount += hdr ? 1 : 100;
+ printf
+ ("mgMP3Decoder::decodeError: mad decode %s error, frame=%d count=%d: %s. Returning dsOK\n",
+ hdr ? "hdr " : "", m_framenum, m_errcount,
+ mad_stream_errorstr (&m_madstream));
+ }
+ return dsOK;
+}
+
+
+struct mgDecode *
+mgMP3Decoder::decode ()
+{
+ lock (); // this is released in Done()
+ eDecodeStatus r;
+
+ while (m_playing)
+ {
+ if (m_errcount >= MAX_FRAME_ERR * 100)
+ {
+ printf ("mgMP3Decoder::decode: excessive decoding errors,"
+ " aborting file %s\n", m_filename.c_str ());
+ return done (dsError);
+ }
+
+ if (mad_header_decode (&m_madframe->header, &m_madstream) == -1)
+ {
+ if ((r = decodeError (true)))
+ {
+ return done (r);
+ }
+ }
+ else
+ {
+ if (!m_isStream)
+ {
+#ifdef DEBUG2
+ if (m_framenum >= m_framemax)
+ {
+ printf ("mgMP3Decoder::start: framenum >= framemax!!!!\n");
+ }
+#endif
+ if (m_frameinfo && m_framenum < m_framemax)
+ {
+ m_frameinfo[m_framenum].Pos =
+ m_stream->bufferPos () +
+ (m_madstream.this_frame - m_madstream.buffer);
+ m_frameinfo[m_framenum].Time = m_playtime;
+ }
+ }
+
+ mad_timer_add (&m_playtime, m_madframe->header.duration);
+ m_framenum++;
+
+ if (mad_timer_compare (m_playtime, m_skiptime) >= 0)
+ {
+ m_skiptime = mad_timer_zero;
+ }
+ else
+ {
+ return done (dsSkip); // skipping, decode next header
+ }
+
+ if (mad_frame_decode (m_madframe, &m_madstream) == -1)
+ {
+ if ((r = decodeError (false)))
+ {
+ return done (r);
+ }
+ }
+ else
+ {
+ m_errcount = 0;
+
+// TODO: // m_scan->InfoHook( &frame->header );
+
+ mad_synth_frame (m_madsynth, m_madframe);
+
+ if (m_mute)
+ {
+ m_mute--;
+ return done (dsSkip);
+ }
+ return done (dsPlay);
+ }
+ }
+ }
+ return done (dsError);
+}
+
+
+void
+mgMP3Decoder::makeSkipTime (mad_timer_t * skiptime,
+mad_timer_t playtime,
+int secs, int avail, int dvbrate)
+{
+ mad_timer_t time;
+
+ *skiptime = playtime;
+
+ mad_timer_set (&time, abs (secs), 0, 0);
+
+ if (secs < 0)
+ {
+ mad_timer_negate (&time);
+ }
+
+ mad_timer_add (skiptime, time);
+
+ // Byte/s = samplerate * 16 bit * 2 chan
+ float bufsecs = (float) avail / (float) (dvbrate * (16 / 8 * 2));
+
+ printf ("mgMP3Decoder::makeSkipTime: skip: avail=%d bufsecs=%f\n", avail,
+ bufsecs);
+
+ int full = (int) bufsecs;
+ bufsecs -= (float) full;
+
+ mad_timer_set (&time, full, (int) (bufsecs * 1000.0), 1000);
+
+ mad_timer_negate (&time);
+
+ mad_timer_add (skiptime, time);
+
+ printf
+ ("mgMP3Decoder::makeSkipTime: skip: playtime=%ld secs=%d full=%d bufsecs=%f skiptime=%ld\n",
+ mad_timer_count (playtime, MAD_UNITS_MILLISECONDS), secs, full, bufsecs,
+ mad_timer_count (*skiptime, MAD_UNITS_MILLISECONDS));
+}
+
+
+bool mgMP3Decoder::skip (int seconds, int avail, int rate)
+{
+ lock ();
+
+ bool
+ res = false;
+ if (m_playing && !m_isStream)
+ {
+ if (!mad_timer_compare (m_skiptime, mad_timer_zero))
+ { // allow only one skip at any time
+ mad_timer_t
+ time;
+ makeSkipTime (&time, m_playtime, seconds, avail, rate);
+
+ if (mad_timer_compare (m_playtime, time) <= 0)
+ { // forward skip
+#ifdef DEBUG
+ int
+ i = mad_timer_count (time, MAD_UNITS_SECONDS);
+ printf ("mgMP3Decoder::skip: forward skipping to %02d:%02d\n",
+ i / 60, i % 60);
+#endif
+ m_skiptime = time;
+ m_mute = 1;
+ res = true;
+ }
+ else
+ { // backward skip
+ if (m_frameinfo)
+ {
+#ifdef DEBUG
+ int
+ i = mad_timer_count (time, MAD_UNITS_SECONDS);
+ printf ("mgMP3Decoder::skip: rewinding to %02d:%02d\n",
+ i / 60, i % 60);
+#endif
+ while (m_framenum
+ && mad_timer_compare (time,
+ m_frameinfo[--m_framenum].
+ Time) < 0);
+ m_mute = 2;
+ if (m_framenum >= 2)
+ {
+ m_framenum -= 2;
+ }
+ m_playtime = m_frameinfo[m_framenum].Time;
+ m_stream->seek (m_frameinfo[m_framenum].Pos);
+ // reset stream buffer
+ mad_stream_finish (&m_madstream);
+ mad_stream_init (&m_madstream);
+#ifdef DEBUG
+ i = mad_timer_count (m_playtime, MAD_UNITS_MILLISECONDS);
+ printf
+ ("mgMP3Decoder::skip: new playtime=%d framenum=%d filepos=%lld\n",
+ i, m_framenum, m_frameinfo[m_framenum].Pos);
+#endif
+ res = true;
+ }
+ }
+ }
+ }
+ unlock ();
+ return res;
+}