HRESULT CDVBSub::ParseClut(CGolombBuffer& gb, WORD wSegLength) { HRESULT hr = E_POINTER; if (m_pCurrentPage) { size_t nExpectedSize = 2; size_t nEnd = gb.GetPos() + wSegLength; BYTE id = gb.ReadByte(); POSITION posClut = FindClut(m_pCurrentPage, id); if (!posClut) { posClut = m_pCurrentPage->CLUTs.AddTail(CAutoPtr<DVB_CLUT>(DEBUG_NEW DVB_CLUT())); } const auto& pClut = m_pCurrentPage->CLUTs.GetAt(posClut); pClut->id = id; pClut->version_number = (BYTE)gb.BitRead(4); gb.BitRead(4); // Reserved pClut->size = 0; while (gb.GetPos() < nEnd) { nExpectedSize += 2; pClut->palette[pClut->size].entry_id = gb.ReadByte(); BYTE _2_bit = (BYTE)gb.BitRead(1); BYTE _4_bit = (BYTE)gb.BitRead(1); BYTE _8_bit = (BYTE)gb.BitRead(1); UNREFERENCED_PARAMETER(_2_bit); UNREFERENCED_PARAMETER(_4_bit); UNREFERENCED_PARAMETER(_8_bit); gb.BitRead(4); // Reserved if (gb.BitRead(1)) { nExpectedSize += 4; pClut->palette[pClut->size].Y = gb.ReadByte(); pClut->palette[pClut->size].Cr = gb.ReadByte(); pClut->palette[pClut->size].Cb = gb.ReadByte(); pClut->palette[pClut->size].T = 0xff - gb.ReadByte(); } else { nExpectedSize += 2; pClut->palette[pClut->size].Y = (BYTE)gb.BitRead(6) << 2; pClut->palette[pClut->size].Cr = (BYTE)gb.BitRead(4) << 4; pClut->palette[pClut->size].Cb = (BYTE)gb.BitRead(4) << 4; pClut->palette[pClut->size].T = 0xff - ((BYTE)gb.BitRead(2) << 6); } if (!pClut->palette[pClut->size].Y) { pClut->palette[pClut->size].Cr = 0; pClut->palette[pClut->size].Cb = 0; pClut->palette[pClut->size].T = 0; } pClut->size++; } hr = (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; } return hr; }
HRESULT CDVBSub::ParseClut(CGolombBuffer& gb, WORD wSegLength) { HRESULT hr = E_FAIL; int nEnd = gb.GetPos() + wSegLength; if (m_pCurrentPage && wSegLength > 2) { DVB_CLUT* pClut = DNew DVB_CLUT(); if (pClut) { pClut->id = gb.ReadByte(); pClut->version_number = (BYTE)gb.BitRead(4); gb.BitRead(4); // Reserved pClut->size = 0; while (gb.GetPos() < nEnd) { BYTE entry_id = gb.ReadByte(); BYTE _2_bit = (BYTE)gb.BitRead(1); BYTE _4_bit = (BYTE)gb.BitRead(1); BYTE _8_bit = (BYTE)gb.BitRead(1); UNREFERENCED_PARAMETER(_2_bit); UNREFERENCED_PARAMETER(_4_bit); UNREFERENCED_PARAMETER(_8_bit); gb.BitRead(4); // Reserved pClut->palette[entry_id].entry_id = entry_id; if (gb.BitRead(1)) { pClut->palette[entry_id].Y = gb.ReadByte(); pClut->palette[entry_id].Cr = gb.ReadByte(); pClut->palette[entry_id].Cb = gb.ReadByte(); pClut->palette[entry_id].T = 0xff - gb.ReadByte(); } else { pClut->palette[entry_id].Y = (BYTE)gb.BitRead(6) << 2; pClut->palette[entry_id].Cr = (BYTE)gb.BitRead(4) << 4; pClut->palette[entry_id].Cb = (BYTE)gb.BitRead(4) << 4; pClut->palette[entry_id].T = 0xff - ((BYTE)gb.BitRead(2) << 6); } if (!pClut->palette[entry_id].Y) { pClut->palette[entry_id].Cr = 0; pClut->palette[entry_id].Cb = 0; pClut->palette[entry_id].T = 0; } if (pClut->size <= entry_id) { pClut->size = entry_id + 1; } } m_pCurrentPage->CLUTs.AddTail(pClut); hr = S_OK; } else { hr = E_OUTOFMEMORY; } } 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; }