demux: Push STREAM_START event when needed
[platform/upstream/gstreamer.git] / gst / flv / gstflvdemux.c
index 4c108a6..3913602 100644 (file)
@@ -105,13 +105,15 @@ static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent,
 static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
     GstEvent * event);
 
+static GstIndex *gst_flv_demux_get_index (GstElement * element);
 
 static void
 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
     guint64 pos, gboolean keyframe)
 {
-  static GstIndexAssociation associations[2];
-  static GstIndexEntry *entry;
+  GstIndexAssociation associations[2];
+  GstIndex *index;
+  GstIndexEntry *entry;
 
   GST_LOG_OBJECT (demux,
       "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
@@ -121,8 +123,13 @@ gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
   if (!demux->upstream_seekable)
     return;
 
+  index = gst_flv_demux_get_index (GST_ELEMENT (demux));
+
+  if (!index)
+    return;
+
   /* entry may already have been added before, avoid adding indefinitely */
-  entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
+  entry = gst_index_get_assoc_entry (index, demux->index_id,
       GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
 
   if (entry) {
@@ -138,6 +145,7 @@ gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
     if (time != ts || key != ! !keyframe)
       GST_DEBUG_OBJECT (demux, "metadata mismatch");
 #endif
+    gst_object_unref (index);
     return;
   }
 
@@ -146,7 +154,7 @@ gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
   associations[1].format = GST_FORMAT_BYTES;
   associations[1].value = pos;
 
-  gst_index_add_associationv (demux->index, demux->index_id,
+  gst_index_add_associationv (index, demux->index_id,
       (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
       GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
       (const GstIndexAssociation *) &associations);
@@ -155,6 +163,8 @@ gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
     demux->index_max_pos = pos;
   if (ts > demux->index_max_time)
     demux->index_max_time = ts;
+
+  gst_object_unref (index);
 }
 
 static gchar *
@@ -534,7 +544,7 @@ gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
   gst_buffer_map (buffer, &map, GST_MAP_READ);
   gst_byte_reader_init (&reader, map.data, map.size);
 
-  gst_byte_reader_skip (&reader, 7);
+  gst_byte_reader_skip_unchecked (&reader, 7);
 
   GST_LOG_OBJECT (demux, "parsing a script tag");
 
@@ -601,7 +611,7 @@ gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
 
     g_free (function_name);
 
-    if (demux->index && demux->times && demux->filepositions) {
+    if (demux->times && demux->filepositions) {
       guint num;
 
       /* If an index was found, insert associations */
@@ -722,6 +732,7 @@ gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
         demux->audio_codec_data, NULL);
   }
 
+  gst_pad_push_event (demux->audio_pad, gst_event_new_stream_start ());
   ret = gst_pad_set_caps (demux->audio_pad, caps);
 
   if (G_LIKELY (ret)) {
@@ -786,7 +797,8 @@ gst_flv_demux_push_tags (GstFlvDemux * demux)
   if (demux->taglist) {
     GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
         demux->taglist);
-    gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
+    gst_flv_demux_push_src_event (demux, gst_event_new_tag ("GstDemuxer",
+            demux->taglist));
     demux->taglist = gst_tag_list_new_empty ();
     demux->push_tags = FALSE;
   }
@@ -1020,7 +1032,7 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
 
   /* Only add audio frames to the index if we have no video,
    * and if the index is not yet complete */
-  if (!demux->has_video && demux->index && !demux->indexed) {
+  if (!demux->has_video && !demux->indexed) {
     gst_flv_demux_parse_and_add_index_entry (demux,
         GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
   }
@@ -1167,6 +1179,7 @@ gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
         demux->video_codec_data, NULL);
   }
 
+  gst_pad_push_event (demux->video_pad, gst_event_new_stream_start ());
   ret = gst_pad_set_caps (demux->video_pad, caps);
 
   if (G_LIKELY (ret)) {
@@ -1399,7 +1412,7 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
   if (!keyframe)
     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
 
-  if (!demux->indexed && demux->index) {
+  if (!demux->indexed) {
     gst_flv_demux_parse_and_add_index_entry (demux,
         GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
   }
@@ -1550,7 +1563,7 @@ gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
   ret = pts * GST_MSECOND;
   GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
 
-  if (index && demux->index && !demux->indexed && (type == 9 || (type == 8
+  if (index && !demux->indexed && (type == 9 || (type == 8
               && !demux->has_video))) {
     gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
         keyframe);
@@ -2080,6 +2093,7 @@ gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
   demux->offset += FLV_TAG_TYPE_SIZE;
 
   /* Pull the whole tag */
+  buffer = NULL;
   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
                   demux->tag_size, &buffer)) != GST_FLOW_OK))
     goto beach;
@@ -2178,6 +2192,7 @@ static GstFlowReturn
 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
 {
   GstFlowReturn ret = GST_FLOW_EOS;
+  GstIndex *index;
   GstIndexEntry *entry = NULL;
 
   GST_DEBUG_OBJECT (demux,
@@ -2196,28 +2211,34 @@ gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
 
   GST_DEBUG_OBJECT (demux, "locating previous position");
 
+  index = gst_flv_demux_get_index (GST_ELEMENT (demux));
+
   /* locate index entry before previous start position */
-  if (demux->index)
-    entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
+  if (index) {
+    entry = gst_index_get_assoc_entry (index, demux->index_id,
         GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
         GST_FORMAT_BYTES, demux->from_offset - 1);
 
-  if (entry) {
-    gint64 bytes = 0, time = 0;
+    if (entry) {
+      gint64 bytes = 0, time = 0;
 
-    gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
-    gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
+      gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
+      gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
 
-    GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
-        " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
-        demux->offset - 1, GST_TIME_ARGS (time), bytes);
+      GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
+          " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
+          demux->offset - 1, GST_TIME_ARGS (time), bytes);
 
-    /* setup for next section */
-    demux->to_offset = demux->from_offset;
-    gst_flv_demux_move_to_offset (demux, bytes, FALSE);
-    ret = GST_FLOW_OK;
+      /* setup for next section */
+      demux->to_offset = demux->from_offset;
+      gst_flv_demux_move_to_offset (demux, bytes, FALSE);
+      ret = GST_FLOW_OK;
+    }
+
+    gst_object_unref (index);
   }
 
+
 done:
   return ret;
 }
@@ -2241,12 +2262,14 @@ gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
   old_offset = demux->offset;
   demux->offset = pos;
 
+  buffer = NULL;
   while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
               12, &buffer)) == GST_FLOW_OK) {
     tag_time =
         gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
 
     gst_buffer_unref (buffer);
+    buffer = NULL;
 
     if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
       goto exit;
@@ -2437,12 +2460,17 @@ pause:
           gst_element_post_message (GST_ELEMENT_CAST (demux),
               gst_message_new_segment_done (GST_OBJECT_CAST (demux),
                   GST_FORMAT_TIME, stop));
+          gst_flv_demux_push_src_event (demux,
+              gst_event_new_segment_done (GST_FORMAT_TIME, stop));
         } else {                /* Reverse playback */
           GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
               "segment");
           gst_element_post_message (GST_ELEMENT_CAST (demux),
               gst_message_new_segment_done (GST_OBJECT_CAST (demux),
                   GST_FORMAT_TIME, demux->segment.start));
+          gst_flv_demux_push_src_event (demux,
+              gst_event_new_segment_done (GST_FORMAT_TIME,
+                  demux->segment.start));
         }
       } else {
         /* normal playback, send EOS to all linked pads */
@@ -2452,7 +2480,10 @@ pause:
         }
 
         GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
-        if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
+        if (!demux->audio_pad && !demux->video_pad)
+          GST_ELEMENT_ERROR (demux, STREAM, FAILED,
+              ("Internal data stream error."), ("Got EOS before any data"));
+        else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
           GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
       }
     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
@@ -2471,15 +2502,18 @@ gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
 {
   gint64 bytes = 0;
   gint64 time = 0;
+  GstIndex *index;
   GstIndexEntry *entry;
 
   g_return_val_if_fail (segment != NULL, 0);
 
   time = segment->position;
 
-  if (demux->index) {
+  index = gst_flv_demux_get_index (GST_ELEMENT (demux));
+
+  if (index) {
     /* Let's check if we have an index entry for that seek time */
-    entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
+    entry = gst_index_get_assoc_entry (index, demux->index_id,
         GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
         GST_FORMAT_TIME, time);
 
@@ -2503,6 +2537,8 @@ gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
       GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
           GST_TIME_ARGS (segment->start));
     }
+
+    gst_object_unref (index);
   }
 
   return bytes;
@@ -2799,7 +2835,7 @@ exit:
     gst_pad_pause_task (demux->sinkpad);
   } else {
     gst_pad_start_task (demux->sinkpad,
-        (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
+        (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
   }
 
   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
@@ -2864,7 +2900,7 @@ gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
       if (active) {
         demux->random_access = TRUE;
         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
-            sinkpad);
+            sinkpad, NULL);
       } else {
         demux->random_access = FALSE;
         res = gst_pad_stop_task (sinkpad);
@@ -2899,20 +2935,34 @@ gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
       ret = gst_flv_demux_push_src_event (demux, event);
       break;
     case GST_EVENT_EOS:
+    {
+      GstIndex *index;
+
       GST_DEBUG_OBJECT (demux, "received EOS");
-      if (demux->index) {
+
+      index = gst_flv_demux_get_index (GST_ELEMENT (demux));
+
+      if (index) {
         GST_DEBUG_OBJECT (demux, "committing index");
-        gst_index_commit (demux->index, demux->index_id);
-      }
-      if (!demux->no_more_pads) {
-        gst_element_no_more_pads (GST_ELEMENT (demux));
-        demux->no_more_pads = TRUE;
+        gst_index_commit (index, demux->index_id);
+        gst_object_unref (index);
       }
 
-      if (!gst_flv_demux_push_src_event (demux, event))
-        GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
+      if (!demux->audio_pad && !demux->video_pad)
+        GST_ELEMENT_ERROR (demux, STREAM, FAILED,
+            ("Internal data stream error."), ("Got EOS before any data"));
+      else {
+        if (!demux->no_more_pads) {
+          gst_element_no_more_pads (GST_ELEMENT (demux));
+          demux->no_more_pads = TRUE;
+        }
+
+        if (!gst_flv_demux_push_src_event (demux, event))
+          GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
+      }
       ret = TRUE;
       break;
+    }
     case GST_EVENT_SEGMENT:
     {
       GstSegment in_segment;
@@ -3041,6 +3091,7 @@ gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
         }
       }
       res = TRUE;
+      /* FIXME, check index this way is not thread safe */
       if (fmt != GST_FORMAT_TIME || !demux->index) {
         gst_query_set_seeking (query, fmt, FALSE, -1, -1);
       } else if (demux->random_access) {
@@ -3127,23 +3178,34 @@ static void
 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
 {
   GstFlvDemux *demux = GST_FLV_DEMUX (element);
+  GstIndex *old_index;
 
   GST_OBJECT_LOCK (demux);
-  if (demux->index)
-    gst_object_unref (demux->index);
+
+  old_index = demux->index;
+
   if (index) {
     demux->index = gst_object_ref (index);
     demux->own_index = FALSE;
   } else
     demux->index = NULL;
 
+  if (old_index)
+    gst_object_unref (demux->index);
+
+  gst_object_ref (index);
+
   GST_OBJECT_UNLOCK (demux);
+
   /* object lock might be taken again */
   if (index)
     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
+
   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
 
+  gst_object_unref (index);
 }
+#endif
 
 static GstIndex *
 gst_flv_demux_get_index (GstElement * element)
@@ -3159,7 +3221,6 @@ gst_flv_demux_get_index (GstElement * element)
 
   return result;
 }
-#endif
 
 static void
 gst_flv_demux_dispose (GObject * object)
@@ -3244,7 +3305,7 @@ gst_flv_demux_class_init (GstFlvDemuxClass * klass)
       gst_static_pad_template_get (&audio_src_template));
   gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&video_src_template));
-  gst_element_class_set_details_simple (gstelement_class, "FLV Demuxer",
+  gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
       "Codec/Demuxer",
       "Demux FLV feeds into digital streams",
       "Julien Moutte <julien@moutte.net>");
@@ -3293,5 +3354,5 @@ plugin_init (GstPlugin * plugin)
 }
 
 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
-    "flv", "FLV muxing and demuxing plugin",
+    flv, "FLV muxing and demuxing plugin",
     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)