// decode one audio frame and returns its uncompressed size int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &audioframe, bool bDropPacket) { int result = 0; // make sure the sent frame is clean memset(&audioframe, 0, sizeof(DVDAudioFrame)); while (!m_bStop) { bool switched = false; /* NOTE: the audio packet can contain several frames */ while( !m_bStop && m_decode.size > 0 ) { if( !m_pAudioCodec ) return DECODE_FLAG_ERROR; /* the packet dts refers to the first audioframe that starts in the packet */ double dts = m_ptsInput.Get(m_decode.size + m_pAudioCodec->GetBufferSize(), true); if (dts != DVD_NOPTS_VALUE) m_audioClock = dts; int len = m_pAudioCodec->Decode(m_decode.data, m_decode.size); m_audioStats.AddSampleBytes(m_decode.size); if (len < 0) { /* if error, we skip the packet */ CLog::Log(LOGERROR, "CDVDPlayerAudio::DecodeFrame - Decode Error. Skipping audio packet"); m_decode.Release(); m_pAudioCodec->Reset(); return DECODE_FLAG_ERROR; } // fix for f****d up decoders if( len > m_decode.size ) { CLog::Log(LOGERROR, "CDVDPlayerAudio:DecodeFrame - Codec tried to consume more data than available. Potential memory corruption"); m_decode.Release(); m_pAudioCodec->Reset(); return DECODE_FLAG_ERROR; } m_decode.data += len; m_decode.size -= len; // get decoded data and the size of it audioframe.size = m_pAudioCodec->GetData(&audioframe.data); audioframe.pts = m_audioClock; if (audioframe.size <= 0) continue; audioframe.channel_layout = m_pAudioCodec->GetChannelMap(); audioframe.channel_count = m_pAudioCodec->GetChannels(); audioframe.encoded_channel_count = m_pAudioCodec->GetEncodedChannels(); audioframe.data_format = m_pAudioCodec->GetDataFormat(); audioframe.bits_per_sample = CAEUtil::DataFormatToBits(audioframe.data_format); audioframe.sample_rate = m_pAudioCodec->GetSampleRate(); audioframe.encoded_sample_rate = m_pAudioCodec->GetEncodedSampleRate(); audioframe.passthrough = m_pAudioCodec->NeedPassthrough(); if (m_streaminfo.samplerate != audioframe.sample_rate) { // The sample rate has changed or we just got it for the first time // for this stream. See if we should enable/disable passthrough due // to it. m_streaminfo.samplerate = audioframe.sample_rate; if (!switched && SwitchCodecIfNeeded()) { // passthrough has been enabled/disabled, reprocess the packet m_decode.data -= len; m_decode.size += len; switched = true; continue; } } // compute duration. int n = (audioframe.channel_count * audioframe.bits_per_sample * audioframe.sample_rate)>>3; if (n > 0) { // safety check, if channels == 0, n will result in 0, and that will result in a nice devide exception audioframe.duration = ((double)audioframe.size * DVD_TIME_BASE) / n; // increase audioclock to after the packet m_audioClock += audioframe.duration; } if(audioframe.duration > 0) m_duration = audioframe.duration; // if demux source want's us to not display this, continue if(m_decode.msg->GetPacketDrop()) continue; //If we are asked to drop this packet, return a size of zero. then it won't be played //we currently still decode the audio.. this is needed since we still need to know it's //duration to make sure clock is updated correctly. if( bDropPacket ) result |= DECODE_FLAG_DROP; return result; } // free the current packet m_decode.Release(); if (m_messageQueue.ReceivedAbortRequest()) return DECODE_FLAG_ABORT; CDVDMsg* pMsg; int priority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0; int timeout; if(m_duration > 0) timeout = (int)(1000 * (m_duration / DVD_TIME_BASE + m_dvdAudio.GetCacheTime())); else timeout = 1000; // read next packet and return -1 on error MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, timeout, priority); if (ret == MSGQ_TIMEOUT) return DECODE_FLAG_TIMEOUT; if (MSGQ_IS_ERROR(ret)) return DECODE_FLAG_ABORT; if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { m_decode.Attach((CDVDMsgDemuxerPacket*)pMsg); m_ptsInput.Add( m_decode.size, m_decode.dts ); } else if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait( 100, SYNCSOURCE_AUDIO )) CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_SYNCHRONIZE"); else m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */ } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { //player asked us to set internal clock CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg; if (pMsgGeneralResync->m_timestamp != DVD_NOPTS_VALUE) m_audioClock = pMsgGeneralResync->m_timestamp; m_ptsInput.Flush(); m_dvdAudio.SetPlayingPts(m_audioClock); if (pMsgGeneralResync->m_clock) { CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, 1)", m_audioClock); m_pClock->Discontinuity(m_dvdAudio.GetPlayingPts()); } else CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, 0)", m_audioClock); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { if (m_pAudioCodec) m_pAudioCodec->Reset(); m_decode.Release(); m_started = false; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) { m_dvdAudio.Flush(); m_ptsInput.Flush(); m_syncclock = true; m_stalled = true; m_started = false; if (m_pAudioCodec) m_pAudioCodec->Reset(); m_decode.Release(); } else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) { if(m_started) m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO)); } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { CDVDPlayer::SPlayerState& state = ((CDVDMsgType<CDVDPlayer::SPlayerState>*)pMsg)->m_value; if(state.time_src == CDVDPlayer::ETIMESOURCE_CLOCK) state.time = DVD_TIME_TO_MSEC(m_pClock->GetClock(state.timestamp) + state.time_offset); else state.timestamp = CDVDClock::GetAbsoluteClock(); state.player = DVDPLAYER_AUDIO; m_messageParent.Put(pMsg->Acquire()); } else if (pMsg->IsType(CDVDMsg::GENERAL_EOF)) { CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_EOF"); m_dvdAudio.Finish(); } else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY)) { if (m_speed != DVD_PLAYSPEED_PAUSE) { double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_DELAY(%f)", timeout); timeout *= (double)DVD_PLAYSPEED_NORMAL / abs(m_speed); timeout += CDVDClock::GetAbsoluteClock(); while(!m_bStop && CDVDClock::GetAbsoluteClock() < timeout) Sleep(1); } } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; if (m_speed == DVD_PLAYSPEED_NORMAL) { m_dvdAudio.Resume(); } else { m_syncclock = true; if (m_speed != DVD_PLAYSPEED_PAUSE) m_dvdAudio.Flush(); m_dvdAudio.Pause(); } } else if (pMsg->IsType(CDVDMsg::AUDIO_SILENCE)) { m_silence = static_cast<CDVDMsgBool*>(pMsg)->m_value; if (m_silence) CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 1)", m_audioClock); else CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 0)", m_audioClock); } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { CDVDMsgAudioCodecChange* msg(static_cast<CDVDMsgAudioCodecChange*>(pMsg)); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; } pMsg->Release(); } return 0; }
void OMXPlayerAudio::Process() { m_audioStats.Start(); while(!m_bStop) { CDVDMsg* pMsg; int timeout = 1000; // read next packet and return -1 on error int priority = 1; //Do we want a new audio frame? if (m_syncState == IDVDStreamPlayer::SYNC_STARTING || /* when not started */ m_speed == DVD_PLAYSPEED_NORMAL || /* when playing normally */ m_speed < DVD_PLAYSPEED_PAUSE || /* when rewinding */ (m_speed > DVD_PLAYSPEED_NORMAL && m_audioClock < m_av_clock->GetClock())) /* when behind clock in ff */ priority = 0; if (m_syncState == IDVDStreamPlayer::SYNC_WAITSYNC) priority = 1; // consider stream stalled if queue is empty // we can't sync audio to clock with an empty queue if (m_speed == DVD_PLAYSPEED_NORMAL) { timeout = 0; } MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, timeout, priority); if (ret == MSGQ_TIMEOUT) { Sleep(10); continue; } if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT) { Sleep(10); continue; } if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); #ifdef _DEBUG CLog::Log(LOGINFO, "Audio: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d,%d", pPacket->dts, pPacket->pts, (int)pPacket->iSize, m_syncState, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, (int)m_omxAudio.GetAudioRenderingLatency(), (int)m_hints_current.samplerate); #endif if(Decode(pPacket, bPacketDrop, m_speed > DVD_PLAYSPEED_NORMAL || m_speed < 0)) { // we are not running until something is cached in output device if(m_stalled && m_omxAudio.GetCacheTime() > 0.0) { CLog::Log(LOGINFO, "COMXPlayerAudio - Switching to normal playback"); m_stalled = false; } } } else if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait( 100, SYNCSOURCE_AUDIO )) CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_SYNCHRONIZE"); else m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */ } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { //player asked us to set internal clock double pts = static_cast<CDVDMsgDouble*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f)", pts); m_audioClock = pts; m_syncState = IDVDStreamPlayer::SYNC_INSYNC; } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESET"); if (m_pAudioCodec) m_pAudioCodec->Reset(); m_syncState = IDVDStreamPlayer::SYNC_STARTING; m_audioClock = DVD_NOPTS_VALUE; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) { bool sync = static_cast<CDVDMsgBool*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_FLUSH(%d)", sync); m_omxAudio.Flush(); m_stalled = true; m_syncState = IDVDStreamPlayer::SYNC_STARTING; if (m_pAudioCodec) m_pAudioCodec->Reset(); m_audioClock = DVD_NOPTS_VALUE; m_flush = false; } else if (pMsg->IsType(CDVDMsg::GENERAL_EOF)) { CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_EOF"); SubmitEOS(); } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { if (m_speed != static_cast<CDVDMsgInt*>(pMsg)->m_value) { m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::PLAYER_SETSPEED %d", m_speed); } } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { COMXMsgAudioCodecChange* msg(static_cast<COMXMsgAudioCodecChange*>(pMsg)); CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_STREAMCHANGE"); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; } pMsg->Release(); } }
void CVideoPlayerAudio::Process() { CLog::Log(LOGNOTICE, "running thread: CVideoPlayerAudio::Process()"); DVDAudioFrame audioframe; m_audioStats.Start(); while (!m_bStop) { CDVDMsg* pMsg; int timeout = (int)(1000 * m_dvdAudio.GetCacheTime()) + 100; // read next packet and return -1 on error int priority = 1; //Do we want a new audio frame? if (m_syncState == IDVDStreamPlayer::SYNC_STARTING || /* when not started */ ALLOW_AUDIO(m_speed) || /* when playing normally */ m_speed < DVD_PLAYSPEED_PAUSE || /* when rewinding */ (m_speed > DVD_PLAYSPEED_NORMAL && m_audioClock < m_pClock->GetClock())) /* when behind clock in ff */ priority = 0; if (m_syncState == IDVDStreamPlayer::SYNC_WAITSYNC) priority = 1; // consider stream stalled if queue is empty // we can't sync audio to clock with an empty queue if (ALLOW_AUDIO(m_speed) && !m_stalled) { timeout = 0; } MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, timeout, priority); if (MSGQ_IS_ERROR(ret)) { CLog::Log(LOGERROR, "Got MSGQ_ABORT or MSGO_IS_ERROR return true"); break; } else if (ret == MSGQ_TIMEOUT) { // Flush as the audio output may keep looping if we don't if (ALLOW_AUDIO(m_speed) && !m_stalled && m_syncState == IDVDStreamPlayer::SYNC_INSYNC) { // while AE sync is active, we still have time to fill buffers if (m_syncTimer.IsTimePast()) { CLog::Log(LOGNOTICE, "CVideoPlayerAudio::Process - stream stalled"); m_stalled = true; } } if (timeout == 0) Sleep(10); continue; } // handle messages if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait( 100, SYNCSOURCE_AUDIO )) CLog::Log(LOGDEBUG, "CVideoPlayerAudio - CDVDMsg::GENERAL_SYNCHRONIZE"); else m_messageQueue.Put(pMsg->Acquire(), 1); // push back as prio message, to process other prio messages } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { //player asked us to set internal clock double pts = static_cast<CDVDMsgDouble*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "CVideoPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f)", pts); m_audioClock = pts + m_dvdAudio.GetDelay(); if (m_speed != DVD_PLAYSPEED_PAUSE) m_dvdAudio.Resume(); m_syncState = IDVDStreamPlayer::SYNC_INSYNC; m_syncTimer.Set(3000); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { if (m_pAudioCodec) m_pAudioCodec->Reset(); m_syncState = IDVDStreamPlayer::SYNC_STARTING; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) { bool sync = static_cast<CDVDMsgBool*>(pMsg)->m_value; m_dvdAudio.Flush(); m_stalled = true; m_audioClock = 0; if (sync) { m_syncState = IDVDStreamPlayer::SYNC_STARTING; m_dvdAudio.Pause(); } if (m_pAudioCodec) m_pAudioCodec->Reset(); } else if (pMsg->IsType(CDVDMsg::GENERAL_EOF)) { CLog::Log(LOGDEBUG, "CVideoPlayerAudio - CDVDMsg::GENERAL_EOF"); } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { double speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; if (ALLOW_AUDIO(speed)) { if (speed != m_speed) { if (m_syncState == IDVDStreamPlayer::SYNC_INSYNC) m_dvdAudio.Resume(); } } else { m_dvdAudio.Pause(); } m_speed = speed; } else if (pMsg->IsType(CDVDMsg::AUDIO_SILENCE)) { m_silence = static_cast<CDVDMsgBool*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "CVideoPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, %d)" , m_audioClock, m_silence); } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { CDVDMsgAudioCodecChange* msg(static_cast<CDVDMsgAudioCodecChange*>(pMsg)); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; } else if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); int consumed = m_pAudioCodec->Decode(pPacket->pData, pPacket->iSize, pPacket->dts, pPacket->pts); if (consumed < 0) { CLog::Log(LOGERROR, "CVideoPlayerAudio::DecodeFrame - Decode Error. Skipping audio packet (%d)", consumed); m_pAudioCodec->Reset(); pMsg->Release(); continue; } m_audioStats.AddSampleBytes(pPacket->iSize); UpdatePlayerInfo(); // loop while no error and decoder produces output while (!m_bStop) { // get decoded data and the size of it m_pAudioCodec->GetData(audioframe); if (audioframe.nb_frames == 0) { if (consumed >= pPacket->iSize) break; int ret = m_pAudioCodec->Decode(pPacket->pData+consumed, pPacket->iSize-consumed, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE); if (ret < 0) { CLog::Log(LOGERROR, "CVideoPlayerAudio::DecodeFrame - Decode Error. Skipping audio packet (%d)", ret); m_pAudioCodec->Reset(); break; } consumed += ret; continue; } audioframe.hasTimestamp = true; if (audioframe.pts == DVD_NOPTS_VALUE) { audioframe.pts = m_audioClock; audioframe.hasTimestamp = false; } else { m_audioClock = audioframe.pts; } //Drop when not playing normally if (!ALLOW_AUDIO(m_speed) && m_syncState == IDVDStreamPlayer::SYNC_INSYNC) { break; } if (audioframe.format.m_sampleRate && m_streaminfo.samplerate != (int) audioframe.format.m_sampleRate) { // The sample rate has changed or we just got it for the first time // for this stream. See if we should enable/disable passthrough due // to it. m_streaminfo.samplerate = audioframe.format.m_sampleRate; if (SwitchCodecIfNeeded()) { break; } } // demuxer reads metatags that influence channel layout if (m_streaminfo.codec == AV_CODEC_ID_FLAC && m_streaminfo.channellayout) audioframe.format.m_channelLayout = CAEUtil::GetAEChannelLayout(m_streaminfo.channellayout); // we have succesfully decoded an audio frame, setup renderer to match if (!m_dvdAudio.IsValidFormat(audioframe)) { if(m_speed) m_dvdAudio.Drain(); m_dvdAudio.Destroy(); if (!m_dvdAudio.Create(audioframe, m_streaminfo.codec, m_setsynctype == SYNC_RESAMPLE)) CLog::Log(LOGERROR, "%s - failed to create audio renderer", __FUNCTION__); if (m_syncState == IDVDStreamPlayer::SYNC_INSYNC) m_dvdAudio.Resume(); m_streaminfo.channels = audioframe.format.m_channelLayout.Count(); m_messageParent.Put(new CDVDMsg(CDVDMsg::PLAYER_AVCHANGE)); } // Zero out the frame data if we are supposed to silence the audio if (m_silence) { int size = audioframe.nb_frames * audioframe.framesize / audioframe.planes; for (unsigned int i=0; i<audioframe.planes; i++) memset(audioframe.data[i], 0, size); } SetSyncType(audioframe.passthrough); if (!bPacketDrop) { OutputPacket(audioframe); // signal to our parent that we have initialized if(m_syncState == IDVDStreamPlayer::SYNC_STARTING) { double cachetotal = DVD_SEC_TO_TIME(m_dvdAudio.GetCacheTotal()); double cachetime = m_dvdAudio.GetDelay(); if (cachetime >= cachetotal * 0.5) { m_syncState = IDVDStreamPlayer::SYNC_WAITSYNC; m_stalled = false; SStartMsg msg; msg.player = VideoPlayer_AUDIO; msg.cachetotal = cachetotal; msg.cachetime = cachetime; msg.timestamp = audioframe.hasTimestamp ? audioframe.pts : DVD_NOPTS_VALUE; m_messageParent.Put(new CDVDMsgType<SStartMsg>(CDVDMsg::PLAYER_STARTED, msg)); } } } // guess next pts m_audioClock += audioframe.duration; int ret = m_pAudioCodec->Decode(nullptr, 0, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE); if (ret < 0) { CLog::Log(LOGERROR, "CVideoPlayerAudio::DecodeFrame - Decode Error. Skipping audio packet (%d)", ret); m_pAudioCodec->Reset(); break; } } // while decoder produces output } // demuxer packet pMsg->Release(); } }
void CDVDPlayerVideo::Process() { CLog::Log(LOGNOTICE, "running thread: video_thread"); DVDVideoPicture picture; CPulldownCorrection pulldown; CDVDVideoPPFFmpeg mPostProcess(""); CStdString sPostProcessType; bool bPostProcessDeint = false; memset(&picture, 0, sizeof(DVDVideoPicture)); double pts = 0; double frametime = (double)DVD_TIME_BASE / m_fFrameRate; int iDropped = 0; //frames dropped in a row bool bRequestDrop = false; m_videoStats.Start(); while (!m_bStop) { int iQueueTimeOut = (int)(m_stalled ? frametime / 4 : frametime * 10) / 1000; int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0; CDVDMsg* pMsg; MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, iQueueTimeOut, iPriority); if (MSGQ_IS_ERROR(ret)) { CLog::Log(LOGERROR, "Got MSGQ_ABORT or MSGO_IS_ERROR return true"); break; } else if (ret == MSGQ_TIMEOUT) { // if we only wanted priority messages, this isn't a stall if( iPriority ) continue; //Okey, start rendering at stream fps now instead, we are likely in a stillframe if( !m_stalled ) { if(m_started) CLog::Log(LOGINFO, "CDVDPlayerVideo - Stillframe detected, switching to forced %f fps", m_fFrameRate); m_stalled = true; pts+= frametime*4; } //Waiting timed out, output last picture if( picture.iFlags & DVP_FLAG_ALLOCATED ) { //Remove interlaced flag before outputting //no need to output this as if it was interlaced picture.iFlags &= ~DVP_FLAG_INTERLACED; picture.iFlags |= DVP_FLAG_NOSKIP; OutputPicture(&picture, pts); pts+= frametime; } continue; } if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait(100, SYNCSOURCE_VIDEO)) { CLog::Log(LOGDEBUG, "CDVDPlayerVideo - CDVDMsg::GENERAL_SYNCHRONIZE"); /* we may be very much off correct pts here, but next picture may be a still*/ /* make sure it isn't dropped */ m_iNrOfPicturesNotToSkip = 5; } else m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */ pMsg->Release(); continue; } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg; if(pMsgGeneralResync->m_timestamp != DVD_NOPTS_VALUE) pts = pMsgGeneralResync->m_timestamp; double delay = m_FlipTimeStamp - m_pClock->GetAbsoluteClock(); if( delay > frametime ) delay = frametime; else if( delay < 0 ) delay = 0; if(pMsgGeneralResync->m_clock) { CLog::Log(LOGDEBUG, "CDVDPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, 1)", pts); m_pClock->Discontinuity(pts - delay); } else CLog::Log(LOGDEBUG, "CDVDPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, 0)", pts); pMsgGeneralResync->Release(); continue; } else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY)) { if (m_speed != DVD_PLAYSPEED_PAUSE) { double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "CDVDPlayerVideo - CDVDMsg::GENERAL_DELAY(%f)", timeout); timeout *= (double)DVD_PLAYSPEED_NORMAL / abs(m_speed); timeout += CDVDClock::GetAbsoluteClock(); while(!m_bStop && CDVDClock::GetAbsoluteClock() < timeout) Sleep(1); } } else if (pMsg->IsType(CDVDMsg::VIDEO_SET_ASPECT)) { CLog::Log(LOGDEBUG, "CDVDPlayerVideo - CDVDMsg::VIDEO_SET_ASPECT"); m_fForcedAspectRatio = *((CDVDMsgDouble*)pMsg); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { if(m_pVideoCodec) m_pVideoCodec->Reset(); picture.iFlags &= ~DVP_FLAG_ALLOCATED; m_packets.clear(); m_started = false; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush()) { if(m_pVideoCodec) m_pVideoCodec->Reset(); picture.iFlags &= ~DVP_FLAG_ALLOCATED; m_packets.clear(); m_pullupCorrection.Flush(); //we need to recalculate the framerate //TODO: this needs to be set on a streamchange instead ResetFrameRateCalc(); m_stalled = true; m_started = false; } else if (pMsg->IsType(CDVDMsg::VIDEO_NOSKIP)) { // libmpeg2 is also returning incomplete frames after a dvd cell change // so the first few pictures are not the correct ones to display in some cases // just display those together with the correct one. // (setting it to 2 will skip some menu stills, 5 is working ok for me). m_iNrOfPicturesNotToSkip = 5; } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; if(m_speed == DVD_PLAYSPEED_PAUSE) m_iNrOfPicturesNotToSkip = 0; if (m_pVideoCodec) m_pVideoCodec->SetSpeed(m_speed); } else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) { if(m_started) m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { CDVDPlayer::SPlayerState& state = ((CDVDMsgType<CDVDPlayer::SPlayerState>*)pMsg)->m_value; if(state.time_src == CDVDPlayer::ETIMESOURCE_CLOCK) state.time = DVD_TIME_TO_MSEC(m_pClock->GetClock(state.timestamp) + state.time_offset); else state.timestamp = CDVDClock::GetAbsoluteClock(); state.player = DVDPLAYER_VIDEO; m_messageParent.Put(pMsg->Acquire()); } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { CDVDMsgVideoCodecChange* msg(static_cast<CDVDMsgVideoCodecChange*>(pMsg)); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; picture.iFlags &= ~DVP_FLAG_ALLOCATED; } if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); if (m_stalled) { CLog::Log(LOGINFO, "CDVDPlayerVideo - Stillframe left, switching to normal playback"); m_stalled = false; //don't allow the first frames after a still to be dropped //sometimes we get multiple stills (long duration frames) after each other //in normal mpegs m_iNrOfPicturesNotToSkip = 5; } else if( iDropped*frametime > DVD_MSEC_TO_TIME(100) && m_iNrOfPicturesNotToSkip == 0 ) { // if we dropped too many pictures in a row, insert a forced picture m_iNrOfPicturesNotToSkip = 1; } if (m_messageQueue.GetDataSize() == 0 || m_speed < 0) { bRequestDrop = false; m_iDroppedRequest = 0; m_iLateFrames = 0; } // if player want's us to drop this packet, do so nomatter what if(bPacketDrop) bRequestDrop = true; // tell codec if next frame should be dropped // problem here, if one packet contains more than one frame // both frames will be dropped in that case instead of just the first // decoder still needs to provide an empty image structure, with correct flags m_pVideoCodec->SetDropState(bRequestDrop); // ask codec to do deinterlacing if possible EDEINTERLACEMODE mDeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; EINTERLACEMETHOD mInt = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod); unsigned int mFilters = 0; if (mDeintMode != VS_DEINTERLACEMODE_OFF) { if (mInt == VS_INTERLACEMETHOD_DEINTERLACE) mFilters = CDVDVideoCodec::FILTER_DEINTERLACE_ANY; else if(mInt == VS_INTERLACEMETHOD_DEINTERLACE_HALF) mFilters = CDVDVideoCodec::FILTER_DEINTERLACE_ANY | CDVDVideoCodec::FILTER_DEINTERLACE_HALFED; if (mDeintMode == VS_DEINTERLACEMODE_AUTO && mFilters) mFilters |= CDVDVideoCodec::FILTER_DEINTERLACE_FLAGGED; } if (!g_renderManager.Supports(RENDERFEATURE_ROTATION)) mFilters |= CDVDVideoCodec::FILTER_ROTATE; mFilters = m_pVideoCodec->SetFilters(mFilters); int iDecoderState = m_pVideoCodec->Decode(pPacket->pData, pPacket->iSize, pPacket->dts, pPacket->pts); // buffer packets so we can recover should decoder flush for some reason if(m_pVideoCodec->GetConvergeCount() > 0) { m_packets.push_back(DVDMessageListItem(pMsg, 0)); if(m_packets.size() > m_pVideoCodec->GetConvergeCount() || m_packets.size() * frametime > DVD_SEC_TO_TIME(10)) m_packets.pop_front(); } m_videoStats.AddSampleBytes(pPacket->iSize); // assume decoder dropped a picture if it didn't give us any // picture from a demux packet, this should be reasonable // for libavformat as a demuxer as it normally packetizes // pictures when they come from demuxer if(bRequestDrop && !bPacketDrop && (iDecoderState & VC_BUFFER) && !(iDecoderState & VC_PICTURE)) { m_iDroppedFrames++; iDropped++; } // reset the request, the following while loop may break before // setting the flag to a new value bRequestDrop = false; // loop while no error while (!m_bStop) { // if decoder was flushed, we need to seek back again to resume rendering if (iDecoderState & VC_FLUSHED) { CLog::Log(LOGDEBUG, "CDVDPlayerVideo - video decoder was flushed"); while(!m_packets.empty()) { CDVDMsgDemuxerPacket* msg = (CDVDMsgDemuxerPacket*)m_packets.front().message->Acquire(); m_packets.pop_front(); // all packets except the last one should be dropped // if prio packets and current packet should be dropped, this is likely a new reset msg->m_drop = !m_packets.empty() || (iPriority > 0 && bPacketDrop); m_messageQueue.Put(msg, iPriority + 10); } m_pVideoCodec->Reset(); m_packets.clear(); picture.iFlags &= ~DVP_FLAG_ALLOCATED; g_renderManager.DiscardBuffer(); break; } // if decoder had an error, tell it to reset to avoid more problems if (iDecoderState & VC_ERROR) { CLog::Log(LOGDEBUG, "CDVDPlayerVideo - video decoder returned error"); break; } // check for a new picture if (iDecoderState & VC_PICTURE) { // try to retrieve the picture (should never fail!), unless there is a demuxer bug ofcours m_pVideoCodec->ClearPicture(&picture); if (m_pVideoCodec->GetPicture(&picture)) { sPostProcessType.clear(); if(picture.iDuration == 0.0) picture.iDuration = frametime; if(bPacketDrop) picture.iFlags |= DVP_FLAG_DROPPED; if (m_iNrOfPicturesNotToSkip > 0) { picture.iFlags |= DVP_FLAG_NOSKIP; m_iNrOfPicturesNotToSkip--; } // validate picture timing, // if both dts/pts invalid, use pts calulated from picture.iDuration // if pts invalid use dts, else use picture.pts as passed if (picture.dts == DVD_NOPTS_VALUE && picture.pts == DVD_NOPTS_VALUE) picture.pts = pts; else if (picture.pts == DVD_NOPTS_VALUE) picture.pts = picture.dts; /* use forced aspect if any */ if( m_fForcedAspectRatio != 0.0f ) picture.iDisplayWidth = (int) (picture.iDisplayHeight * m_fForcedAspectRatio); //Deinterlace if codec said format was interlaced or if we have selected we want to deinterlace //this video if ((mDeintMode == VS_DEINTERLACEMODE_AUTO && (picture.iFlags & DVP_FLAG_INTERLACED)) || mDeintMode == VS_DEINTERLACEMODE_FORCE) { if(mInt == VS_INTERLACEMETHOD_SW_BLEND) { if (!sPostProcessType.empty()) sPostProcessType += ","; sPostProcessType += g_advancedSettings.m_videoPPFFmpegDeint; bPostProcessDeint = true; } } if (CMediaSettings::Get().GetCurrentVideoSettings().m_PostProcess) { if (!sPostProcessType.empty()) sPostProcessType += ","; // This is what mplayer uses for its "high-quality filter combination" sPostProcessType += g_advancedSettings.m_videoPPFFmpegPostProc; } if (!sPostProcessType.empty()) { mPostProcess.SetType(sPostProcessType, bPostProcessDeint); if (mPostProcess.Process(&picture)) mPostProcess.GetPicture(&picture); } /* if frame has a pts (usually originiating from demux packet), use that */ if(picture.pts != DVD_NOPTS_VALUE) { if(pulldown.enabled()) picture.pts += pulldown.pts(); pts = picture.pts; } if(pulldown.enabled()) { picture.iDuration = pulldown.dur(); pulldown.next(); } if (picture.iRepeatPicture) picture.iDuration *= picture.iRepeatPicture + 1; int iResult = OutputPicture(&picture, pts); if(m_started == false) { m_codecname = m_pVideoCodec->GetName(); m_started = true; m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); } // guess next frame pts. iDuration is always valid if (m_speed != 0) pts += picture.iDuration * m_speed / abs(m_speed); if( iResult & EOS_ABORT ) { //if we break here and we directly try to decode again wihout //flushing the video codec things break for some reason //i think the decoder (libmpeg2 atleast) still has a pointer //to the data, and when the packet is freed that will fail. iDecoderState = m_pVideoCodec->Decode(NULL, 0, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE); break; } if( (iResult & EOS_DROPPED) && !bPacketDrop ) { m_iDroppedFrames++; iDropped++; } else iDropped = 0; bRequestDrop = (iResult & EOS_VERYLATE) == EOS_VERYLATE; } else { CLog::Log(LOGWARNING, "Decoder Error getting videoPicture."); m_pVideoCodec->Reset(); } } /* if (iDecoderState & VC_USERDATA) { // found some userdata while decoding a frame // could be closed captioning DVDVideoUserData videoUserData; if (m_pVideoCodec->GetUserData(&videoUserData)) { ProcessVideoUserData(&videoUserData, pts); } } */ // if the decoder needs more data, we just break this loop // and try to get more data from the videoQueue if (iDecoderState & VC_BUFFER) break; // the decoder didn't need more data, flush the remaning buffer iDecoderState = m_pVideoCodec->Decode(NULL, 0, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE); } } // all data is used by the decoder, we can safely free it now pMsg->Release(); } // we need to let decoder release any picture retained resources. m_pVideoCodec->ClearPicture(&picture); }
// decode one audio frame and returns its uncompressed size int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &audioframe) { int result = 0; // make sure the sent frame is clean audioframe.nb_frames = 0; while (!m_bStop) { bool switched = false; /* NOTE: the audio packet can contain several frames */ while( !m_bStop && m_decode.size > 0 ) { if( !m_pAudioCodec ) return DECODE_FLAG_ERROR; /* the packet dts refers to the first audioframe that starts in the packet */ double dts = m_ptsInput.Get(m_decode.size + m_pAudioCodec->GetBufferSize(), true); if (dts != DVD_NOPTS_VALUE) m_audioClock = dts; int len = m_pAudioCodec->Decode(m_decode.data, m_decode.size); if (len < 0 || len > m_decode.size) { /* if error, we skip the packet */ CLog::Log(LOGERROR, "CDVDPlayerAudio::DecodeFrame - Decode Error. Skipping audio packet (%d)", len); m_decode.Release(); m_pAudioCodec->Reset(); return DECODE_FLAG_ERROR; } m_audioStats.AddSampleBytes(len); m_decode.data += len; m_decode.size -= len; // get decoded data and the size of it m_pAudioCodec->GetData(audioframe); if (audioframe.nb_frames == 0) continue; if (audioframe.pts == DVD_NOPTS_VALUE) audioframe.pts = m_audioClock; if (audioframe.encoded_sample_rate && m_streaminfo.samplerate != audioframe.encoded_sample_rate) { // The sample rate has changed or we just got it for the first time // for this stream. See if we should enable/disable passthrough due // to it. m_streaminfo.samplerate = audioframe.encoded_sample_rate; if (!switched && SwitchCodecIfNeeded()) { // passthrough has been enabled/disabled, reprocess the packet m_decode.data -= len; m_decode.size += len; switched = true; continue; } } // increase audioclock to after the packet m_audioClock += audioframe.duration; // if demux source want's us to not display this, continue if(m_decode.msg->GetPacketDrop()) result |= DECODE_FLAG_DROP; return result; } // free the current packet m_decode.Release(); if (m_messageQueue.ReceivedAbortRequest()) return DECODE_FLAG_ABORT; CDVDMsg* pMsg; int timeout = (int)(1000 * m_dvdAudio.GetCacheTime()) + 100; // read next packet and return -1 on error int priority = 1; //Do we want a new audio frame? if (m_started == false /* when not started */ || m_speed == DVD_PLAYSPEED_NORMAL /* when playing normally */ || m_speed < DVD_PLAYSPEED_PAUSE /* when rewinding */ || (m_speed > DVD_PLAYSPEED_NORMAL && m_audioClock < m_pClock->GetClock())) /* when behind clock in ff */ priority = 0; // consider stream stalled if queue is empty // we can't sync audio to clock with an empty queue if (m_speed == DVD_PLAYSPEED_NORMAL) { timeout = 0; } MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, timeout, priority); if (ret == MSGQ_TIMEOUT) return DECODE_FLAG_TIMEOUT; if (MSGQ_IS_ERROR(ret)) return DECODE_FLAG_ABORT; if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { m_decode.Attach((CDVDMsgDemuxerPacket*)pMsg); m_ptsInput.Add( m_decode.size, m_decode.dts ); } else if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait( 100, SYNCSOURCE_AUDIO )) CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_SYNCHRONIZE"); else m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */ } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { //player asked us to set internal clock CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg; CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, %d)" , pMsgGeneralResync->m_timestamp , pMsgGeneralResync->m_clock); if (pMsgGeneralResync->m_timestamp != DVD_NOPTS_VALUE) m_audioClock = pMsgGeneralResync->m_timestamp; m_ptsInput.Flush(); m_dvdAudio.SetPlayingPts(m_audioClock); if (pMsgGeneralResync->m_clock) m_pClock->Discontinuity(m_dvdAudio.GetPlayingPts()); m_syncclock = true; m_errors.Flush(); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { if (m_pAudioCodec) m_pAudioCodec->Reset(); m_decode.Release(); m_started = false; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) { m_dvdAudio.Flush(); m_ptsInput.Flush(); m_syncclock = true; m_stalled = true; m_started = false; if (m_pAudioCodec) m_pAudioCodec->Reset(); m_decode.Release(); } else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) { if(m_started) m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO)); } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { CDVDPlayer::SPlayerState& state = ((CDVDMsgType<CDVDPlayer::SPlayerState>*)pMsg)->m_value; if(state.time_src == CDVDPlayer::ETIMESOURCE_CLOCK) state.time = DVD_TIME_TO_MSEC(m_pClock->GetClock(state.timestamp) + state.time_offset); else state.timestamp = CDVDClock::GetAbsoluteClock(); state.player = DVDPLAYER_AUDIO; m_messageParent.Put(pMsg->Acquire()); } else if (pMsg->IsType(CDVDMsg::GENERAL_EOF)) { CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_EOF"); m_dvdAudio.Finish(); } else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY)) { if (m_speed != DVD_PLAYSPEED_PAUSE) { double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_DELAY(%f)", timeout); timeout *= (double)DVD_PLAYSPEED_NORMAL / abs(m_speed); timeout += CDVDClock::GetAbsoluteClock(); while(!m_bStop && CDVDClock::GetAbsoluteClock() < timeout) Sleep(1); } } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { double speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; if (speed == DVD_PLAYSPEED_NORMAL) { if (speed != m_speed) { m_dvdAudio.Resume(); m_syncclock = true; m_errors.Flush(); } } else { m_dvdAudio.Flush(); m_dvdAudio.Pause(); } m_speed = speed; } else if (pMsg->IsType(CDVDMsg::AUDIO_SILENCE)) { m_silence = static_cast<CDVDMsgBool*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, %d)" , m_audioClock, m_silence); } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { CDVDMsgAudioCodecChange* msg(static_cast<CDVDMsgAudioCodecChange*>(pMsg)); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; } pMsg->Release(); } return 0; }
void OMXPlayerVideo::Process() { double pts = 0; double frametime = (double)DVD_TIME_BASE / m_fFrameRate; bool bRequestDrop = false; m_videoStats.Start(); while(!m_bStop) { CDVDMsg* pMsg; int iQueueTimeOut = (int)(m_stalled ? frametime / 4 : frametime * 10) / 1000; int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0; MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, iQueueTimeOut, iPriority); if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT) { CLog::Log(LOGERROR, "Got MSGQ_ABORT or MSGO_IS_ERROR return true"); break; } else if (ret == MSGQ_TIMEOUT) { // if we only wanted priority messages, this isn't a stall if( iPriority ) continue; //Okey, start rendering at stream fps now instead, we are likely in a stillframe if( !m_stalled ) { if(m_started) CLog::Log(LOGINFO, "COMXPlayerVideo - Stillframe detected, switching to forced %f fps", m_fFrameRate); m_stalled = true; pts += frametime*4; } pts += frametime; continue; } if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait(100, SYNCSOURCE_VIDEO)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_SYNCHRONIZE"); } else m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */ pMsg->Release(); continue; } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg; if(pMsgGeneralResync->m_timestamp != DVD_NOPTS_VALUE) pts = pMsgGeneralResync->m_timestamp; double delay = m_FlipTimeStamp - m_av_clock->GetAbsoluteClock(); if( delay > frametime ) delay = frametime; else if( delay < 0 ) delay = 0; if(pMsgGeneralResync->m_clock) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, 1)", pts); m_av_clock->Discontinuity(pts - delay); //m_av_clock->OMXUpdateClock(pts - delay); } else CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, 0)", pts); pMsgGeneralResync->Release(); continue; } else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY)) { if (m_speed != DVD_PLAYSPEED_PAUSE) { double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_DELAY(%f)", timeout); timeout *= (double)DVD_PLAYSPEED_NORMAL / abs(m_speed); timeout += m_av_clock->GetAbsoluteClock(); while(!m_bStop && m_av_clock->GetAbsoluteClock() < timeout) Sleep(1); } } else if (pMsg->IsType(CDVDMsg::VIDEO_SET_ASPECT)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::VIDEO_SET_ASPECT"); m_fForcedAspectRatio = *((CDVDMsgDouble*)pMsg); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESET"); m_av_clock->Lock(); m_av_clock->OMXStop(false); m_omxVideo.Reset(); m_av_clock->OMXReset(false); m_av_clock->UnLock(); m_started = false; m_iSleepEndTime = DVD_NOPTS_VALUE; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush()) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_FLUSH"); m_stalled = true; m_started = false; m_iSleepEndTime = DVD_NOPTS_VALUE; m_av_clock->Lock(); m_av_clock->OMXStop(false); m_omxVideo.Reset(); m_av_clock->OMXReset(false); m_av_clock->UnLock(); } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; } else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) { if(m_started) m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { COMXMsgVideoCodecChange* msg(static_cast<COMXMsgVideoCodecChange*>(pMsg)); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; } else if (pMsg->IsType(CDVDMsg::GENERAL_EOF) && !m_audio_count) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_EOF"); WaitCompletion(); } else if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); if (m_messageQueue.GetDataSize() == 0 || m_speed < 0) { bRequestDrop = false; } // if player want's us to drop this packet, do so nomatter what if(bPacketDrop) bRequestDrop = true; m_omxVideo.SetDropState(bRequestDrop); while (!m_bStop) { if((int)m_omxVideo.GetFreeSpace() < pPacket->iSize) { Sleep(10); continue; } if (m_stalled) { CLog::Log(LOGINFO, "COMXPlayerVideo - Stillframe left, switching to normal playback"); m_stalled = false; } double output_pts = 0; // validate picture timing, // if both dts/pts invalid, use pts calulated from picture.iDuration // if pts invalid use dts, else use picture.pts as passed if (pPacket->dts == DVD_NOPTS_VALUE && pPacket->pts == DVD_NOPTS_VALUE) output_pts = pts; else if (pPacket->pts == DVD_NOPTS_VALUE) output_pts = pts; else output_pts = pPacket->pts; if(pPacket->pts != DVD_NOPTS_VALUE) pPacket->pts += m_iVideoDelay; if(pPacket->dts != DVD_NOPTS_VALUE) pPacket->dts += m_iVideoDelay; if(pPacket->duration == 0) pPacket->duration = frametime; if(output_pts != DVD_NOPTS_VALUE) pts = output_pts; m_omxVideo.Decode(pPacket->pData, pPacket->iSize, pPacket->dts, pPacket->pts); Output(pPacket->iGroupId, output_pts, bRequestDrop); if(m_started == false) { m_codecname = m_omxVideo.GetDecoderName(); m_started = true; m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); } // guess next frame pts. iDuration is always valid if (m_speed != 0) pts += pPacket->duration * m_speed / abs(m_speed); break; } bRequestDrop = false; m_videoStats.AddSampleBytes(pPacket->iSize); } pMsg->Release(); } }
void OMXPlayerVideo::Process() { double pts = 0; double frametime = (double)DVD_TIME_BASE / m_fFrameRate; bool bRequestDrop = false; m_videoStats.Start(); while(!m_bStop) { CDVDMsg* pMsg; int iQueueTimeOut = (int)(m_stalled ? frametime / 4 : frametime * 10) / 1000; int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0; MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, iQueueTimeOut, iPriority); if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT) { CLog::Log(LOGERROR, "OMXPlayerVideo: Got MSGQ_IS_ERROR(%d) Aborting", (int)ret); break; } else if (ret == MSGQ_TIMEOUT) { continue; } if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait(100, SYNCSOURCE_VIDEO)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_SYNCHRONIZE"); } else m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */ pMsg->Release(); continue; } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg; if(pMsgGeneralResync->m_timestamp != DVD_NOPTS_VALUE) pts = pMsgGeneralResync->m_timestamp; double delay = m_FlipTimeStamp - m_av_clock->GetAbsoluteClock(); if( delay > frametime ) delay = frametime; else if( delay < 0 ) delay = 0; if(pMsgGeneralResync->m_clock) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, 1)", pts); m_av_clock->Discontinuity(pts - delay); //m_av_clock->OMXUpdateClock(pts - delay); } else CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, 0)", pts); pMsgGeneralResync->Release(); continue; } else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY)) { if (m_speed != DVD_PLAYSPEED_PAUSE) { double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_DELAY(%f)", timeout); timeout *= (double)DVD_PLAYSPEED_NORMAL / abs(m_speed); timeout += m_av_clock->GetAbsoluteClock(); while(!m_bStop && m_av_clock->GetAbsoluteClock() < timeout) Sleep(1); } } else if (pMsg->IsType(CDVDMsg::VIDEO_SET_ASPECT)) { m_fForcedAspectRatio = *((CDVDMsgDouble*)pMsg); CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::VIDEO_SET_ASPECT %.2f", m_fForcedAspectRatio); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESET"); m_av_clock->Lock(); m_av_clock->OMXStop(false); m_omxVideo.Reset(); m_av_clock->OMXReset(false); m_av_clock->UnLock(); m_started = false; m_iSleepEndTime = DVD_NOPTS_VALUE; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush()) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_FLUSH"); m_stalled = true; m_started = false; m_iSleepEndTime = DVD_NOPTS_VALUE; m_av_clock->Lock(); m_av_clock->OMXStop(false); m_omxVideo.Reset(); m_av_clock->OMXReset(false); m_av_clock->UnLock(); m_flush = false; } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { if (m_speed != static_cast<CDVDMsgInt*>(pMsg)->m_value) { m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::PLAYER_SETSPEED %d", m_speed); } } else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::PLAYER_STARTED %d", m_started); if(m_started) m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { COMXPlayer::SPlayerState& state = ((CDVDMsgType<COMXPlayer::SPlayerState>*)pMsg)->m_value; if(state.time_src == COMXPlayer::ETIMESOURCE_CLOCK) state.time = DVD_TIME_TO_MSEC(m_av_clock->OMXMediaTime(true)); //state.time = DVD_TIME_TO_MSEC(m_av_clock->GetClock(state.timestamp) + state.time_offset); else state.timestamp = m_av_clock->GetAbsoluteClock(); state.player = DVDPLAYER_VIDEO; m_messageParent.Put(pMsg->Acquire()); } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { COMXMsgVideoCodecChange* msg(static_cast<COMXMsgVideoCodecChange*>(pMsg)); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; } else if (pMsg->IsType(CDVDMsg::GENERAL_EOF) && !m_audio_count) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_EOF"); WaitCompletion(); } else if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); #ifdef _DEBUG CLog::Log(LOGINFO, "Video: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d\n", pPacket->dts, pPacket->pts, (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, m_av_clock->OMXLateCount(1)); #endif if (m_messageQueue.GetDataSize() == 0 || m_speed < 0) { bRequestDrop = false; } // if player want's us to drop this packet, do so nomatter what if(bPacketDrop) bRequestDrop = true; m_omxVideo.SetDropState(bRequestDrop); while (!m_bStop) { // discard if flushing as clocks may be stopped and we'll never submit it if (m_flush) break; if((int)m_omxVideo.GetFreeSpace() < pPacket->iSize) { Sleep(10); continue; } if (m_stalled) { CLog::Log(LOGINFO, "COMXPlayerVideo - Stillframe left, switching to normal playback"); m_stalled = false; } double output_pts = 0; // validate picture timing, // if both dts/pts invalid, use pts calulated from picture.iDuration // if pts invalid use dts, else use picture.pts as passed if (pPacket->dts == DVD_NOPTS_VALUE && pPacket->pts == DVD_NOPTS_VALUE) output_pts = pts; else if (pPacket->pts == DVD_NOPTS_VALUE) output_pts = pts; else output_pts = pPacket->pts; if(pPacket->pts != DVD_NOPTS_VALUE) pPacket->pts += m_iVideoDelay; if(pPacket->dts != DVD_NOPTS_VALUE) pPacket->dts += m_iVideoDelay; if(pPacket->duration == 0) pPacket->duration = frametime; if(output_pts != DVD_NOPTS_VALUE) pts = output_pts; m_omxVideo.Decode(pPacket->pData, pPacket->iSize, pPacket->dts, pPacket->pts); Output(pPacket->iGroupId, output_pts, bRequestDrop); if(m_started == false) { m_codecname = m_omxVideo.GetDecoderName(); m_started = true; m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); } // guess next frame pts. iDuration is always valid if (m_speed != 0) pts += pPacket->duration * m_speed / abs(m_speed); break; } bRequestDrop = false; m_videoStats.AddSampleBytes(pPacket->iSize); } pMsg->Release(); } }
void OMXPlayerVideo::Process() { double frametime = (double)DVD_TIME_BASE / m_fFrameRate; bool bRequestDrop = false; bool settings_changed = false; m_videoStats.Start(); while(!m_bStop) { int iQueueTimeOut = (int)(m_stalled ? frametime / 4 : frametime * 10) / 1000; int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0; if (m_started && !m_sync) iPriority = 1; CDVDMsg* pMsg; MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, iQueueTimeOut, iPriority); if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT) { CLog::Log(LOGERROR, "OMXPlayerVideo: Got MSGQ_IS_ERROR(%d) Aborting", (int)ret); break; } else if (ret == MSGQ_TIMEOUT) { continue; } if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait(100, SYNCSOURCE_VIDEO)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_SYNCHRONIZE"); } else m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */ pMsg->Release(); continue; } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { double pts = static_cast<CDVDMsgDouble*>(pMsg)->m_value; m_nextOverlay = DVD_NOPTS_VALUE; m_iCurrentPts = DVD_NOPTS_VALUE; m_sync = true; CLog::Log(LOGDEBUG, "CVideoPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f)", pts); } else if (pMsg->IsType(CDVDMsg::VIDEO_SET_ASPECT)) { m_fForcedAspectRatio = *((CDVDMsgDouble*)pMsg); CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::VIDEO_SET_ASPECT %.2f", m_fForcedAspectRatio); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESET"); m_started = false; m_nextOverlay = DVD_NOPTS_VALUE; m_iCurrentPts = DVD_NOPTS_VALUE; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush()) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_FLUSH"); m_stalled = true; m_started = false; m_nextOverlay = DVD_NOPTS_VALUE; m_iCurrentPts = DVD_NOPTS_VALUE; m_omxVideo.Reset(); m_flush = false; } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { if (m_speed != static_cast<CDVDMsgInt*>(pMsg)->m_value) { m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::PLAYER_SETSPEED %d", m_speed); } } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { SPlayerState& state = ((CDVDMsgType<SPlayerState>*)pMsg)->m_value; state.player = VideoPlayer_VIDEO; if (m_speed != DVD_PLAYSPEED_NORMAL && m_speed != DVD_PLAYSPEED_PAUSE) { if(state.time_src == ETIMESOURCE_CLOCK) state.time = DVD_TIME_TO_MSEC(m_av_clock->GetClock(state.timestamp) + state.time_offset); else state.timestamp = CDVDClock::GetAbsoluteClock(); } else { double pts = m_iCurrentPts; double stamp = m_av_clock->OMXMediaTime(); if(state.time_src == ETIMESOURCE_CLOCK) state.time = stamp == 0.0 ? state.time : DVD_TIME_TO_MSEC(stamp + state.time_offset); else state.time = stamp == 0.0 || pts == DVD_NOPTS_VALUE ? state.time : state.time + DVD_TIME_TO_MSEC(stamp - pts); state.timestamp = CDVDClock::GetAbsoluteClock(); if (stamp == 0.0) // cause message to be ignored state.player = 0; } m_messageParent.Put(pMsg->Acquire()); } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { COMXMsgVideoCodecChange* msg(static_cast<COMXMsgVideoCodecChange*>(pMsg)); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; } else if (pMsg->IsType(CDVDMsg::GENERAL_EOF)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_EOF"); SubmitEOS(); } else if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); #ifdef _DEBUG CLog::Log(LOGINFO, "Video: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d\n", pPacket->dts, pPacket->pts, (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, 0); #endif if (m_messageQueue.GetDataSize() == 0 || m_speed < 0) { bRequestDrop = false; } // if player want's us to drop this packet, do so nomatter what if(bPacketDrop) bRequestDrop = true; m_omxVideo.SetDropState(bRequestDrop); while (!m_bStop) { // discard if flushing as clocks may be stopped and we'll never submit it if (m_flush) break; if((int)m_omxVideo.GetFreeSpace() < pPacket->iSize) { Sleep(10); continue; } if (m_stalled) { CLog::Log(LOGINFO, "COMXPlayerVideo - Stillframe left, switching to normal playback"); m_stalled = false; } double dts = pPacket->dts; double pts = pPacket->pts; if (dts != DVD_NOPTS_VALUE) dts += m_iVideoDelay - DVD_SEC_TO_TIME(m_renderManager.GetDisplayLatency()); if (pts != DVD_NOPTS_VALUE) pts += m_iVideoDelay - DVD_SEC_TO_TIME(m_renderManager.GetDisplayLatency()); m_omxVideo.Decode(pPacket->pData, pPacket->iSize, dts, m_hints.ptsinvalid ? DVD_NOPTS_VALUE : pts, settings_changed); if (pts == DVD_NOPTS_VALUE) pts = dts; Output(pts, bRequestDrop); if(pts != DVD_NOPTS_VALUE) m_iCurrentPts = pts; if (m_started == false && !bRequestDrop && settings_changed) { m_codecname = m_omxVideo.GetDecoderName(); m_started = true; m_sync = false; SStartMsg msg; msg.player = VideoPlayer_VIDEO; msg.cachetime = DVD_MSEC_TO_TIME(50); // TODO msg.cachetotal = DVD_MSEC_TO_TIME(100); // TODO msg.timestamp = pts; m_messageParent.Put(new CDVDMsgType<SStartMsg>(CDVDMsg::PLAYER_STARTED, msg)); } break; } bRequestDrop = false; m_videoStats.AddSampleBytes(pPacket->iSize); } pMsg->Release(); } }
void OMXPlayerAudio::Process() { m_audioStats.Start(); while(!m_bStop) { CDVDMsg* pMsg; int priority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0; int timeout = 1000; MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, timeout, priority); if (ret == MSGQ_TIMEOUT) { Sleep(10); continue; } if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT) { Sleep(10); continue; } if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); #ifdef _DEBUG CLog::Log(LOGINFO, "Audio: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d,%d", pPacket->dts, pPacket->pts, (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, (int)m_omxAudio.GetAudioRenderingLatency(), (int)m_hints_current.samplerate); #endif if(Decode(pPacket, m_speed > DVD_PLAYSPEED_NORMAL || m_speed < 0 || bPacketDrop)) { // we are not running until something is cached in output device if(m_stalled && m_omxAudio.GetCacheTime() > 0.0) { CLog::Log(LOGINFO, "COMXPlayerAudio - Switching to normal playback"); m_stalled = false; } } } else if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait( 100, SYNCSOURCE_AUDIO )) CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_SYNCHRONIZE"); else m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */ } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { //player asked us to set internal clock CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg; CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, %d)", m_audioClock, pMsgGeneralResync->m_clock); m_flush = false; m_audioClock = DVD_NOPTS_VALUE; } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESET"); if (m_pAudioCodec) m_pAudioCodec->Reset(); m_omxAudio.Flush(); m_started = false; m_audioClock = DVD_NOPTS_VALUE; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) { CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_FLUSH"); m_omxAudio.Flush(); m_stalled = true; m_started = false; if (m_pAudioCodec) m_pAudioCodec->Reset(); m_audioClock = DVD_NOPTS_VALUE; } else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) { CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::PLAYER_STARTED %d", m_started); if(m_started) m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO)); } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { COMXPlayer::SPlayerState& state = ((CDVDMsgType<COMXPlayer::SPlayerState>*)pMsg)->m_value; if(state.time_src == COMXPlayer::ETIMESOURCE_CLOCK) state.time = DVD_TIME_TO_MSEC(m_av_clock->OMXMediaTime()); //state.time = DVD_TIME_TO_MSEC(m_av_clock->GetClock(state.timestamp) + state.time_offset); else state.timestamp = m_av_clock->GetAbsoluteClock(); state.player = DVDPLAYER_AUDIO; m_messageParent.Put(pMsg->Acquire()); } else if (pMsg->IsType(CDVDMsg::GENERAL_EOF)) { CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_EOF"); SubmitEOS(); } else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY)) { double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_DELAY(%f)", timeout); } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { if (m_speed != static_cast<CDVDMsgInt*>(pMsg)->m_value) { m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::PLAYER_SETSPEED %d", m_speed); } } else if (pMsg->IsType(CDVDMsg::AUDIO_SILENCE)) { m_silence = static_cast<CDVDMsgBool*>(pMsg)->m_value; if (m_silence) CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 1)", m_audioClock); else CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 0)", m_audioClock); } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { COMXMsgAudioCodecChange* msg(static_cast<COMXMsgAudioCodecChange*>(pMsg)); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; } pMsg->Release(); } }
void CVideoPlayerVideo::Process() { CLog::Log(LOGNOTICE, "running thread: video_thread"); memset(&m_picture, 0, sizeof(VideoPicture)); double pts = 0; double frametime = (double)DVD_TIME_BASE / m_fFrameRate; bool bRequestDrop = false; int iDropDirective; bool onlyPrioMsgs = false; m_videoStats.Start(); m_droppingStats.Reset(); m_iDroppedFrames = 0; m_rewindStalled = false; m_outputSate = OUTPUT_NORMAL; while (!m_bStop) { int iQueueTimeOut = (int)(m_stalled ? frametime : frametime * 10) / 1000; int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_syncState == IDVDStreamPlayer::SYNC_INSYNC) ? 1 : 0; if (m_syncState == IDVDStreamPlayer::SYNC_WAITSYNC) iPriority = 1; if (m_paused) iPriority = 1; if (onlyPrioMsgs) { iPriority = 1; iQueueTimeOut = 1; } CDVDMsg* pMsg; MsgQueueReturnCode ret = GetMessage(&pMsg, iQueueTimeOut, iPriority); onlyPrioMsgs = false; if (MSGQ_IS_ERROR(ret)) { CLog::Log(LOGERROR, "Got MSGQ_ABORT or MSGO_IS_ERROR return true"); break; } else if (ret == MSGQ_TIMEOUT) { if (m_outputSate == OUTPUT_AGAIN && m_picture.videoBuffer) { m_outputSate = OutputPicture(&m_picture); if (m_outputSate == OUTPUT_AGAIN) { onlyPrioMsgs = true; continue; } } // don't ask for a new frame if we can't deliver it to renderer else if ((m_speed != DVD_PLAYSPEED_PAUSE || m_syncState != IDVDStreamPlayer::SYNC_INSYNC) && !m_paused) { if (ProcessDecoderOutput(frametime, pts)) { onlyPrioMsgs = true; continue; } } // if we only wanted priority messages, this isn't a stall if (iPriority) continue; //Okey, start rendering at stream fps now instead, we are likely in a stillframe if (!m_stalled) { // squeeze pictures out while (!m_bStop && m_pVideoCodec) { m_pVideoCodec->SetCodecControl(DVD_CODEC_CTRL_DRAIN); if (!ProcessDecoderOutput(frametime, pts)) break; } CLog::Log(LOGINFO, "CVideoPlayerVideo - Stillframe detected, switching to forced %f fps", m_fFrameRate); m_stalled = true; pts += frametime * 4; } // Waiting timed out, output last picture if (m_picture.videoBuffer) { m_picture.pts = pts; m_outputSate = OutputPicture(&m_picture); pts += frametime; } continue; } if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if (static_cast<CDVDMsgGeneralSynchronize*>(pMsg)->Wait(100, SYNCSOURCE_VIDEO)) { CLog::Log(LOGDEBUG, "CVideoPlayerVideo - CDVDMsg::GENERAL_SYNCHRONIZE"); } else SendMessage(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */ m_droppingStats.Reset(); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { pts = static_cast<CDVDMsgDouble*>(pMsg)->m_value; m_syncState = IDVDStreamPlayer::SYNC_INSYNC; m_droppingStats.Reset(); m_rewindStalled = false; CLog::Log(LOGDEBUG, "CVideoPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f)", pts); } else if (pMsg->IsType(CDVDMsg::VIDEO_SET_ASPECT)) { CLog::Log(LOGDEBUG, "CVideoPlayerVideo - CDVDMsg::VIDEO_SET_ASPECT"); m_fForcedAspectRatio = static_cast<float>(*static_cast<CDVDMsgDouble*>(pMsg)); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { if(m_pVideoCodec) m_pVideoCodec->Reset(); if (m_picture.videoBuffer) { m_picture.videoBuffer->Release(); m_picture.videoBuffer = nullptr; } m_packets.clear(); m_droppingStats.Reset(); m_syncState = IDVDStreamPlayer::SYNC_STARTING; m_rewindStalled = false; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CVideoPlayerVideo::Flush()) { bool sync = static_cast<CDVDMsgBool*>(pMsg)->m_value; if(m_pVideoCodec) m_pVideoCodec->Reset(); if (m_picture.videoBuffer) { m_picture.videoBuffer->Release(); m_picture.videoBuffer = nullptr; } m_packets.clear(); pts = 0; m_rewindStalled = false; m_ptsTracker.Flush(); //we need to recalculate the framerate //! @todo this needs to be set on a streamchange instead ResetFrameRateCalc(); m_droppingStats.Reset(); m_stalled = true; if (sync) m_syncState = IDVDStreamPlayer::SYNC_STARTING; m_renderManager.DiscardBuffer(); } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; if (m_pVideoCodec) m_pVideoCodec->SetSpeed(m_speed); m_droppingStats.Reset(); } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { CDVDMsgVideoCodecChange* msg(static_cast<CDVDMsgVideoCodecChange*>(pMsg)); while (!m_bStop && m_pVideoCodec) { m_pVideoCodec->SetCodecControl(DVD_CODEC_CTRL_DRAIN); bool cont = ProcessDecoderOutput(frametime, pts); if (!cont) break; } OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; if (m_picture.videoBuffer) { m_picture.videoBuffer->Release(); m_picture.videoBuffer = nullptr; } } else if (pMsg->IsType(CDVDMsg::VIDEO_DRAIN)) { while (!m_bStop && m_pVideoCodec) { m_pVideoCodec->SetCodecControl(DVD_CODEC_CTRL_DRAIN); if (!ProcessDecoderOutput(frametime, pts)) break; } } else if (pMsg->IsType(CDVDMsg::GENERAL_PAUSE)) { m_paused = static_cast<CDVDMsgBool*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "CVideoPlayerVideo - CDVDMsg::GENERAL_PAUSE: %d", m_paused); } else if (pMsg->IsType(CDVDMsg::PLAYER_REQUEST_STATE)) { SStateMsg msg; msg.player = VideoPlayer_VIDEO; msg.syncState = m_syncState; m_messageParent.Put(new CDVDMsgType<SStateMsg>(CDVDMsg::PLAYER_REPORT_STATE, msg)); } else if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { DemuxPacket* pPacket = static_cast<CDVDMsgDemuxerPacket*>(pMsg)->GetPacket(); bool bPacketDrop = static_cast<CDVDMsgDemuxerPacket*>(pMsg)->GetPacketDrop(); if (m_stalled) { CLog::Log(LOGINFO, "CVideoPlayerVideo - Stillframe left, switching to normal playback"); m_stalled = false; } bRequestDrop = false; iDropDirective = CalcDropRequirement(pts); if ((iDropDirective & DROP_VERYLATE) && m_bAllowDrop && !bPacketDrop) { bRequestDrop = true; } if (iDropDirective & DROP_DROPPED) { m_iDroppedFrames++; m_ptsTracker.Flush(); } if (m_messageQueue.GetDataSize() == 0 || m_speed < 0) { bRequestDrop = false; m_iDroppedRequest = 0; m_iLateFrames = 0; } int codecControl = 0; if (iDropDirective & DROP_BUFFER_LEVEL) codecControl |= DVD_CODEC_CTRL_HURRY; if (m_speed > DVD_PLAYSPEED_NORMAL) codecControl |= DVD_CODEC_CTRL_NO_POSTPROC; if (bPacketDrop) codecControl |= DVD_CODEC_CTRL_DROP; if (bRequestDrop) codecControl |= DVD_CODEC_CTRL_DROP_ANY; if (!m_renderManager.Supports(RENDERFEATURE_ROTATION)) codecControl |= DVD_CODEC_CTRL_ROTATE; m_pVideoCodec->SetCodecControl(codecControl); if (m_pVideoCodec->AddData(*pPacket)) { // buffer packets so we can recover should decoder flush for some reason if (m_pVideoCodec->GetConvergeCount() > 0) { m_packets.emplace_back(pMsg, 0); if (m_packets.size() > m_pVideoCodec->GetConvergeCount() || m_packets.size() * frametime > DVD_SEC_TO_TIME(10)) m_packets.pop_front(); } m_videoStats.AddSampleBytes(pPacket->iSize); if (ProcessDecoderOutput(frametime, pts)) { onlyPrioMsgs = true; } } else { SendMessageBack(pMsg->Acquire()); onlyPrioMsgs = true; } } // all data is used by the decoder, we can safely free it now pMsg->Release(); } }
void CVideoPlayerVideo::Process() { CLog::Log(LOGNOTICE, "running thread: video_thread"); memset(&m_picture, 0, sizeof(DVDVideoPicture)); double pts = 0; double frametime = (double)DVD_TIME_BASE / m_fFrameRate; int iDropped = 0; //frames dropped in a row bool bRequestDrop = false; int iDropDirective; m_videoStats.Start(); m_droppingStats.Reset(); m_iDroppedFrames = 0; while (!m_bStop) { int iQueueTimeOut = (int)(m_stalled ? frametime : frametime * 10) / 1000; int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_syncState == IDVDStreamPlayer::SYNC_INSYNC) ? 1 : 0; if (m_syncState == IDVDStreamPlayer::SYNC_WAITSYNC) iPriority = 1; CDVDMsg* pMsg; MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, iQueueTimeOut, iPriority); if (MSGQ_IS_ERROR(ret)) { CLog::Log(LOGERROR, "Got MSGQ_ABORT or MSGO_IS_ERROR return true"); break; } else if (ret == MSGQ_TIMEOUT) { // if we only wanted priority messages, this isn't a stall if( iPriority ) continue; // check if decoder has produced some output m_pVideoCodec->SetCodecControl(DVD_CODEC_CTRL_DRAIN); int decoderState = m_pVideoCodec->Decode(NULL, 0, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE); ProcessDecoderOutput(decoderState, frametime, pts); //Okey, start rendering at stream fps now instead, we are likely in a stillframe if (!m_stalled) { if(m_syncState == IDVDStreamPlayer::SYNC_INSYNC) CLog::Log(LOGINFO, "CVideoPlayerVideo - Stillframe detected, switching to forced %f fps", m_fFrameRate); m_stalled = true; pts += frametime * 4; } //Waiting timed out, output last picture if (m_picture.iFlags & DVP_FLAG_ALLOCATED) { OutputPicture(&m_picture, pts); pts += frametime; } continue; } if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait(100, SYNCSOURCE_VIDEO)) { CLog::Log(LOGDEBUG, "CVideoPlayerVideo - CDVDMsg::GENERAL_SYNCHRONIZE"); } else m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */ m_droppingStats.Reset(); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { pts = static_cast<CDVDMsgDouble*>(pMsg)->m_value; m_syncState = IDVDStreamPlayer::SYNC_INSYNC; m_droppingStats.Reset(); CLog::Log(LOGDEBUG, "CVideoPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f)", pts); } else if (pMsg->IsType(CDVDMsg::VIDEO_SET_ASPECT)) { CLog::Log(LOGDEBUG, "CVideoPlayerVideo - CDVDMsg::VIDEO_SET_ASPECT"); m_fForcedAspectRatio = *((CDVDMsgDouble*)pMsg); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { if(m_pVideoCodec) m_pVideoCodec->Reset(); m_picture.iFlags &= ~DVP_FLAG_ALLOCATED; m_packets.clear(); m_droppingStats.Reset(); m_syncState = IDVDStreamPlayer::SYNC_STARTING; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CVideoPlayerVideo::Flush()) { bool sync = static_cast<CDVDMsgBool*>(pMsg)->m_value; if(m_pVideoCodec) m_pVideoCodec->Reset(); m_picture.iFlags &= ~DVP_FLAG_ALLOCATED; m_packets.clear(); pts = 0; m_pullupCorrection.Flush(); //we need to recalculate the framerate //TODO: this needs to be set on a streamchange instead ResetFrameRateCalc(); m_droppingStats.Reset(); m_stalled = true; if (sync) m_syncState = IDVDStreamPlayer::SYNC_STARTING; m_renderManager.DiscardBuffer(); } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; if (m_pVideoCodec) m_pVideoCodec->SetSpeed(m_speed); m_droppingStats.Reset(); } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { CDVDMsgVideoCodecChange* msg(static_cast<CDVDMsgVideoCodecChange*>(pMsg)); while (!m_bStop && m_pVideoCodec) { m_pVideoCodec->SetCodecControl(DVD_CODEC_CTRL_DRAIN); int decoderState = m_pVideoCodec->Decode(NULL, 0, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE); bool cont = ProcessDecoderOutput(decoderState, frametime, pts); if (!cont) break; if (decoderState & VC_BUFFER) break; } OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; m_picture.iFlags &= ~DVP_FLAG_ALLOCATED; } else if (pMsg->IsType(CDVDMsg::VIDEO_DRAIN)) { while (!m_bStop && m_pVideoCodec) { m_pVideoCodec->SetCodecControl(DVD_CODEC_CTRL_DRAIN); int decoderState = m_pVideoCodec->Decode(NULL, 0, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE); bool cont = ProcessDecoderOutput(decoderState, frametime, pts); if (!cont) break; if (decoderState & VC_BUFFER) break; } } else if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); if (m_stalled) { CLog::Log(LOGINFO, "CVideoPlayerVideo - Stillframe left, switching to normal playback"); m_stalled = false; } bRequestDrop = false; iDropDirective = CalcDropRequirement(pts); if (iDropDirective & EOS_VERYLATE) { if (m_bAllowDrop) { bRequestDrop = true; } } int codecControl = 0; if (iDropDirective & EOS_BUFFER_LEVEL) codecControl |= DVD_CODEC_CTRL_HURRY; if (m_speed > DVD_PLAYSPEED_NORMAL) codecControl |= DVD_CODEC_CTRL_NO_POSTPROC; if (bPacketDrop) codecControl |= DVD_CODEC_CTRL_DROP; if (!m_renderManager.Supports(RENDERFEATURE_ROTATION)) codecControl |= DVD_CODEC_CTRL_ROTATE; m_pVideoCodec->SetCodecControl(codecControl); if (iDropDirective & EOS_DROPPED) { m_iDroppedFrames++; iDropped++; m_pullupCorrection.Flush(); } if (m_messageQueue.GetDataSize() == 0 || m_speed < 0) { bRequestDrop = false; m_iDroppedRequest = 0; m_iLateFrames = 0; } // if player want's us to drop this packet, do so nomatter what if(bPacketDrop) bRequestDrop = true; // tell codec if next frame should be dropped // problem here, if one packet contains more than one frame // both frames will be dropped in that case instead of just the first // decoder still needs to provide an empty image structure, with correct flags m_pVideoCodec->SetDropState(bRequestDrop); int iDecoderState = m_pVideoCodec->Decode(pPacket->pData, pPacket->iSize, pPacket->dts, pPacket->pts); // buffer packets so we can recover should decoder flush for some reason if(m_pVideoCodec->GetConvergeCount() > 0) { m_packets.emplace_back(pMsg, 0); if(m_packets.size() > m_pVideoCodec->GetConvergeCount() || m_packets.size() * frametime > DVD_SEC_TO_TIME(10)) m_packets.pop_front(); } m_videoStats.AddSampleBytes(pPacket->iSize); // reset the request, the following while loop may break before // setting the flag to a new value bRequestDrop = false; // loop while no error and decoder produces pics while (!m_bStop) { int dropped = m_iDroppedFrames; bool cont = ProcessDecoderOutput(iDecoderState, frametime, pts); iDropped += m_iDroppedFrames - dropped; if (!cont) break; if (iDecoderState & VC_BUFFER) break; // the decoder didn't need more data, flush the remaning buffer iDecoderState = m_pVideoCodec->Decode(NULL, 0, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE); } } // all data is used by the decoder, we can safely free it now pMsg->Release(); } // we need to let decoder release any picture retained resources. m_pVideoCodec->ClearPicture(&m_picture); }
void OMXPlayerVideo::Process() { double frametime = (double)DVD_TIME_BASE / m_fFrameRate; bool bRequestDrop = false; m_videoStats.Start(); while(!m_bStop) { CDVDMsg* pMsg; int iQueueTimeOut = (int)(m_stalled ? frametime / 4 : frametime * 10) / 1000; int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0; MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, iQueueTimeOut, iPriority); if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT) { CLog::Log(LOGERROR, "OMXPlayerVideo: Got MSGQ_IS_ERROR(%d) Aborting", (int)ret); break; } else if (ret == MSGQ_TIMEOUT) { continue; } if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait(100, SYNCSOURCE_VIDEO)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_SYNCHRONIZE"); } else m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */ pMsg->Release(); continue; } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg; double delay = 0; if(pMsgGeneralResync->m_clock && pMsgGeneralResync->m_timestamp != DVD_NOPTS_VALUE) { CLog::Log(LOGDEBUG, "CDVDPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, %f, 1)", m_iCurrentPts, pMsgGeneralResync->m_timestamp); m_av_clock->Discontinuity(pMsgGeneralResync->m_timestamp - delay); } else CLog::Log(LOGDEBUG, "CDVDPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, 0)", m_iCurrentPts); m_nextOverlay = DVD_NOPTS_VALUE; m_iCurrentPts = DVD_NOPTS_VALUE; pMsgGeneralResync->Release(); continue; } else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY)) { double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_DELAY(%f)", timeout); } else if (pMsg->IsType(CDVDMsg::VIDEO_SET_ASPECT)) { m_fForcedAspectRatio = *((CDVDMsgDouble*)pMsg); CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::VIDEO_SET_ASPECT %.2f", m_fForcedAspectRatio); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESET"); m_omxVideo.Reset(); m_started = false; m_nextOverlay = DVD_NOPTS_VALUE; m_iCurrentPts = DVD_NOPTS_VALUE; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (COMXPlayerVideo::Flush()) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_FLUSH"); m_stalled = true; m_started = false; m_nextOverlay = DVD_NOPTS_VALUE; m_iCurrentPts = DVD_NOPTS_VALUE; m_omxVideo.Reset(); m_flush = false; } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { if (m_speed != static_cast<CDVDMsgInt*>(pMsg)->m_value) { m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::PLAYER_SETSPEED %d", m_speed); } } else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::PLAYER_STARTED %d", m_started); if(m_started) m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { COMXPlayer::SPlayerState& state = ((CDVDMsgType<COMXPlayer::SPlayerState>*)pMsg)->m_value; double pts = m_iCurrentPts; double stamp = m_av_clock->OMXMediaTime(); if(state.time_src == COMXPlayer::ETIMESOURCE_CLOCK) state.time = stamp == 0.0 ? state.time : DVD_TIME_TO_MSEC(stamp + state.time_offset); else state.time = stamp == 0.0 || pts == DVD_NOPTS_VALUE ? state.time : state.time + DVD_TIME_TO_MSEC(stamp - pts); state.timestamp = m_av_clock->GetAbsoluteClock(); state.player = DVDPLAYER_VIDEO; m_messageParent.Put(pMsg->Acquire()); } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { COMXMsgVideoCodecChange* msg(static_cast<COMXMsgVideoCodecChange*>(pMsg)); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; } else if (pMsg->IsType(CDVDMsg::GENERAL_EOF)) { CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_EOF"); SubmitEOS(); } else if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); #ifdef _DEBUG CLog::Log(LOGINFO, "Video: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d\n", pPacket->dts, pPacket->pts, (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, 0); #endif if (m_messageQueue.GetDataSize() == 0 || m_speed < 0) { bRequestDrop = false; } // if player want's us to drop this packet, do so nomatter what if(bPacketDrop) bRequestDrop = true; m_omxVideo.SetDropState(bRequestDrop); while (!m_bStop) { // discard if flushing as clocks may be stopped and we'll never submit it if (m_flush) break; if((int)m_omxVideo.GetFreeSpace() < pPacket->iSize) { Sleep(10); continue; } if (m_stalled) { CLog::Log(LOGINFO, "COMXPlayerVideo - Stillframe left, switching to normal playback"); m_stalled = false; } // some packed bitstream AVI files set almost all pts values to DVD_NOPTS_VALUE, but have a scattering of real pts values. // the valid pts values match the dts values. // if a stream has had more than 4 valid pts values in the last 16, the use UNKNOWN, otherwise use dts m_history_valid_pts = (m_history_valid_pts << 1) | (pPacket->pts != DVD_NOPTS_VALUE); double pts = pPacket->pts; if(count_bits(m_history_valid_pts & 0xffff) < 4) pts = pPacket->dts; if (pts != DVD_NOPTS_VALUE) pts += m_iVideoDelay; m_omxVideo.Decode(pPacket->pData, pPacket->iSize, pts); Output(pts, bRequestDrop); if(pts != DVD_NOPTS_VALUE) m_iCurrentPts = pts; if(m_started == false) { m_codecname = m_omxVideo.GetDecoderName(); m_started = true; m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_VIDEO)); } break; } bRequestDrop = false; m_videoStats.AddSampleBytes(pPacket->iSize); } pMsg->Release(); } }
void CVideoPlayerAudio::Process() { CLog::Log(LOGNOTICE, "running thread: CVideoPlayerAudio::Process()"); DVDAudioFrame audioframe; audioframe.nb_frames = 0; audioframe.framesOut = 0; m_audioStats.Start(); bool onlyPrioMsgs = false; while (!m_bStop) { CDVDMsg* pMsg; int timeout = (int)(1000 * m_audioSink.GetCacheTime()); // read next packet and return -1 on error int priority = 1; //Do we want a new audio frame? if (m_syncState == IDVDStreamPlayer::SYNC_STARTING || /* when not started */ m_processInfo.IsTempoAllowed(static_cast<float>(m_speed)/DVD_PLAYSPEED_NORMAL) || m_speed < DVD_PLAYSPEED_PAUSE || /* when rewinding */ (m_speed > DVD_PLAYSPEED_NORMAL && m_audioClock < m_pClock->GetClock())) /* when behind clock in ff */ priority = 0; if (m_syncState == IDVDStreamPlayer::SYNC_WAITSYNC) priority = 1; if (m_paused) priority = 1; if (onlyPrioMsgs) { priority = 1; timeout = 0; } MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, timeout, priority); onlyPrioMsgs = false; if (MSGQ_IS_ERROR(ret)) { CLog::Log(LOGERROR, "Got MSGQ_ABORT or MSGO_IS_ERROR return true"); break; } else if (ret == MSGQ_TIMEOUT) { if (ProcessDecoderOutput(audioframe)) { onlyPrioMsgs = true; continue; } // if we only wanted priority messages, this isn't a stall if (priority) continue; if (m_processInfo.IsTempoAllowed(static_cast<float>(m_speed)/DVD_PLAYSPEED_NORMAL) && !m_stalled && m_syncState == IDVDStreamPlayer::SYNC_INSYNC) { // while AE sync is active, we still have time to fill buffers if (m_syncTimer.IsTimePast()) { CLog::Log(LOGNOTICE, "CVideoPlayerAudio::Process - stream stalled"); m_stalled = true; } } if (timeout == 0) Sleep(10); continue; } // handle messages if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) { if (static_cast<CDVDMsgGeneralSynchronize*>(pMsg)->Wait(100, SYNCSOURCE_AUDIO)) CLog::Log(LOGDEBUG, "CVideoPlayerAudio - CDVDMsg::GENERAL_SYNCHRONIZE"); else m_messageQueue.Put(pMsg->Acquire(), 1); // push back as prio message, to process other prio messages } else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC)) { //player asked us to set internal clock double pts = static_cast<CDVDMsgDouble*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "CVideoPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f), level: %d, cache: %f", pts, m_messageQueue.GetLevel(), m_audioSink.GetDelay()); double delay = m_audioSink.GetDelay(); if (pts > m_audioClock - delay + 0.5 * DVD_TIME_BASE) { m_audioSink.Flush(); } m_audioClock = pts + delay; if (m_speed != DVD_PLAYSPEED_PAUSE) m_audioSink.Resume(); m_syncState = IDVDStreamPlayer::SYNC_INSYNC; m_syncTimer.Set(3000); } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { if (m_pAudioCodec) m_pAudioCodec->Reset(); m_audioSink.Flush(); m_stalled = true; m_audioClock = 0; audioframe.nb_frames = 0; m_syncState = IDVDStreamPlayer::SYNC_STARTING; } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) { bool sync = static_cast<CDVDMsgBool*>(pMsg)->m_value; m_audioSink.Flush(); m_stalled = true; m_audioClock = 0; audioframe.nb_frames = 0; if (sync) { m_syncState = IDVDStreamPlayer::SYNC_STARTING; m_audioSink.Pause(); } if (m_pAudioCodec) m_pAudioCodec->Reset(); } else if (pMsg->IsType(CDVDMsg::GENERAL_EOF)) { CLog::Log(LOGDEBUG, "CVideoPlayerAudio - CDVDMsg::GENERAL_EOF"); } else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED)) { double speed = static_cast<CDVDMsgInt*>(pMsg)->m_value; if (m_processInfo.IsTempoAllowed(static_cast<float>(speed)/DVD_PLAYSPEED_NORMAL)) { if (speed != m_speed) { if (m_syncState == IDVDStreamPlayer::SYNC_INSYNC) { m_audioSink.Resume(); m_stalled = false; } } } else { m_audioSink.Pause(); } m_speed = (int)speed; } else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE)) { CDVDMsgAudioCodecChange* msg(static_cast<CDVDMsgAudioCodecChange*>(pMsg)); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; } else if (pMsg->IsType(CDVDMsg::GENERAL_PAUSE)) { m_paused = static_cast<CDVDMsgBool*>(pMsg)->m_value; CLog::Log(LOGDEBUG, "CVideoPlayerAudio - CDVDMsg::GENERAL_PAUSE: %d", m_paused); } else if (pMsg->IsType(CDVDMsg::PLAYER_REQUEST_STATE)) { SStateMsg msg; msg.player = VideoPlayer_AUDIO; msg.syncState = m_syncState; m_messageParent.Put(new CDVDMsgType<SStateMsg>(CDVDMsg::PLAYER_REPORT_STATE, msg)); } else if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { DemuxPacket* pPacket = static_cast<CDVDMsgDemuxerPacket*>(pMsg)->GetPacket(); bool bPacketDrop = static_cast<CDVDMsgDemuxerPacket*>(pMsg)->GetPacketDrop(); if (bPacketDrop || (!m_processInfo.IsTempoAllowed(static_cast<float>(m_speed)/DVD_PLAYSPEED_NORMAL) && m_syncState == IDVDStreamPlayer::SYNC_INSYNC)) { pMsg->Release(); continue; } if (!m_pAudioCodec->AddData(*pPacket)) { m_messageQueue.PutBack(pMsg->Acquire()); onlyPrioMsgs = true; pMsg->Release(); continue; } m_audioStats.AddSampleBytes(pPacket->iSize); UpdatePlayerInfo(); if (ProcessDecoderOutput(audioframe)) { onlyPrioMsgs = true; } } // demuxer packet pMsg->Release(); } }