mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
524 lines
12 KiB
C
524 lines
12 KiB
C
/***************************************************************************
|
|
eit.c - description
|
|
-------------------
|
|
begin : Fri Aug 25 2000
|
|
copyright : (C) 2000 by Robert Schneider
|
|
email : Robert.Schneider@web.de
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* 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. *
|
|
* *
|
|
* $Id: eit.c 1.2 2000/09/17 08:02:30 kls Exp $
|
|
***************************************************************************/
|
|
|
|
#include "eit.h"
|
|
#include <iostream.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <time.h>
|
|
#include <sys/ioctl.h>
|
|
#include <dvb_comcode.h>
|
|
#include "tools.h"
|
|
|
|
typedef struct {
|
|
u_char table_id : 8;
|
|
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
u_char section_syntax_indicator : 1;
|
|
u_char : 3;
|
|
u_char section_length_hi : 4;
|
|
#else
|
|
u_char section_length_hi : 4;
|
|
u_char : 3;
|
|
u_char section_syntax_indicator : 1;
|
|
#endif
|
|
|
|
u_char section_length_lo : 8;
|
|
|
|
u_char service_id_hi : 8;
|
|
u_char service_id_lo : 8;
|
|
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
u_char : 2;
|
|
u_char version_number : 5;
|
|
u_char current_next_indicator : 1;
|
|
#else
|
|
u_char current_next_indicator : 1;
|
|
u_char version_number : 5;
|
|
u_char : 2;
|
|
#endif
|
|
|
|
u_char section_number : 8;
|
|
u_char last_section_number : 8;
|
|
u_char transport_stream_id_hi : 8;
|
|
u_char transport_stream_id_lo : 8;
|
|
u_char original_network_id_hi : 8;
|
|
u_char original_network_id_lo : 8;
|
|
u_char segment_last_section_number : 8;
|
|
u_char segment_last_table_id : 8;
|
|
} eit_t;
|
|
|
|
#define EIT_SIZE 14
|
|
|
|
struct eit_loop_struct1 {
|
|
u_char event_id_hi : 8;
|
|
u_char event_id_lo : 8;
|
|
|
|
u_char date_hi : 8;
|
|
u_char date_lo : 8;
|
|
u_char time_hour : 4;
|
|
u_char time_hour_ten : 4;
|
|
u_char time_minute : 4;
|
|
u_char time_minute_ten : 4;
|
|
u_char time_second : 4;
|
|
u_char time_second_ten : 4;
|
|
|
|
u_char dur_hour_ten : 4;
|
|
u_char dur_hour : 4;
|
|
u_char dur_minute_ten : 4;
|
|
u_char dur_minute : 4;
|
|
u_char dur_second_ten : 4;
|
|
u_char dur_second : 4;
|
|
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
u_char running_status : 3;
|
|
u_char free_ca_mode : 1;
|
|
u_char descriptors_loop_length_hi : 4;
|
|
#else
|
|
u_char descriptors_loop_length_hi : 4;
|
|
u_char free_ca_mode : 1;
|
|
u_char running_status : 3;
|
|
#endif
|
|
|
|
u_char descriptors_loop_length_lo : 8;
|
|
};
|
|
|
|
#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d
|
|
#define EIT_SHORT_EVENT_DESCRIPTOR_SIZE 6
|
|
|
|
struct eit_short_event_descriptor_struct {
|
|
u_char descriptor_tag : 8;
|
|
u_char descriptor_length : 8;
|
|
|
|
u_char language_code_1 : 8;
|
|
u_char language_code_2 : 8;
|
|
u_char language_code_3 : 8;
|
|
|
|
u_char event_name_length : 8;
|
|
};
|
|
|
|
#define EIT_EXTENDED_EVENT_DESCRIPOR 0x4e
|
|
|
|
#define EIT_DESCRIPTOR_SIZE
|
|
|
|
typedef struct eit_event_struct {
|
|
u_char event_id_hi : 8;
|
|
u_char event_id_lo : 8;
|
|
|
|
u_char start_time_1 : 8;
|
|
u_char start_time_2 : 8;
|
|
u_char start_time_3 : 8;
|
|
u_char start_time_4 : 8;
|
|
u_char start_time_5 : 8;
|
|
|
|
u_char duration_1 : 8;
|
|
u_char duration_2 : 8;
|
|
u_char duration_3 : 8;
|
|
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
u_char running_status : 3;
|
|
u_char free_CA_mode : 1;
|
|
u_char descriptors_loop_length_hi : 4;
|
|
#else
|
|
u_char descriptors_loop_length_hi : 4;
|
|
u_char free_CA_mode : 1;
|
|
u_char running_status : 3;
|
|
#endif
|
|
|
|
u_char descriptors_loop_length_lo : 8;
|
|
|
|
} eit_event_t;
|
|
#define EIT_LOOP_SIZE 12
|
|
|
|
|
|
typedef struct tot_t {
|
|
u_char table_id : 8;
|
|
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
u_char section_syntax_indicator : 1;
|
|
u_char : 3;
|
|
u_char section_length_hi : 4;
|
|
#else
|
|
u_char section_length_hi : 4;
|
|
u_char : 3;
|
|
u_char section_syntax_indicator : 1;
|
|
#endif
|
|
|
|
u_char date_hi : 8;
|
|
u_char date_lo : 8;
|
|
u_char time_hour : 4;
|
|
u_char time_hour_ten : 4;
|
|
u_char time_minute : 4;
|
|
u_char time_minute_ten : 4;
|
|
u_char time_second : 4;
|
|
u_char time_second_ten : 4;
|
|
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
u_char : 4;
|
|
u_char descriptor_loop_length_hi : 4;
|
|
#else
|
|
u_char descriptor_loop_length_hi : 4;
|
|
u_char : 4;
|
|
#endif
|
|
|
|
u_char descriptor_loop_length_lo : 8;
|
|
} tot_t;
|
|
|
|
typedef struct local_time_offset {
|
|
|
|
u_char descriptor_tag : 8;
|
|
u_char descriptor_length : 8;
|
|
|
|
u_char language_code_1 : 8;
|
|
u_char language_code_2 : 8;
|
|
u_char language_code_3 : 8;
|
|
|
|
u_char : 8;
|
|
|
|
u_char offset_hour : 4;
|
|
u_char offset_hour_ten : 4;
|
|
u_char offset_minute : 4;
|
|
u_char offset_minute_ten : 4;
|
|
|
|
u_char change_date_hi : 8;
|
|
u_char change_date_lo : 8;
|
|
u_char change_time_hour : 4;
|
|
u_char change_time_hour_ten : 4;
|
|
u_char change_time_minute : 4;
|
|
u_char change_time_minute_ten : 4;
|
|
u_char change_time_second : 4;
|
|
u_char change_time_second_ten : 4;
|
|
|
|
u_char next_offset_hour : 4;
|
|
u_char next_offset_hour_ten : 4;
|
|
u_char next_offset_minute : 4;
|
|
u_char next_offset_minute_ten : 4;
|
|
} local_time_offset;
|
|
|
|
cEIT::cEIT()
|
|
{
|
|
cszBitFilter = "/dev/vbi";
|
|
if((fsvbi = open(cszBitFilter, O_RDWR))<0)
|
|
{
|
|
fsvbi = 0;
|
|
esyslog(LOG_ERR, "Failed to open DVB bitfilter device: %s", cszBitFilter);
|
|
return;
|
|
}
|
|
}
|
|
|
|
cEIT::~cEIT()
|
|
{
|
|
if (fsvbi != 0)
|
|
close(fsvbi);
|
|
fsvbi = 0;
|
|
}
|
|
|
|
/** Set the bitfilter in vbi device to return
|
|
correct tables */
|
|
int cEIT::SetBitFilter(unsigned short pid, unsigned short section, unsigned short mode)
|
|
{
|
|
struct bitfilter filt = {
|
|
pid,
|
|
{ section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
|
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
|
|
mode,0,
|
|
FILTER_MEM,
|
|
{},
|
|
};
|
|
|
|
if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0)
|
|
return 0xffff;
|
|
return 0;
|
|
}
|
|
/** */
|
|
int cEIT::GetSection(unsigned char *buf, ushort PID, unsigned char sec)
|
|
{
|
|
int seclen=0;
|
|
unsigned short handle, pid;
|
|
unsigned char section, sectionnum=0xff, maxsec=0;
|
|
|
|
if ((handle = SetBitFilter(PID, (sec<<8)|0x00ff, SECTION_CONTINUOS))==0xffff)
|
|
return -1;
|
|
|
|
seclen=0;
|
|
if (!cFile::AnyFileReady(fsvbi, 20000))
|
|
{
|
|
//cerr << "Timeout\n";
|
|
return -1;
|
|
}
|
|
|
|
read(fsvbi, buf, 8);
|
|
seclen=(buf[6]<<8)|buf[7];
|
|
pid=(buf[4]<<8)|buf[5];
|
|
|
|
read(fsvbi, buf, seclen);
|
|
section=buf[0];
|
|
sectionnum=buf[6];
|
|
maxsec=buf[7];
|
|
|
|
//cerr << "secnum: " << HEX(2) << (int)sectionnum
|
|
// << ", secmax: " << HEX(2) << (int) msecnum << "\n";
|
|
|
|
CloseFilter(handle);
|
|
|
|
return seclen;
|
|
}
|
|
|
|
/** */
|
|
int cEIT::CloseFilter(unsigned short handle)
|
|
{
|
|
if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &handle)<0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
/** */
|
|
char * cEIT::mjd2string(unsigned short mjd)
|
|
{
|
|
int y, m, d, k;
|
|
static char buf[20];
|
|
|
|
y = (int) ((mjd - 15078.2) / 365.25);
|
|
m = (int) ((mjd - 14956.1 - (int)(y * 365.25)) / 30.6001);
|
|
d = (int) (mjd - 14956 - (int)(y * 365.25) - (int)(m * 30.6001));
|
|
k = (m == 14 || m == 15) ? 1 : 0;
|
|
y = y + k;
|
|
m = m - 1 - k * 12;
|
|
sprintf(buf, "%d.%d.%4d", d, m, y + 1900);
|
|
|
|
return(buf);
|
|
}
|
|
|
|
/** */
|
|
int cEIT::GetEIT()
|
|
{
|
|
unsigned char buf[1024];
|
|
eit_t *eit;
|
|
struct eit_loop_struct1 *eitloop;
|
|
struct eit_short_event_descriptor_struct *eitevt;
|
|
int seclen;
|
|
unsigned short handle, pid;
|
|
eit_event * pevt = (eit_event *)0;
|
|
time_t tstart;
|
|
|
|
if ((handle = SetBitFilter(0x12, (0x4e << 8) | 0x00ff, SECTION_CONTINUOS))==0xffff)
|
|
{
|
|
return -1;
|
|
}
|
|
/*
|
|
pid_t process = fork();
|
|
if (process < 0)
|
|
{
|
|
cerr << "GetEIT -1" << endl;
|
|
return -1;
|
|
}
|
|
|
|
if (process != 0)
|
|
{
|
|
cerr << "GetEIT 0" << endl;
|
|
return 0;
|
|
}
|
|
*/
|
|
int nReceivedEITs = 0;
|
|
tstart = time(NULL);
|
|
while ((!evtRunning.bIsValid || !evtNext.bIsValid) && nReceivedEITs < 20 && difftime(time(NULL), tstart) < 4)
|
|
{
|
|
if (!cFile::AnyFileReady(fsvbi, 5000))
|
|
{
|
|
//cerr << "Timeout\n";
|
|
CloseFilter(handle);
|
|
return -1;
|
|
}
|
|
|
|
read(fsvbi, buf, 8);
|
|
seclen=(buf[6]<<8)|buf[7];
|
|
pid=(buf[4]<<8)|buf[5];
|
|
|
|
read(fsvbi, buf, seclen);
|
|
|
|
if (seclen < (int)(sizeof(eit_t)
|
|
+ sizeof(struct eit_loop_struct1)
|
|
+ sizeof(struct eit_short_event_descriptor_struct)))
|
|
continue;
|
|
|
|
eit = (eit_t *)buf;
|
|
eitloop = (struct eit_loop_struct1 *)&eit[1];
|
|
eitevt = (struct eit_short_event_descriptor_struct *)&eitloop[1];
|
|
|
|
if (eitevt->descriptor_tag != EIT_SHORT_EVENT_DESCRIPTOR)
|
|
{
|
|
// printf("Tag = '%c'\n", eitevt->descriptor_tag);
|
|
continue;
|
|
}
|
|
|
|
if (((eit->service_id_hi << 8) | eit->service_id_lo) != uProgramNumber)
|
|
{
|
|
// printf("Wrong program %04x need %04x\n", (eit->service_id_hi << 8) | eit->service_id_lo, uProgramNumber);
|
|
continue;
|
|
}
|
|
|
|
nReceivedEITs++;
|
|
|
|
pevt = (eit_event *)0;
|
|
if (eitloop->running_status == 4 | eitloop->running_status == 3)
|
|
pevt = (eit_event *)&evtRunning;
|
|
else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0)
|
|
pevt = (eit_event *)&evtNext;
|
|
|
|
if (pevt)
|
|
{
|
|
unsigned char *p = (unsigned char *)&eitevt[1];
|
|
strdvbcpy((unsigned char *)pevt->szTitle, p, eitevt->event_name_length);
|
|
pevt->szSubTitle[0] = 0;
|
|
strdvbcpy((unsigned char *)pevt->szSubTitle, &p[eitevt->event_name_length+1], (int)p[eitevt->event_name_length]);
|
|
strcpy(pevt->szDate, mjd2string((eitloop->date_hi << 8) + eitloop->date_lo));
|
|
int hr = eitloop->time_hour + (eitloop->time_hour_ten * 10);
|
|
hr += 2;
|
|
if (hr >=24)
|
|
{
|
|
hr -= 24;
|
|
// need to switch date one day ahead here
|
|
}
|
|
sprintf(pevt->szTime, "%d:%c%c", hr,
|
|
eitloop->time_minute_ten + '0',
|
|
eitloop->time_minute + '0');
|
|
pevt->bIsValid = true;
|
|
}
|
|
}
|
|
|
|
CloseFilter(handle);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/** */
|
|
int cEIT::SetProgramNumber(unsigned short pnr)
|
|
{
|
|
if (pnr == 0)
|
|
{
|
|
evtRunning.bIsValid = false;
|
|
evtNext.bIsValid = false;
|
|
return -1;
|
|
}
|
|
|
|
if (pnr != uProgramNumber)
|
|
{
|
|
evtRunning.bIsValid = false;
|
|
evtNext.bIsValid = false;
|
|
uProgramNumber = pnr;
|
|
return GetEIT();
|
|
}
|
|
return (IsValid() ? 1 : -1);
|
|
}
|
|
|
|
/** retrieves the string for the running title */
|
|
char * cEIT::GetRunningTitle()
|
|
{
|
|
if (evtRunning.bIsValid)
|
|
return evtRunning.szTitle;
|
|
else
|
|
return "---";
|
|
}
|
|
/** Retrieves the string for the running subtitle */
|
|
char * cEIT::GetRunningSubtitle()
|
|
{
|
|
if (evtRunning.bIsValid)
|
|
return evtRunning.szSubTitle;
|
|
else
|
|
return "---";
|
|
}
|
|
/** Retrieves the string representing the
|
|
date of the current event
|
|
*/
|
|
char * cEIT::GetRunningDate()
|
|
{
|
|
if (evtRunning.bIsValid)
|
|
return evtRunning.szDate;
|
|
else
|
|
return "---";
|
|
}
|
|
/** Retrieves the string representing the
|
|
time of the current event */
|
|
char * cEIT::GetRunningTime()
|
|
{
|
|
if (evtRunning.bIsValid)
|
|
return evtRunning.szTime;
|
|
else
|
|
return "---";
|
|
}
|
|
/** retrieves the string for the running title */
|
|
char * cEIT::GetNextTitle()
|
|
{
|
|
if (evtNext.bIsValid)
|
|
return evtNext.szTitle;
|
|
else
|
|
return "---";
|
|
}
|
|
/** Retrieves the string for the running subtitle */
|
|
char * cEIT::GetNextSubtitle()
|
|
{
|
|
if (evtNext.bIsValid)
|
|
return evtNext.szSubTitle;
|
|
else
|
|
return "---";
|
|
}
|
|
/** Retrieves the string representing the
|
|
date of the current event
|
|
*/
|
|
char * cEIT::GetNextDate()
|
|
{
|
|
if (evtNext.bIsValid)
|
|
return evtNext.szDate;
|
|
else
|
|
return "---";
|
|
}
|
|
/** Retrieves the string representing the
|
|
time of the current event */
|
|
char * cEIT::GetNextTime()
|
|
{
|
|
if (evtNext.bIsValid)
|
|
return evtNext.szTime;
|
|
else
|
|
return "---";
|
|
}
|
|
|
|
/** */
|
|
bool cEIT::IsValid()
|
|
{
|
|
return (evtRunning.bIsValid && evtNext.bIsValid);
|
|
}
|
|
|
|
/** */
|
|
int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max)
|
|
{
|
|
int a;
|
|
for (a = 0; a < max; a++)
|
|
{
|
|
if (*src == 0)
|
|
break;
|
|
|
|
if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff))
|
|
*dst++ = *src++;
|
|
else
|
|
src++;
|
|
}
|
|
*dst = 0;
|
|
return a;
|
|
}
|