void CDVBSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox) { DVB_PAGE* pPage = FindPage(rt); if (pPage != NULL) { pPage->rendered = true; TRACE_DVB(_T("DVB - Renderer - %s - %s\n"), ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); for (int i = 0; i < pPage->regionCount; i++) { DVB_REGION* pRegion = &pPage->regions[i]; DVB_CLUT* pCLUT = FindClut(pPage, pRegion->CLUT_id); if (pCLUT) { for (int j = 0; j < pRegion->objectCount; j++) { CompositionObject* pObject = FindObject(pPage, pRegion->objects[j].object_id); if (pObject) { short nX, nY; nX = pRegion->horizAddr + pRegion->objects[j].object_horizontal_position; nY = pRegion->vertAddr + pRegion->objects[j].object_vertical_position; pObject->m_width = pRegion->width; pObject->m_height = pRegion->height; pObject->SetPalette(pCLUT->size, pCLUT->palette, m_Display.width > 720); pObject->RenderDvb(spd, nX, nY); TRACE_DVB(_T(" --> %d/%d - %d/%d\n"), i + 1, pPage->regionCount, j + 1, pRegion->objectCount); } } } } bbox.left = 0; bbox.top = 0; bbox.right = m_Display.width; bbox.bottom = m_Display.height; } }
void CDVBSub::EndOfStream() { // Enqueue the last page if necessary. TRACE_DVB(_T("DVB - EndOfStream")); if (m_pCurrentPage) { TRACE_DVB(_T(": Enqueue last page")); EnqueuePage(INVALID_TIME); } else { TRACE_DVB(_T(" ignored: no page to enqueue\n")); } }
STDMETHODIMP CDVBSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) { CAutoLock cAutoLock(&m_csCritSec); rt -= m_rtCurrentSegmentStart; // Make sure the timing are relative to the current segment start RemoveOldPages(rt); if (POSITION posPage = FindPage(rt)) { const auto& pPage = m_pages.GetAt(posPage); bool BT709 = m_infoSourceTarget.sourceMatrix == BT_709 ? true : m_infoSourceTarget.sourceMatrix == NONE ? (m_displayInfo.width > 720) : false; pPage->rendered = true; TRACE_DVB(_T("DVB - Renderer - %s - %s\n"), ReftimeToString(pPage->rtStart + m_rtCurrentSegmentStart), ReftimeToString(pPage->rtStop + m_rtCurrentSegmentStart)); int nRegion = 1, nObject = 1; for (POSITION pos = pPage->regionsPos.GetHeadPosition(); pos; nRegion++) { DVB_REGION_POS regionPos = pPage->regionsPos.GetNext(pos); if (POSITION posRegion = FindRegion(pPage, regionPos.id)) { const auto& pRegion = pPage->regions.GetAt(posRegion); if (POSITION posCLUT = FindClut(pPage, pRegion->CLUT_id)) { const auto& pCLUT = pPage->CLUTs.GetAt(posCLUT); for (POSITION posO = pRegion->objects.GetHeadPosition(); posO; nObject++) { DVB_OBJECT objectPos = pRegion->objects.GetNext(posO); if (POSITION posObject = FindObject(pPage, objectPos.object_id)) { const auto& pObject = pPage->objects.GetAt(posObject); short nX = regionPos.horizAddr + objectPos.object_horizontal_position; short nY = regionPos.vertAddr + objectPos.object_vertical_position; pObject->m_width = pRegion->width; pObject->m_height = pRegion->height; pObject->SetPalette(pCLUT->size, pCLUT->palette, BT709, m_infoSourceTarget.sourceBlackLevel, m_infoSourceTarget.sourceWhiteLevel, m_infoSourceTarget.targetBlackLevel, m_infoSourceTarget.targetWhiteLevel); pObject->RenderDvb(spd, nX, nY); TRACE_DVB(_T(" --> %d/%d - %d/%d\n"), nRegion, pPage->regionsPos.GetCount(), nObject, pRegion->objects.GetCount()); } } } } } bbox.left = 0; bbox.top = 0; bbox.right = m_displayInfo.width; bbox.bottom = m_displayInfo.height; } return S_OK; }
void CDVBSub::EndOfStream() { CAutoLock cAutoLock(&m_csCritSec); // Enqueue the last page if necessary. if (m_pCurrentPage) { TRACE_DVB(_T("DVB - EndOfStream: Enqueue last page\n")); EnqueuePage(INVALID_TIME); } else { TRACE_DVB(_T("DVB - EndOfStream ignored: no page to enqueue\n")); } }
HRESULT CDVBSub::AddToBuffer(BYTE* pData, int nSize) { bool bFirstChunk = (*((LONG*)pData) & 0x00FFFFFF) == 0x000f0020; // DVB sub start with 0x20 0x00 0x0F ... if (m_nBufferWritePos > 0 || bFirstChunk) { if (bFirstChunk) { m_nBufferWritePos = 0; m_nBufferReadPos = 0; } if (m_nBufferWritePos + nSize > m_nBufferSize) { if (m_nBufferWritePos + nSize > 20 * BUFFER_CHUNK_GROW) { // Too big to be a DVB sub ! TRACE_DVB("DVB - Too much data received...\n"); ASSERT(FALSE); Reset(); return E_INVALIDARG; } BYTE* pPrev = m_pBuffer; m_nBufferSize = max(m_nBufferWritePos + nSize, m_nBufferSize + BUFFER_CHUNK_GROW); m_pBuffer = DNew BYTE[m_nBufferSize]; if (pPrev != NULL) { memcpy_s(m_pBuffer, m_nBufferSize, pPrev, m_nBufferWritePos); SAFE_DELETE(pPrev); } } memcpy_s(m_pBuffer + m_nBufferWritePos, m_nBufferSize, pData, nSize); m_nBufferWritePos += nSize; return S_OK; } return S_FALSE; }
HRESULT CDVBSub::EndOfStream() { if (m_pCurrentPage != NULL) { TRACE_DVB (_T("DVB - EndOfStream() : %ws => %ws\n"), ReftimeToString(m_pCurrentPage->rtStart), ReftimeToString(m_pCurrentPage->rtStop)); m_Pages.AddTail (m_pCurrentPage.Detach()); } return S_OK; }
HRESULT CDVBSub::EnqueuePage(REFERENCE_TIME rtStop) { if (m_pCurrentPage->rtStart < rtStop && m_pCurrentPage->rtStop > rtStop) { m_pCurrentPage->rtStop = rtStop; } TRACE_DVB(_T(" %s (%s - %s)\n"), ReftimeToString(rtStop), ReftimeToString(m_pCurrentPage->rtStart), ReftimeToString(m_pCurrentPage->rtStop)); m_Pages.AddTail(m_pCurrentPage.Detach()); return S_OK; }
void CDVBSub::RemoveOldPages(REFERENCE_TIME rt) { // Cleanup the old pages. We keep a 2 min buffer to play nice with the queue. while (!m_pages.IsEmpty() && m_pages.GetHead()->rtStop + 120 * 10000000i64 < rt) { auto pPage = m_pages.RemoveHead(); if (!pPage->rendered) { TRACE_DVB(_T("DVB - remove unrendered object, %s - %s\n"), ReftimeToString(pPage->rtStart + m_rtCurrentSegmentStart), ReftimeToString(pPage->rtStop + m_rtCurrentSegmentStart)); } } }
HRESULT CDVBSub::EnqueuePage(REFERENCE_TIME rtStop) { ASSERT(m_pCurrentPage != nullptr); if (m_pCurrentPage->rtStart < rtStop && m_pCurrentPage->rtStop > rtStop) { m_pCurrentPage->rtStop = rtStop; } TRACE_DVB(_T("DVB - Enqueue page %s (%s - %s)\n"), ReftimeToString(rtStop), ReftimeToString(m_pCurrentPage->rtStart), ReftimeToString(m_pCurrentPage->rtStop)); m_pages.AddTail(m_pCurrentPage); return S_OK; }
HRESULT CDVBSub::UpdateTimeStamp(REFERENCE_TIME rtStop) { HRESULT hr = S_FALSE; POSITION pos = m_Pages.GetTailPosition(); while (pos) { DVB_PAGE* pPage = m_Pages.GetPrev(pos); if (pPage->rtStop > rtStop) { TRACE_DVB(_T("DVB - Updated end of display %s - %s --> %s - %s\n"), ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop), ReftimeToString(pPage->rtStart), ReftimeToString(rtStop)); pPage->rtStop = rtStop; hr = S_OK; } else { break; } } return hr; }
void CDVBSub::CleanOld(REFERENCE_TIME rt) { // Cleanup old PG DVB_PAGE* pPage_old; while (m_Pages.GetCount()>0) { pPage_old = m_Pages.GetHead(); if (pPage_old->rtStop < rt) { if (!pPage_old->Rendered) { TRACE_DVB (_T("DVB - remove unrendered object, %ws => %ws, (rt = %ws)\n"), ReftimeToString(pPage_old->rtStart), ReftimeToString(pPage_old->rtStop), ReftimeToString(rt)); } m_Pages.RemoveHead(); delete pPage_old; } else { break; } } }
POSITION CDVBSub::GetStartPosition(REFERENCE_TIME rt, double fps) { DVB_PAGE* pPage; // Cleanup old PG while (m_Pages.GetCount() > 0) { pPage = m_Pages.GetHead(); if (pPage->rtStop < rt) { if (!pPage->Rendered) { TRACE_DVB("DVB - remove unrendered object, %S - %S\n", ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); } m_Pages.RemoveHead(); delete pPage; } else { break; } } return m_Pages.GetHeadPosition(); }
void CDVBSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox) { DVB_PAGE* pPage = FindPage (rt); if (pPage != NULL) { pPage->Rendered = true; for (int i=0; i<pPage->RegionCount; i++) { CDVBSub::DVB_REGION* pRegion = &pPage->Regions[i]; for (int j=0; j<pRegion->ObjectCount; j++) { CompositionObject* pObject = FindObject (pPage, pRegion->Objects[j].object_id); if (pObject) { SHORT nX, nY; nX = pRegion->HorizAddr + pRegion->Objects[j].object_horizontal_position; nY = pRegion->VertAddr + pRegion->Objects[j].object_vertical_position; pObject->m_width = pRegion->width; pObject->m_height = pRegion->height; CDVBSub::DVB_CLUT* pClut = FindClut(pPage, pRegion->CLUT_id); if (pClut != NULL) { pObject->SetPalette(pClut->Size, pClut->Palette, m_Display.width > 720); } TRACE_DVB (_T("CDVBSub::Render() : size = %ld, %d:%d, ObjRes = %dx%d, SPDRes = %dx%d, %I64d = %ws, [%ws => %ws]\n"), pObject->GetRLEDataSize(), nX, nY, pObject->m_width, pObject->m_height, spd.w, spd.h, rt, ReftimeToString(rt), ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); pObject->RenderDvb(spd, nX, nY); } } } bbox.left = 0; bbox.top = 0; bbox.right = m_Display.width < spd.w ? m_Display.width : spd.w; ASSERT(spd.h >= 0); bbox.bottom = m_Display.height < spd.h ? m_Display.height : spd.h; } }
POSITION CDVBSub::GetStartPosition(REFERENCE_TIME rt, double fps) { DVB_PAGE* pPage; // Cleanup old PG while (m_Pages.GetCount()>0) { pPage = m_Pages.GetHead(); if (pPage->rtStop < rt) { if (!pPage->Rendered) { TRACE_DVB ("DVB - remove unrendered object, %S - %S\n", ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); } //TRACE_HDMVSUB ("CHdmvSub:HDMV remove object %d %S => %S (rt=%S)\n", pPage->GetRLEDataSize(), // ReftimeToString (pPage->rtStart), ReftimeToString(pPage->rtStop), ReftimeToString(rt)); m_Pages.RemoveHead(); delete pPage; } else { break; } } return m_Pages.GetHeadPosition(); }
HRESULT CDVBSub::ParseObject(CGolombBuffer& gb, WORD wSegLength) { HRESULT hr = E_POINTER; if (m_pCurrentPage) { size_t nExpectedSize = 3; size_t nEnd = gb.GetPos() + wSegLength; short id = gb.ReadShort(); POSITION posObject = FindObject(m_pCurrentPage, id); if (!posObject) { posObject = m_pCurrentPage->objects.AddTail(CAutoPtr<CompositionObject>(DEBUG_NEW CompositionObject())); } const auto& pObject = m_pCurrentPage->objects.GetAt(posObject); pObject->m_object_id_ref = id; pObject->m_version_number = (BYTE)gb.BitRead(4); BYTE object_coding_method = (BYTE)gb.BitRead(2); // object_coding_method gb.BitRead(1); // non_modifying_colour_flag gb.BitRead(1); // reserved if (object_coding_method == 0x00) { pObject->SetRLEData(gb.GetBufferPos(), wSegLength - nExpectedSize, wSegLength - nExpectedSize); gb.SkipBytes(wSegLength - 3); hr = (wSegLength >= nExpectedSize) ? S_OK : E_UNEXPECTED; } else { TRACE_DVB(_T("DVB - Text subtitles are currently not supported\n")); m_pCurrentPage->objects.RemoveTail(); hr = E_NOTIMPL; } } return hr; }
HRESULT CDVBSub::ParseSample(IMediaSample* pSample) { CheckPointer (pSample, E_POINTER); HRESULT hr; BYTE* pData = NULL; int nSize; DVB_SEGMENT_TYPE nCurSegment; hr = pSample->GetPointer(&pData); if (FAILED(hr) || pData == NULL) { return hr; } nSize = pSample->GetActualDataLength(); if (*((LONG*)pData) == 0xBD010000) { CGolombBuffer gb (pData, nSize); gb.SkipBytes(4); WORD wLength = (WORD)gb.BitRead(16); UNREFERENCED_PARAMETER(wLength); if (gb.BitRead(2) != 2) { return E_FAIL; // type } gb.BitRead(2); // scrambling gb.BitRead(1); // priority gb.BitRead(1); // alignment gb.BitRead(1); // copyright gb.BitRead(1); // original BYTE fpts = (BYTE)gb.BitRead(1); // fpts BYTE fdts = (BYTE)gb.BitRead(1); // fdts gb.BitRead(1); // escr gb.BitRead(1); // esrate gb.BitRead(1); // dsmtrickmode gb.BitRead(1); // morecopyright gb.BitRead(1); // crc gb.BitRead(1); // extension gb.BitRead(8); // hdrlen if (fpts) { BYTE b = (BYTE)gb.BitRead(4); if (!(fdts && b == 3 || !fdts && b == 2)) { ASSERT(0); return(E_FAIL); } REFERENCE_TIME pts = 0; pts |= gb.BitRead(3) << 30; MARKER; // 32..30 pts |= gb.BitRead(15) << 15; MARKER; // 29..15 pts |= gb.BitRead(15); MARKER; // 14..0 pts = 10000*pts/90; m_rtStart = pts; m_rtStop = pts+1; } else { m_rtStart = INVALID_TIME; m_rtStop = INVALID_TIME; } nSize -= 14; pData += 14; pSample->GetTime(&m_rtStart, &m_rtStop); pSample->GetMediaTime(&m_rtStart, &m_rtStop); } else if (SUCCEEDED (pSample->GetTime(&m_rtStart, &m_rtStop))) { pSample->SetTime(&m_rtStart, &m_rtStop); } if (AddToBuffer (pData, nSize) == S_OK) { CGolombBuffer gb (m_pBuffer+m_nBufferReadPos, m_nBufferWritePos-m_nBufferReadPos); int nLastPos = 0; while (!gb.IsEOF()) { if (gb.ReadByte() == 0x0F) { WORD wPageId; WORD wSegLength; nCurSegment = (DVB_SEGMENT_TYPE) gb.ReadByte(); wPageId = gb.ReadShort(); wSegLength = gb.ReadShort(); if (gb.RemainingSize() < wSegLength) { hr = S_FALSE; break; } TRACE_DVB (_T("DVB - ParseSample, Segment = [%ws], PageId = [%d], SegLength/Buffer = [%d]/[%d]\n"), GetSegmentType(nCurSegment), wPageId, wSegLength, gb.RemainingSize()); switch (nCurSegment) { case PAGE : { CAutoPtr<DVB_PAGE> pPage; ParsePage(gb, wSegLength, pPage); if (pPage->PageState == DPS_ACQUISITION || pPage->PageState == DPS_MODE) { TRACE_DVB (_T("DVB - Page start\n")); if (m_pCurrentPage != NULL) { m_pCurrentPage->rtStop = min(m_pCurrentPage->rtStop, m_rtStart); TRACE_DVB (_T("DVB - store Page : %ws => %ws\n"), ReftimeToString(m_pCurrentPage->rtStart), ReftimeToString(m_pCurrentPage->rtStop)); m_Pages.AddTail (m_pCurrentPage.Detach()); } UpdateTimeStamp(m_rtStart); m_pCurrentPage = pPage; m_pCurrentPage->rtStart = m_rtStart; m_pCurrentPage->rtStop = m_pCurrentPage->rtStart + m_pCurrentPage->PageTimeOut * UNITS; // TODO - need to limit the duration of the segment TRACE_DVB (_T("DVB - Page started : %ws, TimeOut = %d\n"), ReftimeToString(m_pCurrentPage->rtStart), m_pCurrentPage->PageTimeOut); } else if (pPage->PageState == DPS_NORMAL) { TRACE_DVB (_T("DVB - Page update\n")); if (m_pCurrentPage && !m_pCurrentPage->RegionCount && pPage->RegionCount) { m_pCurrentPage = pPage; m_pCurrentPage->rtStart = m_rtStart; m_pCurrentPage->rtStop = m_pCurrentPage->rtStart + m_pCurrentPage->PageTimeOut * UNITS; // TODO - need to limit the duration of the segment TRACE_DVB (_T("DVB - Page started[update] : %ws, TimeOut = %d\n"), ReftimeToString(m_pCurrentPage->rtStart), m_pCurrentPage->PageTimeOut); } } } break; case REGION : ParseRegion(gb, wSegLength); TRACE_DVB (_T("DVB - Region\n")); break; case CLUT : ParseClut(gb, wSegLength); TRACE_DVB (_T("DVB - Clut\n")); break; case OBJECT : ParseObject(gb, wSegLength); TRACE_DVB (_T("DVB - Object\n")); break; case DISPLAY : ParseDisplay(gb, wSegLength); TRACE_DVB (_T("DVB - Display\n")); break; case END_OF_DISPLAY : /* if (m_pCurrentPage != NULL && (m_pCurrentPage->rtStart != m_rtStart)) { m_pCurrentPage->rtStop = max(m_pCurrentPage->rtStop, m_rtStart); TRACE_DVB (_T("DVB - End display : %ws => %ws\n"), ReftimeToString(m_pCurrentPage->rtStart), ReftimeToString(m_pCurrentPage->rtStop)); m_Pages.AddTail (m_pCurrentPage.Detach()); } */ TRACE_DVB (_T("DVB - End display\n")); break; default : TRACE_DVB (_T("DVB - unknown Segment\n")); break; } nLastPos = gb.GetPos(); } } m_nBufferReadPos += nLastPos; } return hr; }
HRESULT CDVBSub::ParseSample(IMediaSample* pSample) { CheckPointer(pSample, E_POINTER); HRESULT hr; BYTE* pData = NULL; int nSize; DVB_SEGMENT_TYPE nCurSegment; hr = pSample->GetPointer(&pData); if (FAILED(hr) || pData == NULL) { return hr; } nSize = pSample->GetActualDataLength(); if (*((LONG*)pData) == 0xBD010000) { CGolombBuffer gb(pData, nSize); gb.SkipBytes(4); WORD wLength = (WORD)gb.BitRead(16); UNREFERENCED_PARAMETER(wLength); if (gb.BitRead(2) != 2) { return E_FAIL; // type } gb.BitRead(2); // scrambling gb.BitRead(1); // priority gb.BitRead(1); // alignment gb.BitRead(1); // copyright gb.BitRead(1); // original BYTE fpts = (BYTE)gb.BitRead(1); // fpts BYTE fdts = (BYTE)gb.BitRead(1); // fdts gb.BitRead(1); // escr gb.BitRead(1); // esrate gb.BitRead(1); // dsmtrickmode gb.BitRead(1); // morecopyright gb.BitRead(1); // crc gb.BitRead(1); // extension gb.BitRead(8); // hdrlen if (fpts) { BYTE b = (BYTE)gb.BitRead(4); if (!(fdts && b == 3 || !fdts && b == 2)) { ASSERT(0); return E_FAIL; } REFERENCE_TIME pts = 0; pts |= gb.BitRead(3) << 30; MARKER; // 32..30 pts |= gb.BitRead(15) << 15; MARKER; // 29..15 pts |= gb.BitRead(15); MARKER; // 14..0 pts = 10000 * pts / 90; m_rtStart = pts; m_rtStop = pts + 1; } else { m_rtStart = INVALID_TIME; m_rtStop = INVALID_TIME; } nSize -= 14; pData += 14; pSample->GetTime(&m_rtStart, &m_rtStop); pSample->GetMediaTime(&m_rtStart, &m_rtStop); } else if (SUCCEEDED(pSample->GetTime(&m_rtStart, &m_rtStop))) { pSample->SetTime(&m_rtStart, &m_rtStop); } //FILE* hFile = fopen("D:\\Sources\\mpc-hc\\A garder\\TestSubRip\\dvbsub.dat", "ab"); //if (hFile != NULL) //{ // //BYTE Buff[5] = {48}; // //*((DWORD*)(Buff+1)) = lSampleLen; // //fwrite(Buff, 1, sizeof(Buff), hFile); // fwrite(pData, 1, lSampleLen, hFile); // fclose(hFile); //} if (AddToBuffer(pData, nSize) == S_OK) { CGolombBuffer gb(m_pBuffer + m_nBufferReadPos, m_nBufferWritePos - m_nBufferReadPos); int nLastPos = 0; while (!gb.IsEOF()) { if (gb.ReadByte() == 0x0F) { TRACE_DVB("DVB - ParseSample\n"); WORD wPageId; WORD wSegLength; nCurSegment = (DVB_SEGMENT_TYPE) gb.ReadByte(); wPageId = gb.ReadShort(); wSegLength = gb.ReadShort(); if (gb.RemainingSize() < wSegLength) { hr = S_FALSE; break; } switch (nCurSegment) { case PAGE: { CAutoPtr<DVB_PAGE> pPage; ParsePage(gb, wSegLength, pPage); if (pPage->PageState == DPS_ACQUISITION) { if (m_pCurrentPage != NULL) { m_pCurrentPage->rtStop = max(m_pCurrentPage->rtStop, m_rtStart); m_Pages.AddTail(m_pCurrentPage.Detach()); } UpdateTimeStamp(m_rtStart); m_pCurrentPage = pPage; m_pCurrentPage->rtStart = m_rtStart; m_pCurrentPage->rtStop = m_pCurrentPage->rtStart + m_pCurrentPage->PageTimeOut * 1000000; TRACE_DVB("DVB - Page started %S, TimeOut = %d\n", ReftimeToString(m_rtStart), m_pCurrentPage->PageTimeOut); } else { TRACE_DVB("DVB - Page update\n"); if (m_pCurrentPage && !m_pCurrentPage->RegionCount) { m_pCurrentPage = pPage; m_pCurrentPage->rtStart = m_rtStart; m_pCurrentPage->rtStop = m_pCurrentPage->rtStart + m_pCurrentPage->PageTimeOut * 1000000; TRACE_DVB("DVB - Page started[update] %S, TimeOut = %d\n", ReftimeToString(m_rtStart), m_pCurrentPage->PageTimeOut); } } } break; case REGION: ParseRegion(gb, wSegLength); TRACE_DVB("DVB - Region\n"); break; case CLUT: ParseClut(gb, wSegLength); TRACE_DVB("DVB - Clut\n"); break; case OBJECT: ParseObject(gb, wSegLength); TRACE_DVB("DVB - Object\n"); break; case DISPLAY: ParseDisplay(gb, wSegLength); TRACE_DVB("DVB - Display\n"); break; case END_OF_DISPLAY: if (m_pCurrentPage != NULL && (m_pCurrentPage->rtStart != m_rtStart)) { m_pCurrentPage->rtStop = max(m_pCurrentPage->rtStop, m_rtStart); TRACE_DVB("DVB - End display %S - %S\n", ReftimeToString(m_pCurrentPage->rtStart), ReftimeToString(m_pCurrentPage->rtStop)); m_Pages.AddTail(m_pCurrentPage.Detach()); } break; default: break; } nLastPos = gb.GetPos(); } } m_nBufferReadPos += nLastPos; } return hr; }
HRESULT CDVBSub::ParseSample(IMediaSample* pSample) { CheckPointer(pSample, E_POINTER); HRESULT hr; BYTE* pData = nullptr; int nSize; DVB_SEGMENT_TYPE nCurSegment; hr = pSample->GetPointer(&pData); if (FAILED(hr) || pData == nullptr) { return hr; } nSize = pSample->GetActualDataLength(); if (*((LONG*)pData) == 0xBD010000) { CGolombBuffer gb(pData, nSize); gb.SkipBytes(4); WORD wLength = (WORD)gb.BitRead(16); UNREFERENCED_PARAMETER(wLength); if (gb.BitRead(2) != 2) { return E_FAIL; // type } gb.BitRead(2); // scrambling gb.BitRead(1); // priority gb.BitRead(1); // alignment gb.BitRead(1); // copyright gb.BitRead(1); // original BYTE fpts = (BYTE)gb.BitRead(1); // fpts BYTE fdts = (BYTE)gb.BitRead(1); // fdts gb.BitRead(1); // escr gb.BitRead(1); // esrate gb.BitRead(1); // dsmtrickmode gb.BitRead(1); // morecopyright gb.BitRead(1); // crc gb.BitRead(1); // extension gb.BitRead(8); // hdrlen if (fpts) { BYTE b = (BYTE)gb.BitRead(4); if (!(fdts && b == 3 || !fdts && b == 2)) { ASSERT(0); return E_FAIL; } REFERENCE_TIME pts = 0; pts |= gb.BitRead(3) << 30; MARKER; // 32..30 pts |= gb.BitRead(15) << 15; MARKER; // 29..15 pts |= gb.BitRead(15); MARKER; // 14..0 pts = 10000 * pts / 90; m_rtStart = pts; m_rtStop = pts + 1; } else { m_rtStart = INVALID_TIME; m_rtStop = INVALID_TIME; } nSize -= 14; pData += 14; pSample->GetTime(&m_rtStart, &m_rtStop); pSample->GetMediaTime(&m_rtStart, &m_rtStop); } else if (SUCCEEDED(pSample->GetTime(&m_rtStart, &m_rtStop))) { pSample->SetTime(&m_rtStart, &m_rtStop); } if (AddToBuffer(pData, nSize) == S_OK) { CGolombBuffer gb(m_pBuffer + m_nBufferReadPos, m_nBufferWritePos - m_nBufferReadPos); int nLastPos = 0; while (gb.RemainingSize() >= 6) { // Ensure there is enough data to parse the entire segment header if (gb.ReadByte() == 0x0F) { TRACE_DVB(_T("DVB - ParseSample\n")); WORD wPageId; WORD wSegLength; nCurSegment = (DVB_SEGMENT_TYPE)gb.ReadByte(); wPageId = gb.ReadShort(); wSegLength = gb.ReadShort(); if (gb.RemainingSize() < wSegLength) { hr = S_FALSE; break; } switch (nCurSegment) { case PAGE: { if (m_pCurrentPage != nullptr) { TRACE_DVB(_T("DVB - Force End display")); EnqueuePage(m_rtStart); } UpdateTimeStamp(m_rtStart); CAutoPtr<DVB_PAGE> pPage; ParsePage(gb, wSegLength, pPage); if (pPage->pageState == DPS_ACQUISITION || pPage->pageState == DPS_MODE_CHANGE) { m_pCurrentPage = pPage; m_pCurrentPage->rtStart = m_rtStart; m_pCurrentPage->rtStop = m_pCurrentPage->rtStart + m_pCurrentPage->pageTimeOut * 10000000; TRACE_DVB(_T("DVB - Page started [pageState = %d] %s, TimeOut = %ds\n"), m_pCurrentPage->pageState, ReftimeToString(m_rtStart), m_pCurrentPage->pageTimeOut); } else if (!m_Pages.IsEmpty()) { m_pCurrentPage = pPage; m_pCurrentPage->rtStart = m_rtStart; m_pCurrentPage->rtStop = m_pCurrentPage->rtStart + m_pCurrentPage->pageTimeOut * 10000000; // Copy data from the previous page DVB_PAGE* pPrevPage = m_Pages.GetTail(); memcpy(m_pCurrentPage->regions, pPrevPage->regions, sizeof(m_pCurrentPage->regions)); for (POSITION pos = pPrevPage->objects.GetHeadPosition(); pos;) { m_pCurrentPage->objects.AddTail(pPrevPage->objects.GetNext(pos)->Copy()); } for (POSITION pos = pPrevPage->CLUTs.GetHeadPosition(); pos;) { m_pCurrentPage->CLUTs.AddTail(DEBUG_NEW DVB_CLUT(*pPrevPage->CLUTs.GetNext(pos))); } TRACE_DVB(_T("DVB - Page started [update] %s, TimeOut = %ds\n"), ReftimeToString(m_rtStart), m_pCurrentPage->pageTimeOut); } else { TRACE_DVB(_T("DVB - Page update ignored %s\n"), ReftimeToString(m_rtStart)); } } break; case REGION: ParseRegion(gb, wSegLength); TRACE_DVB(_T("DVB - Region\n")); break; case CLUT: ParseClut(gb, wSegLength); TRACE_DVB(_T("DVB - Clut\n")); break; case OBJECT: ParseObject(gb, wSegLength); TRACE_DVB(_T("DVB - Object\n")); break; case DISPLAY: ParseDisplay(gb, wSegLength); TRACE_DVB(_T("DVB - Display\n")); break; case END_OF_DISPLAY: if (m_pCurrentPage == nullptr) { TRACE_DVB(_T("DVB - Ignored End display %s: no current page\n"), ReftimeToString(m_rtStart)); } else if (m_pCurrentPage->rtStart < m_rtStart) { TRACE_DVB(_T("DVB - End display")); EnqueuePage(m_rtStart); } else { TRACE_DVB(_T("DVB - Ignored End display %s: no information on page duration\n"), ReftimeToString(m_rtStart)); } break; default: break; } nLastPos = gb.GetPos(); } } m_nBufferReadPos += nLastPos; } return hr; }