/*************************************************************************** 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.3 2000/09/17 15:23:05 kls Exp $ ***************************************************************************/ #include "eit.h" #include #include #include #include #include #include #include #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[4096+1]; // max. allowed size for any EIT section (+1 for safety ;-) eit_t *eit; struct eit_loop_struct1 *eitloop; struct eit_short_event_descriptor_struct *eitevt; unsigned 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]; if (seclen >= sizeof(buf)) seclen = sizeof(buf) - 1; 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; }