2
base class for all mpeglib decoders
3
Copyright (C) 2000 Martin Vogt
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU Library General Public License as published by
7
the Free Software Foundation.
9
For more information look at the file COPYRIGHT in this package
13
#include "decoderBaseObject_impl.h"
14
#include "../mpeglib/lib/decoder/decoderPlugin.h"
15
#include "../mpeglib/lib/decoder/splayPlugin.h"
18
// define this to run the playobject without the
19
// arts backend. (usefull to check if a bug is in arts or mpeglib)
24
static int instanceCnt=0;
26
DecoderBaseObject_impl::DecoderBaseObject_impl()
35
outputStream=new ArtsOutputStream(NULL);
36
arts_debug("outputStream created");
41
setStreamState(_THREADSTATE_INIT);
47
DecoderBaseObject_impl::~DecoderBaseObject_impl() {
48
arts_debug("~DecoderBaseObject_impl -s");
51
if (decoderPlugin != NULL) {
52
arts_debug("delete decoderPlugin");
56
if (outputStream != NULL) {
57
arts_debug("delete outputStream");
64
DecoderPlugin* DecoderBaseObject_impl::createPlugin() {
65
arts_fatal("direct virtual call DecoderBaseObject_impl::getPlugin");
70
::InputStream* DecoderBaseObject_impl::createInputStream(const char* url) {
71
::InputStream* back=InputPlugin::createInputStream(url,true);
76
bool DecoderBaseObject_impl::loadMedia(const string &filename) {
80
if ( inputStream != NULL ) {
81
arts_fatal("remove resources first with a call to: halt()");
83
if (decoderPlugin == NULL) {
84
decoderPlugin=createPlugin();
85
if(doFloat()) decoderPlugin->config("dofloat",0,0);
91
lastAudioBufferSize=-1;
93
Note: you can only play one file with a PlayObject !!
94
Then you must destroy it.
95
A StreamEnd call should do the job.
102
inputStream=createInputStream(filename.c_str());
104
// the plugin does not open the stream!
106
back=inputStream->open((char*)filename.c_str());
107
setStreamState(_THREADSTATE_OPENED);
109
// we are still in posIdle here
110
outputStream->audioOpen();
113
decoderPlugin->setOutputPlugin(outputStream);
114
decoderPlugin->setInputPlugin(inputStream);
122
string DecoderBaseObject_impl::description() {
123
arts_debug("description");
128
PluginInfo* pluginInfo=decoderPlugin->getPluginInfo();
134
void DecoderBaseObject_impl::description(const string &) {
135
arts_debug("description");
136
// what should do this?
139
poTime DecoderBaseObject_impl::currentTime() {
144
AudioTime* audioTime=outputStream->getAudioTime();
145
float currentTime=audioTime->getTime()+(float)startTime;
146
time.seconds=(long)(currentTime);
147
time.ms=(long) (1000.0*(currentTime-(float)time.seconds));
153
poTime DecoderBaseObject_impl::overallTime() {
159
PluginInfo* pluginInfo=decoderPlugin->getPluginInfo();
160
time.seconds=pluginInfo->getLength();
165
poCapabilities DecoderBaseObject_impl::capabilities() {
166
arts_debug("capabilities");
170
PluginInfo* pluginInfo=decoderPlugin->getPluginInfo();
171
long len=pluginInfo->getLength();
173
return capPause; /* no seek supported */
175
// seek and pause supported
176
return (poCapabilities)(capSeek | capPause);
179
string DecoderBaseObject_impl::mediaName() {
180
arts_debug("mediaName");
182
// whats a mediaName?
186
poState DecoderBaseObject_impl::state() {
190
void DecoderBaseObject_impl::play() {
191
arts_debug("play: %d", (int)streamState);
192
if (streamState == _THREADSTATE_OPENED) {
193
decoderPlugin->play();
195
Command cmd(_COMMAND_PLAY);
196
decoderPlugin->insertAsyncCommand(&cmd);
198
setStreamState(_THREADSTATE_PLAYING);
202
void DecoderBaseObject_impl::seek(const class poTime& seekTime) {
207
long sec=seekTime.seconds;
209
arts_debug("sec in plugin is %d:", sec);
211
// we send an async command
212
Command cmd(_COMMAND_SEEK,sec);
213
decoderPlugin->insertAsyncCommand(&cmd);
215
// if the thread blocks on the artsOutputstream: kick him out
216
// the next command will the the seek command
217
outputStream->audioClose();
220
// thread blocking allowed
221
outputStream->audioOpen();
222
arts_debug("************ reopen");
223
// now set a new startTime
227
void DecoderBaseObject_impl::pause() {
230
Command cmd(_COMMAND_PAUSE);
231
decoderPlugin->insertAsyncCommand(&cmd);
234
void DecoderBaseObject_impl::halt() {
237
* halt() (which the normal programmer would probably refer to as stop())
238
* should seek to the beginning and go into the posIdle state, like a just
249
void DecoderBaseObject_impl::streamInit() {
257
void DecoderBaseObject_impl::streamStart() {
260
int DecoderBaseObject_impl::fillArts(unsigned long samples,
261
float* left , float* right) {
262
unsigned long haveSamples = 0;
264
AudioTime* audioTime=outputStream->getAudioTime();
265
int wav_samplingRate=audioTime->getSpeed();
266
int wav_sampleWidth=audioTime->getSampleSize();
267
int wav_channelCount=audioTime->getStereo()+1;
269
if(doFloat()) wav_sampleWidth = sizeof(float)*8;
271
// here seems to be an error, I have clicks sometimes in the stream
272
int byteMultiplikator=(wav_sampleWidth/8)*wav_channelCount;
277
int bufferSize=getBufferSize();
278
if (bufferSize != lastAudioBufferSize) {
279
lastAudioBufferSize=bufferSize;
280
outputStream->setAudioBufferSize(bufferSize);
283
/* difference between the sampling rates in percent */
284
float diff = fabs((double)wav_samplingRate - (double)(samplingRateFloat/_speed))
285
/ (double)samplingRateFloat;
288
* efficient optimized case:
289
* 1. decoder -> float rendering
290
* 2. no resampling (i.e. artsd running @ 44100 Hz, playing an 44100 Hz mp3)
292
if(_state == posPlaying && doFloat() && diff < 0.0005) {
293
wantBytes = sizeof(float) * wav_channelCount * samples;
294
hasBytes = outputStream->read(&buffer,wantBytes);
295
float *flptr = (float *)buffer;
297
if(wav_channelCount == 1)
299
while((int)(haveSamples * sizeof(float)) < hasBytes)
301
left[haveSamples] = right[haveSamples] = flptr[haveSamples];
305
else if(wav_channelCount == 2)
307
while((int)(haveSamples * 2 * sizeof(float)) < hasBytes)
309
left[haveSamples] = flptr[haveSamples*2];
310
right[haveSamples] = flptr[haveSamples*2+1];
314
outputStream->forwardReadPtr(haveSamples*sizeof(float)*wav_channelCount);
316
else if(_state == posPlaying) {
318
// since the samplingrate of the MP3 and the samplingrate of the output
319
// device (soundcard) are not necessarily the same, it's a bit tricky
322
// calculate "how fast" we consume input samples (2.0 means, we need 2
323
// input samples to generate one output sample)
324
double speed = (double)wav_samplingRate / (double)(samplingRateFloat/_speed);
326
// calculate how many input samples we need, then to satisfy the request
327
// use a larger amount than "really" required, to ensure that samples are
328
// available for rounding errors and interpolation
329
double wantWavSamples = (double)samples*speed+8.0;
331
// convert that into bytes and try to read that many bytes
332
wantBytes=(int) (wantWavSamples*byteMultiplikator);
333
hasBytes=outputStream->read(&buffer,wantBytes);
335
int format = doFloat()?uni_convert_float_ne:wav_sampleWidth;
337
// convert those bytes into the suitable output form
338
haveSamples = uni_convert_stereo_2float(samples, (unsigned char *)buffer,
339
hasBytes, wav_channelCount,
341
left,right,speed,flpos);
343
// calculate where we are now (as floating point position) in our
344
// inputsample buffer
345
flpos += (double)haveSamples * speed;
347
// Good - so how many input samples we won't need anymore (for the
348
// next request)? Skip them.
349
int skip = (int)floor(flpos);
350
// we need to call this even on skip == 0
351
// because we must unlock the remoteBuffer
352
int forward=skip*byteMultiplikator;
355
flpos = flpos - floor(flpos);
357
outputStream->forwardReadPtr(forward);
360
if(haveSamples != samples) {
364
for(i=haveSamples;i<samples;i++)
365
left[i] = right[i] = 0.0;
371
void DecoderBaseObject_impl::calculateBlock(unsigned long samples,
372
float* left , float* right) {
377
int audioState=outputStream->waitStreamState(_OUTPUT_WAIT_METHOD_POLL,
380
if (audioState & _STREAM_MASK_IS_INIT) {
381
// now check if we already have enough data
383
if (audioState & _STREAM_MASK_IS_EOF) {
384
if(_state == posPlaying) {
385
arts_debug("eof got in arts********** END");
391
if (outputStream->getBufferFillgrade() >= 0) {
394
if ( ((lenough) || _blocking) && (_state == posPlaying) ) {
395
fillArts(samples,left,right);
401
// filling with zero , stream not ready(yet)
404
for(i=0;i<samples;i++)
405
left[i] = right[i] = 0.0;
408
void DecoderBaseObject_impl::streamEnd() {
416
int DecoderBaseObject_impl::getBufferSize() {
417
float hardwareBuffer;
422
fragmentSize=AudioSubSystem::the()->fragmentSize();
423
fragmentCount=AudioSubSystem::the()->fragmentCount();
424
channels=AudioSubSystem::the()->channels();
427
hardwareBuffer=fragmentSize*fragmentCount;
430
return (int)hardwareBuffer;
434
void DecoderBaseObject_impl::shudownPlugins() {
436
The order here is important.
437
First we close the audio so that the thread never blocks
439
Then we are sure thst we can safley call plugin->close,
440
because the thread does not block.
441
We then have the thread back in the decoder_loop of
445
// this should theoretically be faster
446
Command cmd(_COMMAND_CLOSE);
447
decoderPlugin->insertAsyncCommand(&cmd);
449
if (outputStream != NULL) {
450
outputStream->audioClose();
453
// very likely the thread already is closed
454
// because of the asyncCommand above.
455
if (decoderPlugin != NULL) {
456
decoderPlugin->close();
460
if (inputStream != NULL) {
464
setStreamState(_THREADSTATE_CLOSED);
469
void DecoderBaseObject_impl::setStreamState(int state) {
472
case _THREADSTATE_INIT: {
473
streamState=_THREADSTATE_INIT;
476
case _THREADSTATE_OPENED: {
477
streamState=_THREADSTATE_OPENED;
480
case _THREADSTATE_PLAYING: {
481
streamState=_THREADSTATE_PLAYING;
484
case _THREADSTATE_CLOSED: {
485
streamState=_THREADSTATE_INIT;
489
cout << "unknown streamState:DecoderBaseObject_impl:"<<state<<endl;
494
/** internal stuff for testing **/
496
void DecoderBaseObject_impl::blocking(bool newvalue)
498
_blocking = newvalue;
501
bool DecoderBaseObject_impl::blocking()
506
void DecoderBaseObject_impl::speed(float newValue)
511
float DecoderBaseObject_impl::speed()