void CDVDPlayerSubtitle::Process(double pts) { CSingleLock lock(m_section); if (m_pSubtitleFileParser) { if(pts == DVD_NOPTS_VALUE) return; if (pts + DVD_SEC_TO_TIME(1) < m_lastPts) { m_pOverlayContainer->Clear(); m_pSubtitleFileParser->Reset(); } if(m_pOverlayContainer->GetSize() >= 5) return; CDVDOverlay* pOverlay = m_pSubtitleFileParser->Parse(pts); // add all overlays which fit the pts while(pOverlay) { m_pOverlayContainer->Add(pOverlay); pOverlay->Release(); pOverlay = m_pSubtitleFileParser->Parse(pts); } m_lastPts = pts; } }
void CDVDPlayerSubtitle::GetCurrentSubtitle(CStdString& strSubtitle, double pts) { strSubtitle = ""; Process(pts); // TODO: move to separate thread? CSingleLock lock(*m_pOverlayContainer); VecOverlays* pOverlays = m_pOverlayContainer->GetOverlays(); if (pOverlays) { for(vector<CDVDOverlay*>::iterator it = pOverlays->begin();it != pOverlays->end();it++) { CDVDOverlay* pOverlay = *it; if (pOverlay->IsOverlayType(DVDOVERLAY_TYPE_TEXT) && (pOverlay->iPTSStartTime <= pts) && (pOverlay->iPTSStopTime >= pts || pOverlay->iPTSStopTime == 0LL)) { CDVDOverlayText::CElement* e = ((CDVDOverlayText*)pOverlay)->m_pHead; while (e) { if (e->IsElementType(CDVDOverlayText::ELEMENT_TYPE_TEXT)) { CDVDOverlayText::CElementText* t = (CDVDOverlayText::CElementText*)e; strSubtitle += t->m_text; strSubtitle += "\n"; } e = e->pNext; } } } } strSubtitle.TrimRight('\n'); }
void CDVDPlayerVideo::ProcessVideoUserData(DVDVideoUserData* pVideoUserData, double pts) { /* 参数: 1、 返回: 1、 说明: 1、 */ // check userdata type BYTE* data = pVideoUserData->data; int size = pVideoUserData->size; if (size >= 2) { if (data[0] == 'C' && data[1] == 'C') { data += 2; size -= 2; // closed captioning if (!m_pOverlayCodecCC) { m_pOverlayCodecCC = new CDVDOverlayCodecCC(); CDVDCodecOptions options; CDVDStreamInfo info; if (!m_pOverlayCodecCC->Open(info, options)) { delete m_pOverlayCodecCC; m_pOverlayCodecCC = NULL; } } if (m_pOverlayCodecCC) { m_pOverlayCodecCC->Decode(data, size, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE); CDVDOverlay* overlay; while((overlay = m_pOverlayCodecCC->GetOverlay()) != NULL) { overlay->iGroupId = 0; overlay->iPTSStartTime += pts; if(overlay->iPTSStopTime != 0.0) overlay->iPTSStopTime += pts; m_pOverlayContainer->Add(overlay); overlay->Release(); } } } } }
VecOverlaysIter CDVDOverlayContainer::Remove(VecOverlaysIter itOverlay) { VecOverlaysIter itNext; CDVDOverlay* pOverlay = *itOverlay; { CSingleLock lock(*this); itNext = m_overlays.erase(itOverlay); } pOverlay->Release(); return itNext; }
void CDVDPlayerVideo::ProcessVideoUserData(DVDVideoUserData* pVideoUserData, double pts) { // check userdata type uint8_t* data = pVideoUserData->data; int size = pVideoUserData->size; if (size >= 2) { if (data[0] == 'C' && data[1] == 'C') { data += 2; size -= 2; // closed captioning if (!m_pOverlayCodecCC) { m_pOverlayCodecCC = new CDVDOverlayCodecCC(); CDVDCodecOptions options; CDVDStreamInfo info; if (!m_pOverlayCodecCC->Open(info, options)) { delete m_pOverlayCodecCC; m_pOverlayCodecCC = NULL; } } if (m_pOverlayCodecCC) { DemuxPacket packet; packet.pData = data; packet.iSize = size; packet.pts = DVD_NOPTS_VALUE; packet.dts = DVD_NOPTS_VALUE; m_pOverlayCodecCC->Decode(&packet); CDVDOverlay* overlay; while((overlay = m_pOverlayCodecCC->GetOverlay()) != NULL) { overlay->iPTSStartTime += pts; if(overlay->iPTSStopTime != 0.0) overlay->iPTSStopTime += pts; m_pOverlayContainer->Add(overlay); overlay->Release(); } } } } }
void CDVDOverlayContainer::Remove() { if (!m_overlays.empty()) { CDVDOverlay* pOverlay; { CSingleLock lock(*this); pOverlay = m_overlays.front(); m_overlays.erase(m_overlays.begin()); } pOverlay->Release(); } }
void CVideoPlayerVideo::ProcessOverlays(const VideoPicture* pSource, double pts) { // remove any overlays that are out of time if (m_syncState == IDVDStreamPlayer::SYNC_INSYNC) m_pOverlayContainer->CleanUp(pts - m_iSubtitleDelay); VecOverlays overlays; { CSingleLock lock(*m_pOverlayContainer); VecOverlays* pVecOverlays = m_pOverlayContainer->GetOverlays(); VecOverlaysIter it = pVecOverlays->begin(); //Check all overlays and render those that should be rendered, based on time and forced //Both forced and subs should check timing while (it != pVecOverlays->end()) { CDVDOverlay* pOverlay = *it++; if(!pOverlay->bForced && !m_bRenderSubs) continue; double pts2 = pOverlay->bForced ? pts : pts - m_iSubtitleDelay; if((pOverlay->iPTSStartTime <= pts2 && (pOverlay->iPTSStopTime > pts2 || pOverlay->iPTSStopTime == 0LL))) { if(pOverlay->IsOverlayType(DVDOVERLAY_TYPE_GROUP)) overlays.insert(overlays.end(), static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.begin() , static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.end()); else overlays.push_back(pOverlay); } } for(it = overlays.begin(); it != overlays.end(); ++it) { double pts2 = (*it)->bForced ? pts : pts - m_iSubtitleDelay; m_renderManager.AddOverlay(*it, pts2); } } }
void OMXPlayerVideo::ProcessOverlays(int iGroupId, double pts) { // remove any overlays that are out of time if (m_started) m_pOverlayContainer->CleanUp(pts - m_iSubtitleDelay); VecOverlays overlays; CSingleLock lock(*m_pOverlayContainer); VecOverlays* pVecOverlays = m_pOverlayContainer->GetOverlays(); VecOverlaysIter it = pVecOverlays->begin(); //Check all overlays and render those that should be rendered, based on time and forced //Both forced and subs should check timeing, pts == 0 in the stillframe case while (it != pVecOverlays->end()) { CDVDOverlay* pOverlay = *it++; if(!pOverlay->bForced && !m_bRenderSubs) continue; if(pOverlay->iGroupId != iGroupId) continue; double pts2 = pOverlay->bForced ? pts : pts - m_iSubtitleDelay; if((pOverlay->iPTSStartTime <= pts2 && (pOverlay->iPTSStopTime > pts2 || pOverlay->iPTSStopTime == 0LL)) || pts == 0) { if(pOverlay->IsOverlayType(DVDOVERLAY_TYPE_GROUP)) overlays.insert(overlays.end(), static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.begin() , static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.end()); else overlays.push_back(pOverlay); } } for(it = overlays.begin(); it != overlays.end(); ++it) { double pts2 = (*it)->bForced ? pts : pts - m_iSubtitleDelay; g_renderManager.AddOverlay(*it, pts2); } }
void CDVDPlayerVideo::ProcessOverlays(DVDVideoPicture* pSource, double pts) { // remove any overlays that are out of time if (m_started) m_pOverlayContainer->CleanUp(pts - m_iSubtitleDelay); enum EOverlay { OVERLAY_AUTO // select mode auto , OVERLAY_GPU // render osd using gpu , OVERLAY_BUF // render osd on buffer } render = OVERLAY_AUTO; if(pSource->format == DVDVideoPicture::FMT_YUV420P) { if(g_Windowing.GetRenderQuirks() & RENDER_QUIRKS_MAJORMEMLEAK_OVERLAYRENDERER) { // for now use cpu for ssa overlays as it currently allocates and // frees textures for each frame this causes a hugh memory leak // on some mesa intel drivers if(m_pOverlayContainer->ContainsOverlayType(DVDOVERLAY_TYPE_SPU) || m_pOverlayContainer->ContainsOverlayType(DVDOVERLAY_TYPE_IMAGE) || m_pOverlayContainer->ContainsOverlayType(DVDOVERLAY_TYPE_SSA) ) render = OVERLAY_BUF; } if(render == OVERLAY_BUF) { // rendering spu overlay types directly on video memory costs a lot of processing power. // thus we allocate a temp picture, copy the original to it (needed because the same picture can be used more than once). // then do all the rendering on that temp picture and finaly copy it to video memory. // In almost all cases this is 5 or more times faster!. if(m_pTempOverlayPicture && ( m_pTempOverlayPicture->iWidth != pSource->iWidth || m_pTempOverlayPicture->iHeight != pSource->iHeight)) { CDVDCodecUtils::FreePicture(m_pTempOverlayPicture); m_pTempOverlayPicture = NULL; } if(!m_pTempOverlayPicture) m_pTempOverlayPicture = CDVDCodecUtils::AllocatePicture(pSource->iWidth, pSource->iHeight); if(!m_pTempOverlayPicture) return; CDVDCodecUtils::CopyPicture(m_pTempOverlayPicture, pSource); memcpy(pSource->data , m_pTempOverlayPicture->data , sizeof(pSource->data)); memcpy(pSource->iLineSize, m_pTempOverlayPicture->iLineSize, sizeof(pSource->iLineSize)); } } if(render == OVERLAY_AUTO) render = OVERLAY_GPU; VecOverlays overlays; { CSingleLock lock(*m_pOverlayContainer); VecOverlays* pVecOverlays = m_pOverlayContainer->GetOverlays(); VecOverlaysIter it = pVecOverlays->begin(); //Check all overlays and render those that should be rendered, based on time and forced //Both forced and subs should check timeing, pts == 0 in the stillframe case while (it != pVecOverlays->end()) { CDVDOverlay* pOverlay = *it++; if(!pOverlay->bForced && !m_bRenderSubs) continue; if(pOverlay->iGroupId != pSource->iGroupId) continue; double pts2 = pOverlay->bForced ? pts : pts - m_iSubtitleDelay; if((pOverlay->iPTSStartTime <= pts2 && (pOverlay->iPTSStopTime > pts2 || pOverlay->iPTSStopTime == 0LL)) || pts == 0) { if(pOverlay->IsOverlayType(DVDOVERLAY_TYPE_GROUP)) overlays.insert(overlays.end(), static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.begin() , static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.end()); else overlays.push_back(pOverlay); } } for(it = overlays.begin(); it != overlays.end(); ++it) { double pts2 = (*it)->bForced ? pts : pts - m_iSubtitleDelay; if (render == OVERLAY_GPU) g_renderManager.AddOverlay(*it, pts2); if (render == OVERLAY_BUF) CDVDOverlayRenderer::Render(pSource, *it, pts2); } } }
void CDVDPlayerSubtitle::SendMessage(CDVDMsg* pMsg) { if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { CDVDMsgDemuxerPacket* pMsgDemuxerPacket = (CDVDMsgDemuxerPacket*)pMsg; DemuxPacket* pPacket = pMsgDemuxerPacket->GetPacket(); if (m_pOverlayCodec) { double pts = pPacket->dts != DVD_NOPTS_VALUE ? pPacket->dts : pPacket->pts; double duration = pPacket->duration; int result = m_pOverlayCodec->Decode(pPacket->pData, pPacket->iSize, pts, duration); if(result == OC_OVERLAY) { CDVDOverlay* overlay; while((overlay = m_pOverlayCodec->GetOverlay()) != NULL) { overlay->iGroupId = pPacket->iGroupId; // we assume pts is better than what // decoder gives us, only take duration // from decoder if available if(overlay->iPTSStopTime > overlay->iPTSStartTime) duration = overlay->iPTSStopTime - overlay->iPTSStartTime; else if(pPacket->duration != DVD_NOPTS_VALUE) duration = pPacket->duration; else duration = 0.0; if (pPacket->pts != DVD_NOPTS_VALUE) pts = pPacket->pts; else if(pPacket->dts != DVD_NOPTS_VALUE) pts = pPacket->dts; else pts = overlay->iPTSStartTime; overlay->iPTSStartTime = pts; if(duration) overlay->iPTSStopTime = pts + duration; else { overlay->iPTSStopTime = 0; overlay->replace = true; } m_pOverlayContainer->Add(overlay); overlay->Release(); } } } else if (m_streaminfo.codec == CODEC_ID_DVD_SUBTITLE) { CDVDOverlaySpu* pSPUInfo = m_dvdspus.AddData(pPacket->pData, pPacket->iSize, pPacket->pts); if (pSPUInfo) { CLog::Log(LOGDEBUG, "CDVDPlayer::ProcessSubData: Got complete SPU packet"); pSPUInfo->iGroupId = pPacket->iGroupId; m_pOverlayContainer->Add(pSPUInfo); pSPUInfo->Release(); } } } else if( pMsg->IsType(CDVDMsg::SUBTITLE_CLUTCHANGE) ) { CDVDMsgSubtitleClutChange* pData = (CDVDMsgSubtitleClutChange*)pMsg; for (int i = 0; i < 16; i++) { BYTE* color = m_dvdspus.m_clut[i]; BYTE* t = (BYTE*)pData->m_data[i]; // pData->m_data[i] points to an uint32_t // Byte swapping is needed between big and little endian systems #ifdef WORDS_BIGENDIAN color[0] = t[1]; // Y color[1] = t[2]; // Cr color[2] = t[3]; // Cb #else color[0] = t[2]; // Y color[1] = t[0]; // Cr color[2] = t[1]; // Cb #endif } m_dvdspus.m_bHasClut = true; } else if( pMsg->IsType(CDVDMsg::GENERAL_FLUSH) || pMsg->IsType(CDVDMsg::GENERAL_RESET) ) { m_dvdspus.Reset(); if (m_pSubtitleFileParser) m_pSubtitleFileParser->Reset(); if (m_pOverlayCodec) m_pOverlayCodec->Flush(); m_lastPts = DVD_NOPTS_VALUE; } pMsg->Release(); }
void CDVDPlayerSubtitle::SendMessage(CDVDMsg* pMsg) { CSingleLock lock(m_section); if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { CDVDMsgDemuxerPacket* pMsgDemuxerPacket = (CDVDMsgDemuxerPacket*)pMsg; DemuxPacket* pPacket = pMsgDemuxerPacket->GetPacket(); if (m_pOverlayCodec) { int result = m_pOverlayCodec->Decode(pPacket); if(result == OC_OVERLAY) { CDVDOverlay* overlay; while((overlay = m_pOverlayCodec->GetOverlay()) != NULL) { overlay->iGroupId = pPacket->iGroupId; m_pOverlayContainer->Add(overlay); overlay->Release(); } } } else if (m_streaminfo.codec == CODEC_ID_DVD_SUBTITLE) { CDVDOverlaySpu* pSPUInfo = m_dvdspus.AddData(pPacket->pData, pPacket->iSize, pPacket->pts); if (pSPUInfo) { CLog::Log(LOGDEBUG, "CDVDPlayer::ProcessSubData: Got complete SPU packet"); pSPUInfo->iGroupId = pPacket->iGroupId; m_pOverlayContainer->Add(pSPUInfo); pSPUInfo->Release(); } } } else if( pMsg->IsType(CDVDMsg::SUBTITLE_CLUTCHANGE) ) { CDVDMsgSubtitleClutChange* pData = (CDVDMsgSubtitleClutChange*)pMsg; for (int i = 0; i < 16; i++) { BYTE* color = m_dvdspus.m_clut[i]; BYTE* t = (BYTE*)pData->m_data[i]; // pData->m_data[i] points to an uint32_t // Byte swapping is needed between big and little endian systems #ifdef WORDS_BIGENDIAN color[0] = t[1]; // Y color[1] = t[2]; // Cr color[2] = t[3]; // Cb #else color[0] = t[2]; // Y color[1] = t[0]; // Cr color[2] = t[1]; // Cb #endif } m_dvdspus.m_bHasClut = true; } else if( pMsg->IsType(CDVDMsg::GENERAL_FLUSH) || pMsg->IsType(CDVDMsg::GENERAL_RESET) ) { m_dvdspus.Reset(); if (m_pSubtitleFileParser) m_pSubtitleFileParser->Reset(); if (m_pOverlayCodec) m_pOverlayCodec->Flush(); /* We must flush active overlays on flush or if we have a file * parser since it will re-populate active items. */ if(pMsg->IsType(CDVDMsg::GENERAL_FLUSH) || m_pSubtitleFileParser) m_pOverlayContainer->Clear(); m_lastPts = DVD_NOPTS_VALUE; } pMsg->Release(); }
void CDVDPlayerSubtitle::SendMessage(CDVDMsg* pMsg) { if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) { CDVDMsgDemuxerPacket* pMsgDemuxerPacket = (CDVDMsgDemuxerPacket*)pMsg; DemuxPacket* pPacket = pMsgDemuxerPacket->GetPacket(); if (m_pOverlayCodec) { double pts = pPacket->dts != DVD_NOPTS_VALUE ? pPacket->dts : pPacket->pts; double duration = pPacket->duration; int result = m_pOverlayCodec->Decode(pPacket->pData, pPacket->iSize, pts, duration); if(result == OC_OVERLAY) { CDVDOverlay* overlay; while((overlay = m_pOverlayCodec->GetOverlay()) != NULL) { overlay->iGroupId = pPacket->iGroupId; if(pts == DVD_NOPTS_VALUE) { if(overlay->iPTSStartTime == 0 && overlay->iPTSStopTime == 0) CLog::Log(LOGWARNING, "%s - unable to find timestamp for overlay", __FUNCTION__); } else { // we assume pts is better than what // decoder gives us, only take duration // from decoder if available overlay->iPTSStopTime -= overlay->iPTSStartTime; overlay->iPTSStartTime = pts; if(overlay->iPTSStopTime == 0.0) overlay->iPTSStopTime = duration; overlay->iPTSStopTime += overlay->iPTSStartTime; } m_pOverlayContainer->Add(overlay); overlay->Release(); } } } else if (m_streaminfo.codec == CODEC_ID_DVD_SUBTITLE) { CSPUInfo* pSPUInfo = m_dvdspus.AddData(pPacket->pData, pPacket->iSize, pPacket->pts); if (pSPUInfo) { CLog::Log(LOGDEBUG, "CDVDPlayer::ProcessSubData: Got complete SPU packet"); pSPUInfo->iGroupId = pPacket->iGroupId; m_pOverlayContainer->Add(pSPUInfo); pSPUInfo->Release(); } } } else if( pMsg->IsType(CDVDMsg::SUBTITLE_CLUTCHANGE) ) { CDVDMsgSubtitleClutChange* pData = (CDVDMsgSubtitleClutChange*)pMsg; for (int i = 0; i < 16; i++) { BYTE* color = m_dvdspus.m_clut[i]; BYTE* t = (BYTE*)pData->m_data[i]; color[0] = t[2]; // Y color[1] = t[1]; // Cr color[2] = t[0]; // Cb } m_dvdspus.m_bHasClut = true; } else if( pMsg->IsType(CDVDMsg::GENERAL_FLUSH) ) { m_dvdspus.Reset(); if (m_pSubtitleFileParser) m_pSubtitleFileParser->Reset(); if (m_pOverlayCodec) m_pOverlayCodec->Flush(); m_lastPts = DVD_NOPTS_VALUE; } pMsg->Release(); }
void OMXPlayerVideo::ProcessOverlays(int iGroupId, double pts) { // remove any overlays that are out of time if (m_started) m_pOverlayContainer->CleanUp(pts - m_iSubtitleDelay); enum EOverlay { OVERLAY_AUTO // select mode auto , OVERLAY_GPU // render osd using gpu , OVERLAY_BUF // render osd on buffer } render = OVERLAY_AUTO; /* if(m_pOverlayContainer->ContainsOverlayType(DVDOVERLAY_TYPE_SPU) || m_pOverlayContainer->ContainsOverlayType(DVDOVERLAY_TYPE_IMAGE) || m_pOverlayContainer->ContainsOverlayType(DVDOVERLAY_TYPE_SSA) ) render = OVERLAY_BUF; */ if(render == OVERLAY_BUF) { // rendering spu overlay types directly on video memory costs a lot of processing power. // thus we allocate a temp picture, copy the original to it (needed because the same picture can be used more than once). // then do all the rendering on that temp picture and finaly copy it to video memory. // In almost all cases this is 5 or more times faster!. if(m_pTempOverlayPicture && ( m_pTempOverlayPicture->iWidth != m_width || m_pTempOverlayPicture->iHeight != m_height)) { CDVDCodecUtils::FreePicture(m_pTempOverlayPicture); m_pTempOverlayPicture = NULL; } if(!m_pTempOverlayPicture) m_pTempOverlayPicture = CDVDCodecUtils::AllocatePicture(m_width, m_height); if(!m_pTempOverlayPicture) return; m_pTempOverlayPicture->format = RENDER_FMT_YUV420P; } if(render == OVERLAY_AUTO) render = OVERLAY_GPU; VecOverlays overlays; { CSingleLock lock(*m_pOverlayContainer); VecOverlays* pVecOverlays = m_pOverlayContainer->GetOverlays(); VecOverlaysIter it = pVecOverlays->begin(); //Check all overlays and render those that should be rendered, based on time and forced //Both forced and subs should check timeing, pts == 0 in the stillframe case while (it != pVecOverlays->end()) { CDVDOverlay* pOverlay = *it++; if(!pOverlay->bForced && !m_bRenderSubs) continue; if(pOverlay->iGroupId != iGroupId) continue; double pts2 = pOverlay->bForced ? pts : pts - m_iSubtitleDelay; if((pOverlay->iPTSStartTime <= pts2 && (pOverlay->iPTSStopTime > pts2 || pOverlay->iPTSStopTime == 0LL)) || pts == 0) { if(pOverlay->IsOverlayType(DVDOVERLAY_TYPE_GROUP)) overlays.insert(overlays.end(), static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.begin() , static_cast<CDVDOverlayGroup*>(pOverlay)->m_overlays.end()); else overlays.push_back(pOverlay); } } for(it = overlays.begin(); it != overlays.end(); ++it) { double pts2 = (*it)->bForced ? pts : pts - m_iSubtitleDelay; if (render == OVERLAY_GPU) g_renderManager.AddOverlay(*it, pts2); /* printf("subtitle : DVDOVERLAY_TYPE_SPU %d DVDOVERLAY_TYPE_IMAGE %d DVDOVERLAY_TYPE_SSA %d\n", m_pOverlayContainer->ContainsOverlayType(DVDOVERLAY_TYPE_SPU), m_pOverlayContainer->ContainsOverlayType(DVDOVERLAY_TYPE_IMAGE), m_pOverlayContainer->ContainsOverlayType(DVDOVERLAY_TYPE_SSA) ); */ if (render == OVERLAY_BUF) CDVDOverlayRenderer::Render(m_pTempOverlayPicture, *it, pts2); } } }