// Updates the player (called from the decoder thread.) // Will return 0 if the stream is in good condition and there is nothing else // to do for now. // Will return -1 is there is still work to be done // Will return 1 if there was an error or the stream ended int cMedia::Update( cMedia* pMedia ) { KBASSERT( !!pMedia && "cMedia::Update() requires valid player" ); AVFormatContext* pFormatContext = (AVFormatContext *)pMedia->m_pSource->m_pFormatContext; // Handle the control queue ProfileCPU( "cMedia::Update [Control]" ) { pMedia->m_pControlMutex->Lock(); cMediaControlPacket* pControlPacket; while ( ( pControlPacket = (cMediaControlPacket *)cMediaBuffer::Read( (cMediaBuffer *)pMedia->m_pControlBuffer ) ) ) { cMediaControlPacket::Handle( pMedia, (void *)pControlPacket ); cMediaControlPacket::Free( (void *)pControlPacket ); } pMedia->m_pControlMutex->Unlock(); } // If either buffer is full, just stop here. // Since we don't know what kind of data we'll encounter out of av_read_frame, we // have to handle all strange cases and drop the ones we don't support if ( pMedia->m_pVideoCodecContext ) { pMedia->m_pVideoMutex->Lock(); const kbBool bReturn = cMediaBuffer::IsFull( (cMediaBuffer *)pMedia->m_pVideoBuffer ); pMedia->m_pVideoMutex->Unlock(); if ( bReturn ) { return 0; } } if ( pMedia->m_pAudioCodecContext ) { pMedia->m_pAudioMutex->Lock(); const kbBool bReturn = cMediaBuffer::IsFull( (cMediaBuffer *)pMedia->m_pAudioBuffer ); pMedia->m_pAudioMutex->Unlock(); if ( bReturn ) { return 0; } } AVPacket packet; ProfileCPU( "cMedia::Update [Read]" ) { // Attempt to read a frame; just return if it fails if ( av_read_frame( pFormatContext, &packet ) < 0 ) { return 1; } } ProfileCPU( "cMedia::Update [Handle]" ) { HandlePacket( pMedia, &packet ); } av_packet_unref( &packet ); return -1; } // The decoder thread int cMedia::DecodeThreadFunction( void* pData ) { scThread::SetPriority( cThreadPriority::High ); cMedia* pMedia = (cMedia *)pData; const cString strName = Format( "cMedia %s", cMediaSource::GetURI( pMedia->m_pSource ) ); scProfile::SetThreadName( &strName[ 0 ] ); kbBool bIsRunning = true; kbBool bIsPlaying = false; while ( bIsRunning ) { if ( pMedia->m_eState == eMediaPlayerState::kClosed ) { bIsRunning = false; continue; } if ( pMedia->m_eState == eMediaPlayerState::kPlaying ) { bIsPlaying = true; } while ( bIsRunning && bIsPlaying ) { if ( pMedia->m_eState == eMediaPlayerState::kClosed ) { bIsRunning = false; continue; } if ( pMedia->m_eState == eMediaPlayerState::kStopped ) { bIsPlaying = false; continue; } // Acquire more data from the demuxer and decode it. // Wait a bit if there's no more work for now. int nResult = 0; ProfileCPU( "cMedia::DecodeThreadFunction [Update]" ) { nResult = Update( pMedia ); } if ( nResult == 1 ) { pMedia->m_eState = eMediaPlayerState::kStopped; } else if ( nResult == 0 ) { scSystem::Delay( 1 ); } } scSystem::Delay( 10 ); } return 0; }