HRESULT CDVBSub::ParseObject(CGolombBuffer& gb, WORD wSegLength) { HRESULT hr = E_FAIL; if (m_pCurrentPage && wSegLength > 2) { CompositionObject* pObject = DNew CompositionObject(); BYTE object_coding_method; pObject->m_object_id_ref = gb.ReadShort(); pObject->m_version_number = (BYTE)gb.BitRead(4); 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 - 3, wSegLength - 3); gb.SkipBytes(wSegLength - 3); m_pCurrentPage->Objects.AddTail(pObject); hr = S_OK; } else { delete pObject; hr = E_NOTIMPL; } } return hr; }
int CPGSSub::ParsePresentationSegment(REFERENCE_TIME rt, CGolombBuffer* pGBuffer) { m_pCurrentPresentationSegment.Free(); m_pCurrentPresentationSegment.Attach(DEBUG_NEW HDMV_PRESENTATION_SEGMENT()); m_pCurrentPresentationSegment->rtStart = rt; m_pCurrentPresentationSegment->rtStop = UNKNOWN_TIME; // Unknown for now ParseVideoDescriptor(pGBuffer, &m_pCurrentPresentationSegment->video_descriptor); ParseCompositionDescriptor(pGBuffer, &m_pCurrentPresentationSegment->composition_descriptor); m_pCurrentPresentationSegment->palette_update_flag = !!(pGBuffer->ReadByte() & 0x80); m_pCurrentPresentationSegment->CLUT.id = pGBuffer->ReadByte(); m_pCurrentPresentationSegment->objectCount = pGBuffer->ReadByte(); TRACE_PGSSUB(_T("CPGSSub::ParsePresentationSegment Size = %d, state = %#x, nObjectNumber = %d\n"), pGBuffer->GetSize(), m_pCurrentPresentationSegment->composition_descriptor.bState, m_pCurrentPresentationSegment->objectCount); for (int i = 0; i < m_pCurrentPresentationSegment->objectCount; i++) { std::unique_ptr<CompositionObject> pCompositionObject(DEBUG_NEW CompositionObject()); if (ParseCompositionObject(pGBuffer, pCompositionObject)) { m_pCurrentPresentationSegment->objects.emplace_back(std::move(pCompositionObject)); } } return m_pCurrentPresentationSegment->objectCount; }
int CHdmvSub::ParsePresentationSegment(CGolombBuffer* pGBuffer) { COMPOSITION_DESCRIPTOR CompositionDescriptor; BYTE nObjectNumber; //bool palette_update_flag; //BYTE palette_id_ref; ParseVideoDescriptor(pGBuffer, &m_VideoDescriptor); ParseCompositionDescriptor(pGBuffer, &CompositionDescriptor); pGBuffer->ReadByte(); //palette_update_flag = !!(pGBuffer->ReadByte() & 0x80); pGBuffer->ReadByte(); //palette_id_ref = pGBuffer->ReadByte(); nObjectNumber = pGBuffer->ReadByte(); TRACE_HDMVSUB( "CHdmvSub::ParsePresentationSegment Size = %d, nObjectNumber = %d\n", pGBuffer->GetSize(), nObjectNumber); if (nObjectNumber > 0) { delete m_pCurrentObject; m_pCurrentObject = DNew CompositionObject(); m_pCurrentObject->m_nObjectNumber = nObjectNumber; for (int i=0; i<nObjectNumber; i++) { ParseCompositionObject (pGBuffer, m_pCurrentObject); } } return nObjectNumber; }
int CHdmvSub::ParsePresentationSegment(CGolombBuffer* pGBuffer) { COMPOSITION_DESCRIPTOR CompositionDescriptor; BYTE nObjectNumber; bool palette_update_flag; BYTE palette_id_ref; ParseVideoDescriptor(pGBuffer, &m_VideoDescriptor); ParseCompositionDescriptor(pGBuffer, &CompositionDescriptor); palette_update_flag = !!(pGBuffer->ReadByte() & 0x80); palette_id_ref = pGBuffer->ReadByte(); nObjectNumber = pGBuffer->ReadByte(); if (nObjectNumber > 0) { delete m_pCurrentObject; m_pCurrentObject = DNew CompositionObject(); ParseCompositionObject (pGBuffer, m_pCurrentObject); } return nObjectNumber; }
int CHdmvSub::ParsePresentationSegment(REFERENCE_TIME rt, CGolombBuffer* pGBuffer) { m_pCurrentPresentationSegment = DEBUG_NEW HDMV_PRESENTATION_SEGMENT(); m_pCurrentPresentationSegment->rtStart = rt; m_pCurrentPresentationSegment->rtStop = _I64_MAX; ParseVideoDescriptor(pGBuffer, &m_pCurrentPresentationSegment->video_descriptor); ParseCompositionDescriptor(pGBuffer, &m_pCurrentPresentationSegment->composition_descriptor); m_pCurrentPresentationSegment->palette_update_flag = !!(pGBuffer->ReadByte() & 0x80); m_pCurrentPresentationSegment->CLUT.id = pGBuffer->ReadByte(); m_pCurrentPresentationSegment->objectCount = pGBuffer->ReadByte(); TRACE_HDMVSUB( (_T("CHdmvSub::ParsePresentationSegment Size = %d, state = %#x, nObjectNumber = %d\n"), pGBuffer->GetSize(), m_pCurrentPresentationSegment->composition_descriptor.bState, m_pCurrentPresentationSegment->objectCount) ); for (int i = 0; i < m_pCurrentPresentationSegment->objectCount; i++) { CompositionObject* pCompositionObject = DEBUG_NEW CompositionObject(); ParseCompositionObject(pGBuffer, pCompositionObject); m_pCurrentPresentationSegment->objects.AddTail(pCompositionObject); } return m_pCurrentPresentationSegment->objectCount; }
void CHdmvSub::ParsePresentationSegment(CGolombBuffer* pGBuffer, REFERENCE_TIME rtTime) { COMPOSITION_DESCRIPTOR CompositionDescriptor; BYTE nObjectNumber; bool palette_update_flag; BYTE palette_id_ref; ParseVideoDescriptor(pGBuffer, &m_VideoDescriptor); ParseCompositionDescriptor(pGBuffer, &CompositionDescriptor); palette_update_flag = !!(pGBuffer->ReadByte() & 0x80); UNREFERENCED_PARAMETER(palette_update_flag); palette_id_ref = pGBuffer->ReadByte(); nObjectNumber = pGBuffer->ReadByte(); TRACE_HDMVSUB(_T("CHdmvSub::ParsePresentationSegment() : Size = %d, nObjectNumber = %d, palette_id_ref = %d, compositionNumber = %d\n"), pGBuffer->GetSize(), nObjectNumber, palette_id_ref, CompositionDescriptor.nNumber); if (m_pCurrentWindow && m_pCurrentWindow->m_nObjectNumber && m_pCurrentWindow->m_compositionNumber != -1) { for (int i = 0; i < m_pCurrentWindow->m_nObjectNumber; i++) { if (m_pCurrentWindow->Objects[i]) { CompositionObject* pObject = m_pCurrentWindow->Objects[i]; CompositionObject& pObjectData = m_ParsedObjects[pObject->m_object_id_ref]; if (pObjectData.m_width) { pObject->m_rtStop = rtTime; pObject->m_width = pObjectData.m_width; pObject->m_height = pObjectData.m_height; pObject->SetRLEData(pObjectData.GetRLEData(), pObjectData.GetRLEDataSize(), pObjectData.GetRLEDataSize()); if (!pObject->HavePalette() && m_CLUT[palette_id_ref].Palette) { pObject->SetPalette(m_CLUT[palette_id_ref].pSize, m_CLUT[palette_id_ref].Palette, m_VideoDescriptor.nVideoWidth > 720); } TRACE_HDMVSUB(_T(" store Segment : m_object_id_ref = %d, m_window_id_ref = %d, compositionNumber = %d, [%10I64d -> %10I64d], [%s -> %s]\n"), m_pCurrentWindow->Objects[i]->m_object_id_ref, m_pCurrentWindow->Objects[i]->m_window_id_ref, m_pCurrentWindow->Objects[i]->m_compositionNumber, m_pCurrentWindow->Objects[i]->m_rtStart, m_pCurrentWindow->Objects[i]->m_rtStop, ReftimeToString(m_pCurrentWindow->Objects[i]->m_rtStart), ReftimeToString(m_pCurrentWindow->Objects[i]->m_rtStop)); m_pObjects.AddTail (m_pCurrentWindow->Objects[i]); } else { delete m_pCurrentWindow->Objects[i]; } } m_pCurrentWindow->Objects[i] = NULL; } } if (!m_pCurrentWindow) { m_pCurrentWindow = DNew HDMV_WindowDefinition(); } else { m_pCurrentWindow->Reset(); } if (nObjectNumber > 0) { m_pCurrentWindow->m_nObjectNumber = nObjectNumber; m_pCurrentWindow->m_palette_id_ref = (SHORT)palette_id_ref; m_pCurrentWindow->m_compositionNumber = CompositionDescriptor.nNumber; for (int i = 0; i < nObjectNumber; i++) { m_pCurrentWindow->Objects[i] = DNew CompositionObject(); m_pCurrentWindow->Objects[i]->m_rtStart = rtTime; m_pCurrentWindow->Objects[i]->m_rtStop = _I64_MAX; m_pCurrentWindow->Objects[i]->m_compositionNumber = CompositionDescriptor.nNumber; ParseCompositionObject(pGBuffer, m_pCurrentWindow->Objects[i]); } } }
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); CAutoLock cAutoLock(&m_csCritSec); 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(FALSE); 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); } hr = AddToBuffer(pData, nSize); if (hr == S_OK) { CGolombBuffer gb(m_pBuffer + m_nBufferReadPos, m_nBufferWritePos - m_nBufferReadPos); size_t 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) { TRACE_DVB(_T("DVB - Full segment isn't availabled yet, delaying parsing (%Iu/%hu)\n"), gb.RemainingSize(), wSegLength); hr = S_FALSE; break; } hr = S_OK; switch (nCurSegment) { case PAGE: { if (m_pCurrentPage != nullptr) { TRACE_DVB(_T("DVB - Force End display\n")); EnqueuePage(m_rtStart); } UpdateTimeStamp(m_rtStart); CAutoPtr<DVB_PAGE> pPage; hr = ParsePage(gb, wSegLength, pPage); pPage->rtStart = m_rtStart; pPage->rtStop = pPage->rtStart + pPage->pageTimeOut * 10000000; if (FAILED(hr)) { pPage.Free(); } else if (pPage->pageState == DPS_ACQUISITION || pPage->pageState == DPS_MODE_CHANGE) { m_pCurrentPage = pPage; TRACE_DVB(_T("DVB - Page started [pageState = %d] %s, TimeOut = %ds\n"), m_pCurrentPage->pageState, ReftimeToString(m_rtStart + m_rtCurrentSegmentStart), m_pCurrentPage->pageTimeOut); } else if (pPage->pageState == DPS_NORMAL && !m_pages.IsEmpty()) { m_pCurrentPage = pPage; // Copy data from the previous page const auto& pPrevPage = m_pages.GetTail(); for (POSITION pos = pPrevPage->regions.GetHeadPosition(); pos;) { m_pCurrentPage->regions.AddTail(CAutoPtr<DVB_REGION>(DEBUG_NEW DVB_REGION(*pPrevPage->regions.GetNext(pos)))); } for (POSITION pos = pPrevPage->objects.GetHeadPosition(); pos;) { m_pCurrentPage->objects.AddTail(CAutoPtr<CompositionObject>(DEBUG_NEW CompositionObject(*pPrevPage->objects.GetNext(pos)))); } for (POSITION pos = pPrevPage->CLUTs.GetHeadPosition(); pos;) { m_pCurrentPage->CLUTs.AddTail(CAutoPtr<DVB_CLUT>(DEBUG_NEW DVB_CLUT(*pPrevPage->CLUTs.GetNext(pos)))); } TRACE_DVB(_T("DVB - Page started [update] %s, TimeOut = %ds\n"), ReftimeToString(m_rtStart + m_rtCurrentSegmentStart), m_pCurrentPage->pageTimeOut); } else { TRACE_DVB(_T("DVB - Page update ignored %s\n"), ReftimeToString(m_rtStart + m_rtCurrentSegmentStart)); } } 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 + m_rtCurrentSegmentStart)); } else if (m_pCurrentPage->rtStart < m_rtStart) { TRACE_DVB(_T("DVB - End display\n")); EnqueuePage(m_rtStart); } else { TRACE_DVB(_T("DVB - Ignored End display %s: no information on page duration\n"), ReftimeToString(m_rtStart + m_rtCurrentSegmentStart)); } break; default: TRACE_DVB(_T("DVB - Ignored segment with unknown type %d\n"), nCurSegment); break; } if (FAILED(hr)) { gb.SkipBytes(6 + wSegLength - (gb.GetPos() - nLastPos)); TRACE_DVB(_T("Parsing failed with code %x, skipping to the end of the segment\n"), hr); } } nLastPos = gb.GetPos(); } m_nBufferReadPos += nLastPos; } return hr; }