Re: How to decode EIT and SDT?

"Bernhard Ehlers" <[email protected]>
Newsgroups gmane.comp.video.videolan.libdvbpsi.devel
Message-ID <[email protected]>
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
_______________________________________________
libdvbpsi-devel mailing list
[email protected]
http://mailman.videolan.org/listinfo/libdvbpsi-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.