Bump GLib requirement to >= 2.62
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst / mpegtsdemux / mpegtsbase.c
index cc567f0..01bc68e 100644 (file)
@@ -37,7 +37,7 @@
 
 #include <glib.h>
 
-#include <gst/gst-i18n-plugin.h>
+#include <glib/gi18n-lib.h>
 #include "mpegtsbase.h"
 #include "gstmpegdesc.h"
 
@@ -96,7 +96,7 @@ static gboolean mpegts_base_get_tags_from_eit (MpegTSBase * base,
     GstMpegtsSection * section);
 static gboolean mpegts_base_parse_atsc_mgt (MpegTSBase * base,
     GstMpegtsSection * section);
-static gboolean remove_each_program (gpointer key, MpegTSBaseProgram * program,
+static void remove_each_program (MpegTSBaseProgram * program,
     MpegTSBase * base);
 
 static void
@@ -162,6 +162,7 @@ mpegts_base_class_init (MpegTSBaseClass * klass)
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   klass->sink_query = GST_DEBUG_FUNCPTR (mpegts_base_default_sink_query);
+  klass->handle_psi = NULL;
 
   gst_type_mark_as_plugin_api (GST_TYPE_MPEGTS_BASE, 0);
 }
@@ -240,14 +241,16 @@ mpegts_base_reset (MpegTSBase * base)
   base->seen_pat = FALSE;
   base->seek_offset = -1;
 
-  g_hash_table_foreach_remove (base->programs, (GHRFunc) remove_each_program,
-      base);
+  g_ptr_array_foreach (base->programs, (GFunc) remove_each_program, base);
+  g_ptr_array_remove_range (base->programs, 0, base->programs->len);
 
   base->streams_aware = GST_OBJECT_PARENT (base)
       && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (base),
       GST_BIN_FLAG_STREAMS_AWARE);
   GST_DEBUG_OBJECT (base, "Streams aware : %d", base->streams_aware);
 
+  gst_event_replace (&base->seek_event, NULL);
+
   if (klass->reset)
     klass->reset (base);
 }
@@ -266,8 +269,8 @@ mpegts_base_init (MpegTSBase * base)
 
   base->disposed = FALSE;
   base->packetizer = mpegts_packetizer_new ();
-  base->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
-      NULL, (GDestroyNotify) mpegts_base_free_program);
+  base->programs =
+      g_ptr_array_new_full (16, (GDestroyNotify) mpegts_base_free_program);
 
   base->parse_private_sections = FALSE;
   base->is_pes = g_new0 (guint8, 1024);
@@ -307,7 +310,9 @@ mpegts_base_finalize (GObject * object)
     g_ptr_array_unref (base->pat);
     base->pat = NULL;
   }
-  g_hash_table_destroy (base->programs);
+  g_ptr_array_free (base->programs, TRUE);
+
+  gst_event_replace (&base->seek_event, NULL);
 
   if (G_OBJECT_CLASS (parent_class)->finalize)
     G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -349,8 +354,7 @@ typedef struct
 } PIDLookup;
 
 static void
-foreach_pid_in_program (gpointer key, MpegTSBaseProgram * program,
-    PIDLookup * lookup)
+foreach_pid_in_program (MpegTSBaseProgram * program, PIDLookup * lookup)
 {
   if (!program->active)
     return;
@@ -365,8 +369,7 @@ mpegts_pid_in_active_programs (MpegTSBase * base, guint16 pid)
 
   lookup.res = FALSE;
   lookup.pid = pid;
-  g_hash_table_foreach (base->programs, (GHFunc) foreach_pid_in_program,
-      &lookup);
+  g_ptr_array_foreach (base->programs, (GFunc) foreach_pid_in_program, &lookup);
 
   return lookup.res;
 }
@@ -429,7 +432,7 @@ mpegts_base_new_program (MpegTSBase * base,
   MpegTSBaseProgram *program;
   gchar *upstream_id, *stream_id;
 
-  GST_DEBUG_OBJECT (base, "program_number : %d, pmt_pid : %d",
+  GST_DEBUG_OBJECT (base, "program_number : %d, pmt_pid : 0x%04x",
       program_number, pmt_pid);
 
   program = g_malloc0 (base->program_size);
@@ -454,7 +457,7 @@ mpegts_base_add_program (MpegTSBase * base,
 {
   MpegTSBaseProgram *program;
 
-  GST_DEBUG_OBJECT (base, "program_number : %d, pmt_pid : %d",
+  GST_DEBUG_OBJECT (base, "program_number : %d, pmt_pid : 0x%04x",
       program_number, pmt_pid);
 
   program = mpegts_base_new_program (base, program_number, pmt_pid);
@@ -466,8 +469,14 @@ mpegts_base_add_program (MpegTSBase * base,
   }
   MPEGTS_BIT_SET (base->known_psi, pmt_pid);
 
-  g_hash_table_insert (base->programs,
-      GINT_TO_POINTER (program_number), program);
+  /* Ensure the PMT PID was not used by some PES stream */
+  if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->is_pes, pmt_pid))) {
+    GST_DEBUG ("New program PMT PID was previously used by a PES stream");
+    MPEGTS_BIT_UNSET (base->is_pes, pmt_pid);
+  }
+
+
+  g_ptr_array_add (base->programs, program);
 
   return program;
 }
@@ -475,27 +484,29 @@ mpegts_base_add_program (MpegTSBase * base,
 MpegTSBaseProgram *
 mpegts_base_get_program (MpegTSBase * base, gint program_number)
 {
-  MpegTSBaseProgram *program;
-
-  program = (MpegTSBaseProgram *) g_hash_table_lookup (base->programs,
-      GINT_TO_POINTER ((gint) program_number));
+  guint i;
 
-  return program;
+  for (i = 0; i < base->programs->len; i++) {
+    MpegTSBaseProgram *program = g_ptr_array_index (base->programs, i);
+    if (program->program_number == program_number)
+      return program;
+  }
+  return NULL;
 }
 
 static MpegTSBaseProgram *
 mpegts_base_steal_program (MpegTSBase * base, gint program_number)
 {
-  MpegTSBaseProgram *program;
-
-  program = (MpegTSBaseProgram *) g_hash_table_lookup (base->programs,
-      GINT_TO_POINTER ((gint) program_number));
+  guint i;
 
-  if (program)
-    g_hash_table_steal (base->programs,
-        GINT_TO_POINTER ((gint) program_number));
+  for (i = 0; i < base->programs->len; i++) {
+    MpegTSBaseProgram *program = g_ptr_array_index (base->programs, i);
+    if (program->program_number == program_number) {
+      return g_ptr_array_steal_index (base->programs, i);
+    }
+  }
 
-  return program;
+  return NULL;
 }
 
 static void
@@ -513,6 +524,11 @@ mpegts_base_free_program (MpegTSBaseProgram * program)
 {
   GList *tmp;
 
+  if (program->recycle) {
+    program->recycle = FALSE;
+    return;
+  }
+
   if (program->pmt) {
     gst_mpegts_section_unref (program->section);
     program->pmt = NULL;
@@ -546,11 +562,11 @@ mpegts_base_deactivate_and_free_program (MpegTSBase * base,
 }
 
 static void
-mpegts_base_remove_program (MpegTSBase * base, gint program_number)
+mpegts_base_remove_program (MpegTSBase * base, MpegTSBaseProgram * program)
 {
-  GST_DEBUG_OBJECT (base, "program_number : %d", program_number);
+  GST_DEBUG_OBJECT (base, "program_number : %d", program->program_number);
 
-  g_hash_table_remove (base->programs, GINT_TO_POINTER (program_number));
+  g_ptr_array_remove (base->programs, program);
 }
 
 static guint32
@@ -570,6 +586,28 @@ get_registration_from_descriptors (GPtrArray * descriptors)
   return 0;
 }
 
+static gboolean
+find_registration_in_descriptors (GPtrArray * descriptors,
+    guint32 registration_id)
+{
+
+  guint i, nb_desc;
+
+  if (!descriptors)
+    return FALSE;
+
+  nb_desc = descriptors->len;
+  for (i = 0; i < nb_desc; i++) {
+    GstMpegtsDescriptor *desc = g_ptr_array_index (descriptors, i);
+    if (desc->tag == GST_MTS_DESC_REGISTRATION) {
+      guint32 reg_desc = GST_READ_UINT32_BE (desc->data + 2);
+      if (reg_desc == registration_id)
+        return TRUE;
+    }
+  }
+  return FALSE;
+}
+
 static MpegTSBaseStream *
 mpegts_base_program_add_stream (MpegTSBase * base,
     MpegTSBaseProgram * program, guint16 pid, guint8 stream_type,
@@ -758,10 +796,8 @@ _stream_is_private_section (const GstMpegtsPMT * pmt,
       return TRUE;
     case GST_MPEGTS_STREAM_TYPE_SCTE_SIT:
     {
-      guint32 registration_id =
-          get_registration_from_descriptors (pmt->descriptors);
       /* Not a private section stream */
-      if (registration_id != DRF_ID_CUEI)
+      if (!find_registration_in_descriptors (pmt->descriptors, DRF_ID_CUEI))
         return FALSE;
       return TRUE;
     }
@@ -1029,10 +1065,21 @@ mpegts_base_apply_pat (MpegTSBase * base, GstMpegtsSection * section)
   for (i = 0; i < pat->len; ++i) {
     GstMpegtsPatProgram *patp = g_ptr_array_index (pat, i);
 
+    GST_LOG ("Looking for program %d / 0x%04x", patp->program_number,
+        patp->network_or_program_map_PID);
     program = mpegts_base_get_program (base, patp->program_number);
     if (program) {
-      /* IF the program already existed, just check if the PMT PID changed */
-      if (program->pmt_pid != patp->network_or_program_map_PID) {
+      GST_LOG ("Program exists on pid 0x%04x", program->pmt_pid);
+      /* If the new PMT PID clashes with an existing known PES stream, we know
+       * it is not an update */
+      if (MPEGTS_BIT_IS_SET (base->is_pes, patp->network_or_program_map_PID)) {
+        GST_LOG ("Program is not an update");
+        program =
+            mpegts_base_add_program (base, patp->program_number,
+            patp->network_or_program_map_PID);
+      } else if (program->pmt_pid != patp->network_or_program_map_PID) {
+        /* IF the program already existed, just check if the PMT PID changed */
+        GST_LOG ("PMT is on a different PID");
         if (program->pmt_pid != G_MAXUINT16) {
           /* pmt pid changed */
           /* FIXME: when this happens it may still be pmt pid of another
@@ -1047,6 +1094,8 @@ mpegts_base_apply_pat (MpegTSBase * base, GstMpegtsSection * section)
               ("Refcounting issue. Setting twice a PMT PID (0x%04x) as know PSI",
               program->pmt_pid);
         MPEGTS_BIT_SET (base->known_psi, patp->network_or_program_map_PID);
+      } else {
+        GST_LOG ("Regular program update");
       }
     } else {
       /* Create a new program */
@@ -1073,21 +1122,25 @@ mpegts_base_apply_pat (MpegTSBase * base, GstMpegtsSection * section)
         continue;
       }
 
-      if (--program->patcount > 0)
+      GST_LOG ("Deactivating program %d / 0x%04x", patp->program_number,
+          patp->network_or_program_map_PID);
+
+      if (--program->patcount > 0) {
+        GST_LOG ("Referenced by new program, keeping");
         /* the program has been referenced by the new pat, keep it */
         continue;
+      }
 
       GST_INFO_OBJECT (base, "PAT removing program 0x%04x 0x%04x",
           patp->program_number, patp->network_or_program_map_PID);
 
       if (klass->can_remove_program (base, program)) {
         mpegts_base_deactivate_program (base, program);
-        mpegts_base_remove_program (base, patp->program_number);
+        mpegts_base_remove_program (base, program);
       } else {
         /* sub-class now owns the program and must call
          * mpegts_base_deactivate_and_free_program later */
-        g_hash_table_steal (base->programs,
-            GINT_TO_POINTER ((gint) patp->program_number));
+        mpegts_base_steal_program (base, patp->program_number);
       }
       /* FIXME: when this happens it may still be pmt pid of another
        * program, so setting to False may make it go through expensive
@@ -1131,6 +1184,12 @@ mpegts_base_apply_pmt (MpegTSBase * base, GstMpegtsSection * section)
     return TRUE;
   }
 
+  /* Don't attempt to handle pmt without any streams */
+  if (G_UNLIKELY (pmt->streams->len == 0)) {
+    GST_WARNING ("Skipping PMT without any entries");
+    return TRUE;
+  }
+
   program_number = section->subtable_extension;
   GST_DEBUG ("Applying PMT (program_number:%d, pid:0x%04x)",
       program_number, section->pid);
@@ -1172,12 +1231,10 @@ mpegts_base_apply_pmt (MpegTSBase * base, GstMpegtsSection * section)
     } else {
       /* sub-class now owns the program and must call
        * mpegts_base_deactivate_and_free_program later */
-      g_hash_table_steal (base->programs,
-          GINT_TO_POINTER ((gint) old_program->program_number));
+      mpegts_base_steal_program (base, old_program->program_number);
     }
     /* Add new program to the programs we track */
-    g_hash_table_insert (base->programs,
-        GINT_TO_POINTER (program_number), program);
+    g_ptr_array_add (base->programs, program);
     initial_program = FALSE;
   } else {
     GST_DEBUG ("Program update, re-using same program");
@@ -1238,6 +1295,10 @@ mpegts_base_handle_psi (MpegTSBase * base, GstMpegtsSection * section)
       break;
   }
 
+  /* Give the subclass a chance to look at the section */
+  if (GST_MPEGTS_BASE_GET_CLASS (base)->handle_psi)
+    GST_MPEGTS_BASE_GET_CLASS (base)->handle_psi (base, section);
+
   /* Finally post message (if it wasn't corrupted) */
   if (post_message)
     gst_element_post_message (GST_ELEMENT_CAST (base),
@@ -1333,14 +1394,11 @@ mpegts_base_get_tags_from_eit (MpegTSBase * base, GstMpegtsSection * section)
   return TRUE;
 }
 
-static gboolean
-remove_each_program (gpointer key, MpegTSBaseProgram * program,
-    MpegTSBase * base)
+static void
+remove_each_program (MpegTSBaseProgram * program, MpegTSBase * base)
 {
   /* First deactivate it */
   mpegts_base_deactivate_program (base, program);
-
-  return TRUE;
 }
 
 static inline GstFlowReturn