00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "mediaplayerstate.h"
00024 #include "loopcontrol.h"
00025 #include "videowidget.h"
00026 #include "audiodevice.h"
00027
00028
00029 #include <qpe/qpeapplication.h>
00030 #include <qpe/mediaplayerplugininterface.h>
00031 #include <opie2/odebug.h>
00032
00033 #ifdef Q_WS_QWS
00034 #include <qpe/qcopenvelope_qws.h>
00035 #endif
00036
00037
00038
00039
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #include <pthread.h>
00044 #include <errno.h>
00045 #include <unistd.h>
00046
00047
00048 extern VideoWidget *videoUI;
00049 extern MediaPlayerState *mediaPlayerState;
00050
00051
00052
00053 #define DecodeLoopDebug(x)
00054
00055
00056 static char *audioBuffer = NULL;
00057 static AudioDevice *audioDevice = NULL;
00058 static bool disabledSuspendScreenSaver = FALSE;
00059 static bool previousSuspendMode = FALSE;
00060
00061
00062 pthread_t audio_tid;
00063 pthread_attr_t audio_attr;
00064 bool threadOkToGo = FALSE;
00065
00066
00067 class Mutex {
00068 public:
00069 Mutex() {
00070 pthread_mutexattr_t attr;
00071 pthread_mutexattr_init( &attr );
00072 pthread_mutex_init( &mutex, &attr );
00073 pthread_mutexattr_destroy( &attr );
00074 }
00075
00076 ~Mutex() {
00077 pthread_mutex_destroy( &mutex );
00078 }
00079
00080 void lock() {
00081 pthread_mutex_lock( &mutex );
00082 }
00083
00084 void unlock() {
00085 pthread_mutex_unlock( &mutex );
00086 }
00087 private:
00088 pthread_mutex_t mutex;
00089 };
00090
00091
00092 void *startAudioThread( void *ptr ) {
00093 LoopControl *mpegView = (LoopControl *)ptr;
00094 while ( TRUE ) {
00095 if ( threadOkToGo && mpegView->moreAudio )
00096 mpegView->startAudio();
00097 else
00098 usleep( 10000 );
00099 }
00100 return 0;
00101 }
00102
00103
00104 Mutex *audioMutex;
00105
00106
00107 LoopControl::LoopControl( QObject *parent, const char *name )
00108 : QObject( parent, name ) {
00109 isMuted = FALSE;
00110 connect( qApp, SIGNAL( volumeChanged(bool) ), this, SLOT( setMute(bool) ) );
00111
00112 audioMutex = new Mutex;
00113
00114 pthread_attr_init(&audio_attr);
00115 #define USE_REALTIME_AUDIO_THREAD
00116 #ifdef USE_REALTIME_AUDIO_THREAD
00117
00118 if ( pthread_attr_setschedpolicy( &audio_attr, SCHED_RR ) == 0 ) {
00119 sched_param params;
00120 params.sched_priority = 50;
00121 pthread_attr_setschedparam(&audio_attr,¶ms);
00122 } else {
00123
00124 pthread_attr_destroy(&audio_attr);
00125 pthread_attr_init(&audio_attr);
00126 }
00127 #endif
00128
00129 pthread_create(&audio_tid, &audio_attr, (void * (*)(void *))startAudioThread, this);
00130 }
00131
00132
00133 LoopControl::~LoopControl() {
00134 stop();
00135 }
00136
00137
00138 static long prev_frame = 0;
00139 static int currentSample = 0;
00140
00141
00142 void LoopControl::timerEvent( QTimerEvent *te ) {
00143
00144 if ( te->timerId() == videoId )
00145 startVideo();
00146
00147 if ( te->timerId() == sliderId ) {
00148 if ( hasAudioChannel && !hasVideoChannel && moreAudio ) {
00149 mediaPlayerState->updatePosition( audioSampleCounter );
00150 } else if ( hasVideoChannel && moreVideo ) {
00151 mediaPlayerState->updatePosition( current_frame );
00152 }
00153 }
00154
00155 if ( !moreVideo && !moreAudio ) {
00156 mediaPlayerState->setPlaying( FALSE );
00157 mediaPlayerState->setNext();
00158 }
00159 }
00160
00161
00162 void LoopControl::setPosition( long pos ) {
00163 audioMutex->lock();
00164
00165 if ( hasVideoChannel && hasAudioChannel ) {
00166 playtime.restart();
00167 playtime = playtime.addMSecs( long((double)-pos * 1000.0 / framerate) );
00168 current_frame = pos + 1;
00169 mediaPlayerState->curDecoder()->videoSetFrame( current_frame, stream );
00170 prev_frame = current_frame - 1;
00171 currentSample = (int)( (double)current_frame * freq / framerate );
00172 mediaPlayerState->curDecoder()->audioSetSample( currentSample, stream );
00173 audioSampleCounter = currentSample - 1;
00174 } else if ( hasVideoChannel ) {
00175 playtime.restart();
00176 playtime = playtime.addMSecs( long((double)-pos * 1000.0 / framerate) );
00177 current_frame = pos + 1;
00178 mediaPlayerState->curDecoder()->videoSetFrame( current_frame, stream );
00179 prev_frame = current_frame - 1;
00180 } else if ( hasAudioChannel ) {
00181 playtime.restart();
00182 playtime = playtime.addMSecs( long((double)-pos * 1000.0 / freq) );
00183 currentSample = pos + 1;
00184 mediaPlayerState->curDecoder()->audioSetSample( currentSample, stream );
00185 audioSampleCounter = currentSample - 1;
00186 }
00187
00188 audioMutex->unlock();
00189 }
00190
00191
00192 void LoopControl::startVideo() {
00193
00194 if ( moreVideo ) {
00195
00196 if ( mediaPlayerState->curDecoder() ) {
00197
00198 if ( hasAudioChannel && !isMuted ) {
00199
00200 current_frame = long( playtime.elapsed() * framerate / 1000 );
00201
00202 if ( prev_frame != -1 && current_frame <= prev_frame )
00203 return;
00204
00205 } else {
00206
00207 current_frame++;
00208 }
00209
00210 if ( prev_frame == -1 || current_frame > prev_frame ) {
00211 if ( current_frame > prev_frame + 1 ) {
00212 mediaPlayerState->curDecoder()->videoSetFrame( current_frame, stream );
00213 }
00214 moreVideo = videoUI->playVideo();
00215 prev_frame = current_frame;
00216 }
00217
00218 } else {
00219
00220 moreVideo = FALSE;
00221 killTimer( videoId );
00222
00223 }
00224
00225 }
00226 }
00227
00228
00229 void LoopControl::startAudio() {
00230
00231 audioMutex->lock();
00232 if ( moreAudio ) {
00233
00234 if ( !isMuted && mediaPlayerState->curDecoder() ) {
00235
00236 currentSample = audioSampleCounter + 1;
00237
00238
00239
00240
00241 long samplesRead = 0;
00242 bool readOk=mediaPlayerState->curDecoder()->audioReadSamples( (short*)audioBuffer, channels, 1024, samplesRead, stream );
00243 long sampleWeShouldBeAt = long( playtime.elapsed() ) * freq / 1000;
00244 long sampleWaitTime = currentSample - sampleWeShouldBeAt;
00245
00246
00247 if ( hasVideoChannel ) {
00248 if ( ( sampleWaitTime > 2000 ) && ( sampleWaitTime < 20000 ) ) {
00249 usleep( (long)((double)sampleWaitTime * 1000000.0 / freq) );
00250 }
00251 else if ( sampleWaitTime <= -5000 ) {
00252
00253
00254 currentSample = sampleWeShouldBeAt;
00255 }
00256 }
00257
00258 audioDevice->write( audioBuffer, samplesRead * 2 * channels );
00259
00260 if( mediaPlayerState->isStreaming == FALSE)
00261 audioSampleCounter = currentSample + samplesRead - 1;
00262
00263 moreAudio = readOk && (audioSampleCounter <= total_audio_samples);
00264
00265 } else {
00266
00267 moreAudio = FALSE;
00268
00269 }
00270
00271 }
00272
00273 audioMutex->unlock();
00274 }
00275
00276
00277 void LoopControl::killTimers() {
00278
00279 audioMutex->lock();
00280
00281 if ( hasVideoChannel )
00282 killTimer( videoId );
00283 killTimer( sliderId );
00284 threadOkToGo = FALSE;
00285
00286 audioMutex->unlock();
00287 }
00288
00289
00290 void LoopControl::startTimers() {
00291
00292 audioMutex->lock();
00293
00294 moreVideo = FALSE;
00295 moreAudio = FALSE;
00296
00297 if ( hasVideoChannel ) {
00298 moreVideo = TRUE;
00299 int mSecsBetweenFrames = (int)(100 / framerate);
00300 videoId = startTimer( mSecsBetweenFrames );
00301 }
00302
00303 if ( hasAudioChannel ) {
00304 moreAudio = TRUE;
00305 threadOkToGo = TRUE;
00306 }
00307
00308 sliderId = startTimer( 300 );
00309
00310 audioMutex->unlock();
00311 }
00312
00313
00314 void LoopControl::setPaused( bool pause ) {
00315
00316 if ( !mediaPlayerState->curDecoder() || !mediaPlayerState->curDecoder()->isOpen() )
00317 return;
00318
00319 if ( pause ) {
00320 killTimers();
00321 } else {
00322
00323 mediaPlayerState->setPosition( mediaPlayerState->position() + 1 );
00324 mediaPlayerState->setPosition( mediaPlayerState->position() - 1 );
00325
00326 startTimers();
00327 }
00328 }
00329
00330
00331 void LoopControl::stop( bool willPlayAgainShortly ) {
00332
00333 #if defined(Q_WS_QWS) && !defined(QT_NO_COP)
00334 if ( !willPlayAgainShortly && disabledSuspendScreenSaver ) {
00335 disabledSuspendScreenSaver = FALSE;
00336
00337 QCopEnvelope("QPE/System", "setScreenSaverMode(int)" ) << QPEApplication::Enable;
00338 }
00339 #endif
00340
00341 if ( mediaPlayerState->curDecoder() && mediaPlayerState->curDecoder()->isOpen() ) {
00342
00343 killTimers();
00344
00345 audioMutex->lock();
00346
00347 mediaPlayerState->curDecoder()->close();
00348
00349 if ( audioDevice ) {
00350 delete audioDevice;
00351 delete audioBuffer;
00352 audioDevice = 0;
00353 audioBuffer = 0;
00354 }
00355
00356 audioMutex->unlock();
00357 }
00358 audioSampleCounter=0;
00359 current_frame=0;
00360 total_audio_samples=0;
00361 }
00362
00363
00364 bool LoopControl::init( const QString& filename ) {
00365 stop();
00366 audioMutex->lock();
00367
00368 fileName = filename;
00369 stream = 0;
00370 current_frame = total_video_frames = total_audio_samples = 0;
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 if ( !mediaPlayerState->curDecoder()|| !mediaPlayerState->curDecoder()->open( filename ) ) {
00383 audioMutex->unlock();
00384 return FALSE;
00385 }
00386
00387 hasAudioChannel = mediaPlayerState->curDecoder()->audioStreams() > 0;
00388 hasVideoChannel = mediaPlayerState->curDecoder()->videoStreams() > 0;
00389
00390 if ( hasAudioChannel ) {
00391 int astream = 0;
00392
00393 if ( mediaPlayerState->curDecoder()->pluginName() == QString("LibMpeg3Plugin") )
00394 channels = 2;
00395 else
00396 channels = mediaPlayerState->curDecoder()->audioChannels( astream );
00397
00398
00399
00400
00401 total_audio_samples = mediaPlayerState->curDecoder()->audioSamples( astream );
00402
00403 total_audio_samples += 1000;
00404
00405 mediaPlayerState->setLength( total_audio_samples );
00406
00407 freq = mediaPlayerState->curDecoder()->audioFrequency( astream );
00408
00409
00410 audioSampleCounter = 0;
00411 int bits_per_sample;
00412 if ( mediaPlayerState->curDecoder()->pluginName() == QString("LibWavPlugin") ) {
00413 bits_per_sample =(int) mediaPlayerState->curDecoder()->getTime();
00414
00415 } else {
00416 bits_per_sample=0;
00417 }
00418
00419 audioDevice = new AudioDevice( freq, channels, bits_per_sample);
00420 audioBuffer = new char[ audioDevice->bufferSize() ];
00421 channels = audioDevice->channels();
00422
00423
00424 static const int size = 1;
00425 short int buf[size];
00426 long samplesRead = 0;
00427 mediaPlayerState->curDecoder()->audioReadSamples( buf, channels, size, samplesRead, stream );
00428 }
00429
00430 if ( hasVideoChannel ) {
00431 total_video_frames = mediaPlayerState->curDecoder()->videoFrames( stream );
00432
00433 mediaPlayerState->setLength( total_video_frames );
00434
00435 framerate = mediaPlayerState->curDecoder()->videoFrameRate( stream );
00436 DecodeLoopDebug(( "Frame rate %g total %ld", framerate, total_video_frames ));
00437
00438 if ( framerate <= 1.0 ) {
00439 DecodeLoopDebug(( "Crazy frame rate, resetting to sensible" ));
00440 framerate = 25;
00441 }
00442
00443 if ( total_video_frames == 1 ) {
00444 DecodeLoopDebug(( "Cannot seek to frame" ));
00445 }
00446
00447 }
00448
00449 current_frame = 0;
00450 prev_frame = -1;
00451
00452 connect( mediaPlayerState, SIGNAL( positionChanged(long) ), this, SLOT( setPosition(long) ) );
00453 connect( mediaPlayerState, SIGNAL( pausedToggled(bool) ), this, SLOT( setPaused(bool) ) );
00454
00455 audioMutex->unlock();
00456
00457 return TRUE;
00458 }
00459
00460
00461 void LoopControl::play() {
00462
00463 mediaPlayerState->setPosition( 0);
00464
00465 #if defined(Q_WS_QWS) && !defined(QT_NO_COP)
00466 if ( !disabledSuspendScreenSaver || previousSuspendMode != hasVideoChannel ) {
00467 disabledSuspendScreenSaver = TRUE;
00468 previousSuspendMode = hasVideoChannel;
00469
00470 QCopEnvelope("QPE/System", "setScreenSaverMode(int)" )
00471 << ( hasVideoChannel ? QPEApplication::Disable : QPEApplication::DisableSuspend );
00472 }
00473 #endif
00474
00475 playtime.start();
00476 startTimers();
00477 }
00478
00479
00480 void LoopControl::setMute( bool on ) {
00481 if ( on != isMuted ) {
00482 isMuted = on;
00483 if ( !on ) {
00484
00485 mediaPlayerState->setPosition( mediaPlayerState->position() + 1 );
00486 mediaPlayerState->setPosition( mediaPlayerState->position() - 1 );
00487
00488 moreAudio = TRUE;
00489 }
00490 }
00491 }
00492
00493