📄 dvbteletextsubtitles.cpp
字号:
BYTE streamType;
int video_pid = -1;
int teletext_pid = -1;
int private_pid = -1;
ATLTRACE(" PID : stream type\n");
for(pTmp = pStartEs; pTmp < pEndEs; pTmp += offset)
{
int esInfoLength = (NTOH_S(WORD_VALUE(pTmp,3)) & 0x0fff);
offset = 5 + esInfoLength; //5+ES_info_length
int esPID = (NTOH_S(WORD_VALUE(pTmp,1)) & 0x1fff);
ATLTRACE(TEXT(" 0x%.4x (%i)"), esPID, esPID);
streamType = BYTE_VALUE(pTmp,0);
ATLTRACE(TEXT(" : 0x%.2x"), streamType);
switch(streamType)
{
case 0x00:
ATLTRACE(_T(" NotSet "));
break;
case 0x01:
ATLTRACE(_T(" Other "));
break;
case 0x02:
ATLTRACE(_T(" Video "));
video_pid = esPID;
break;
case 0x03:
ATLTRACE(_T(" Audio "));
break;
case 0x04:
if ((esInfoLength > 0) && (pTmp[5] == 0x03))
ATLTRACE(_T(" Audio "));
else
ATLTRACE(_T(" Text "));
break;
case 0x05:
ATLTRACE(_T(" Data "));
break;
case 0x06:
if ((esInfoLength > 0) && (pTmp[5] == 0x6a))
{
ATLTRACE(_T(" AC3 "));
}
else if ((esInfoLength > 0) && (pTmp[5] == 0x56))
{
ATLTRACE(_T(" Teletext "));
teletext_pid = esPID;
}
else
{
ATLTRACE(_T(" Private "));
private_pid = esPID;
}
break;
default:
ATLTRACE(_T(" Unknown "));
break;
}
//elementary_stream_info[EsNumber].ES_info_length = (NTOH_S(WORD_VALUE(pTmp,3)) & 0x0fff);
ATLTRACE(TEXT("\n"));
EsNumber++;
}
if (video_pid != -1)
{
if (teletext_pid == -1)
{
if (private_pid != -1)
{
m_TeletextPids[video_pid] = private_pid;
}
}
else
{
m_TeletextPids[video_pid] = teletext_pid;
}
}
//number_of_elementary_streams = EsNumber;
break;
}
case 0x3B: // Look for DSM-CC message types.
case 0x3C:
{
DSMCC_SECTION *pDsmcc = (DSMCC_SECTION*) pSection;
ATLTRACE(L" DSM-CC section fields ...\n");
ATLTRACE(L" Protocol Discriminator: 0x%.2x\n", pDsmcc->ProtocolDiscriminator);
ATLTRACE(L" Type: 0x%.2x\n", pDsmcc->DsmccType);
ATLTRACE(L" MessageId: 0x%.4x\n", pDsmcc->MessageId);
ATLTRACE(L" TransactionId: 0x%.8x\n", pDsmcc->TransactionId);
ATLTRACE(L" Reserved: 0x%.2x\n", pDsmcc->Reserved);
ATLTRACE(L" AdaptationLength: 0x%.2x\n", pDsmcc->AdaptationLength);
ATLTRACE(L" MessageLength: 0x%.4x\n", pDsmcc->MessageLength);
ATLTRACE(L" Remaining bytes ...\n");
break;
}
default:
// This is not a DSM-CC message.
break;
}
}
else
{
// Not a long section header.
}
return hr;
}
HRESULT
CDVBTeletextSubtitles::PrintMpeg2Table
(
IMpeg2Data* pMpeg2Data,
PID pid,
TID tid,
DWORD dwTimeout
)
{
HRESULT hr = E_POINTER;
if (pMpeg2Data != NULL)
{
CComPtr<ISectionList> piSectionList;
hr = pMpeg2Data->GetTable(pid, tid, NULL, dwTimeout, &piSectionList);
if (SUCCEEDED(hr))
{
WORD cSections;
hr = piSectionList->GetNumberOfSections(&cSections);
if (SUCCEEDED(hr))
{
for (WORD i = 0; i < cSections; i++)
{
// Iterate through the list of sections.
SECTION* pSection;
DWORD size;
hr = piSectionList->GetSectionData(i, &size, &pSection);
if (SUCCEEDED(hr))
{
hr = PrintMpeg2Section(pMpeg2Data, pSection, size);
if (!SUCCEEDED(hr))
{
return hr;
}
}
}
}
else
{
ATLTRACE(_T("Error 0x%x getting number of sections\n"), hr);
}
}
else
{
ATLTRACE(_T("Timeout getting table (pid=%.4x, tid=%.2x)\n"), pid, tid);
}
}
return hr;
}
/*
The aim of this method, until a better solution can be found,
is to collect information about which pids are available
for programs.
For each program, there is generally a video, audio and possible teletext or private
PID (among others).
It is possible that there is just one PID for all programs for teletext.
If so, we will use that PID.
If there is more than one PID for teletext we want to try to collect
all the related video, audio and teletext PIDs together.
We would then use the "MPEG-2 Demultiplexer" to determine which video pid is in use.
To do this, we look at the "Video" output pin on "MPEG-2 Demultiplexer".
We then look up the teletext PID for that video PID.
*/
STDMETHODIMP
CDVBTeletextSubtitles::FindTeletextPid(void)
{
if (m_pGraph == NULL)
{
return E_FAIL;
}
HRESULT hr = E_FAIL;
if (m_TeletextPids.size() == 0)
{
if (m_pGraph != NULL)
{
CComPtr<IBaseFilter> pBDASecTab;
hr = m_pGraph->FindFilterByName(L"MPEG-2 Sections and Tables", &pBDASecTab);
if (SUCCEEDED(hr))
{
CComQIPtr<IMpeg2Data> pMpeg2Data = pBDASecTab;
if (pMpeg2Data != NULL)
{
m_TeletextPids.clear();
int retries = 0;
hr = E_FAIL;
while
(
!SUCCEEDED(hr)
&&
(m_TeletextPids.size() == 0)
&&
(m_pGraph != NULL)
&&
(retries++ < 10)
)
{
hr = PrintMpeg2Table(pMpeg2Data, 0x0000, 0x00, 1000);
}
}
}
}
}
if (m_TeletextPids.size() != 0)
{
if (m_pGraph != NULL)
{
bool found_video_pid = false;
CComPtr<IBaseFilter> pDemux;
hr = m_pGraph->FindFilterByName(L"MPEG-2 Demultiplexer", &pDemux);
if (SUCCEEDED(hr) && (pDemux != NULL))
{
CComPtr<IPin> video_output_pin;
hr = pDemux->FindPin(L"Video", &video_output_pin);
if (SUCCEEDED(hr) && (video_output_pin != NULL))
{
CComQIPtr<IMPEG2PIDMap> mpeg2pidmap = video_output_pin;
if (mpeg2pidmap != NULL)
{
CComPtr<IEnumPIDMap> enum_map;
hr = mpeg2pidmap->EnumPIDMap(&enum_map);
if (SUCCEEDED(hr))
{
enum_map->Reset();
PID_MAP pid_map;
ULONG received = 0;
hr = enum_map->Next(1, &pid_map, &received);
while (SUCCEEDED(hr) && (received != 0))
{
//
// Found the video output PID
//
if (pid_map.MediaSampleContent == MEDIA_ELEMENTARY_STREAM)
{
m_nTeletextPid = m_TeletextPids[pid_map.ulPID];
if (SUCCEEDED(m_pTeletextPIDInput->FixTeletextInputPin()))
{
found_video_pid = true;
m_ConnectedToInputPID = true;
break;
}
}
}
}
}
}
}
if (!found_video_pid)
{
//
// Just use the first teletext pid.
//
m_nTeletextPid = m_TeletextPids.begin()->second;
if (SUCCEEDED(m_pTeletextPIDInput->FixTeletextInputPin()))
{
m_ConnectedToInputPID = true;
}
}
}
}
return hr;
}
void
CDVBTeletextSubtitles::FindTeletextPidThread(void* pParam)
{
//
// Reference count the filter.
//
CComPtr<CDVBTeletextSubtitles> filter = (CDVBTeletextSubtitles*)pParam;
filter->FindTeletextPid();
filter->m_ThreadId = 0;
}
void
CDVBTeletextSubtitles::StartFixTeletextInputPinThread(void)
{
if (!m_ConnectedToInputPID && (m_ThreadId == 0))
{
m_ThreadId = _beginthread(FindTeletextPidThread, 0, (void*)this);
}
}
STDMETHODIMP
CDVBTeletextSubtitles::set_TeletextPid(LONG teletext_pid)
{
m_nTeletextPid = teletext_pid;
m_ConnectedToInputPID = false;
StartFixTeletextInputPinThread();
SetDirty(TRUE);
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_TeletextPid(LONG* teletext_pid)
{
*teletext_pid = m_nTeletextPid;
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_Pages(IEnumTeletextPages** enum_pages)
{
*enum_pages = new CDVBTeletextPageEnumerator(this);
(*enum_pages)->AddRef();
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_SubPages(int page, IEnumTeletextSubPages** enum_subpages)
{
*enum_subpages = new CDVBTeletextSubPageEnumerator(page, this);
(*enum_subpages)->AddRef();
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::set_LastLine(LONG last_line)
{
m_nLastLine = last_line;
if (m_nLastLine < 1)
{
m_nLastLine = 1;
}
if (m_nLastLine > 24)
{
m_nLastLine = 24;
}
SetDirty(TRUE);
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_LastLine(LONG* last_line)
{
*last_line = m_nLastLine;
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::set_Colour(colour_types colour_index, LONG colour)
{
m_Colours[colour_index - Colour_Background] = colour;
SetDirty(TRUE);
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_Colour(colour_types colour_index, LONG* colour)
{
*colour = m_Colours[colour_index - Colour_Background];
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::set_TextMode(BOOL opaque)
{
m_pTeletextOutput->m_TextMode = opaque ? OPAQUE : TRANSPARENT;
SetDirty(TRUE);
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_TextMode(BOOL* opaque)
{
*opaque = m_pTeletextOutput->m_TextMode == OPAQUE;
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::set_DisplayHeadingLine(BOOL display_heading_line)
{
m_DisplayHeadingLine = display_heading_line;
SetDirty(TRUE);
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::set_File(BSTR file_path)
{
m_FilePath = file_path;
SetDirty(TRUE);
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_File(BSTR* file_path)
{
*file_path = SysAllocString(m_FilePath);
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_DisplayHeadingLine(BOOL* display_heading_line)
{
*display_heading_line = m_DisplayHeadingLine;
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::set_TransparencyPercent(LONG transparency_percent)
{
m_TransparencyPercent = transparency_percent;
if (m_TransparencyPercent < 0)
{
m_TransparencyPercent = 0;
}
if (m_TransparencyPercent > 100)
{
m_TransparencyPercent = 100;
}
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_TransparencyPercent(LONG* transparency_percent)
{
*transparency_percent = m_TransparencyPercent;
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::RefreshDisplay(void)
{
if (m_pTeletextOutput != NULL)
{
m_pTeletextOutput->m_EventDataReady.Set();
}
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::ClearDisplay(void)
{
for (std::map<int, SMagazine>::iterator it = m_Magazines.begin(); it != m_Magazines.end(); it++)
{
it->second.m_SubPageUnderConstruction.Clear();
for (std::map<int, SMagazinePage>::iterator mag_it = it->second.m_Pages.begin(); mag_it != it->second.m_Pages.end(); mag_it++)
{
mag_it->second.Clear();
}
}
return RefreshDisplay();
}
HRESULT CDVBTeletextSubtitles::ReadTeletextTransportStreamFile(BSTR file_path)
{
m_PesPacketDirty = false;
m_PesPacketLength = -1;
m_tsPacketCounter = -1;
m_tsStatus = TS_WAITING;
ClearDisplay();
USES_CONVERSION;
FILE* stream = fopen(W2T(file_path), "rb");
if (stream != NULL)
{
while (1)
{
unsigned char ts_buf[188];
long length = fread(ts_buf, 1, sizeof(ts_buf), stream);
if (ts_buf[0] == 0x47)
{
// complete TS packet
if (!ReadTeletextTransportStreamPacket(ts_buf))
{
// m_pTeletextOutput->DeliverEndOfStream();
fclose(stream);
return E_FAIL;
}
}
}
fclose(stream);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -