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 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 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 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 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 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(); } }
// decode one audio frame and returns its uncompressed size int CVideoPlayerAudio::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, "CVideoPlayerAudio::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.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 (!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_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)) { 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, "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_ptsInput.Flush(); if (m_speed != DVD_PLAYSPEED_PAUSE) m_dvdAudio.Resume(); m_syncState = IDVDStreamPlayer::SYNC_INSYNC; } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { if (m_pAudioCodec) m_pAudioCodec->Reset(); m_decode.Release(); } else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) { bool sync = static_cast<CDVDMsgBool*>(pMsg)->m_value; m_dvdAudio.Flush(); m_ptsInput.Flush(); m_stalled = true; if (sync) { m_syncState = IDVDStreamPlayer::SYNC_STARTING; m_dvdAudio.Pause(); } if (m_pAudioCodec) m_pAudioCodec->Reset(); m_decode.Release(); } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { SPlayerState& state = ((CDVDMsgType<SPlayerState>*)pMsg)->m_value; if(state.time_src == ETIMESOURCE_CLOCK) state.time = DVD_TIME_TO_MSEC(m_pClock->GetClock(state.timestamp) + state.time_offset); else state.timestamp = CDVDClock::GetAbsoluteClock(); state.player = VideoPlayer_AUDIO; m_messageParent.Put(pMsg->Acquire()); } 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; } pMsg->Release(); } return 0; }
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; CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESYNC(%f, %d)", pMsgGeneralResync->m_timestamp, pMsgGeneralResync->m_clock); 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; 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_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(pPacket->pts == DVD_NOPTS_VALUE && 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); 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 CVideoPlayerVideo::Process() { CLog::Log(LOGNOTICE, "running thread: video_thread"); 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 = 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_processInfo.IsFrameAdvance() || 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; m_renderManager.ShowVideo(true); 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_renderManager.ShowVideo(false); 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.ShowVideo(false); } 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(); } }