📄 mpeg2dataparser.cpp
字号:
/**
* Mpeg2DataParser.cpp
* Copyright (C) 2004 Nate
* Copyright (C) 2004 JoeyBloggs
*
* significant portions of this code are taken from
* the linuxtv-dvb-apps-1.1.0 scan.c file
*
* 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 "Mpeg2DataParser.h"
#include <process.h>
#include <math.h>
void ParseMpeg2DataThread( void *pParam )
{
Mpeg2DataParser *scanner;
scanner = (Mpeg2DataParser *)pParam;
scanner->StartMpeg2DataScanThread();
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Mpeg2DataParser::Mpeg2DataParser()
{
m_hScanningDoneEvent = CreateEvent(NULL, TRUE, FALSE, "ScanningDone");
m_piIMpeg2Data = NULL;
long_timeout = 0;
m_networkNumber = 0;
current_tp = NULL;
//verbose = FALSE;
m_bThreadStarted = FALSE;
m_bActivity = FALSE;
}
Mpeg2DataParser::~Mpeg2DataParser()
{
if (m_piIMpeg2Data != NULL)
m_piIMpeg2Data.Release();
}
void Mpeg2DataParser::SetNetworkNumber(int network)
{
m_networkNumber = network;
}
void Mpeg2DataParser::SetFilter(CComPtr <IBaseFilter> pBDASecTab)
{
m_piIMpeg2Data.Release();
if (pBDASecTab != NULL)
{
HRESULT hr = pBDASecTab->QueryInterface(__uuidof(IMpeg2Data), reinterpret_cast<void**>(&m_piIMpeg2Data));
}
}
void Mpeg2DataParser::ReleaseFilter()
{
m_piIMpeg2Data.Release();
}
//////////////////////////////////////////////////////////////////////
// Event stuff
//////////////////////////////////////////////////////////////////////
void Mpeg2DataParser::Reset()
{
current_tp = NULL;
struct section_buf *s;
while (waiting_filters.size())
{
s = waiting_filters.back();
waiting_filters.pop_back();
free (s);
}
struct transponder *t;
while (transponders.size())
{
t = transponders.back();
transponders.pop_back();
DeleteTransponder(t);
}
m_bThreadStarted = FALSE;
m_bActivity = FALSE;
ResetEvent(m_hScanningDoneEvent);
}
void Mpeg2DataParser::DeleteTransponder(struct transponder *t)
{
struct service *s;
while (t->services.size())
{
s = t->services.back();
t->services.pop_back();
DeleteService(s);
}
if (t->other_f)
free(t->other_f);
t->other_f = NULL;
free(t);
}
void Mpeg2DataParser::DeleteService(struct service *s)
{
if (s->provider_name)
free(s->provider_name);
s->provider_name = NULL;
if (s->service_name)
free(s->service_name);
s->service_name = NULL;
free(s);
}
DWORD Mpeg2DataParser::WaitForScanToFinish()
{
DWORD result;
do
{
result = WaitForSingleObject(m_hScanningDoneEvent, 15000);
} while ((result == WAIT_TIMEOUT) && (m_bActivity));
return result;
}
//////////////////////////////////////////////////////////////////////
// Method just to kick off a separate thread
//////////////////////////////////////////////////////////////////////
void Mpeg2DataParser::StartMpeg2DataScan()
{
//Make sure we only start scanning the first time the ServiceChanged event calls us.
if (m_bThreadStarted)
return;
m_bThreadStarted = TRUE;
//Start a new thread to do the scanning because the
//IGuideDataEvent::ServiceChanged method isn't allowed to block.
DWORD dwThreadId = 0;
unsigned long result = _beginthread(ParseMpeg2DataThread, 0, (void *) this);
}
//////////////////////////////////////////////////////////////////////
// The real work starts here
//////////////////////////////////////////////////////////////////////
void Mpeg2DataParser::StartMpeg2DataScanThread()
{
HRESULT hr = S_OK;
m_bActivity = TRUE;
try
{
if (m_piIMpeg2Data != NULL)
{
struct section_buf *s0;
s0 = (struct section_buf *)malloc(sizeof(struct section_buf));
SetupFilter(s0, 0x00, 0x00, 1, 0, 5); // PAT
AddFilter(s0);
s0 = (struct section_buf *)malloc(sizeof(struct section_buf));
SetupFilter(s0, 0x10, 0x40, 1, 0, 15); // NIT
AddFilter(s0);
s0 = (struct section_buf *)malloc(sizeof(struct section_buf));
SetupFilter(s0, 0x11, 0x42, 1, 0, 5); // SDT
AddFilter(s0);
ReadFilters();
}
}
catch(...)
{
output.showf("# Unhandled exception in Mpeg2DataParser::StartMpeg2DataScanThread()\n");
}
m_bActivity = FALSE;
SetEvent(m_hScanningDoneEvent);
}
//////////////////////////////////////////////////////////////////////
void Mpeg2DataParser::SetupFilter (struct section_buf* s, int pid, int tid, int run_once, int segmented, int timeout)
{
memset (s, 0, sizeof(struct section_buf));
s->fd = -1;
s->pid = pid;
s->table_id = tid;
s->run_once = run_once;
s->segmented = segmented;
if (long_timeout)
s->timeout = 5 * timeout;
else
s->timeout = timeout;
s->table_id_ext = -1;
s->section_version_number = -1;
}
void Mpeg2DataParser::AddFilter (struct section_buf *s)
{
waiting_filters.push_back(s);
}
void Mpeg2DataParser::ReadFilters(void)
{
struct section_buf *s;
while (waiting_filters.size())
{
s = waiting_filters.front();
ReadSection(s);
waiting_filters.erase(waiting_filters.begin());
free (s);
}
}
//////////////////////////////////////////////////////////////////////
void Mpeg2DataParser::ReadSection(struct section_buf *s)
{
PID pid = s->pid;
TID tid = s->table_id;
DWORD dwTimeout = s->timeout * 1000;
if (m_piIMpeg2Data != NULL)
{
HRESULT hr;
ISectionList* piSectionList = NULL;
if (SUCCEEDED(hr = m_piIMpeg2Data->GetTable(pid, tid, NULL, dwTimeout, &piSectionList)))
{
WORD cSections;
if (SUCCEEDED(hr = piSectionList->GetNumberOfSections(&cSections)))
{
verbose.showf(_T("\n%d section(s) found for pid=%.4x, tid=%.2x\n"), cSections, pid, tid);
verbose.showf("pid \n");
for (WORD i = 0; i < cSections; i++)
{
// Iterate through the list of sections.
SECTION* pstSection;
DWORD ulSize;
hr = piSectionList->GetSectionData(i, &ulSize, &pstSection);
if (SUCCEEDED(hr))
{
s->buf = (unsigned char *)pstSection;
parse_section(s);
}
}
}
else
{
output.showf(_T("Error 0x%x getting number of sections\n"), hr);
}
piSectionList->Release();
}
else
{
output.showf(_T("Timeout getting table (pid=%.4x, tid=%.2x)\n"), pid, tid);
}
}
}
/* service_ids are guaranteed to be unique within one TP
* (the DVB standards say theay should be unique within one
* network, but in real life...)
*/
struct service *Mpeg2DataParser::alloc_service(struct transponder *tp, int service_id)
{
struct service *s = (struct service *)calloc(1, sizeof(*s));
s->service_id = service_id;
tp->services.push_back(s);
return s;
}
struct service *Mpeg2DataParser::find_service(struct transponder *tp, int service_id)
{
struct service *s;
vector<service *>::iterator it;
for ( it = tp->services.begin() ; it != tp->services.end() ; it++ )
{
s = *it;
if (s->service_id == service_id)
return s;
}
return NULL;
}
struct transponder *Mpeg2DataParser::alloc_transponder(int transport_stream_id)
{
struct transponder *tp = (struct transponder *)calloc(1, sizeof(*tp));
tp->transport_stream_id = transport_stream_id;
transponders.push_back(tp);
return tp;
}
struct transponder *Mpeg2DataParser::find_transponder(int transport_stream_id)
{
struct transponder *tp;
vector<transponder *>::iterator it;
for ( it = transponders.begin() ; it != transponders.end() ; it++ )
{
tp = *it;
if (tp->transport_stream_id == transport_stream_id)
return tp;
}
return NULL;
}
void Mpeg2DataParser::parse_iso639_language_descriptor (const unsigned char *buf, struct service *s)
{
unsigned char len = buf [1];
buf += 2;
if (len >= 4)
{
verbose.showf(" LANG=%.3s %d\n", buf, buf[3]);
memcpy(s->audio_lang[s->audio_num], buf, 3);
#if 0
/* seems like the audio_type is wrong all over the place */
//if (buf[3] == 0) -> normal
if (buf[3] == 1)
s->audio_lang[s->audio_num][3] = '!'; /* clean effects (no language) */
else if (buf[3] == 2)
s->audio_lang[s->audio_num][3] = '?'; /* for the hearing impaired */
else if (buf[3] == 3)
s->audio_lang[s->audio_num][3] = '+'; /* visually impaired commentary */
#endif
}
}
void Mpeg2DataParser::parse_network_name_descriptor (const unsigned char *buf, struct transponder *tp)
{
if (tp->network_name)
free (tp->network_name);
unsigned char len = buf [1];
tp->network_name = (unsigned char *)malloc (len + 1);
memcpy (tp->network_name, buf+2, len);
tp->network_name[len] = '\0';
verbose.showf(" Network Name '%.*s'\n", len, buf + 2);
}
void Mpeg2DataParser::print_unknown_descriptor(const unsigned char *buf, int descriptor_len)
{
PrintByteArray(buf, descriptor_len);
}
void Mpeg2DataParser::parse_terrestrial_delivery_system_descriptor (const unsigned char *buf, struct transponder *t)
{
//static const fe_modulation_t m_tab [] = { QPSK, QAM_16, QAM_64, QAM_AUTO };
//static const fe_code_rate_t ofec_tab [8] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8 };
//struct dvb_ofdm_parameters *o;
if (!t) {
verbose.showf(" terrestrial_delivery_system_descriptor outside transport stream definition (ignored)\n");
return;
}
//o = &t->param.u.ofdm;
//t->type = FE_OFDM;
t->frequency = (buf[2] << 24) | (buf[3] << 16);
t->frequency |= (buf[4] << 8) | buf[5];
t->frequency /= 100;
verbose.showf(" Frequency %i", t->frequency);
t->bandwidth = 8 - ((buf[6] >> 5) & 0x3);
verbose.showf(" Bandwidth %i", t->bandwidth);
//o->constellation = m_tab[(buf[7] >> 6) & 0x3];
switch ((buf[7] >> 6) & 0x3)
{
case 0:
verbose.showf(" QPSK\n");
break;
case 1:
verbose.showf(" QAM_16\n");
break;
case 2:
verbose.showf(" QAM_64\n");
break;
case 3:
verbose.showf(" QAM_AUTO\n");
break;
}
//o->hierarchy_information = HIERARCHY_NONE + ((buf[7] >> 3) & 0x3);
//DWORD coderateHP = buf[7] & 0x7;
switch (buf[7] & 0x7)
{
case 0:
verbose.showf(" HP - FEC_1_2");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -