bool CDVDSubtitlesLibass::DecodeDemuxPkt(char* data, int size, double start, double duration) { CSingleLock lock(m_section); if(!m_track) { CLog::Log(LOGERROR, "CDVDSubtitlesLibass: No SSA header found."); return false; } m_dll.ass_process_chunk(m_track, data, size, DVD_TIME_TO_MSEC(start), DVD_TIME_TO_MSEC(duration)); return true; }
bool CDVDSubtitlesLibass::DecodeDemuxPkt(const char* data, int size, double start, double duration) { CSingleLock lock(m_section); if(!m_track) { CLog::Log(LOGERROR, "CDVDSubtitlesLibass: No SSA header found."); return false; } //! @bug libass isn't const correct ass_process_chunk(m_track, const_cast<char*>(data), size, DVD_TIME_TO_MSEC(start), DVD_TIME_TO_MSEC(duration)); return true; }
bool OMXReader::SeekChapter(int chapter, double* startpts) { if(chapter < 1) { chapter = 1; } if(m_pFormatContext == NULL) { return false; } #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,14,0) if(chapter < 1 || chapter > (int)m_pFormatContext->nb_chapters) { return false; } AVChapter *ch = m_pFormatContext->chapters[chapter-1]; double dts = ConvertTimestamp(ch->start, ch->time_base.den, ch->time_base.num); return SeekTime(DVD_TIME_TO_MSEC(dts), 0, startpts); #else return false; #endif }
DemuxPacket* CDVDDemuxClient::Read() { if (!m_IDemux) return nullptr; if (m_packet) return m_packet.release(); m_packet.reset(m_IDemux->ReadDemux()); if (!m_packet) { return nullptr; } if (m_packet->iStreamId == DMX_SPECIALID_STREAMINFO) { RequestStreams(); CDVDDemuxUtils::FreeDemuxPacket(m_packet.release()); return CDVDDemuxUtils::AllocateDemuxPacket(0); } else if (m_packet->iStreamId == DMX_SPECIALID_STREAMCHANGE) { RequestStreams(); } else if (m_packet->iStreamId >= 0 && m_streams.count(m_packet->iStreamId) > 0) { if (ParsePacket(m_packet.get())) { RequestStreams(); DemuxPacket *pPacket = CDVDDemuxUtils::AllocateDemuxPacket(0); pPacket->iStreamId = DMX_SPECIALID_STREAMCHANGE; pPacket->demuxerId = m_demuxerId; return pPacket; } } CDVDInputStream::IDisplayTime *inputStream = m_pInput->GetIDisplayTime(); if (inputStream) { int dispTime = inputStream->GetTime(); if (m_displayTime != dispTime) { m_displayTime = dispTime; if (m_packet->dts != DVD_NOPTS_VALUE) { m_dtsAtDisplayTime = m_packet->dts; } } if (m_dtsAtDisplayTime != DVD_NOPTS_VALUE && m_packet->dts != DVD_NOPTS_VALUE) { m_packet->dispTime = m_displayTime; m_packet->dispTime += DVD_TIME_TO_MSEC(m_packet->dts - m_dtsAtDisplayTime); } } return m_packet.release(); }
DemuxPacket* CDVDDemuxClient::Read() { if (!m_IDemux) return nullptr; DemuxPacket* pPacket = m_IDemux->ReadDemux(); if (!pPacket) { return nullptr; } if (pPacket->iStreamId == DMX_SPECIALID_STREAMINFO) { RequestStreams(); CDVDDemuxUtils::FreeDemuxPacket(pPacket); return CDVDDemuxUtils::AllocateDemuxPacket(0); } else if (pPacket->iStreamId == DMX_SPECIALID_STREAMCHANGE) { RequestStreams(); } else if (pPacket->iStreamId >= 0 && m_streams[pPacket->iStreamId]) { ParsePacket(pPacket); } CDVDInputStream::IDisplayTime *inputStream = m_pInput->GetIDisplayTime(); if (inputStream) { int dispTime = inputStream->GetTime(); if (m_displayTime != dispTime) { m_displayTime = dispTime; if (pPacket->dts != DVD_NOPTS_VALUE) { m_dtsAtDisplayTime = pPacket->dts; } } if (m_dtsAtDisplayTime != DVD_NOPTS_VALUE && pPacket->dts != DVD_NOPTS_VALUE) { pPacket->dispTime = m_displayTime; pPacket->dispTime += DVD_TIME_TO_MSEC(pPacket->dts - m_dtsAtDisplayTime); } } return pPacket; }
ASS_Image* CDVDSubtitlesLibass::RenderImage(int frameWidth, int frameHeight, int videoWidth, int videoHeight, double pts, int useMargin, double position, int *changes) { CSingleLock lock(m_section); if(!m_renderer || !m_track) { CLog::Log(LOGERROR, "CDVDSubtitlesLibass: %s - Missing ASS structs(m_track or m_renderer)", __FUNCTION__); return NULL; } double storage_aspect = (double)frameWidth / frameHeight; m_dll.ass_set_frame_size(m_renderer, frameWidth, frameHeight); int topmargin = (frameHeight - videoHeight) / 2; int leftmargin = (frameWidth - videoWidth) / 2; m_dll.ass_set_margins(m_renderer, topmargin, topmargin, leftmargin, leftmargin); m_dll.ass_set_use_margins(m_renderer, useMargin); m_dll.ass_set_line_position(m_renderer, position); m_dll.ass_set_aspect_ratio(m_renderer, storage_aspect / g_graphicsContext.GetResInfo().fPixelRatio, storage_aspect); return m_dll.ass_render_frame(m_renderer, m_track, DVD_TIME_TO_MSEC(pts), changes); }
ASS_Image* CDVDSubtitlesLibass::RenderImage(int frameWidth, int frameHeight, int videoWidth, int videoHeight, int sourceWidth, int sourceHeight, double pts, int useMargin, double position, int *changes) { CSingleLock lock(m_section); if(!m_renderer || !m_track) { CLog::Log(LOGERROR, "CDVDSubtitlesLibass: %s - Missing ASS structs(m_track or m_renderer)", __FUNCTION__); return NULL; } double sar = (double)sourceWidth / sourceHeight; double dar = (double)videoWidth / videoHeight; ass_set_frame_size(m_renderer, frameWidth, frameHeight); int topmargin = (frameHeight - videoHeight) / 2; int leftmargin = (frameWidth - videoWidth) / 2; ass_set_margins(m_renderer, topmargin, topmargin, leftmargin, leftmargin); ass_set_use_margins(m_renderer, useMargin); ass_set_line_position(m_renderer, position); ass_set_aspect_ratio(m_renderer, dar, sar); return ass_render_frame(m_renderer, m_track, DVD_TIME_TO_MSEC(pts), changes); }
bool CRetroPlayerVideo::ProcessFrame(const VideoFrame &frame) { DVDVideoPicture *pPicture = CDVDCodecUtils::AllocatePicture(frame.meta.width, frame.meta.height); try { if (!pPicture) { CLog::Log(LOGERROR, "RetroPlayerVideo: Failed to allocate picture"); throw false; } pPicture->dts = DVD_NOPTS_VALUE; pPicture->pts = DVD_NOPTS_VALUE; pPicture->format = RENDER_FMT_YUV420P; // PIX_FMT_YUV420P pPicture->color_range = 0; // *not* CONF_FLAGS_YUV_FULLRANGE pPicture->color_matrix = 4; // CONF_FLAGS_YUVCOEF_BT601 pPicture->iFlags = DVP_FLAG_ALLOCATED; pPicture->iDisplayWidth = frame.meta.width; // iWidth was set in AllocatePicture() pPicture->iDisplayHeight = frame.meta.height; // iHeight was set in AllocatePicture() pPicture->iDuration = 1.0 / m_framerate; // Got the picture, now make sure we're ready to render it if (!CheckConfiguration(*pPicture)) throw false; // CheckConfiguration() should have set up our SWScale context if (!m_swsContext) { CLog::Log(LOGERROR, "RetroPlayerVideo: Failed to grab SWScale context, bailing"); throw false; } ColorspaceConversion(frame, *pPicture); // Get ready to drop the picture off on RenderManger's doorstep if (!g_renderManager.IsStarted()) { CLog::Log(LOGERROR, "RetroPlayerVideo: Renderer not started, bailing"); throw false; } const double sleepTime = 0; // TODO: How is this calculated in DVDPlayer? int buffer = g_renderManager.WaitForBuffer(m_bStop, std::max(DVD_TIME_TO_MSEC(sleepTime) + 500, 0)); // If buffer < 0, there was a timeout waiting for buffer, drop the frame if (buffer >= 0) { int index = g_renderManager.AddVideoPicture(*pPicture); // If index < 0, video device might not be done yet, drop the frame if (index >= 0) g_renderManager.FlipPage(CThread::m_bStop); } } catch (bool result) { if (pPicture) CDVDCodecUtils::FreePicture(pPicture); return result; } CDVDCodecUtils::FreePicture(pPicture); return true; }
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 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_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_av_clock->GetClock())) /* when behind clock in ff */ priority = 0; if (m_started && !m_sync) 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_started, 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_sync = true; } else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESET"); if (m_pAudioCodec) m_pAudioCodec->Reset(); 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; m_flush = false; } else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME)) { SPlayerState& state = ((CDVDMsgType<SPlayerState>*)pMsg)->m_value; state.player = VideoPlayer_AUDIO; 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_audioClock; 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_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::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)); CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_STREAMCHANGE"); OpenStream(msg->m_hints, msg->m_codec); msg->m_codec = NULL; } 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(); } }
// 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(); } }
bool CDVDPlayerAudio::OutputPacket(DVDAudioFrame &audioframe) { if (m_syncclock) { double absolute; double clock = m_pClock->GetClock(absolute); double error = m_dvdAudio.GetPlayingPts() - clock; m_dvdAudio.SetResampleRatio(1.0); // sync audio by skipping or dropping frames if we are above or // below a given threshold. the constants are aligned with known // durations: DTS = 11ms, AC3 = 32ms // during this stage audio is muted if (error > DVD_MSEC_TO_TIME(10)) { if (AE_IS_RAW_RAW(audioframe.data_format)) { double correction = int(std::min(DVD_MSEC_TO_TIME(100), error) / audioframe.duration) * audioframe.duration; if (correction > 0) { // Force clock sync to audio CLog::Log(LOGNOTICE,"CDVDPlayerAudio::OutputPacket forcing clock sync for passthrough - dup error(%f), clock(%f), correction(%f)", error, clock, correction); m_pClock->Update(clock+correction, absolute, 0.0, "CDVDPlayerAudio::OutputPacket"); } m_dvdAudio.AddPackets(audioframe); } else { unsigned int nb_frames = audioframe.nb_frames; double duration = audioframe.duration; // reduce large packets for better sync, i.e. FLAC can have 96ms packets // 32ms because I know this works good for AC3 if (audioframe.duration > DVD_MSEC_TO_TIME(32) && audioframe.sample_rate) { audioframe.nb_frames = 0.032 * audioframe.sample_rate; audioframe.duration = ((double)audioframe.nb_frames * DVD_TIME_BASE) / audioframe.sample_rate; } int dups = std::min(DVD_MSEC_TO_TIME(100), error) / audioframe.duration; if (dups > 0) CLog::Log(LOGNOTICE,"CDVDPlayerAudio::OutputPacket duplicate %d packets of duration %d", dups, DVD_TIME_TO_MSEC(audioframe.duration)); for (int i = 0; i < dups; i++) { m_dvdAudio.AddPackets(audioframe); } audioframe.nb_frames = nb_frames; audioframe.duration = duration; m_dvdAudio.AddPackets(audioframe); } } else if (error < -DVD_MSEC_TO_TIME(32)) { if (AE_IS_RAW_RAW(audioframe.data_format)) { double correction = audioframe.duration; // Force clock sync to audio CLog::Log(LOGNOTICE,"CDVDPlayerAudio::OutputPacket forcing clock sync for passthrough - skip error(%f), clock(%f), correction(%f)", error, clock, correction); m_pClock->Update(clock-correction, absolute, 0.0, "CDVDPlayerAudio::OutputPacket"); m_dvdAudio.AddPackets(audioframe); } else { m_dvdAudio.SetPlayingPts(audioframe.pts); CLog::Log(LOGNOTICE,"CDVDPlayerAudio::OutputPacket skipping a packets of duration %d", DVD_TIME_TO_MSEC(audioframe.duration)); } } else { m_dvdAudio.AddPackets(audioframe); } } else if (m_synctype == SYNC_DISCON) { m_dvdAudio.AddPackets(audioframe); } else if (m_synctype == SYNC_SKIPDUP) { double limit = std::max(DVD_MSEC_TO_TIME(10), audioframe.duration * 2.0 / 3.0); if (m_error < -limit) { m_prevskipped = !m_prevskipped; if (m_prevskipped) m_dvdAudio.AddPackets(audioframe); else { CLog::Log(LOGDEBUG, "CDVDPlayerAudio:: Dropping packet of %d ms", DVD_TIME_TO_MSEC(audioframe.duration)); m_error += audioframe.duration; } } else if(m_error > limit) { CLog::Log(LOGDEBUG, "CDVDPlayerAudio:: Duplicating packet of %d ms", DVD_TIME_TO_MSEC(audioframe.duration)); m_dvdAudio.AddPackets(audioframe); m_dvdAudio.AddPackets(audioframe); m_error -= audioframe.duration; } else m_dvdAudio.AddPackets(audioframe); } else if (m_synctype == SYNC_RESAMPLE) { m_dvdAudio.SetResampleRatio(m_resampleratio); m_dvdAudio.AddPackets(audioframe); } return true; }
CVideoPlayerVideo::EOutputState CVideoPlayerVideo::OutputPicture(const VideoPicture* pPicture) { m_bAbortOutput = false; if (m_processInfo.GetVideoStereoMode() != pPicture->stereoMode) { m_processInfo.SetVideoStereoMode(pPicture->stereoMode); // signal about changes in video parameters m_messageParent.Put(new CDVDMsg(CDVDMsg::PLAYER_AVCHANGE)); } double config_framerate = m_bFpsInvalid ? 0.0 : m_fFrameRate; if (m_processInfo.GetVideoInterlaced()) { if (MathUtils::FloatEquals(config_framerate, 25.0, 0.02)) config_framerate = 50.0; else if (MathUtils::FloatEquals(config_framerate, 29.97, 0.02)) config_framerate = 59.94; } int sorient = m_processInfo.GetVideoSettings().m_Orientation; int orientation = sorient != 0 ? (sorient + m_hints.orientation) % 360 : m_hints.orientation; if (!m_renderManager.Configure(*pPicture, static_cast<float>(config_framerate), orientation, m_pVideoCodec->GetAllowedReferences())) { CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); return OUTPUT_ABORT; } //try to calculate the framerate m_ptsTracker.Add(pPicture->pts); if (!m_stalled) CalcFrameRate(); // signal to clock what our framerate is, it may want to adjust it's // speed to better match with our video renderer's output speed m_pClock->UpdateFramerate(m_fFrameRate); // calculate the time we need to delay this picture before displaying double iPlayingClock, iCurrentClock; iPlayingClock = m_pClock->GetClock(iCurrentClock, false); // snapshot current clock if (m_speed < 0) { double renderPts; int queued, discard; int lateframes; double inputPts = m_droppingStats.m_lastPts; m_renderManager.GetStats(lateframes, renderPts, queued, discard); if (pPicture->pts > renderPts || queued > 0) { if (inputPts >= renderPts) { m_rewindStalled = true; Sleep(50); } return OUTPUT_DROPPED; } else if (pPicture->pts < iPlayingClock) { return OUTPUT_DROPPED; } } if ((pPicture->iFlags & DVP_FLAG_DROPPED)) { m_droppingStats.AddOutputDropGain(pPicture->pts, 1); CLog::Log(LOGDEBUG,"%s - dropped in output", __FUNCTION__); return OUTPUT_DROPPED; } int timeToDisplay = DVD_TIME_TO_MSEC(pPicture->pts - iPlayingClock); // make sure waiting time is not negative int maxWaitTime = std::min(std::max(timeToDisplay + 500, 50), 500); // don't wait when going ff if (m_speed > DVD_PLAYSPEED_NORMAL) maxWaitTime = std::max(timeToDisplay, 0); int buffer = m_renderManager.WaitForBuffer(m_bAbortOutput, maxWaitTime); if (buffer < 0) { return OUTPUT_AGAIN; } ProcessOverlays(pPicture, pPicture->pts); EINTERLACEMETHOD deintMethod = EINTERLACEMETHOD::VS_INTERLACEMETHOD_NONE; deintMethod = m_processInfo.GetVideoSettings().m_InterlaceMethod; if (!m_processInfo.Supports(deintMethod)) deintMethod = m_processInfo.GetDeinterlacingMethodDefault(); if (!m_renderManager.AddVideoPicture(*pPicture, m_bAbortOutput, deintMethod, (m_syncState == ESyncState::SYNC_STARTING))) { m_droppingStats.AddOutputDropGain(pPicture->pts, 1); return OUTPUT_DROPPED; } return OUTPUT_NORMAL; }