libdvbpsi  2.0.0-git
MPEG Transport Stream PSI table parser
Migrate from dvbpsi API version 1.0.0 to version 2.0.0

In libdvbpsi version 2 the API has changed considerably in the area of subtable decoders. Upto version 1.x.x this was handled by demux functions (dvbpsi/demux.h). It required for each PSI subtable that a new dvbpsi_subsdec_t struct was used to wrap other subtable decoders. Not all PSI tables implemented that, such as PAT, PMT and CAT. The version 2 removes all demux_XXX functions and replaces it with a simple linked list implemented by dvbpsi_decoder_chain_XXX() functions. As a result all PSI Tables can be chained now and handled by only one demuxing function operating on a dvbpsi_t handle. It is still possible to allocate a dvbpsi_t handle per PSI table, which is compatible with the old way of working in writing libdvbpsi table decoders.

Example: PAT table

The following examples shows howto translate existing applications. In these examples only source code snippits are used and can thus not be compiled standalone. The examples are taken from existing applications using libdvbpsi. For a more elaborate example take a look in examples/ directory and especially to the file examples/dvbinfo/libdvbpsi.c from the dvbinfo application.

In many existing applications the following scheme is used to attach a PAT decoder to a dvbpsi handle (This code is still supported by libdvbpsi version 2.0.0):

  dvbpsi_t *handle = dvbpsi_new(&dvbpsi_message, DVBPSI_MSG_DEBUG);
  if (handle == NULL)
   goto error;
  if (!dvbpsi_pat_attach(handle, handle_PAT, data))
  {
    dvbpsi_delete(handle);
    handle = NULL;
    goto error;
  }
  ... other code ...  
  return 0;
 
error:
  if (dvbpsi_decoder_present(handle))
    dvbpsi_pat_detach(handle);
  if (handle)
  nbsp; dvbpsi_delete(handle);
  return -1;

The same snippit of code using the dvbpsi_decoder_chain_XX() functions looks like this:

static void AttachPAT(dvbpsi_t *p_dvbpsi, uint8_t i_table_id, uint16_t i_extension,
  void *p_zero)
{
  if (!dvbpsi_pat_attach(p_dvbpsi, i_table_id, i_extension, DumpPAT, NULL))
    fprintf(stderr, "Failed to attach PAT decoder\n");
}

static void DetachPAT(dvbpsi_t *p_dvbpsi, uint8_t i_table_id, uint16_t i_extension)
{
  dvbpsi_pat_detach(p_dvbpsi, i_table_id, i_extension);
}

void main(int argc, char** argv)
{
  dvbpsi_t *handle = dvbpsi_new(&dvbpsi_message, DVBPSI_MSG_DEBUG);
  if (handle == NULL)
    goto error;
  if (!dvbpsi_decoder_chain_new(p_dvbpsi, AttachPAT, DetachPAT, NULL))
    goto error;
 
  .. other code ..
  return 0;

error:  
  if (!dvbpsi_decoder_chain_delete(p_dvbpsi))
    goto error;
   if (handle)
    dvbpsi_delete(handle);
  return -1;
}

Example: Demuxing SDT table

The scheme used for demuxing PSI tables and subtables is very similar, but requires different APIs. With the new API (version 2 and up), the code looks the same as with the example above. The first code segment shows the old way of doing things. The second shows you how to write it with dvbpsi_decoder_chain_XXX() functions.

static void NewSubtable(dvbpsi_t *p_dvbpsi, uint8_t i_table_id, uint16_t i_extension,
  void * p_zero)
{
  if (i_table_id == 0x42)
  {
    if (!dvbpsi_sdt_attach(p_dvbpsi, i_table_id, i_extension, DumpSDT, NULL))
      fprintf(stderr, "Failed to attach SDT subdecoder\n");
  }
}

int main(int i_argc, char* pa_argv[])
{
  int i_fd;
  int ret = 1;
  uint8_t data[188];
  dvbpsi_t *p_dvbpsi;
  bool b_ok;

  if(i_argc != 2)
    return 1;

  i_fd = open(pa_argv[1], 0);
  if (i_fd < 0)
    return 1;

  p_dvbpsi = dvbpsi_new(&message, DVBPSI_MSG_DEBUG);
  if (p_dvbpsi == NULL)
    goto out;

  if (!dvbpsi_AttachDemux(p_dvbpsi, NewSubtable, NULL))
    goto out;

  b_ok = ReadPacket(i_fd, data);

  while(b_ok)
  {
    uint16_t i_pid = ((uint16_t)(data[1] & 0x1f) << 8) + data[2];
    if(i_pid == 0x11)
      dvbpsi_packet_push(p_dvbpsi, data);
    b_ok = ReadPacket(i_fd, data);
  }

  ret = 0;

out:
  if (p_dvbpsi)
  {
    dvbpsi_DetachDemux(p_dvbpsi);
    dvbpsi_delete(p_dvbpsi);
  }
  close(i_fd);
  return ret;
}

Using v2 libdvbpsi demuxing API the above code translates in:

static void NewSubtable(dvbpsi_t *p_dvbpsi, uint8_t i_table_id, uint16_t i_extension,
  void * p_zero)
{
  if(i_table_id == 0x42)
  {
    if (!dvbpsi_sdt_attach(p_dvbpsi, i_table_id, i_extension, DumpSDT, NULL))
      fprintf(stderr, "Failed to attach SDT subdecoder\n");
  }
}

static void DelSubtable(dvbpsi_t <em>p_dvbpsi, uint8_t i_table_id, uint16_t i_extension)
{
  if(i_table_id == 0x42)
  {
    dvbpsi_sdt_detach(p_dvbpsi, i_table_id, i_extension);
  }
}

int main(int i_argc, char pa_argv[])
{
  int i_fd;
  int ret = 1;
  uint8_t data[188];
  dvbpsi_t *p_dvbpsi;
  bool b_ok;

  if(i_argc != 2)
    return 1;

  i_fd = open(pa_argv[1], 0);
  if (i_fd < 0)
    return 1;

  p_dvbpsi = dvbpsi_new(&message, DVBPSI_MSG_DEBUG);
  if (p_dvbpsi == NULL)
    goto out;

  if (!dvbpsi_decoder_chain_new(p_dvbpsi, NewSubtable, DelSubtable, NULL))
    goto out;

  b_ok = ReadPacket(i_fd, data);

  while(b_ok)
  {
    uint16_t i_pid = ((uint16_t)(data[1] & 0x1f) << 8) + data[2];
    if(i_pid == 0x11)
      dvbpsi_packet_push(p_dvbpsi, data);
    b_ok = ReadPacket(i_fd, data);
  }

  ret = 0;

out:
  if (p_dvbpsi)
  {
    if (!dvbpsi_decoder_chain_delete(p_dvbpsi))
      ret = 1;
    dvbpsi_delete(p_dvbpsi);
  }
  close(i_fd);
  return ret;
}