~ubuntu-branches/ubuntu/hoary/kdemultimedia/hoary

« back to all changes in this revision

Viewing changes to mpeglib_artsplug/decoderBaseObject_impl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Martin Schulze
  • Date: 2003-01-22 15:00:51 UTC
  • Revision ID: james.westby@ubuntu.com-20030122150051-uihwkdoxf15mi1tn
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  base class for all mpeglib decoders
 
3
  Copyright (C) 2000  Martin Vogt
 
4
 
 
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.
 
8
 
 
9
  For more information look at the file COPYRIGHT in this package
 
10
 
 
11
 */
 
12
 
 
13
#include "decoderBaseObject_impl.h"
 
14
#include "../mpeglib/lib/decoder/decoderPlugin.h"
 
15
#include "../mpeglib/lib/decoder/splayPlugin.h"
 
16
#include "debug.h"
 
17
 
 
18
// define this to run the playobject without the
 
19
// arts backend. (usefull to check if a bug is in arts or mpeglib)
 
20
//#define _STRIP_ZERO
 
21
 
 
22
using namespace Arts;
 
23
 
 
24
static int instanceCnt=0;
 
25
 
 
26
DecoderBaseObject_impl::DecoderBaseObject_impl()
 
27
    : _speed(1.0f)
 
28
{
 
29
 
 
30
  flpos=0.0;
 
31
  _blocking = false;
 
32
#ifdef _STRIP_ZERO
 
33
  outputStream=NULL;
 
34
#else
 
35
  outputStream=new ArtsOutputStream(NULL);
 
36
  arts_debug("outputStream created");
 
37
  decoderPlugin=NULL;
 
38
#endif
 
39
  startTime=0.0;
 
40
  inputStream=NULL;
 
41
  setStreamState(_THREADSTATE_INIT);
 
42
  _state=posIdle;
 
43
  instance=instanceCnt;
 
44
  instanceCnt++;
 
45
}
 
46
 
 
47
DecoderBaseObject_impl::~DecoderBaseObject_impl() {
 
48
  arts_debug("~DecoderBaseObject_impl -s");
 
49
  shudownPlugins();
 
50
 
 
51
  if (decoderPlugin != NULL) {
 
52
    arts_debug("delete decoderPlugin");
 
53
    delete decoderPlugin;
 
54
    decoderPlugin=NULL;
 
55
  }
 
56
  if (outputStream != NULL) {
 
57
    arts_debug("delete outputStream");
 
58
    delete outputStream;
 
59
    outputStream=NULL;
 
60
  }
 
61
}
 
62
 
 
63
 
 
64
DecoderPlugin* DecoderBaseObject_impl::createPlugin() {
 
65
  arts_fatal("direct virtual call DecoderBaseObject_impl::getPlugin");
 
66
  return NULL;
 
67
}
 
68
 
 
69
 
 
70
::InputStream* DecoderBaseObject_impl::createInputStream(const char* url) {
 
71
  ::InputStream* back=InputPlugin::createInputStream(url,true);
 
72
  return back;
 
73
}
 
74
 
 
75
 
 
76
bool DecoderBaseObject_impl::loadMedia(const string &filename) {
 
77
  int back=true;
 
78
 
 
79
 
 
80
  if ( inputStream != NULL ) {
 
81
    arts_fatal("remove resources first with a call to: halt()");
 
82
  }
 
83
  if (decoderPlugin == NULL) {
 
84
    decoderPlugin=createPlugin();
 
85
    if(doFloat()) decoderPlugin->config("dofloat",0,0);
 
86
  }
 
87
 
 
88
  flpos=0.0;
 
89
  startTime=0.0;
 
90
 
 
91
  lastAudioBufferSize=-1;
 
92
  /**
 
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.
 
96
  */
 
97
 
 
98
#ifdef _STRIP_ZERO
 
99
  return true;
 
100
#endif
 
101
 
 
102
  inputStream=createInputStream(filename.c_str());
 
103
 
 
104
  // the plugin does not open the stream!
 
105
  // we do it.
 
106
  back=inputStream->open((char*)filename.c_str());
 
107
  setStreamState(_THREADSTATE_OPENED);
 
108
 
 
109
  // we are still in posIdle here
 
110
  outputStream->audioOpen();
 
111
 
 
112
  // watch the order!
 
113
  decoderPlugin->setOutputPlugin(outputStream);
 
114
  decoderPlugin->setInputPlugin(inputStream);
 
115
 
 
116
 
 
117
  return back;
 
118
}
 
119
 
 
120
 
 
121
 
 
122
string DecoderBaseObject_impl::description() {
 
123
  arts_debug("description");
 
124
  string back;
 
125
#ifdef _STRIP_ZERO
 
126
  return back;
 
127
#endif
 
128
  PluginInfo* pluginInfo=decoderPlugin->getPluginInfo();
 
129
  pluginInfo->print();
 
130
  return back;
 
131
 
 
132
}
 
133
 
 
134
void DecoderBaseObject_impl::description(const string &) {
 
135
  arts_debug("description");
 
136
    // what should do this?
 
137
}
 
138
 
 
139
poTime DecoderBaseObject_impl::currentTime() {
 
140
  poTime time;
 
141
#ifdef _STRIP_ZERO
 
142
  return time;
 
143
#endif
 
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));
 
148
  return time;
 
149
}
 
150
 
 
151
 
 
152
 
 
153
poTime DecoderBaseObject_impl::overallTime() {
 
154
  poTime time;
 
155
#ifdef _STRIP_ZERO
 
156
  return time;
 
157
#endif
 
158
 
 
159
  PluginInfo* pluginInfo=decoderPlugin->getPluginInfo();
 
160
  time.seconds=pluginInfo->getLength();
 
161
  time.ms=0;    
 
162
  return time;
 
163
}
 
164
 
 
165
poCapabilities DecoderBaseObject_impl::capabilities() {
 
166
  arts_debug("capabilities");
 
167
#ifdef _STRIP_ZERO
 
168
  return capSeek;
 
169
#endif
 
170
  PluginInfo* pluginInfo=decoderPlugin->getPluginInfo();
 
171
  long len=pluginInfo->getLength();
 
172
  if (len == 0) {
 
173
    return capPause;  /* no seek supported */
 
174
  }
 
175
  // seek and pause supported
 
176
  return (poCapabilities)(capSeek | capPause);
 
177
}
 
178
 
 
179
string DecoderBaseObject_impl::mediaName() {
 
180
  arts_debug("mediaName");
 
181
  string back;
 
182
  // whats a mediaName?
 
183
  return back;
 
184
}
 
185
 
 
186
poState DecoderBaseObject_impl::state() {
 
187
  return _state;
 
188
}
 
189
 
 
190
void DecoderBaseObject_impl::play() {
 
191
  arts_debug("play: %d", (int)streamState);
 
192
  if (streamState == _THREADSTATE_OPENED) {
 
193
    decoderPlugin->play();
 
194
  } else {
 
195
    Command cmd(_COMMAND_PLAY);
 
196
    decoderPlugin->insertAsyncCommand(&cmd);
 
197
  }
 
198
  setStreamState(_THREADSTATE_PLAYING);
 
199
  _state = posPlaying;
 
200
}
 
201
 
 
202
void DecoderBaseObject_impl::seek(const class poTime& seekTime) {
 
203
#ifdef _STRIP_ZERO
 
204
  return;
 
205
#endif
 
206
 
 
207
  long sec=seekTime.seconds;
 
208
 
 
209
  arts_debug("sec in plugin is %d:", sec);
 
210
 
 
211
  // we send an async command
 
212
  Command cmd(_COMMAND_SEEK,sec);
 
213
  decoderPlugin->insertAsyncCommand(&cmd);
 
214
 
 
215
  // if the thread blocks on the artsOutputstream: kick him out
 
216
  // the next command will the the seek command
 
217
  outputStream->audioClose();
 
218
 
 
219
 
 
220
  // thread blocking allowed
 
221
  outputStream->audioOpen();
 
222
  arts_debug("************ reopen");
 
223
  // now set a new startTime
 
224
  startTime=sec;
 
225
}
 
226
 
 
227
void DecoderBaseObject_impl::pause() {
 
228
  arts_debug("pause");
 
229
  _state = posPaused;
 
230
  Command cmd(_COMMAND_PAUSE);
 
231
  decoderPlugin->insertAsyncCommand(&cmd);
 
232
}
 
233
 
 
234
void DecoderBaseObject_impl::halt() {
 
235
  /*
 
236
   *
 
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
 
239
   * opened PlayObject
 
240
   *
 
241
   */
 
242
 
 
243
  arts_debug("halt");
 
244
  _state=posIdle;
 
245
  shudownPlugins();
 
246
}
 
247
 
 
248
 
 
249
void DecoderBaseObject_impl::streamInit() {
 
250
#ifdef _STRIP_ZERO
 
251
  return;
 
252
#endif
 
253
 
 
254
}
 
255
 
 
256
 
 
257
void DecoderBaseObject_impl::streamStart() {
 
258
}
 
259
 
 
260
int DecoderBaseObject_impl::fillArts(unsigned long samples,
 
261
                                     float* left , float* right) {
 
262
  unsigned long haveSamples = 0;
 
263
 
 
264
  AudioTime* audioTime=outputStream->getAudioTime();
 
265
  int wav_samplingRate=audioTime->getSpeed();
 
266
  int wav_sampleWidth=audioTime->getSampleSize();
 
267
  int wav_channelCount=audioTime->getStereo()+1;
 
268
 
 
269
  if(doFloat()) wav_sampleWidth = sizeof(float)*8;
 
270
 
 
271
  // here seems to be an error, I have clicks sometimes in the stream
 
272
  int byteMultiplikator=(wav_sampleWidth/8)*wav_channelCount;
 
273
 
 
274
  char* buffer;
 
275
  int hasBytes = 0;
 
276
  int wantBytes = 0;
 
277
  int bufferSize=getBufferSize();
 
278
  if (bufferSize != lastAudioBufferSize) {
 
279
    lastAudioBufferSize=bufferSize;
 
280
    outputStream->setAudioBufferSize(bufferSize);
 
281
  }
 
282
 
 
283
  /* difference between the sampling rates in percent */
 
284
  float diff = fabs((double)wav_samplingRate - (double)(samplingRateFloat/_speed))
 
285
             / (double)samplingRateFloat;
 
286
 
 
287
  /*
 
288
   * efficient optimized case:
 
289
   * 1. decoder -> float rendering
 
290
   * 2. no resampling (i.e. artsd running @ 44100 Hz, playing an 44100 Hz mp3)
 
291
   */
 
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;
 
296
 
 
297
    if(wav_channelCount == 1)
 
298
    {
 
299
      while((int)(haveSamples * sizeof(float)) < hasBytes)
 
300
      {
 
301
        left[haveSamples] = right[haveSamples] = flptr[haveSamples];
 
302
        haveSamples++;
 
303
      }
 
304
    }
 
305
    else if(wav_channelCount == 2)
 
306
    {
 
307
      while((int)(haveSamples * 2 * sizeof(float)) < hasBytes)
 
308
      {
 
309
        left[haveSamples] = flptr[haveSamples*2];
 
310
        right[haveSamples] = flptr[haveSamples*2+1];
 
311
        haveSamples++;
 
312
      }
 
313
    }
 
314
    outputStream->forwardReadPtr(haveSamples*sizeof(float)*wav_channelCount);
 
315
  }
 
316
  else if(_state == posPlaying) {
 
317
    //
 
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
 
320
    //
 
321
 
 
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);
 
325
 
 
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;
 
330
 
 
331
    // convert that into bytes and try to read that many bytes
 
332
    wantBytes=(int) (wantWavSamples*byteMultiplikator);
 
333
    hasBytes=outputStream->read(&buffer,wantBytes);
 
334
 
 
335
    int format = doFloat()?uni_convert_float_ne:wav_sampleWidth;
 
336
 
 
337
    // convert those bytes into the suitable output form
 
338
    haveSamples = uni_convert_stereo_2float(samples, (unsigned char *)buffer,
 
339
                                            hasBytes, wav_channelCount,
 
340
                                            format,
 
341
                                            left,right,speed,flpos);
 
342
 
 
343
    // calculate where we are now (as floating point position) in our
 
344
    // inputsample buffer
 
345
    flpos += (double)haveSamples * speed;
 
346
 
 
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;
 
353
 
 
354
 
 
355
    flpos = flpos - floor(flpos);
 
356
 
 
357
    outputStream->forwardReadPtr(forward);
 
358
  }
 
359
 
 
360
  if(haveSamples != samples) {
 
361
 
 
362
    unsigned long i;
 
363
 
 
364
    for(i=haveSamples;i<samples;i++)
 
365
      left[i] = right[i] = 0.0;
 
366
 
 
367
  }
 
368
  return samples;
 
369
}
 
370
 
 
371
void DecoderBaseObject_impl::calculateBlock(unsigned long samples,
 
372
                                            float* left , float* right) {
 
373
 
 
374
 
 
375
#ifndef _STRIP_ZERO
 
376
 
 
377
  int audioState=outputStream->waitStreamState(_OUTPUT_WAIT_METHOD_POLL,
 
378
                                               _STREAM_MASK_ALL,
 
379
                                               _STREAMTYPE_AUDIO);
 
380
  if (audioState & _STREAM_MASK_IS_INIT) {
 
381
    // now check if we already have enough data
 
382
    int lenough=false;
 
383
    if (audioState & _STREAM_MASK_IS_EOF) {
 
384
      if(_state == posPlaying) {
 
385
        arts_debug("eof got in arts********** END");
 
386
        _state = posIdle;
 
387
      }
 
388
 
 
389
      lenough=true;
 
390
    }
 
391
    if (outputStream->getBufferFillgrade() >= 0) {
 
392
      lenough=true;
 
393
    }
 
394
    if ( ((lenough) || _blocking) && (_state == posPlaying) ) {
 
395
      fillArts(samples,left,right);
 
396
      return;
 
397
    }
 
398
  }
 
399
#endif
 
400
 
 
401
  // filling with zero , stream not ready(yet)
 
402
 
 
403
  unsigned int i;
 
404
  for(i=0;i<samples;i++)
 
405
    left[i] = right[i] = 0.0;
 
406
}
 
407
 
 
408
void DecoderBaseObject_impl::streamEnd() {
 
409
#ifdef _STRIP_ZERO
 
410
  return;
 
411
#endif
 
412
  halt();
 
413
}
 
414
 
 
415
 
 
416
int DecoderBaseObject_impl::getBufferSize() {
 
417
  float hardwareBuffer;
 
418
  float fragmentSize;
 
419
  float fragmentCount;
 
420
  float channels;
 
421
  float sampleSize;
 
422
  fragmentSize=AudioSubSystem::the()->fragmentSize();
 
423
  fragmentCount=AudioSubSystem::the()->fragmentCount();
 
424
  channels=AudioSubSystem::the()->channels();
 
425
  sampleSize=16.0/8.0;
 
426
 
 
427
  hardwareBuffer=fragmentSize*fragmentCount;
 
428
 
 
429
 
 
430
  return (int)hardwareBuffer;
 
431
}
 
432
 
 
433
 
 
434
void DecoderBaseObject_impl::shudownPlugins() {
 
435
  /**
 
436
     The order here is important.
 
437
     First we close the audio so that the thread never blocks
 
438
     on the ringbuffer.
 
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
 
442
     the plugin.
 
443
  */
 
444
 
 
445
  // this should theoretically be faster
 
446
  Command cmd(_COMMAND_CLOSE);
 
447
  decoderPlugin->insertAsyncCommand(&cmd);
 
448
 
 
449
  if (outputStream != NULL) {
 
450
    outputStream->audioClose();
 
451
  }
 
452
 
 
453
  // very likely the thread already is closed
 
454
  // because of the asyncCommand above.
 
455
  if (decoderPlugin != NULL) {
 
456
    decoderPlugin->close();
 
457
  }
 
458
 
 
459
 
 
460
  if (inputStream != NULL) {
 
461
    delete inputStream;
 
462
    inputStream=NULL;
 
463
  }
 
464
  setStreamState(_THREADSTATE_CLOSED);
 
465
}
 
466
 
 
467
 
 
468
 
 
469
void DecoderBaseObject_impl::setStreamState(int state) {
 
470
 
 
471
  switch (state) {
 
472
  case _THREADSTATE_INIT: {
 
473
    streamState=_THREADSTATE_INIT;
 
474
    break;
 
475
  }
 
476
  case _THREADSTATE_OPENED: {
 
477
    streamState=_THREADSTATE_OPENED;
 
478
    break;
 
479
  }
 
480
  case _THREADSTATE_PLAYING: {
 
481
    streamState=_THREADSTATE_PLAYING;
 
482
    break;
 
483
  }
 
484
  case _THREADSTATE_CLOSED: {
 
485
    streamState=_THREADSTATE_INIT;
 
486
    break;
 
487
  }
 
488
  default:
 
489
    cout << "unknown streamState:DecoderBaseObject_impl:"<<state<<endl;
 
490
  }
 
491
 
 
492
}
 
493
 
 
494
/** internal stuff for testing **/
 
495
 
 
496
void DecoderBaseObject_impl::blocking(bool newvalue)
 
497
{
 
498
  _blocking = newvalue;
 
499
}
 
500
 
 
501
bool DecoderBaseObject_impl::blocking()
 
502
{
 
503
  return _blocking;
 
504
}
 
505
 
 
506
void DecoderBaseObject_impl::speed(float newValue)
 
507
{
 
508
    _speed= newValue;
 
509
}
 
510
 
 
511
float DecoderBaseObject_impl::speed()
 
512
{
 
513
    return _speed;
 
514
}