Thanks for your time. It's my first time to do this, so I have been trying to follow literally on the wiki page to do it right. If you can elaborate a bit about what is broken? Is it the patch created incorrectly, or it is pasted incorrectly, or the style is still problematic? I noticed that cutting and pasting from my console to the gmail compose window does not seem working alright. How do you normally do the inlining? I have a full weekend to do this, and I do realize from the wiki page that it does not appear to be simple, :) I now simply disable the footer, don't worry. Regards, On Fri, Jun 19, 2009 at 7:41 PM, hermann pitton<hermann-pitton@xxxxxxxx> wrote: > > Am Donnerstag, den 18.06.2009, 20:39 -0500 schrieb Yufei Yuan: >> This one is about the utility itself. I do apologize for the length >> here as "inline" patch is preferred according to the guide and I don't >> have any public online storage. Please let me know if this causes any >> inconvenience. >> >> Signed-off-by: Yufei Yuan <yfyuan@xxxxxxxxx> >> >> diff -uprN dvb-apps/util/atsc_epg/atsc_epg.c >> dvb-apps_new/util/atsc_epg/atsc_epg.c >> --- dvb-apps/util/atsc_epg/atsc_epg.c 1969-12-31 18:00:00.000000000 >> -0600 >> +++ dvb-apps_new/util/atsc_epg/atsc_epg.c 2009-06-18 >> 20:17:24.527925142 -0500 >> @@ -0,0 +1,1249 @@ >> +/* >> + * atsc_epg utility >> + * >> + * Copyright (C) 2009 Yufei Yuan <yfyuan@xxxxxxxxx> >> + * 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. >> + */ >> + >> +#include <stdio.h> >> +#include <stdlib.h> >> +#include <unistd.h> >> +#include <string.h> >> +#include <time.h> >> +#include <signal.h> >> +#include <sys/types.h> >> +#include <sys/stat.h> >> +#include <fcntl.h> >> +#include <sys/ioctl.h> >> +#include <sys/poll.h> >> +#include <errno.h> >> +#include <getopt.h> >> +#include <stdarg.h> >> +#include <libdvbapi/dvbfe.h> >> +#include <libdvbapi/dvbdemux.h> >> +#include <libucsi/dvb/section.h> >> +#include <libucsi/atsc/section.h> >> +#include <libucsi/atsc/types.h> >> + >> +#define TIMEOUT 60 >> +#define RRT_TIMEOUT 60 >> +#define MAX_NUM_EVENT_TABLES 128 >> +#define TITLE_BUFFER_LEN 4096 >> +#define MESSAGE_BUFFER_LEN (16 * 1024) >> +#define MAX_NUM_CHANNELS 16 >> +#define MAX_NUM_EVENTS_PER_CHANNEL (4 * 24 * 7) >> + >> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum >> atsc_section_tag tag, >> + void **table_section); >> + >> +static const char *program; >> +static int adapter = 0; >> +static int period = 12; /* hours */ >> +static int frequency; >> +static int enable_ett = 0; >> +static int ctrl_c = 0; >> +static const char *modulation = NULL; >> +static char separator[80]; >> +void (*old_handler)(int); >> + >> +struct atsc_string_buffer { >> + int buf_len; >> + int buf_pos; >> + char *string; >> +}; >> + >> +struct atsc_event_info { >> + uint16_t id; >> + struct tm start; >> + struct tm end; >> + int title_pos; >> + int title_len; >> + int msg_pos; >> + int msg_len; >> +}; >> + >> +struct atsc_eit_section_info { >> + uint8_t section_num; >> + uint8_t num_events; >> + uint8_t num_etms; >> + uint8_t num_received_etms; >> + struct atsc_event_info **events; >> +}; >> + >> +struct atsc_eit_info { >> + int num_eit_sections; >> + struct atsc_eit_section_info *section; >> +}; >> + >> +struct atsc_channel_info { >> + uint8_t num_eits; >> + uint8_t service_type; >> + char short_name[8]; >> + uint16_t major_num; >> + uint16_t minor_num; >> + uint16_t tsid; >> + uint16_t prog_num; >> + uint16_t src_id; >> + struct atsc_eit_info *eit; >> + struct atsc_event_info *last_event; >> + int event_info_index; >> + struct atsc_event_info e[MAX_NUM_EVENTS_PER_CHANNEL]; >> + struct atsc_string_buffer title_buf; >> + struct atsc_string_buffer msg_buf; >> +}; >> + >> +struct atsc_virtual_channels_info { >> + int num_channels; >> + uint16_t eit_pid[MAX_NUM_EVENT_TABLES]; >> + uint16_t ett_pid[MAX_NUM_EVENT_TABLES]; >> + struct atsc_channel_info ch[MAX_NUM_CHANNELS]; >> +} guide; >> + >> +struct mgt_table_name { >> + uint16_t range; >> + const char *string; >> +}; >> + >> +struct mgt_table_name mgt_tab_name_array[] = { >> + {0x0000, "terrestrial VCT with current_next_indictor=1"}, >> + {0x0001, "terrestrial VCT with current_next_indictor=0"}, >> + {0x0002, "cable VCT with current_next_indictor=1"}, >> + {0x0003, "cable VCT with current_next_indictor=0"}, >> + {0x0004, "channel ETT"}, >> + {0x0005, "DCCSCT"}, >> + {0x00FF, "reserved for future ATSC use"}, >> + {0x017F, "EIT"}, >> + {0x01FF, "reserved for future ATSC use"}, >> + {0x027F, "event ETT"}, >> + {0x02FF, "reserved for future ATSC use"}, /* FIXME */ >> + {0x03FF, "RRT with rating region"}, >> + {0x0FFF, "user private"}, >> + {0x13FF, "reserved for future ATSC use"}, >> + {0x14FF, "DCCT with dcc_id"}, >> + {0xFFFF, "reserved for future ATSC use"} >> +}; >> + >> +const char *channel_modulation_mode[] = { >> + "", >> + "analog", >> + "SCTE mode 1", >> + "SCTE mode 2", >> + "ATSC 8VSB", >> + "ATSC 16VSB" >> +}; >> + >> +const char *channel_service_type[] = { >> + "", >> + "analog TV", >> + "ATSC digital TV", >> + "ATSC audio", >> + "ATSC data-only" >> +}; >> + >> +void *(*table_callback[16])(struct atsc_section_psip *) = >> +{ >> + NULL, NULL, NULL, NULL, NULL, NULL, NULL, >> + (void *(*)(struct atsc_section_psip *))atsc_mgt_section_codec, >> + (void *(*)(struct atsc_section_psip >> *))atsc_tvct_section_codec, >> + (void *(*)(struct atsc_section_psip >> *))atsc_cvct_section_codec, >> + (void *(*)(struct atsc_section_psip *))atsc_rrt_section_codec, >> + (void *(*)(struct atsc_section_psip *))atsc_eit_section_codec, >> + (void *(*)(struct atsc_section_psip *))atsc_ett_section_codec, >> + (void *(*)(struct atsc_section_psip *))atsc_stt_section_codec, >> + NULL, NULL >> +}; >> + >> +static void int_handler(int sig_num) >> +{ >> + if(SIGINT != sig_num) { >> + return; >> + } >> + ctrl_c = 1; >> +} >> + >> +/* shamelessly stolen from dvbsnoop, but almost not modified */ >> +static uint32_t get_bits(const uint8_t *buf, int startbit, int >> bitlen) >> +{ >> + const uint8_t *b; >> + uint32_t mask,tmp_long; >> + int bitHigh,i; >> + >> + b = &buf[startbit / 8]; >> + startbit %= 8; >> + >> + bitHigh = 8; >> + tmp_long = b[0]; >> + for (i = 0; i < ((bitlen-1) >> 3); i++) { >> + tmp_long <<= 8; >> + tmp_long |= b[i+1]; >> + bitHigh += 8; >> + } >> + >> + startbit = bitHigh - startbit - bitlen; >> + tmp_long = tmp_long >> startbit; >> + mask = (1ULL << bitlen) - 1; >> + return tmp_long & mask; >> +} >> + >> +static void usage(void) >> +{ >> + fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p >> <period>]" >> + " [-m <modulation>] [-t] [-h]\n", program); >> +} >> + >> +static void help(void) >> +{ >> + fprintf(stderr, >> + "\nhelp:\n" >> + "%s [-a <n>] -f <frequency> [-p <period>] [-m <modulation>] >> [-t] [-h]\n" >> + " -a: adapter index to use, (default 0)\n" >> + " -f: tuning frequency\n" >> + " -p: period in hours, (default 12)\n" >> + " -m: modulation ATSC vsb_8|vsb_16 (default vsb_8)\n" >> + " -t: enable ETT to receive program details, if available\n" >> + " -h: display this message\n", program); >> +} >> + >> +static int close_frontend(struct dvbfe_handle *fe) >> +{ >> + if(NULL == fe) { >> + fprintf(stderr, "%s(): NULL pointer detected\n", >> __FUNCTION__); >> + } >> + >> + dvbfe_close(fe); >> + >> + return 0; >> +} >> + >> +static int open_frontend(struct dvbfe_handle **fe) >> +{ >> + struct dvbfe_info fe_info; >> + >> + if(NULL == (*fe = dvbfe_open(adapter, 0, 0))) { >> + fprintf(stderr, "%s(): error calling dvbfe_open()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + dvbfe_get_info(*fe, 0, &fe_info, >> DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0); >> + if(DVBFE_TYPE_ATSC != fe_info.type) { >> + fprintf(stderr, "%s(): only ATSC frontend supported >> currently\n", >> + __FUNCTION__); >> + return -1; >> + } >> + fe_info.feparams.frequency = frequency; >> + fe_info.feparams.inversion = DVBFE_INVERSION_AUTO; >> + fe_info.feparams.u.atsc.modulation = DVBFE_ATSC_MOD_VSB_8; >> + fprintf(stdout, "tuning to %d Hz, please wait...\n", >> frequency); >> + if(dvbfe_set(*fe, &fe_info.feparams, TIMEOUT * 1000)) { >> + fprintf(stderr, "%s(): cannot lock to %d Hz in %d >> seconds\n", >> + __FUNCTION__, frequency, TIMEOUT); >> + return -1; >> + } >> + fprintf(stdout, "tuner locked.\n"); >> + >> + return 0; >> +} >> + >> +#if ENABLE_RRT >> +/* this is untested as since this part of the library is broken */ >> +static int parse_rrt(int dmxfd) >> +{ >> + const enum atsc_section_tag tag = stag_atsc_rating_region; >> + struct atsc_rrt_section *rrt; >> + struct atsc_text *region_name; >> + struct atsc_text_string *atsc_str; >> + int i, j, ret; >> + >> + i = 0; >> + fprintf(stdout, "waiting for RRT: "); >> + fflush(stdout); >> + while(i < RRT_TIMEOUT) { >> + ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void >> **)&rrt); >> + if(0 > ret) { >> + fprintf(stderr, "%s(): error calling >> atsc_scan_table()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + if(0 == ret) { >> + if(RRT_TIMEOUT > i) { >> + fprintf(stdout, "."); >> + fflush(stdout); >> + } else { >> + fprintf(stdout, "\nno RRT in %d >> seconds\n", >> + RRT_TIMEOUT); >> + return 0; >> + } >> + i += TIMEOUT; >> + } else { >> + fprintf(stdout, "\n"); >> + fflush(stdout); >> + break; >> + } >> + } >> + >> + region_name = atsc_rrt_section_rating_region_name_text(rrt); >> + atsc_text_strings_for_each(region_name, atsc_str, i) { >> + struct atsc_text_string_segment *seg; >> + >> + atsc_text_string_segments_for_each(atsc_str, seg, j) { >> + const char *c; >> + int k; >> + if(seg->mode < 0x3E) { >> + fprintf(stderr, "%s(): text mode of >> 0x%02X " >> + "not supported yet\n", >> + __FUNCTION__, seg->mode); >> + return -1; >> + } >> + c = (const char >> *)atsc_text_string_segment_bytes(seg); >> + for(k = 0; k < seg->number_bytes; k++) { >> + fprintf(stdout, "%c", c[k]); >> + } >> + } >> + } >> + >> + return 0; >> +} >> +#endif >> + >> +static int parse_stt(int dmxfd) >> +{ >> + const enum atsc_section_tag tag = stag_atsc_system_time; >> + const struct atsc_stt_section *stt; >> + time_t rx_time; >> + time_t sys_time; >> + int ret; >> + >> + ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void >> **)&stt); >> + if(0 > ret) { >> + fprintf(stderr, "%s(): error calling >> atsc_scan_table()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + if(0 == ret) { >> + fprintf(stdout, "no STT in %d seconds\n", TIMEOUT); >> + return 0; >> + } >> + >> + rx_time = atsctime_to_unixtime(stt->system_time); >> + time(&sys_time); >> + fprintf(stdout, "system time: %s", ctime(&sys_time)); >> + fprintf(stdout, "TS STT time: %s", ctime(&rx_time)); >> + >> + return 0; >> +} >> + >> +static int parse_tvct(int dmxfd) >> +{ >> + int num_sections; >> + uint32_t section_pattern; >> + const enum atsc_section_tag tag = >> stag_atsc_terrestrial_virtual_channel; >> + struct atsc_tvct_section *tvct; >> + struct atsc_tvct_channel *ch; >> + struct atsc_channel_info *curr_info; >> + int i, k, ret; >> + >> + section_pattern = 0; >> + num_sections = -1; >> + >> + do { >> + ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void >> **)&tvct); >> + if(0 > ret) { >> + fprintf(stderr, "%s(): error calling >> atsc_scan_table()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + if(0 == ret) { >> + fprintf(stdout, "no TVCT in %d seconds\n", >> TIMEOUT); >> + return 0; >> + } >> + >> + if(-1 == num_sections) { >> + num_sections = 1 + >> tvct->head.ext_head.last_section_number; >> + if(32 < num_sections) { >> + fprintf(stderr, "%s(): no support yet >> for " >> + "tables having more than 32 >> sections\n", >> + __FUNCTION__); >> + return -1; >> + } >> + } else { >> + if(num_sections != >> + 1 + >> tvct->head.ext_head.last_section_number) { >> + fprintf(stderr, >> + "%s(): last section number >> does not match\n", >> + __FUNCTION__); >> + return -1; >> + } >> + } >> + if(section_pattern & (1 << >> tvct->head.ext_head.section_number)) { >> + continue; >> + } >> + section_pattern |= 1 << >> tvct->head.ext_head.section_number; >> + >> + if(MAX_NUM_CHANNELS < guide.num_channels + >> + tvct->num_channels_in_section) { >> + fprintf(stderr, "%s(): no support for more >> than %d " >> + "virtual channels in a pyhsical >> channel\n", >> + __FUNCTION__, MAX_NUM_CHANNELS); >> + return -1; >> + } >> + curr_info = &guide.ch[guide.num_channels]; >> + guide.num_channels += tvct->num_channels_in_section; >> + >> + atsc_tvct_section_channels_for_each(tvct, ch, i) { >> + /* initialize the curr_info structure */ >> + /* each EIT covers 3 hours */ >> + curr_info->num_eits = (period / 3) + !!(period % 3); >> + while (curr_info->num_eits && >> + (0xFFFF == guide.eit_pid[curr_info->num_eits - >> 1])) { >> + curr_info->num_eits -= 1; >> + } >> + if(curr_info->eit) { >> + fprintf(stderr, "%s(): non-NULL pointer >> detected " >> + "during initialization", >> __FUNCTION__); >> + return -1; >> + } >> + if(NULL == (curr_info->eit = >> calloc(curr_info->num_eits, >> + sizeof(struct atsc_eit_info)))) { >> + fprintf(stderr, "%s(): error calling >> calloc()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + if(NULL == (curr_info->title_buf.string = >> calloc(TITLE_BUFFER_LEN, >> + sizeof(char)))) { >> + fprintf(stderr, "%s(): error calling >> calloc()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + curr_info->title_buf.buf_len = TITLE_BUFFER_LEN; >> + curr_info->title_buf.buf_pos = 0; >> + >> + if(NULL == (curr_info->msg_buf.string = >> calloc(MESSAGE_BUFFER_LEN, >> + sizeof(char)))) { >> + fprintf(stderr, "%s(): error calling >> calloc()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + curr_info->msg_buf.buf_len = MESSAGE_BUFFER_LEN; >> + curr_info->msg_buf.buf_pos = 0; >> + >> + for(k = 0; k < 7; k++) { >> + curr_info->short_name[k] = >> + get_bits((const uint8_t >> *)ch->short_name, >> + k * 16, 16); >> + } >> + curr_info->service_type = ch->service_type; >> + curr_info->major_num = ch->major_channel_number; >> + curr_info->minor_num = ch->minor_channel_number; >> + curr_info->tsid = ch->channel_TSID; >> + curr_info->prog_num = ch->program_number; >> + curr_info->src_id = ch->source_id; >> + curr_info++; >> + } >> + } while(section_pattern != (uint32_t)((1 << num_sections) - >> 1)); >> + >> + return 0; >> +} >> + >> +static int match_event(struct atsc_eit_info *eit, uint16_t event_id, >> + struct atsc_event_info **event, uint8_t *curr_index) >> +{ >> + int j, k; >> + struct atsc_eit_section_info *section; >> + >> + if(NULL == eit || NULL == event || NULL == curr_index) { >> + fprintf(stderr, "%s(): NULL pointer detected\n", >> __FUNCTION__); >> + return -1; >> + } >> + >> + for(j = 0; j < eit->num_eit_sections; j++) { >> + section = &eit->section[j]; >> + >> + for(k = 0; k < section->num_events; k++) { >> + if(section->events[k] && >> section->events[k]->id == >> + event_id) { >> + *event = section->events[k]; >> + break; >> + } >> + } >> + if(*event) { >> + *curr_index = j; >> + break; >> + } >> + } >> + >> + return 0; >> +} >> + >> +static int parse_message(struct atsc_channel_info *channel, >> + struct atsc_ett_section *ett, struct atsc_event_info *event) >> +{ >> + int i, j; >> + struct atsc_text *text; >> + struct atsc_text_string *str; >> + >> + if(NULL == ett || NULL == event || NULL == channel) { >> + fprintf(stderr, "%s(): NULL pointer detected\n", >> __FUNCTION__); >> + return -1; >> + } >> + >> + text = atsc_ett_section_extended_text_message(ett); >> + atsc_text_strings_for_each(text, str, i) { >> + struct atsc_text_string_segment *seg; >> + >> + atsc_text_string_segments_for_each(str, seg, j) { >> + event->msg_pos = channel->msg_buf.buf_pos; >> + if(0 > atsc_text_segment_decode(seg, >> + (uint8_t **)&channel->msg_buf.string, >> + (size_t *)&channel->msg_buf.buf_len, >> + (size_t *)&channel->msg_buf.buf_pos)) >> { >> + fprintf(stderr, "%s(): error calling " >> + >> "atsc_text_segment_decode()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + event->msg_len = 1 + channel->msg_buf.buf_pos >> - >> + event->msg_pos; >> + } >> + } >> + >> + return 0; >> +} >> + >> +static int parse_ett(int dmxfd, int index, uint16_t pid) >> +{ >> + uint8_t curr_index; >> + uint32_t section_pattern; >> + const enum atsc_section_tag tag = stag_atsc_extended_text; >> + struct atsc_eit_info *eit; >> + struct atsc_ett_section *ett; >> + struct atsc_channel_info *channel; >> + struct atsc_event_info *event; >> + struct atsc_eit_section_info *section; >> + uint16_t source_id, event_id; >> + int c, ret; >> + >> + if(0xFFFF == guide.ett_pid[index]) { >> + return 0; >> + } >> + >> + for(c = 0; c < guide.num_channels; c++) { >> + channel = &guide.ch[c]; >> + eit = &channel->eit[index]; >> + >> + section_pattern = 0; >> + while(section_pattern != >> + (uint32_t)((1 << eit->num_eit_sections) - 1)) >> { >> + if(ctrl_c) { >> + return 0; >> + } >> + ret = atsc_scan_table(dmxfd, pid, tag, (void >> **)&ett); >> + fprintf(stdout, "."); >> + fflush(stdout); >> + if(0 > ret) { >> + fprintf(stderr, "%s(): error calling " >> + "atsc_scan_table()\n", >> __FUNCTION__); >> + return -1; >> + } >> + if(0 == ret) { >> + fprintf(stdout, "no ETT %d in %d >> seconds\n", >> + index, TIMEOUT); >> + return 0; >> + } >> + >> + source_id = ett->ETM_source_id; >> + event_id = ett->ETM_sub_id; >> + if(source_id != channel->src_id) { >> + continue; >> + } >> + >> + event = NULL; >> + if(match_event(eit, event_id, &event, >> &curr_index)) { >> + fprintf(stderr, "%s(): error calling " >> + "match_event()\n", >> __FUNCTION__); >> + return -1; >> + } >> + if(NULL == event) { >> + continue; >> + } >> + if(section_pattern & (1 << curr_index)) { >> + /* the section has been filled, so >> skip, >> + * not consider version yet >> + */ >> + continue; >> + } >> + if(event->msg_len) { >> + /* the message has been filled */ >> + continue; >> + } >> + >> + if(parse_message(channel, ett, event)) { >> + fprintf(stderr, "%s(): error calling " >> + "parse_message()\n", >> __FUNCTION__); >> + return -1; >> + } >> + section = &eit->section[curr_index]; >> + if(++section->num_received_etms == >> section->num_etms) { >> + section_pattern |= 1 << curr_index; >> + } >> + } >> + } >> + >> + return 0; >> +} >> + >> +static int parse_events(struct atsc_channel_info *curr_info, >> + struct atsc_eit_section *eit, struct atsc_eit_section_info >> *section) >> +{ >> + int i, j, k; >> + struct atsc_eit_event *e; >> + time_t start_time, end_time; >> + >> + if(NULL == curr_info || NULL == eit) { >> + fprintf(stderr, "%s(): NULL pointer detected\n", >> __FUNCTION__); >> + return -1; >> + } >> + >> + atsc_eit_section_events_for_each(eit, e, i) { >> + struct atsc_text *title; >> + struct atsc_text_string *str; >> + struct atsc_event_info *e_info = >> + &curr_info->e[curr_info->event_info_index]; >> + >> + if(0 == i && curr_info->last_event) { >> + if(e->event_id == curr_info->last_event->id) { >> + section->events[i] = NULL; >> + /* skip if it's the same event >> spanning >> + * over sections >> + */ >> + continue; >> + } >> + } >> + curr_info->event_info_index += 1; >> + section->events[i] = e_info; >> + e_info->id = e->event_id; >> + start_time = atsctime_to_unixtime(e->start_time); >> + end_time = start_time + e->length_in_seconds; >> + localtime_r(&start_time, &e_info->start); >> + localtime_r(&end_time, &e_info->end); >> + if(0 != e->ETM_location && 3 != e->ETM_location) { >> + /* FIXME assume 1 and 2 is interchangable as >> of now */ >> + section->num_etms++; >> + } >> + >> + title = atsc_eit_event_name_title_text(e); >> + atsc_text_strings_for_each(title, str, j) { >> + struct atsc_text_string_segment *seg; >> + >> + atsc_text_string_segments_for_each(str, seg, >> k) { >> + e_info->title_pos = >> curr_info->title_buf.buf_pos; >> + if(0 > atsc_text_segment_decode(seg, >> + (uint8_t >> **)&curr_info->title_buf.string, >> + (size_t >> *)&curr_info->title_buf.buf_len, >> + (size_t >> *)&curr_info->title_buf.buf_pos)) { >> + fprintf(stderr, "%s(): error >> calling " >> + >> "atsc_text_segment_decode()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + e_info->title_len = >> curr_info->title_buf.buf_pos - >> + e_info->title_pos + 1; >> + } >> + } >> + } >> + >> + return 0; >> +} >> + >> +static int parse_eit(int dmxfd, int index, uint16_t pid) >> +{ >> + int num_sections; >> + uint8_t section_num; >> + uint8_t curr_channel_index; >> + uint32_t section_pattern; >> + const enum atsc_section_tag tag = stag_atsc_event_information; >> + struct atsc_eit_section *eit; >> + struct atsc_channel_info *curr_info; >> + struct atsc_eit_info *eit_info; >> + struct atsc_eit_section_info *section; >> + uint16_t source_id; >> + uint32_t eit_instance_pattern = 0; >> + int i, k, ret; >> + >> + while(eit_instance_pattern != >> + (uint32_t)((1 << guide.num_channels) - 1)) { >> + source_id = 0xFFFF; >> + section_pattern = 0; >> + num_sections = -1; >> + >> + do { >> + ret = atsc_scan_table(dmxfd, pid, tag, (void >> **)&eit); >> + fprintf(stdout, "."); >> + fflush(stdout); >> + if(0 > ret) { >> + fprintf(stderr, "%s(): error calling " >> + "atsc_scan_table()\n", >> __FUNCTION__); >> + return -1; >> + } >> + if(0 == ret) { >> + fprintf(stdout, "no EIT %d in %d >> seconds\n", >> + index, TIMEOUT); >> + return 0; >> + } >> + >> + if(0xFFFF == source_id) { >> + source_id = atsc_eit_section_source_id(eit); >> + for(k = 0; k < guide.num_channels; k++) { >> + if(source_id == guide.ch[k].src_id) { >> + curr_info = &guide.ch[k]; >> + curr_channel_index = k; >> + if(0 == index) { >> + curr_info->last_event >> = NULL; >> + } >> + break; >> + } >> + } >> + if(k == guide.num_channels) { >> + fprintf(stderr, "%s(): cannot find >> source_id " >> + "0x%04X in the EIT\n", >> + __FUNCTION__, source_id); >> + return -1; >> + } >> + } else { >> + if(source_id != >> + >> atsc_eit_section_source_id(eit)) { >> + continue; >> + } >> + } >> + if(eit_instance_pattern & (1 << >> curr_channel_index)) { >> + /* we have received this instance, >> + * so quit quick >> + */ >> + break; >> + } >> + >> + if(-1 == num_sections) { >> + num_sections = 1 + >> + >> eit->head.ext_head.last_section_number; >> + if(32 < num_sections) { >> + fprintf(stderr, >> + "%s(): no support yet >> for " >> + "tables having more >> than " >> + "32 sections\n", >> __FUNCTION__); >> + return -1; >> + } >> + } else { >> + if(num_sections != 1 + >> + >> eit->head.ext_head.last_section_number) { >> + fprintf(stderr, >> + "%s(): last section >> number " >> + "does not match\n", >> + __FUNCTION__); >> + return -1; >> + } >> + } >> + if(section_pattern & >> + (1 << >> eit->head.ext_head.section_number)) { >> + continue; >> + } >> + section_pattern |= 1 << >> eit->head.ext_head.section_number; >> + >> + eit_info = &curr_info->eit[index]; >> + if(NULL == (eit_info->section = >> + realloc(eit_info->section, >> + (eit_info->num_eit_sections + 1) * >> + sizeof(struct >> atsc_eit_section_info)))) { >> + fprintf(stderr, >> + "%s(): error calling >> realloc()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + section_num = >> eit->head.ext_head.section_number; >> + if(0 == eit_info->num_eit_sections) { >> + eit_info->num_eit_sections = 1; >> + section = eit_info->section; >> + } else { >> + /* have to sort it into section order >> + * (temporal order) >> + */ >> + for(i = 0; i < >> eit_info->num_eit_sections; i++) { >> + >> if(eit_info->section[i].section_num > >> + section_num) { >> + break; >> + } >> + } >> + memmove(&eit_info->section[i + 1], >> + &eit_info->section[i], >> + (eit_info->num_eit_sections - >> i) * >> + sizeof(struct >> atsc_eit_section_info)); >> + section = &eit_info->section[i - 1]; >> + section = &eit_info->section[i]; >> + eit_info->num_eit_sections += 1; >> + } >> + >> + section->section_num = section_num; >> + section->num_events = >> eit->num_events_in_section; >> + section->num_etms = 0; >> + section->num_received_etms = 0; >> + if(NULL == (section->events = >> calloc(section->num_events, >> + sizeof(struct atsc_event_info *)))) { >> + fprintf(stderr, "%s(): error calling >> calloc()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + if(parse_events(curr_info, eit, section)) { >> + fprintf(stderr, "%s(): error calling " >> + "parse_events()\n", >> __FUNCTION__); >> + return -1; >> + } >> + } while(section_pattern != (uint32_t)((1 << >> num_sections) - 1)); >> + eit_instance_pattern |= 1 << curr_channel_index; >> + } >> + >> + for(i = 0; i < guide.num_channels; i++) { >> + struct atsc_channel_info *channel = &guide.ch[i]; >> + struct atsc_eit_info *ei = &channel->eit[index]; >> + struct atsc_eit_section_info *s; >> + >> + if(0 == ei->num_eit_sections) { >> + channel->last_event = NULL; >> + continue; >> + } >> + s = &ei->section[ei->num_eit_sections - 1]; >> + /* BUG: it's incorrect when last section has no event >> */ >> + if(0 == s->num_events) { >> + channel->last_event = NULL; >> + continue; >> + } >> + channel->last_event = s->events[s->num_events - 1]; >> + } >> + >> + return 0; >> +} >> + >> +static int parse_mgt(int dmxfd) >> +{ >> + const enum atsc_section_tag tag = stag_atsc_master_guide; >> + struct atsc_mgt_section *mgt; >> + struct atsc_mgt_table *t; >> + int i, j, ret; >> + >> + ret = atsc_scan_table(dmxfd, ATSC_BASE_PID, tag, (void >> **)&mgt); >> + if(0 > ret) { >> + fprintf(stderr, "%s(): error calling >> atsc_scan_table()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + if(0 == ret) { >> + fprintf(stdout, "no MGT in %d seconds\n", TIMEOUT); >> + return 0; >> + } >> + >> + fprintf(stdout, "MGT table:\n"); >> + atsc_mgt_section_tables_for_each(mgt, t, i) { >> + struct mgt_table_name table; >> + >> + for(j = 0; j < (int)(sizeof(mgt_tab_name_array) / >> + sizeof(struct mgt_table_name)); j++) { >> + if(t->table_type > mgt_tab_name_array[j].range) { >> + continue; >> + } >> + table = mgt_tab_name_array[j]; >> + if(0 == j || mgt_tab_name_array[j - 1].range + 1 == >> + mgt_tab_name_array[j].range) { >> + j = -1; >> + } else { >> + j = t->table_type - mgt_tab_name_array[j - >> 1].range - 1; >> + if(0x017F == table.range) { >> + guide.eit_pid[j] = t->table_type_PID; >> + } else if (0x027F == table.range) { >> + guide.ett_pid[j] = t->table_type_PID; >> + } >> + } >> + break; >> + } >> + >> + fprintf(stdout, " %2d: type = 0x%04X, PID = 0x%04X, >> %s", i, >> + t->table_type, t->table_type_PID, table.string); >> + if(-1 != j) { >> + fprintf(stdout, " %d", j); >> + } >> + fprintf(stdout, "\n"); >> + } >> + >> + return 0; >> +} >> + >> +static int cleanup_guide(void) >> +{ >> + int i, j, k; >> + >> + for(i = 0; i < guide.num_channels; i++) { >> + struct atsc_channel_info *channel = &guide.ch[i]; >> + >> + if(channel->title_buf.string) { >> + free(channel->title_buf.string); >> + } >> + if(channel->msg_buf.string) { >> + free(channel->msg_buf.string); >> + } >> + for(j = 0; j < channel->num_eits; j++) { >> + struct atsc_eit_info *eit = &channel->eit[j]; >> + >> + for(k = 0; k < eit->num_eit_sections; k++) { >> + struct atsc_eit_section_info *section >> = >> + &eit->section[k]; >> + if(section->num_events) { >> + free(section->events); >> + } >> + } >> + if(k) { >> + free(eit->section); >> + } >> + } >> + if(j) { >> + free(channel->eit); >> + } >> + } >> + >> + return 0; >> +} >> + >> +static int print_events(struct atsc_channel_info *channel, >> + struct atsc_eit_section_info *section) >> +{ >> + int m; >> + char line[256]; >> + >> + if(NULL == section) { >> + fprintf(stderr, "%s(): NULL pointer detected", >> __FUNCTION__); >> + return -1; >> + } >> + for(m = 0; m < section->num_events; m++) { >> + struct atsc_event_info *event = >> + section->events[m]; >> + >> + if(NULL == event) { >> + continue; >> + } >> + fprintf(stdout, "|%02d:%02d--%02d:%02d| ", >> + event->start.tm_hour, event->start.tm_min, >> + event->end.tm_hour, event->end.tm_min); >> + snprintf(line, event->title_len, "%s", >> + &channel->title_buf.string[event->title_pos]); >> + line[event->title_len] = '\0'; >> + fprintf(stdout, "%s\n", line); >> + if(event->msg_len) { >> + int len = event->msg_len; >> + int pos = event->msg_pos; >> + size_t part; >> + >> + do { >> + part = len > 255 ? 255 : len; >> + snprintf(line, part, "%s", >> + >> &channel->msg_buf.string[pos]); >> + line[part] = '\0'; >> + fprintf(stdout, "%s", line); >> + len -= part; >> + pos += part; >> + } while(0 < len); >> + fprintf(stdout, "\n"); >> + } >> + } >> + return 0; >> +} >> + >> +static int print_guide(void) >> +{ >> + int i, j, k; >> + >> + fprintf(stdout, "%s\n", separator); >> + for(i = 0; i < guide.num_channels; i++) { >> + struct atsc_channel_info *channel = &guide.ch[i]; >> + >> + fprintf(stdout, "%d.%d %s\n", channel->major_num, >> + channel->minor_num, channel->short_name); >> + for(j = 0; j < channel->num_eits; j++) { >> + struct atsc_eit_info *eit = &channel->eit[j]; >> + >> + for(k = 0; k < eit->num_eit_sections; k++) { >> + struct atsc_eit_section_info *section >> = >> + &eit->section[k]; >> + if(print_events(channel, section)) { >> + fprintf(stderr, "%s(): error >> calling " >> + "print_events()\n", >> __FUNCTION__); >> + return -1; >> + } >> + } >> + } >> + fprintf(stdout, "%s\n", separator); >> + } >> + >> + return 0; >> +} >> + >> +static int open_demux(int *dmxfd) >> +{ >> + if((*dmxfd = dvbdemux_open_demux(adapter, 0, 0)) < 0) { >> + fprintf(stderr, "%s(): error calling >> dvbdemux_open_demux()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + return 0; >> +} >> + >> +static int close_demux(int dmxfd) >> +{ >> + if(dvbdemux_stop(dmxfd)) { >> + fprintf(stderr, "%s(): error calling >> dvbdemux_stop()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + return 0; >> +} >> + >> +/* used other utilities as template and generalized here */ >> +static int atsc_scan_table(int dmxfd, uint16_t pid, enum >> atsc_section_tag tag, >> + void **table_section) >> +{ >> + uint8_t filter[18]; >> + uint8_t mask[18]; >> + unsigned char sibuf[4096]; >> + int size; >> + int ret; >> + struct pollfd pollfd; >> + struct section *section; >> + struct section_ext *section_ext; >> + struct atsc_section_psip *psip; >> + >> + /* create a section filter for the table */ >> + memset(filter, 0, sizeof(filter)); >> + memset(mask, 0, sizeof(mask)); >> + filter[0] = tag; >> + mask[0] = 0xFF; >> + if(dvbdemux_set_section_filter(dmxfd, pid, filter, mask, 1, >> 1)) { >> + fprintf(stderr, "%s(): error calling >> atsc_scan_table()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + /* poll for data */ >> + pollfd.fd = dmxfd; >> + pollfd.events = POLLIN | POLLERR |POLLPRI; >> + if((ret = poll(&pollfd, 1, TIMEOUT * 1000)) < 0) { >> + if(ctrl_c) { >> + return 0; >> + } >> + fprintf(stderr, "%s(): error calling poll()\n", >> __FUNCTION__); >> + return -1; >> + } >> + >> + if(0 == ret) { >> + return 0; >> + } >> + >> + /* read it */ >> + if((size = read(dmxfd, sibuf, sizeof(sibuf))) < 0) { >> + fprintf(stderr, "%s(): error calling read()\n", >> __FUNCTION__); >> + return -1; >> + } >> + >> + /* parse section */ >> + section = section_codec(sibuf, size); >> + if(NULL == section) { >> + fprintf(stderr, "%s(): error calling >> section_codec()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + section_ext = section_ext_decode(section, 0); >> + if(NULL == section_ext) { >> + fprintf(stderr, "%s(): error calling >> section_ext_decode()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + psip = atsc_section_psip_decode(section_ext); >> + if(NULL == psip) { >> + fprintf(stderr, >> + "%s(): error calling >> atsc_section_psip_decode()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + *table_section = table_callback[tag & 0x0F](psip); >> + if(NULL == *table_section) { >> + fprintf(stderr, "%s(): error decode table section\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + return 1; >> +} >> + >> +int main(int argc, char *argv[]) >> +{ >> + int i, dmxfd; >> + struct dvbfe_handle *fe; >> + >> + program = argv[0]; >> + >> + if(1 == argc) { >> + usage(); >> + exit(-1); >> + } >> + >> + for( ; ; ) { >> + char c; >> + >> + if(-1 == (c = getopt(argc, argv, "a:f:p:m:th"))) { >> + break; >> + } >> + >> + switch(c) { >> + case 'a': >> + adapter = strtoll(optarg, NULL, 0); >> + break; >> + >> + case 'f': >> + frequency = strtol(optarg, NULL, 0); >> + break; >> + >> + case 'p': >> + period = strtol(optarg, NULL, 0); >> + /* each table covers 3 hours */ >> + if((3 * MAX_NUM_EVENT_TABLES) < period) { >> + period = 3 * MAX_NUM_EVENT_TABLES; >> + } >> + break; >> + >> + case 'm': >> + /* just stub, so far ATSC only has VSB_8 */ >> + modulation = optarg; >> + break; >> + >> + case 't': >> + enable_ett = 1; >> + break; >> + >> + case 'h': >> + help(); >> + exit(0); >> + >> + default: >> + usage(); >> + exit(-1); >> + } >> + } >> + >> + memset(separator, '-', sizeof(separator)); >> + separator[79] = '\0'; >> + memset(&guide, 0, sizeof(struct atsc_virtual_channels_info)); >> + memset(guide.eit_pid, 0xFF, MAX_NUM_EVENT_TABLES * >> sizeof(uint16_t)); >> + memset(guide.ett_pid, 0xFF, MAX_NUM_EVENT_TABLES * >> sizeof(uint16_t)); >> + >> + if(open_frontend(&fe)) { >> + fprintf(stderr, "%s(): error calling >> open_frontend()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + if(open_demux(&dmxfd)) { >> + fprintf(stderr, "%s(): error calling open_demux()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + if(parse_stt(dmxfd)) { >> + fprintf(stderr, "%s(): error calling parse_stt()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + if(parse_mgt(dmxfd)) { >> + fprintf(stderr, "%s(): error calling parse_mgt()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + if(parse_tvct(dmxfd)) { >> + fprintf(stderr, "%s(): error calling parse_tvct()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> +#ifdef ENABLE_RRT >> + if(parse_rrt(dmxfd)) { >> + fprintf(stderr, "%s(): error calling parse_rrt()\n", >> + __FUNCTION__); >> + return -1; >> + } >> +#endif >> + >> + fprintf(stdout, "receiving EIT "); >> + for(i = 0; i < guide.ch[0].num_eits; i++) { >> + if(parse_eit(dmxfd, i, guide.eit_pid[i])) { >> + fprintf(stderr, "%s(): error calling >> parse_eit()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + } >> + fprintf(stdout, "\n"); >> + >> + old_handler = signal(SIGINT, int_handler); >> + if(enable_ett) { >> + fprintf(stdout, "receiving ETT "); >> + for(i = 0; i < guide.ch[0].num_eits; i++) { >> + if(0xFFFF != guide.ett_pid[i]) { >> + if(parse_ett(dmxfd, i, >> guide.ett_pid[i])) { >> + fprintf(stderr, "%s(): error >> calling " >> + "parse_eit()\n", >> __FUNCTION__); >> + return -1; >> + } >> + } >> + if(ctrl_c) { >> + break; >> + } >> + } >> + fprintf(stdout, "\n"); >> + } >> + signal(SIGINT, old_handler); >> + >> + if(print_guide()) { >> + fprintf(stderr, "%s(): error calling print_guide()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + if(cleanup_guide()) { >> + fprintf(stderr, "%s(): error calling >> cleanup_guide()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + if(close_demux(dmxfd)) { >> + fprintf(stderr, "%s(): error calling close_demux()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + if(close_frontend(fe)) { >> + fprintf(stderr, "%s(): error calling close_demux()\n", >> + __FUNCTION__); >> + return -1; >> + } >> + >> + return 0; >> +} >> diff -uprN dvb-apps/util/atsc_epg/Makefile >> dvb-apps_new/util/atsc_epg/Makefile >> --- dvb-apps/util/atsc_epg/Makefile 1969-12-31 18:00:00.000000000 >> -0600 >> +++ dvb-apps_new/util/atsc_epg/Makefile 2009-06-18 20:11:58.362985962 >> -0500 >> @@ -0,0 +1,16 @@ >> +# Makefile for linuxtv.org dvb-apps/util/atsc_epg >> + >> +binaries = atsc_epg >> + >> +inst_bin = $(binaries) >> + >> +CPPFLAGS += -I../../lib -std=c99 -D_POSIX_SOURCE >> +#LDFLAGS += -static -L../../lib/libdvbapi -L../../lib/libucsi >> +LDFLAGS += -L../../lib/libdvbapi -L../../lib/libucsi >> +LDLIBS += -ldvbapi -lucsi >> + >> +.PHONY: all >> + >> +all: $(binaries) >> + >> +include ../../Make.rules >> diff -uprN dvb-apps/util/atsc_epg/README dvb-apps_new/util/atsc_epg/README >> --- dvb-apps/util/atsc_epg/README 1969-12-31 18:00:00.000000000 -0600 >> +++ dvb-apps_new/util/atsc_epg/README 2009-06-18 20:33:47.836924378 -0500 >> @@ -0,0 +1,12 @@ >> +Hi there, >> + >> +atsc_epg is a small utility for obtaining information such as programs, EPG >> +(electronic program guide) from an ATSC channel. >> + >> +Pulling the detailed information, i.e., option '-t', may take fairly long >> +time, or never ending, which is a bug of the PSIP generator. Ctrl+C can be >> +used to abort and the received parts will be printed. >> + >> +Enjoy, >> +Yufei >> + >> diff -uprN dvb-apps/util/Makefile dvb-apps_new/util/Makefile >> --- dvb-apps/util/Makefile 2009-06-18 19:43:30.034986539 -0500 >> +++ dvb-apps_new/util/Makefile 2009-06-18 20:11:41.169986806 -0500 >> @@ -3,6 +3,7 @@ >> .PHONY: all clean install >> >> all clean install: >> + $(MAKE) -C atsc_epg $@ >> $(MAKE) -C av7110_loadkeys $@ >> $(MAKE) -C dib3000-watch $@ >> $(MAKE) -C dst-utils $@ >> > > -- > Even uttering "HI" or "HAO" is offensive, sometime, somewhere. Reader > discretion is advised. > -- > > My, the patch is still pretty well broken. > > I leave it to Manu to help you further in the submission procedures ;) > > As said, keep your Confucius stuff if you like. > > I won't rant a second time on it. > > But don't ever complain here, if others do have some good arguments too, > in their footers ... > > Cheers, > Hermann > > > > > > > > > -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html