diff --git a/gst/mpegtsdemux/gstmpegdesc.h b/gst/mpegtsdemux/gstmpegdesc.h
index c4ae91c..b137ed5 100644
--- a/gst/mpegtsdemux/gstmpegdesc.h
+++ b/gst/mpegtsdemux/gstmpegdesc.h
@@ -256,6 +256,9 @@
 #define DESC_DVB_COMPONENT_tag(desc)    (desc[4])
 #define DESC_DVB_COMPONENT_language(desc)   (desc + 5)
 
+/* DVB Content Identifier Descriptor */
+#define DESC_DVB_CONTENT_IDENTIFIER_data(desc) (desc + 2)
+
 /* DVB Bouquet Name Descriptor */
 #define DESC_DVB_BOUQUET_NAME_text(desc)    (desc + 2)
 
diff --git a/gst/mpegtsdemux/mpegtsbase.c b/gst/mpegtsdemux/mpegtsbase.c
index f3fb88f..5f1aa07 100644
--- a/gst/mpegtsdemux/mpegtsbase.c
+++ b/gst/mpegtsdemux/mpegtsbase.c
@@ -1047,6 +1047,19 @@ mpegts_base_apply_tdt (MpegTSBase * base,
           gst_structure_copy (tdt_info)));
 }
 
+static void
+mpegts_base_apply_cit (MpegTSBase * base,
+    guint16 tdt_pid, GstStructure * cit_info)
+{
+  gst_element_post_message (GST_ELEMENT_CAST (base),
+      gst_message_new_element (GST_OBJECT (base),
+          gst_structure_copy (cit_info)));
+
+  GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base,
+      gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
+          gst_structure_copy (cit_info)));
+}
+
 
 gboolean
 mpegts_base_handle_psi (MpegTSBase * base, MpegTSPacketizerSection * section)
@@ -1158,6 +1171,14 @@ mpegts_base_handle_psi (MpegTSBase * base, MpegTSPacketizerSection * section)
       else
         res = FALSE;
       break;
+    case 0x77:
+      /* CIT (Content Identifier table) */
+      structure = mpegts_packetizer_parse_cit (base->packetizer, section);
+      if (G_LIKELY (structure))
+        mpegts_base_apply_cit (base, section->pid, structure);
+      else
+        res = FALSE;
+      break;
     default:
       break;
   }
diff --git a/gst/mpegtsdemux/mpegtspacketizer.c b/gst/mpegtsdemux/mpegtspacketizer.c
index 41ff6dd..dfdf237 100644
--- a/gst/mpegtsdemux/mpegtspacketizer.c
+++ b/gst/mpegtsdemux/mpegtspacketizer.c
@@ -77,6 +77,8 @@ static GQuark QUARK_EVENTS;
 #define MPEGTS_PACKETIZER_GET_PRIVATE(obj)  \
    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_MPEGTS_PACKETIZER, MpegTSPacketizerPrivate))
 
+static GQuark QUARK_CIT;
+
 static void _init_local (void);
 G_DEFINE_TYPE_EXTENDED (MpegTSPacketizer2, mpegts_packetizer, G_TYPE_OBJECT, 0,
     _init_local ());
@@ -1740,6 +1742,7 @@ mpegts_packetizer_parse_eit (MpegTSPacketizer2 * packetizer,
 
     if (descriptors_loop_length) {
       guint8 *event_descriptor;
+      guint8 *content_identifier_descriptor;
       GArray *component_descriptors;
       GArray *extended_event_descriptors;
       GstMPEGDescriptor *mpegdescriptor;
@@ -1780,6 +1783,77 @@ mpegts_packetizer_parse_eit (MpegTSPacketizer2 * packetizer,
           g_free (eventdescription_tmp);
         }
       }
+      content_identifier_descriptor = gst_mpeg_descriptor_find (mpegdescriptor,
+          DESC_DVB_CONTENT_IDENTIFIER);
+      if (content_identifier_descriptor != NULL) {
+        guint8 length_aux;
+        guint8 *crid_aux_ptr =
+            DESC_DVB_CONTENT_IDENTIFIER_data (content_identifier_descriptor);
+        guint8 *desc_end = crid_aux_ptr +
+            DESC_LENGTH (content_identifier_descriptor);
+        gboolean valid = TRUE;
+        GValue crid_items = { 0 };
+        GValue crid_item_value = { 0 };
+        GstStructure *crid_item;
+        g_value_init (&crid_items, GST_TYPE_LIST);
+        while (valid && crid_aux_ptr < desc_end) {
+          guint8 crid_type = (*crid_aux_ptr) >> 2;
+          guint8 crid_location = (*crid_aux_ptr) & 0x03;
+          ++crid_aux_ptr;
+          if (crid_location == 0) {
+            if (crid_aux_ptr < desc_end) {
+              length_aux = *crid_aux_ptr;
+              ++crid_aux_ptr;
+              if (crid_aux_ptr + length_aux <= desc_end) {
+                gchar *crid_byte =
+                    g_strndup ((gchar *) crid_aux_ptr, length_aux);
+                crid_aux_ptr += length_aux;
+
+                crid_item = gst_structure_new ("crid",
+                    "type", G_TYPE_UINT, crid_type,
+                    "location", G_TYPE_UINT, crid_location,
+                    "byte", G_TYPE_STRING, crid_byte, NULL);
+              } else {
+                valid = FALSE;
+                GST_DEBUG
+                    ("Found content identifier descriptor with wrong crid_length");
+              }
+            } else {
+              valid = FALSE;
+              GST_DEBUG
+                  ("Found content identifier descriptor with data size (crid_location == 0)");
+            }
+          } else if (crid_location == 1) {
+            if (crid_aux_ptr + 1 < desc_end) {
+              guint16 crid_ref = GST_READ_UINT16_BE (crid_aux_ptr);
+              crid_aux_ptr += 2;
+
+              crid_item = gst_structure_new ("crid",
+                  "type", G_TYPE_UINT, crid_type,
+                  "location", G_TYPE_UINT, crid_location,
+                  "ref", G_TYPE_UINT, crid_ref, NULL);
+            } else {
+              valid = FALSE;
+              GST_DEBUG
+                  ("Found content identifier descriptor with data size (crid_location == 0)");
+            }
+          } else {
+            valid = FALSE;
+            GST_DEBUG
+                ("Found content identifier descriptor with wrong crid_location");
+          }
+
+          if (valid) {
+            g_value_init (&crid_item_value, GST_TYPE_STRUCTURE);
+            g_value_take_boxed (&crid_item_value, crid_item);
+            gst_value_list_append_value (&crid_items, &crid_item_value);
+            g_value_unset (&crid_item_value);
+          }
+        }
+        gst_structure_set_value (event, "content-identifier-items",
+            &crid_items);
+        g_value_unset (&crid_items);
+      }
       extended_event_descriptors = gst_mpeg_descriptor_find_all (mpegdescriptor,
           DESC_DVB_EXTENDED_EVENT);
       if (extended_event_descriptors) {
@@ -2064,6 +2138,116 @@ error:
 }
 
 GstStructure *
+mpegts_packetizer_parse_cit (MpegTSPacketizer2 * packetizer,
+    MpegTSPacketizerSection * section)
+{
+  GstStructure *cit = NULL;
+  guint8 *data, *end, *prepend_strings_aux, *prepend_strings_end;
+  guint8 tmp, prepend_strings_length, prepend_string_index,
+      unique_string_length;
+  guint service_id, transport_stream_id, original_network_id, crid_ref;
+  gchar *prepend_string, *crid_byte;
+  GArray *prepend_strings;
+  GValue entries = { 0 };
+  GValue value = { 0 };
+  GstStructure *entry = NULL;
+
+  data = GST_BUFFER_DATA (section->buffer);
+  end = data + GST_BUFFER_SIZE (section->buffer);
+
+  section->table_id = *data++;
+  // Check section_syntax_indicator and private_indicator are 1
+  if ((data[0] & 0xc0) != 0xc0) {
+    goto error;
+  }
+
+  section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF;
+  data++;
+  service_id = GST_READ_UINT16_BE (data);
+  data += 2;
+
+  tmp = *data++;
+  section->version_number = (tmp >> 1) & 0x1F;
+  section->current_next_indicator = tmp & 0x01;
+
+  /* skip section_number and last_section_number */
+  data += 2;
+
+  transport_stream_id = GST_READ_UINT16_BE (data);
+  data += 2;
+
+  original_network_id = GST_READ_UINT16_BE (data);
+  data += 2;
+
+  prepend_strings = g_array_new (FALSE, FALSE, sizeof (gchar *));
+  prepend_strings_length = *data++;
+  prepend_strings_aux = data;
+  prepend_strings_end = data + prepend_strings_length;
+  while (prepend_strings_aux < prepend_strings_end) {
+    while (prepend_strings_aux < prepend_strings_end
+        && *prepend_strings_aux != 0x0) {
+      prepend_strings_aux++;
+    }
+    prepend_string = g_strndup ((gchar *) data, prepend_strings_aux - data);
+    g_array_append_val (prepend_strings, prepend_string);
+    if (prepend_strings_aux < prepend_strings_end && prepend_strings_aux == 0x0) {
+      prepend_strings_aux++;
+    }
+    data = prepend_strings_aux;
+  }
+
+  cit = gst_structure_id_new (QUARK_CIT,
+      QUARK_SERVICE_ID, G_TYPE_UINT, service_id,
+      QUARK_TRANSPORT_STREAM_ID, G_TYPE_UINT, transport_stream_id,
+      QUARK_ORIGINAL_NETWORK_ID, G_TYPE_UINT, original_network_id, NULL);
+
+  g_value_init (&entries, GST_TYPE_LIST);
+
+  /* stop at the CRC */
+  while (data < end - 4) {
+    crid_ref = GST_READ_UINT16_BE (data);
+    data += 2;
+
+    prepend_string_index = *data++;
+    unique_string_length = *data++;
+    crid_byte = g_strndup ((gchar *) data, unique_string_length);
+    data += unique_string_length;
+    if (prepend_string_index != 0xFF) {
+      gchar *old_crid_byte = crid_byte;
+      prepend_string =
+          g_array_index (prepend_strings, gchar *, prepend_string_index);
+      crid_byte = g_strconcat (crid_byte, prepend_string, NULL);
+      g_free (old_crid_byte);
+    }
+
+    entry = gst_structure_new ("entry", "ref", G_TYPE_UINT, crid_ref,
+        "string", G_TYPE_UINT, crid_byte, NULL);
+    g_value_init (&value, GST_TYPE_STRUCTURE);
+    g_value_take_boxed (&value, entry);
+    gst_value_list_append_value (&entries, &value);
+    g_value_unset (&value);
+
+  }
+
+  gst_structure_set_value (cit, "entries", &entries);
+  g_value_unset (&entries);
+
+  if (data != end - 4) {
+    /* FIXME: check the CRC before parsing the packet */
+    GST_ERROR ("at the end of CIT data != end - 4");
+    goto error;
+  }
+
+  return cit;
+
+error:
+  if (cit)
+    gst_structure_free (cit);
+
+  return NULL;
+}
+
+GstStructure *
 mpegts_packetizer_parse_tdt (MpegTSPacketizer2 * packetizer,
     MpegTSPacketizerSection * section)
 {
@@ -2568,6 +2752,8 @@ _init_local (void)
       g_quark_from_string ("segment-last-section-number");
   QUARK_LAST_TABLE_ID = g_quark_from_string ("last-table-id");
   QUARK_EVENTS = g_quark_from_string ("events");
+
+  QUARK_CIT = g_quark_from_string ("cit");
 }
 
 /**
diff --git a/gst/mpegtsdemux/mpegtspacketizer.h b/gst/mpegtsdemux/mpegtspacketizer.h
index 418da08..12220ad 100644
--- a/gst/mpegtsdemux/mpegtspacketizer.h
+++ b/gst/mpegtsdemux/mpegtspacketizer.h
@@ -194,6 +194,8 @@ GstStructure *mpegts_packetizer_parse_eit (MpegTSPacketizer2 *packetizer,
   MpegTSPacketizerSection *section);
 GstStructure *mpegts_packetizer_parse_tdt (MpegTSPacketizer2 *packetizer,
   MpegTSPacketizerSection *section);
+GstStructure *mpegts_packetizer_parse_cit (MpegTSPacketizer2 *packetizer,
+  MpegTSPacketizerSection *section);
 
 /* Only valid if calculate_offset is TRUE */
 guint mpegts_packetizer_get_seen_pcr (MpegTSPacketizer2 *packetizer);
