Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

loopcontrol.cpp

Go to the documentation of this file.
00001 /**********************************************************************
00002  ** Copyright (C) 2000 Trolltech AS.  All rights reserved.
00003  **
00004  ** This file is part of Qtopia Environment.
00005  **
00006  ** This file may be distributed and/or modified under the terms of the
00007  ** GNU General Public License version 2 as published by the Free Software
00008  ** Foundation and appearing in the file LICENSE.GPL included in the
00009  ** packaging of this file.
00010  **
00011  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00012  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00013  **
00014  ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00015  **
00016  ** Contact info@trolltech.com if any conditions of this licensing are
00017  ** not clear to you.
00018  **
00019  **********************************************************************/
00020 // L.J.Potter added changes Fri 02-15-2002
00021 
00022 
00023 #include "mediaplayerstate.h"
00024 #include "loopcontrol.h"
00025 #include "videowidget.h"
00026 #include "audiodevice.h"
00027 
00028 /* OPIE */
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 /* QT */
00038 
00039 /* STD */
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; // now only needed to tell it to play a frame
00049 extern MediaPlayerState *mediaPlayerState;
00050 
00051 
00052 //#define DecodeLoopDebug(x)  qDebug x
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 ); // Semi-buzy-wait till we are playing again
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     //odebug << "starting loopcontrol" << oendl;
00112     audioMutex = new Mutex;
00113 
00114     pthread_attr_init(&audio_attr);
00115 #define USE_REALTIME_AUDIO_THREAD
00116 #ifdef USE_REALTIME_AUDIO_THREAD
00117       // Attempt to set it to real-time round robin
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,&params);
00122     } else {
00123        //        odebug << "Error setting up a realtime thread, reverting to using a normal thread." << oendl;
00124         pthread_attr_destroy(&audio_attr);
00125         pthread_attr_init(&audio_attr);
00126     }
00127 #endif
00128     //odebug << "create audio thread" << oendl;
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 //    odebug << "Loop control " << pos << "" << oendl;
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                   // Don't skip
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 //              if ( currentSample != audioSampleCounter + 1 )
00239 //                  odebug << "out of sync with decoder " << currentSample << " " << audioSampleCounter << "" << oendl;
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 // this causes drop outs not sure why its even here
00247          if ( hasVideoChannel ) {
00248            if ( ( sampleWaitTime > 2000 ) && ( sampleWaitTime < 20000 ) ) {
00249          usleep( (long)((double)sampleWaitTime * 1000000.0 / freq) );
00250            }
00251          else if ( sampleWaitTime <= -5000 ) {
00252             //        odebug << "need to catch up by: " << -sampleWaitTime << " (" << currentSample << "," << sampleWeShouldBeAt << ")" << oendl;
00253  //       //mediaPlayerState->curDecoder()->audioSetSample( sampleWeShouldBeAt, stream );
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); // 10% of the real value
00300         videoId = startTimer( mSecsBetweenFrames );
00301     }
00302 
00303     if ( hasAudioChannel ) {
00304         moreAudio = TRUE;
00305         threadOkToGo = TRUE;
00306     }
00307 
00308     sliderId = startTimer( 300 ); // update slider every 1/3 second
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           // Force an update of the position
00323         mediaPlayerState->setPosition( mediaPlayerState->position() + 1 );
00324         mediaPlayerState->setPosition( mediaPlayerState->position() - 1 );
00325           // Just like we never stopped
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           // Re-enable the suspend mode
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; // only play stream 0 for now
00370     current_frame = total_video_frames = total_audio_samples = 0;
00371 
00372     //    odebug << "Using the " << mediaPlayerState->curDecoder()->pluginName() << " decoder" << oendl;
00373 
00374       // ### Hack to use libmpeg3plugin to get the number of audio samples if we are using the libmad plugin
00375 //     if ( mediaPlayerState->curDecoder()->pluginName() == QString("LibMadPlugin") ) {
00376 //         if ( mediaPlayerState->libMpeg3Decoder() && mediaPlayerState->libMpeg3Decoder()->open( filename )) {
00377 //             total_audio_samples = mediaPlayerState->libMpeg3Decoder()->audioSamples( 0 );
00378 //             mediaPlayerState->libMpeg3Decoder()->close();
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; //dont akx me why, but it needs this hack
00395         else
00396             channels = mediaPlayerState->curDecoder()->audioChannels( astream );
00397 
00398         //        odebug << "LC- channels = " << channels << "" << oendl;
00399 
00400 //        if ( !total_audio_samples )
00401             total_audio_samples = mediaPlayerState->curDecoder()->audioSamples( astream );
00402 
00403         total_audio_samples += 1000;
00404         //        odebug << "total samples " << total_audio_samples << "" << oendl;
00405         mediaPlayerState->setLength( total_audio_samples );
00406 
00407         freq = mediaPlayerState->curDecoder()->audioFrequency( astream );
00408         //        odebug << "LC- frequency = " << freq << "" << oendl;
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             //            odebug << "using stupid hack" << oendl;
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           //### must check which frequency is actually used.
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    //    odebug << "LC- play" << oendl;
00463     mediaPlayerState->setPosition( 0); //uglyhack
00464 
00465 #if defined(Q_WS_QWS) && !defined(QT_NO_COP)
00466     if ( !disabledSuspendScreenSaver || previousSuspendMode != hasVideoChannel ) {
00467         disabledSuspendScreenSaver = TRUE;
00468         previousSuspendMode = hasVideoChannel;
00469           // Stop the screen from blanking and power saving state
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               // Force an update of the position
00485             mediaPlayerState->setPosition( mediaPlayerState->position() + 1 );
00486             mediaPlayerState->setPosition( mediaPlayerState->position() - 1 );
00487               // Resume playing audio
00488             moreAudio = TRUE;
00489         }
00490     }
00491 }
00492 
00493 

Generated on Sat Nov 5 16:15:37 2005 for OPIE by  doxygen 1.4.2