📄 dvbteletextsubtitles.cpp
字号:
// DVBTeletextSubtitles.cpp
/*
(C) Luke Paton 2004.
Copyright notice:
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Parts of this code from Mpeg2DataParser.cpp, part of the ScanChannelsBDA program
written by Nate.
* Mpeg2DataParser.cpp
* Copyright (C) 2004 Nate
*
* This file is part of DigitalWatch, a free DTV watching and recording
* program for the VisionPlus DVB-T.
*
* DigitalWatch is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DigitalWatch is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DigitalWatch; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "stdafx.h"
#include "resource.h"
#include "DVBTeletextSubtitles.h"
#include "DVBSubtitlesFilter.h"
#include "DVBTeletextSubtitlesPropertiesPage1.h"
#include <ks.h>
#include <ksmedia.h>
#include <bdatypes.h>
#include <bdamedia.h>
#define NTOH_S(s) ( (((s) & 0xFF00) >> 8) | (((s) & 0x00FF) << 8) )
#define BYTE_OFFSET(pb,i) (& BYTE_VALUE((pb),i))
#define BYTE_VALUE(pb,i) (((BYTE *) (pb))[i])
#define WORD_VALUE(pb,i) (* (UNALIGNED WORD *) BYTE_OFFSET((pb),i))
CDVBTeletextSubtitles::CDVBTeletextSubtitles(LPUNKNOWN punk,HRESULT *phr)
: CSource(TEXT("DVBTeletextSubtitles"), punk, CLSID_DVBTeletextSubtitles)
, CPersistStream(punk, phr)
, m_pTeletextPIDInput(NULL)
, m_pTeletextOutput(NULL)
, m_nTeletextPid(0x204)
, m_nSubtitlesDecimalPage(801)
, m_nSubtitlesDecimalSubPage(0)
, m_nLastLine(23)
, m_DisplayHeadingLine(FALSE)
, m_TransparencyPercent(85)
, m_FilePath(L"C:\\home\\lukep\\DTV\\capture\\teletextdump.ts")
, m_ConnectedToInputPID(false)
, m_ThreadId(0)
, m_FirstEventMilliseconds(0)
, m_SubtitleDelayTime(0)
, m_SubtitleDelayRange(2000)
{
ClearDisplay();
HRESULT hr;
m_pTeletextOutput = new CTeletextOutputPin
(
NAME("Teletext video output pin"),
this, // Owner filter
&m_csFilter,
&hr, // Result code
L"Teletext Video Output" // Pin name
);
m_Colours[Colour_Background] = RGB(0, 0, 0);
m_Colours[Colour_Black] = RGB(128, 128, 128);
m_Colours[Colour_Red] = RGB(255, 0, 0);
m_Colours[Colour_Green] = RGB(0, 255, 0);
m_Colours[Colour_Yellow] = RGB(255, 255, 0);
m_Colours[Colour_Blue] = RGB(0, 0, 255);
m_Colours[Colour_Magenta] = RGB(255, 0, 255);
m_Colours[Colour_Cyan] = RGB(0, 255, 255);
m_Colours[Colour_White] = RGB(255, 255, 255);
m_Colours[Colour_Key] = RGB(0, 0, 0);
}
CDVBTeletextSubtitles::~CDVBTeletextSubtitles(void)
{
if (m_pTeletextPIDInput != NULL)
{
delete m_pTeletextPIDInput;
}
if (m_pTeletextOutput != NULL)
{
delete m_pTeletextOutput;
}
}
int CDVBTeletextSubtitles::GetPinCount()
{
return 2;
}
CBasePin* CDVBTeletextSubtitles::GetPin(int n)
{
if (n == 0)
{
// Create an input pin if not already done
if (m_pTeletextPIDInput == NULL)
{
HRESULT hr;
m_pTeletextPIDInput = new CTeletextPIDInputPin
(
NAME("Teletext PID input pin"),
this, // Owner filter
&m_csFilter,
&hr, // Result code
L"Teletext PID Input" // Pin name
);
// Constructor for CTeletextPIDInputPin can't fail
}
return m_pTeletextPIDInput;
}
else
{
if (n == 1)
{
// Create an output pin if not already done
if (m_pTeletextOutput == NULL)
{
HRESULT hr;
m_pTeletextOutput = new CTeletextOutputPin
(
NAME("Teletext video output pin"),
this, // Owner filter
&m_csFilter,
&hr, // Result code
L"Teletext Video Output" // Pin name
);
// Constructor for CTeletextOutputPin can't fail
}
return m_pTeletextOutput;
}
}
return NULL;
}
HRESULT CDVBTeletextSubtitles::Run(REFERENCE_TIME tStart)
{
if (m_pGraph == NULL)
{
return E_POINTER;
}
/*
CComPtr<IBaseFilter> video_mixing_renderer_filter_9;
HRESULT hr = m_pGraph->FindFilterByName(L"Video Mixing Renderer 9", &video_mixing_renderer_filter_9);
if (!SUCCEEDED(hr) || (video_mixing_renderer_filter_9 == NULL))
{
return hr;
}
CComPtr<IBasicVideo> basic_video;
basic_video.Release();
hr = video_mixing_renderer_filter_9->QueryInterface(IID_IBasicVideo, (void**)&basic_video);
if (!SUCCEEDED(hr) || (basic_video == NULL))
{
return hr;
}
hr = basic_video->GetVideoSize(&m_nWidth, &m_nHeight);
if (!SUCCEEDED(hr) || (m_nWidth == 0) || (m_nHeight == 0))
{
return hr;
}
// Get alpha-blended bitmap interface
m_pVMRMixerBitmap9.Release();
hr = video_mixing_renderer_filter_9->QueryInterface(IID_IVMRMixerBitmap9, (void**)&m_pVMRMixerBitmap9);
if (!SUCCEEDED(hr) || (m_pVMRMixerBitmap9 == NULL))
{
return hr;
}
*/
m_PesPacketDirty = false;
m_PesPacketLength = -1;
m_tsPacketCounter = -1;
m_tsStatus = TS_WAITING;
ClearDisplay();
return CSource::Run(tStart);
}
/*
Structure of Transport Stream (from ISO/IEC 13818-1):
transport_packet()
{
sync_byte 8 bslbf 0
transport_error_indicator 1 bslbf 1
payload_unit_start_indicator 1 bslbf 1
transport_priority 1 bslbf 1
PID 13 uimsbf 1,2
transport_scrambling_control 2 bslbf 3
adaption_field_control 2 bslbf 3
continuity_counter 4 uimsbf 3
if (adaption_field_control == '10' || adaption_field_control == '11')
{
adaption_field()
}
if (adaption_field_control == '01' || adaption_field_control=='11')
{
for (i = 0; i < N; i++)
{
data_byte 8 bslbf
}
}
}
*/
bool CDVBTeletextSubtitles::ReadTeletextTransportStreamPacket(unsigned char* ts_buf)
{
if ( ( ( ( ts_buf[1] & 0x1f ) << 8 ) | ts_buf[2]) == m_nTeletextPid)
{
int continuity_counter = ts_buf[3] & 0x0f;
int adaption_field_control = (ts_buf[3] & 0x30) >> 4;
int discontinuity_indicator = 0;
if ( (adaption_field_control == 2) || (adaption_field_control == 3) )
{
// adaption_field
if (ts_buf[4] > 0)
{
// adaption_field_length
discontinuity_indicator = (ts_buf[5] & 0x80) >> 7;
}
}
/* Firstly, check the integrity of the stream */
if (m_tsPacketCounter == -1)
{
m_tsPacketCounter = continuity_counter;
}
else
{
if ( (adaption_field_control != 0) && (adaption_field_control != 2) )
{
m_tsPacketCounter++;
m_tsPacketCounter %= 16;
}
}
if (m_tsPacketCounter != continuity_counter)
{
if (discontinuity_indicator == 0)
{
m_PesPacketDirty = true;
}
m_tsPacketCounter = continuity_counter;
}
// Check payload start indicator.
if (ts_buf[1] & 0x40)
{
if (m_tsStatus == TS_IN_PAYLOAD)
{
if ( !m_PesPacketDirty && CheckPesPacket() )
{
if (!ProcessPesPacket())
{
return false;
}
}
m_PesPacketDirty = false;
}
else
{
m_tsStatus = TS_IN_PAYLOAD;
}
m_PesPacketLength = 0;
}
if (m_tsStatus == TS_IN_PAYLOAD)
{
int i = 4;
if ( (adaption_field_control == 2) || (adaption_field_control == 3) )
{
// Adaption field!!!
int adaption_field_length = ts_buf[i++];
if (adaption_field_length > 182)
{
adaption_field_length = 182;
m_tsStatus = TS_WAITING;
return false;
}
i += adaption_field_length;
}
if ( (adaption_field_control == 1) || (adaption_field_control == 3) )
{
// Data
if ( (m_PesPacketLength + (188 - i)) > sizeof(m_PesPacketBuffer) )
{
}
else
{
memcpy(&m_PesPacketBuffer[m_PesPacketLength], &ts_buf[i],188-i);
}
m_PesPacketLength += (188 - i);
if (m_PesPacketLength > 2000)
{
return false;
}
}
}
}
return true;
}
bool CDVBTeletextSubtitles::ReadTeletextTransportStreamSample(IMediaSample * pSample)
{
REFERENCE_TIME rtStart = 0;
REFERENCE_TIME rtStop = 0;
pSample->GetTime( &rtStart, &rtStop );
BYTE* pBuffer = 0;
pSample->GetPointer(&pBuffer);
long length = pSample->GetActualDataLength();
unsigned char* buf_pos = pBuffer;
while ((buf_pos - pBuffer) < length)
{
if (((buf_pos - pBuffer) + 188) < length)
{
unsigned char ts_buf[188];
memcpy(&ts_buf, buf_pos, 188);
if (ts_buf[0] == 0x47)
{
// complete TS packet
if (!ReadTeletextTransportStreamPacket(ts_buf))
{
return false;
}
}
else
{
StartFixTeletextInputPinThread();
return true;
}
}
buf_pos += 188;
}
return true;
}
STDMETHODIMP
CDVBTeletextSubtitles::set_SubtitlesDecimalPage(LONG subtitles_page)
{
m_nSubtitlesDecimalPage = subtitles_page;
SetDirty(TRUE);
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_SubtitlesDecimalPage(LONG* subtitles_page)
{
*subtitles_page = m_nSubtitlesDecimalPage;
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::set_SubtitlesDecimalSubPage(LONG subtitles_subpage)
{
m_nSubtitlesDecimalSubPage = subtitles_subpage;
SetDirty(TRUE);
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_SubtitlesDecimalSubPage(LONG* subtitles_subpage)
{
*subtitles_subpage = m_nSubtitlesDecimalSubPage;
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::set_SubtitleDelayTime(/* [in] */ DWORD subtitle_delay_time)
{
m_SubtitleDelayTime = subtitle_delay_time;
SetDirty(TRUE);
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_SubtitleDelayTime(/* [out] */ DWORD *subtitle_delay_time)
{
*subtitle_delay_time = m_SubtitleDelayTime;
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::set_SubtitleDelayRange(/* [in] */ DWORD subtitle_delay_range)
{
m_SubtitleDelayRange = subtitle_delay_range;
SetDirty(TRUE);
return S_OK;
}
STDMETHODIMP
CDVBTeletextSubtitles::get_SubtitleDelayRange(/* [out] */ DWORD *subtitle_delay_range)
{
*subtitle_delay_range = m_SubtitleDelayRange;
return S_OK;
}
HRESULT
CDVBTeletextSubtitles::PrintMpeg2Section
(
IMpeg2Data* pMpeg2Data,
SECTION *pSection,
DWORD dwPacketLength
)
{
if (!pSection)
return E_POINTER;
if (dwPacketLength < sizeof(SECTION))
{
ATLTRACE(L"Malformed MPEG-2 section data.\n");
return E_FAIL;
}
HRESULT hr = S_OK;
// Coerce the header bits to a bit field structure.
MPEG_HEADER_BITS *pHeader = (MPEG_HEADER_BITS*)&pSection->Header.W;
if (pHeader->SectionSyntaxIndicator)
{
// Coerce the section structure to a long section header.
LONG_SECTION *pLong = (LONG_SECTION*) pSection;
MPEG_HEADER_VERSION_BITS *pVersion = (MPEG_HEADER_VERSION_BITS*)&pLong->Version.B;
switch (pSection->TableId)
{
case 0x00: //PAT
{
ATLTRACE(TEXT("Transport Stream ID = %.4x\n\n"), NTOH_S(WORD_VALUE(pSection,3)));
BYTE* pbBuf = pLong->RemainingData;
int number_of_programs = (pHeader->SectionLength - 5 - 4) / 4;
int i = 0;
while (i < pHeader->SectionLength - 5)
{
int programNumber = (pbBuf[i] << 8) | pbBuf[i+1];
int programId = ((pbBuf[i+2] & 0x1f) << 8) | pbBuf[i+3];
if ((pbBuf[i+2] & 0xe0) == 0xe0)
{
if (programNumber != 0)
{
hr = PrintMpeg2Table(pMpeg2Data, programId, 0x02, 5000);
if (!SUCCEEDED(hr))
{
return hr;
}
}
ATLTRACE("\n");
}
i += 4;
}
ATLTRACE("\n");
break;
}
case 0x01: //CAT
{
break;
}
case 0x02: //PMT
{
int program_info_length = (NTOH_S(WORD_VALUE(pSection, 10)) & 0x0fff);
ATLTRACE(TEXT("Program Number = 0x%.4x (%d)\n"), WORD_VALUE(pSection, 3), WORD_VALUE(pSection, 3));
BYTE* pStartEs = (BYTE*)pSection + 12 + program_info_length;
BYTE* pEndEs = (BYTE*)pSection + pHeader->SectionLength + 3 - 4; //points to the byte before CRS_323, 4
BYTE* pTmp ;
unsigned short EsNumber = 0;
int offset = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -