aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp')
-rw-r--r--src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp342
1 files changed, 342 insertions, 0 deletions
diff --git a/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp b/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp
new file mode 100644
index 000000000..095f818e7
--- /dev/null
+++ b/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp
@@ -0,0 +1,342 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include <QObject>
+#include <QFile>
+
+#include "constants.h"
+#include "buffer.h"
+#include "output.h"
+#include "recycler.h"
+
+#include "decoder_ffmpeg.h"
+
+// Decoder class
+
+DecoderFFmpeg::DecoderFFmpeg(QObject *parent, DecoderFactory *d, QIODevice *i, Output *o)
+ : Decoder(parent, d, i, o)
+{
+ inited = FALSE;
+ user_stop = FALSE;
+ stat = 0;
+ output_buf = 0;
+ output_bytes = 0;
+ output_at = 0;
+ bks = 0;
+ done = FALSE;
+ finish = FALSE;
+ freq = 0;
+ bitrate = 0;
+ seekTime = -1.0;
+ totalTime = 0.0;
+ chan = 0;
+ output_size = 0;
+ ic = 0;
+ wma_outbuf = 0;
+}
+
+
+DecoderFFmpeg::~DecoderFFmpeg()
+{
+ deinit();
+ if (wma_outbuf)
+ {
+ delete [] wma_outbuf;
+ wma_outbuf = 0;
+ }
+ if (output_buf)
+ delete [] output_buf;
+ output_buf = 0;
+
+ if (ic)
+ av_close_input_file(ic);
+}
+
+
+void DecoderFFmpeg::stop()
+{
+ user_stop = TRUE;
+}
+
+
+void DecoderFFmpeg::flush(bool final)
+{
+ ulong min = final ? 0 : bks;
+
+ while ((! done && ! finish) && output_bytes > min)
+ {
+ output()->recycler()->mutex()->lock ();
+
+ while ((! done && ! finish) && output()->recycler()->full())
+ {
+ mutex()->unlock();
+
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+
+ mutex()->lock ();
+ done = user_stop;
+ }
+
+ if (user_stop || finish)
+ {
+ inited = FALSE;
+ done = TRUE;
+ }
+ else
+ {
+ output_bytes -= produceSound(output_buf, output_bytes, bitrate, chan);
+ output_size += bks;
+ output_at = output_bytes;
+ }
+
+ if (output()->recycler()->full())
+ {
+ output()->recycler()->cond()->wakeOne();
+ }
+
+ output()->recycler()->mutex()->unlock();
+ }
+}
+
+
+bool DecoderFFmpeg::initialize()
+{
+ bks = blockSize();
+ inited = user_stop = done = finish = FALSE;
+ freq = bitrate = 0;
+ stat = chan = 0;
+ output_size = 0;
+ seekTime = -1.0;
+ totalTime = 0.0;
+
+
+ if (! input())
+ {
+ error("DecoderFFmpeg: cannot initialize. No input.");
+
+ return FALSE;
+ }
+
+ if (! output_buf)
+ output_buf = new char[globalBufferSize];
+ output_at = 0;
+ output_bytes = 0;
+
+ if (! input())
+ {
+ error("DecoderFFmpeg: cannot initialize. No input.");
+
+ return FALSE;
+ }
+
+ if (! output_buf)
+ output_buf = new char[globalBufferSize];
+ output_at = 0;
+ output_bytes = 0;
+
+ QString filename = qobject_cast<QFile*>(input())->fileName ();
+ input()->close();
+ avcodec_init();
+ avcodec_register_all();
+ av_register_all();
+
+ AVCodec *codec;
+ if (av_open_input_file(&ic, filename.toLocal8Bit(), NULL,0, NULL) < 0)
+ {
+ qDebug("DecoderFFmpeg: cannot open input file");
+ return FALSE;
+ }
+ for (wma_idx = 0; wma_idx < ic->nb_streams; wma_idx++)
+ {
+ c = ic->streams[wma_idx]->codec;
+ if (c->codec_type == CODEC_TYPE_AUDIO) break;
+ }
+
+ av_find_stream_info(ic);
+
+ codec = avcodec_find_decoder(c->codec_id);
+
+ if (!codec) return FALSE;
+ if (avcodec_open(c, codec) < 0)
+ return FALSE;
+
+ totalTime = ic->duration/AV_TIME_BASE;
+
+ configure(c->sample_rate, c->channels, 16, c->bit_rate);
+
+ bitrate = c->bit_rate;
+ chan = c->channels;
+ wma_outbuf = new uint8_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*sizeof(int16_t)];
+ inited = TRUE;
+ qDebug("DecoderFFmpeg: initialize succes");
+ return TRUE;
+}
+
+
+double DecoderFFmpeg::lengthInSeconds()
+{
+ if (! inited)
+ return 0;
+
+ return totalTime;
+}
+
+
+void DecoderFFmpeg::seek(double pos)
+{
+ seekTime = pos;
+}
+
+
+void DecoderFFmpeg::deinit()
+{
+ inited = user_stop = done = finish = FALSE;
+ freq = bitrate = 0;
+ stat = chan = 0;
+ output_size = 0;
+}
+
+void DecoderFFmpeg::run()
+{
+// mpc_uint32_t vbrAcc = 0;
+// mpc_uint32_t vbrUpd = 0;
+ uint8_t *inbuf_ptr;
+ int out_size, size;
+ AVPacket pkt;
+
+ mutex()->lock ();
+
+ if (! inited)
+ {
+ mutex()->unlock();
+
+ return;
+ }
+ stat = DecoderState::Decoding;
+ mutex()->unlock();
+ {
+ dispatch(DecoderState ((DecoderState::Type) stat));
+ }
+
+ while (! done && ! finish)
+ {
+ mutex()->lock ();
+ // decode
+
+ if (seekTime >= 0.0)
+ {
+ int64_t timestamp;
+ timestamp = int64_t(seekTime)*AV_TIME_BASE;
+ if (ic->start_time != AV_NOPTS_VALUE)
+ timestamp += ic->start_time;
+ av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
+ avcodec_flush_buffers(c);
+ seekTime = -1.0;
+ }
+
+ int l = 0;
+ if (av_read_frame(ic, &pkt) < 0)
+ {
+ finish = TRUE;
+ goto end;
+ }
+ size = pkt.size;
+ inbuf_ptr = pkt.data;
+
+ out_size = 0;
+
+ while (size > 0)
+ {
+ out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE*sizeof(int16_t);
+ l = avcodec_decode_audio2(c, (int16_t *)(wma_outbuf), &out_size, inbuf_ptr, size);
+
+ if(l < 0)
+ goto end;
+ ffmpeg_out(out_size);
+ size -= l;
+ inbuf_ptr += l;
+ if (pkt.data)
+ av_free_packet(&pkt);
+ }
+ bitrate = c->bit_rate/1024;
+end:
+ if (finish)
+ {
+ flush(TRUE);
+
+ if (output())
+ {
+ output()->recycler()->mutex()->lock ();
+ // end of stream
+ while (! output()->recycler()->empty() && ! user_stop)
+ {
+ output()->recycler()->cond()->wakeOne();
+ mutex()->unlock();
+ output()->recycler()->cond()->wait(output()->recycler()->mutex());
+ mutex()->lock ();
+ }
+ output()->recycler()->mutex()->unlock();
+ }
+
+ done = TRUE;
+ if (! user_stop)
+ {
+ finish = TRUE;
+ }
+ }
+
+ mutex()->unlock();
+
+ }
+
+ mutex()->lock ();
+
+ if (finish)
+ stat = DecoderState::Finished;
+ else if (user_stop)
+ stat = DecoderState::Stopped;
+
+ mutex()->unlock();
+
+ {
+ dispatch(DecoderState ((DecoderState::Type) stat));
+ }
+
+ deinit();
+}
+
+void DecoderFFmpeg::ffmpeg_out(int size)
+{
+ if (size == 0)
+ return;
+ int at = 0;
+ int to_copy = 0;
+ while (size > 0 && !user_stop)
+ {
+ to_copy = qMin(int(globalBufferSize - output_at), int(size) );
+ memmove ( (char *) (output_buf + output_at), wma_outbuf + at, to_copy);
+ at += to_copy;
+ size -= to_copy;
+ output_at += to_copy;
+ output_bytes += to_copy;
+ if (output())
+ flush();
+ }
+}