All of lore.kernel.org
 help / color / mirror / Atom feed
* [Patch] New utility program atsc_epg added to dvb-apps utility suite.
@ 2009-06-17 23:18 Yufei Yuan
  2009-06-17 23:51 ` hermann pitton
  2009-06-18  8:32 ` Manu Abraham
  0 siblings, 2 replies; 22+ messages in thread
From: Yufei Yuan @ 2009-06-17 23:18 UTC (permalink / raw)
  To: Linux Media Mailing List

[-- Attachment #1: Type: text/plain, Size: 668 bytes --]

Hi,

I am not sure if this is the correct mailing list to send this patch.
>From the LinuxTV website, it seems that currently dvb-apps project has
no owner.

A new utility atsc_epg is added into the dvb-apps utility suite. It
parses PSIP information carried in OTA ATSC channels, and constructs a
basic EPG in a terminal window. Changes were also made to files to
please GCC4.4.

The patch is against latest revision 1278 from the dvb-apps repository.

Regards,
Yufei Yuan

-- 
好学近乎智,力行近乎仁,知耻近乎勇。
Eagerness in learning is close to intelligence.
Commitment in doing is close to nobleness.
Realization of shamefulness is close to courageousness.

[-- Attachment #2: atsc_epg_base_1278.patch --]
[-- Type: application/octet-stream, Size: 47116 bytes --]

# HG changeset patch
# User Yufei Yuan <yfyuan@gmail.com>
# Date 1245259744 18000
# Node ID 48605397912baf834f2ffbe95d44c51faed382c6
# Parent  ee4f2dbb8f28e93351d00aa38b0bd36469155769
Pulling ETT information can now be interrupted using Ctrl+C and still have partial printout.

diff -r ee4f2dbb8f28 -r 48605397912b util/atsc_epg/README
--- a/util/atsc_epg/README	Mon Jun 15 22:13:20 2009 -0500
+++ b/util/atsc_epg/README	Wed Jun 17 12:29:04 2009 -0500
@@ -3,6 +3,8 @@
 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 -r ee4f2dbb8f28 -r 48605397912b util/atsc_epg/atsc_epg.c
--- a/util/atsc_epg/atsc_epg.c	Mon Jun 15 22:13:20 2009 -0500
+++ b/util/atsc_epg/atsc_epg.c	Wed Jun 17 12:29:04 2009 -0500
@@ -23,6 +23,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <time.h>
+#include <signal.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -53,8 +54,10 @@
 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;
@@ -75,6 +78,8 @@
 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;
 };
 
@@ -161,6 +166,14 @@
     NULL, NULL
 };
 
+static void int_handler(int sig_num) 
+{
+    if(SIGINT != sig_num) {
+        return;
+    }
+    ctrl_c = 1;
+}
+
 /* shamelessly stolen from dvbsnoop, but modified */
 static uint32_t get_bits(const uint8_t *buf, int startbit, int bitlen)
 {
@@ -428,82 +441,100 @@
 
 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_eit_section_info *section;
     struct atsc_ett_section *ett;
     struct atsc_channel_info *channel;
     struct atsc_event_info *event;
     struct atsc_text *text;
     struct atsc_text_string *str;
     uint16_t source_id, event_id;
-    int i, j, k, ret;
+    int i, j, k, c, ret;
 
-    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 EIT %d in %d seconds\n", index, TIMEOUT);
+    if(0xFFFF == guide.ett_pid[index]) {
         return 0;
     }
 
-    source_id = ett->ETM_source_id;
-    event_id = ett->ETM_sub_id;
-    channel = NULL;
-    for(i = 0; i < guide.num_channels; i++) {
-        if(source_id == guide.ch[i].src_id) {
-            channel = &guide.ch[i];
-            break;
-        }
-    }
-    if(NULL == channel) {
-        return 0;
-    }
+    for(c = 0; c < guide.num_channels; c++) {
+        channel = &guide.ch[c];
+        eit = &channel->eit[index];
 
-    event = NULL;
-    for(i = 0; i < channel->num_eits; i++) {
-        struct atsc_eit_info *eit = &channel->eit[i];
+        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;
+            }
 
-        for(j = 0; j < eit->num_eit_sections; j++) {
-            struct atsc_eit_section_info *section = &eit->section[j];
+            source_id = ett->ETM_source_id;
+            event_id = ett->ETM_sub_id;
+            if(source_id != channel->src_id) {
+                continue;
+            }
 
-            for(k = 0; k < section->num_events; k++) {
-                if(section->events[k] && section->events[k]->id == event_id) {
-                    event = section->events[k];
+            event = NULL;
+            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;
                 }
             }
-            if(event) {
-                break;
+            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;
+            }
+
+            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;
+                }
+            }
+            if(++section->num_received_etms == section->num_etms) {
+                section_pattern |= 1 << curr_index;
             }
         }
-        if(event) {
-            break;
-        }
-    }
-    if(NULL == event) {
-        return 0;
     }
 
-    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;
 }
 
@@ -614,6 +645,8 @@
 
             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__);
@@ -639,6 +672,10 @@
                 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) {
@@ -868,6 +905,9 @@
     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;
     }
@@ -1003,6 +1043,7 @@
     }
     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++) {
@@ -1012,9 +1053,13 @@
                     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__);
# HG changeset patch
# User Yufei Yuan <yfyuan@gmail.com>
# Date 1245122000 18000
# Node ID ee4f2dbb8f28e93351d00aa38b0bd36469155769
# Parent  38609cb0d9c586c78a80b7173f80aa32e355a811
Help information print fixed.

diff -r 38609cb0d9c5 -r ee4f2dbb8f28 util/atsc_epg/atsc_epg.c
--- a/util/atsc_epg/atsc_epg.c	Mon Jun 15 20:32:08 2009 -0500
+++ b/util/atsc_epg/atsc_epg.c	Mon Jun 15 22:13:20 2009 -0500
@@ -187,15 +187,15 @@
 
 static void usage(void)
 {
-    fprintf(stderr, "usage: %s [-a <n>] -f <frequency> [-p <period>][-m <modulation>] [-h]\n", 
-        program);
+    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> [-m <modulation>] [-t] [-h]\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"
# HG changeset patch
# User Yufei Yuan <yfyuan@gmail.com>
# Date 1245115928 18000
# Node ID 38609cb0d9c586c78a80b7173f80aa32e355a811
# Parent  9b5c731498085a0f9e03242092f7489f5ac09230
1. A new utility atsc_epg is added.
2. Makefile and Perl script changed to be compiled with GCC 4.4.

diff -r 9b5c73149808 -r 38609cb0d9c5 util/Makefile
--- a/util/Makefile	Wed Jun 10 20:23:15 2009 +0200
+++ b/util/Makefile	Mon Jun 15 20:32:08 2009 -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 $@
diff -r 9b5c73149808 -r 38609cb0d9c5 util/atsc_epg/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/atsc_epg/Makefile	Mon Jun 15 20:32:08 2009 -0500
@@ -0,0 +1,15 @@
+# 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
+LDLIBS   += -ldvbapi -lucsi
+
+.PHONY: all
+
+all: $(binaries)
+
+include ../../Make.rules
diff -r 9b5c73149808 -r 38609cb0d9c5 util/atsc_epg/README
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/atsc_epg/README	Mon Jun 15 20:32:08 2009 -0500
@@ -0,0 +1,8 @@
+Hi there,
+
+atsc_epg is a small utility for obtaining information such as programs, EPG 
+(electronic program guide) from an ATSC channel. 
+
+Enjoy,
+Yufei
+
diff -r 9b5c73149808 -r 38609cb0d9c5 util/atsc_epg/atsc_epg.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/atsc_epg/atsc_epg.c	Mon Jun 15 20:32:08 2009 -0500
@@ -0,0 +1,1058 @@
+/*
+ * atsc_epg utility
+ * 
+ * Copyright (C) 2009 Yufei Yuan <yfyuan@gmail.com>
+ * 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 <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 const char *modulation = NULL;
+static char separator[80];
+
+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;
+    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
+};
+
+/* shamelessly stolen from dvbsnoop, but 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>] [-h]\n", 
+        program);
+}
+
+static void help(void)
+{
+    fprintf(stderr,
+    "\nhelp:\n"
+        "%s [-a <n>] -f <frequency> [-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 0
+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 parse_ett(int dmxfd, int index, uint16_t pid) 
+{
+    const enum atsc_section_tag tag = stag_atsc_extended_text;
+    struct atsc_ett_section *ett;
+    struct atsc_channel_info *channel;
+    struct atsc_event_info *event;
+    struct atsc_text *text;
+    struct atsc_text_string *str;
+    uint16_t source_id, event_id;
+    int i, j, k, ret;
+
+    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 EIT %d in %d seconds\n", index, TIMEOUT);
+        return 0;
+    }
+
+    source_id = ett->ETM_source_id;
+    event_id = ett->ETM_sub_id;
+    channel = NULL;
+    for(i = 0; i < guide.num_channels; i++) {
+        if(source_id == guide.ch[i].src_id) {
+            channel = &guide.ch[i];
+            break;
+        }
+    }
+    if(NULL == channel) {
+        return 0;
+    }
+
+    event = NULL;
+    for(i = 0; i < channel->num_eits; i++) {
+        struct atsc_eit_info *eit = &channel->eit[i];
+
+        for(j = 0; j < eit->num_eit_sections; j++) {
+            struct atsc_eit_section_info *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) {
+                break;
+            }
+        }
+        if(event) {
+            break;
+        }
+    }
+    if(NULL == event) {
+        return 0;
+    }
+
+    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_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_eit_event *e;
+    struct atsc_channel_info *curr_info;
+    struct atsc_eit_info *eit_info;
+    struct atsc_eit_section_info *section;
+    uint16_t source_id;
+    time_t start_time, end_time;
+    uint32_t eit_instance_pattern = 0;
+    int i, j, 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(section_num < eit_info->section[i].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;
+            if(NULL == (section->events = calloc(section->num_events, 
+                sizeof(struct atsc_event_info *)))) {
+                fprintf(stderr, "%s(): error calling calloc()\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);
+
+                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 = 1 + curr_info->title_buf.buf_pos - 
+                            e_info->title_pos; 
+                    }
+                }
+            }
+        } 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_guide(void) 
+{
+    int i, j, k, m;
+    char line[256];
+
+    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];
+
+                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");
+                    }
+                }
+            }
+        }
+        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;
+}
+
+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) {
+        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;
+
+    if(1 == argc) {
+        usage();
+    }
+
+    program = argv[0];
+
+    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':
+            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;
+    }
+
+    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");
+
+    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;
+                }
+            }
+        }
+        fprintf(stdout, "\n");
+    }
+
+    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 0
+    i = 0;
+    while(0 != ch_info[i].source_id) {
+        ch_info[i].string[ch_info[i].buffer_pos] = '\0';
+        fprintf(stdout, "%s", ch_info[i].string);
+        free(ch_info[i++].string);
+    }
+    fprintf(stdout, "%s\n", separator);
+#endif
+
+#if 0
+    if(parse_rrt(dmxfd)) {
+        fprintf(stderr, "%s(): error calling parse_rrt()\n", __FUNCTION__);
+        return -1;
+    }
+#endif
+
+    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 -r 9b5c73149808 -r 38609cb0d9c5 util/scan/Makefile
--- a/util/scan/Makefile	Wed Jun 10 20:23:15 2009 +0200
+++ b/util/scan/Makefile	Mon Jun 15 20:32:08 2009 -0500
@@ -14,7 +14,7 @@
 
 removing = atsc_psip_section.c atsc_psip_section.h
 
-CPPFLAGS += -DDATADIR=\"$(prefix)/share\"
+CPPFLAGS += -D__KERNEL_STRICT_NAMES -DDATADIR=\"$(prefix)/share\"
 
 .PHONY: all
 
diff -r 9b5c73149808 -r 38609cb0d9c5 util/scan/atsc_psip_section.pl
--- a/util/scan/atsc_psip_section.pl	Wed Jun 10 20:23:15 2009 +0200
+++ b/util/scan/atsc_psip_section.pl	Mon Jun 15 20:32:08 2009 -0500
@@ -65,10 +65,11 @@
 				hidden => 1,
 				reserved1 => 2,
 				hide_guide => 1,
-				reserved2 => 3,
+				reserved2 => 1,
+				reserved3 => 2,
 				service_type => 6,
 				source_id => 16,
-				reserved3 => 6,
+				reserved4 => 6,
 				descriptors_length => 10,
 			],
 		},

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2009-06-23  0:56 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-17 23:18 [Patch] New utility program atsc_epg added to dvb-apps utility suite Yufei Yuan
2009-06-17 23:51 ` hermann pitton
     [not found]   ` <ccdf9f470906171706gc36e43bq4e2092d948c1fbf5@mail.gmail.com>
     [not found]     ` <1245284055.8827.36.camel@pc07.localdom.local>
     [not found]       ` <ccdf9f470906171720i4076642dna483643c55a4a85f@mail.gmail.com>
2009-06-18  0:52         ` hermann pitton
     [not found]         ` <1245285015.10476.4.camel@pc07.localdom.local>
     [not found]           ` <ccdf9f470906171746k8e5ac37j9c0a48823f98ba87@mail.gmail.com>
2009-06-18  1:05             ` hermann pitton
2009-06-18  1:12               ` Yufei Yuan
2009-06-18  1:23                 ` hermann pitton
2009-06-18  8:32 ` Manu Abraham
2009-06-18  8:48   ` Manu Abraham
2009-06-18 13:06     ` Yufei Yuan
2009-06-19  0:52       ` Yufei Yuan
2009-06-19  1:39         ` Yufei Yuan
2009-06-20  0:41           ` hermann pitton
2009-06-20  1:00             ` Yufei Yuan
2009-06-20  1:28               ` hermann pitton
2009-06-20  2:38                 ` Yufei Yuan
2009-06-20  3:04                   ` hermann pitton
     [not found]           ` <ccdf9f470906181855m2d6c471cm12afea3f228fd57c@mail.gmail.com>
2009-06-20  7:30             ` Manu Abraham
2009-06-20 13:30               ` Yufei Yuan
2009-06-20 17:15               ` [Patch] dvb-apps: code cleanup and bug fix Yufei Yuan
2009-06-20 17:31                 ` Yufei Yuan
2009-06-22 23:43               ` [Patch] New utility program atsc_epg added to dvb-apps utility suite Yufei Yuan
2009-06-23  0:52                 ` hermann pitton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.