[libdvbpsi-devel] How to decode EIT and SDT?

Bernhard Ehlers b-ehlers at gmx.de
Tue Feb 21 13:48:10 CET 2012


Hi

for EIT decoding you register a function via dvbpsi_AttachDemux.
Afterwards you attach the EIT decoder function with dvbpsi_AttachEIT.

This doesn't have to happen in the AttachDemux callback function as
shown in this example. In another program I do the dvbpsi_AttachEIT
in the PAT decoder.

With SDT it works similar.

Have a look at the following program, which does a basic EIT decoding.
Please note, that this program ignores the charset in the EIT data.
A correct charset handling is quite complex.

Best regards

Bernhard


/*
 * eit - some basic informations about EIT contents
 *
 * Usage: eit [-e <EIT Pid>] [-s <Service ID>] <file>
 */

#define _FILE_OFFSET_BITS	64

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>

#include <dvbpsi/dvbpsi.h>
#include <dvbpsi/demux.h>
#include <dvbpsi/descriptor.h>
#include <dvbpsi/dr_4d.h>
#include <dvbpsi/dr_69.h>
#include <dvbpsi/eit.h>

#define EIT_PID			18		/* EIT pid */
#define TS_LEN			188		/* length of MPEG-2 TS frame */
#define BUF_SIZE		(TS_LEN*256)	/* Buffer size */

static int eit_pid = EIT_PID;
static int service_id = -1;

static void usage(void) {
  fprintf(stderr, "\
eit - some basic informations about EIT contents\n\n\
Usage: eit [-e <EIT Pid>] [-s <Service ID>] <file>\n\
");
  exit(1);
}

/*
 * printf_err - printf to stderr and exit(1)
 */
static void printf_err(char *format, ...) {
  va_list varg;

  va_start(varg, format);
  fprintf(stderr, "tseit: ");
  vfprintf(stderr, format, varg);
  va_end(varg);

  exit(1);
}

/*
 * si_time - convert DVB-SI time to seconds since 00:00
 */
int si_time(uint32_t time) {
  int hour, min, sec;
  hour = (time >> 16) & 0xff;
  hour = (hour >> 4) * 10 + (hour & 0x0f);
  min  = (time >> 8) & 0xff;
  min  = (min >> 4) * 10 + (min & 0x0f);
  sec  = time  & 0xff;
  sec  = (sec >> 4) * 10 + (sec & 0x0f);

  return ((hour * 60) + min) * 60 + sec;
}

/*
 * si_date - convert DVB-SI date to unix time (seconds since 1970-01-01)
 */
time_t si_date(uint64_t date) {
  time_t epoch;

  epoch = (date >> 24) & 0xffff;	/* modified julian date */
  if (epoch < 40587) return 0;		/* mjd-40587 = days since 1970-01-01 */
  epoch = (epoch-40587) * 24*60*60 + si_time((uint32_t)date & 0xffffff);

  return epoch;
}

/*
 * asc_localtime - generate date string
 */
static char *asc_localtime(time_t *clock) {
  struct tm tm;
  static char strtime[20];

  localtime_r(clock, &tm);
  sprintf(strtime, "%02d.%02d.%04d %02d:%02d:%02d",
          tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900,
          tm.tm_hour, tm.tm_min, tm.tm_sec);

  return strtime;
}

/*
 * copy SI string to C string, ignore charset
 */
void cp_si(char *dest, int size, unsigned char *si, int len) {
  if (len > 0 && *si < 0x20) {
    si++; len--;
  }
  if (len >= size) len = size-1;
  memcpy(dest, si, len);
  dest[len] = '\0';
}

void show_eit(void *private, dvbpsi_eit_t* eit) {
  dvbpsi_eit_event_t *event;
  dvbpsi_descriptor_t *descriptor;
  dvbpsi_short_event_dr_t *short_dr;
  dvbpsi_PDC_dr_t *pdc_dr;
  time_t  start, end;
  char title[129], subtitle[129];
  char pdc[6];

  for (event = eit->p_first_event; event != NULL; event = event->p_next) {
    if (event->i_running_status == 1) continue;

    start = si_date(event->i_start_time);
    end   = start + si_time(event->i_duration);

    title[0] = '\0';
    subtitle[0] = '\0';
    pdc[0] = '\0';

    for (descriptor = event->p_first_descriptor;
         descriptor != NULL; descriptor = descriptor->p_next)
      switch (descriptor->i_tag) {
        case 0x4d:		/* short event descriptor */
          short_dr = dvbpsi_DecodeShortEventDr(descriptor);
          if (short_dr->i_event_name_length != short_dr->i_text_length ||
              memcmp(short_dr->i_event_name, short_dr->i_text,
                     short_dr->i_event_name_length) != 0) {
            cp_si(subtitle, sizeof(subtitle),
                  short_dr->i_text, short_dr->i_text_length);
          }

          cp_si(title, sizeof(title),
                short_dr->i_event_name, short_dr->i_event_name_length);
          break;

        case 0x69:		/* PDC descriptor */
          pdc_dr = dvbpsi_DecodePDCDr(descriptor);
          sprintf(pdc, "%02d:%02d", pdc_dr->i_PDC[2], pdc_dr->i_PDC[3]);
          break;

        default:
          break;
      }

    /* output event */
    printf("Service=%u ", eit->i_service_id);
    printf("%d ", event->i_running_status);
    printf("%.16s", asc_localtime(&start));
    printf("-%.5s", asc_localtime(&end)+11);
    if (pdc[0] != '\0')
      printf(" PDC=%s", pdc);
    printf(" %s", title);
    if (subtitle[0] != '\0')
      printf(" / %s", subtitle);
    printf("\n");
  }

  dvbpsi_DeleteEIT(eit);
}

void NewEIT(void *private, dvbpsi_handle h_dvbpsi,
            uint8_t table_id, uint16_t extension) {
  if (table_id == 0x4E) {
    if (service_id < 0 || service_id == extension)
      dvbpsi_AttachEIT(h_dvbpsi, table_id, extension, show_eit, NULL);
  }
}

static dvbpsi_handle dvbpsi_eit = NULL;

/*
 * analyze_buf - analyze a buffer with several MPEG transport frames
 */
static void analyze_buf(unsigned char *buffer, int len) {
//  static int num = 0;
  unsigned char *bp;
  int pid;

  for (bp = buffer; len >= TS_LEN; bp += TS_LEN, len -= TS_LEN) {
    if (bp[0] != 0x47)
      printf_err("Invalid sync byte 0x%02X - should be 0x47\n", bp[0]);

    pid = ((bp[1] & 0x1f) << 8) + bp[2];
    if (pid == eit_pid) {
      dvbpsi_PushPacket(dvbpsi_eit, bp);
    }
  }

  if (len != 0)
    printf_err("Input data size not multiple of %d.\n", TS_LEN);
}

/*
 * read_file - read MPEG from file
 */
static void read_file(char *fname) {
  int fd;
  int len;
  unsigned char buffer[BUF_SIZE];

  if ((fd = open(fname, O_RDONLY)) < 0)
    { perror(fname); exit(1); }

  /* analyze file */
  while (1) {
    len = read(fd, buffer, sizeof(buffer));
    if (len < 0) { perror("read"); exit(1); }
    if (len == 0) break;

    analyze_buf(buffer, len);
  }

  close(fd);
}

int main(int argc, char *argv[]) {
  int ch;
  char *fname;

  eit_pid = EIT_PID;
  service_id = -1;

  /* handle command line options */
  while ((ch = getopt(argc, argv, "e:s:")) > 0) {
    switch (ch) {
      case 'e':
        eit_pid = atoi(optarg);
        break;
      case 's':
        service_id = atoi(optarg);
        break;
      case '?':
      default:
        usage();
        break;
    }
  }

  if ((argc - optind) !=  1) usage();
  fname = argv[optind];

  dvbpsi_eit = dvbpsi_AttachDemux(NewEIT, NULL);

  read_file(fname);

  dvbpsi_DetachDemux(dvbpsi_eit);

  return 0;
}

-- 
Empfehlen Sie GMX DSL Ihren Freunden und Bekannten und wir
belohnen Sie mit bis zu 50,- Euro! https://freundschaftswerbung.gmx.de


More information about the libdvbpsi-devel mailing list