Пример #1
0
static gboolean
vorbis_dec_src_event (GstPad * pad, GstEvent * event)
{
  gboolean res = TRUE;
  GstVorbisDec *dec;

  dec = GST_VORBIS_DEC (gst_pad_get_parent (pad));
  if (G_UNLIKELY (dec == NULL)) {
    gst_event_unref (event);
    return FALSE;
  }

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
    {
      GstFormat format, tformat;
      gdouble rate;
      GstEvent *real_seek;
      GstSeekFlags flags;
      GstSeekType cur_type, stop_type;
      gint64 cur, stop;
      gint64 tcur, tstop;
      guint32 seqnum;

      gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
          &stop_type, &stop);
      seqnum = gst_event_get_seqnum (event);
      gst_event_unref (event);

      /* First bring the requested format to time */
      tformat = GST_FORMAT_TIME;
      if (!(res = vorbis_dec_convert (pad, format, cur, &tformat, &tcur)))
        goto convert_error;
      if (!(res = vorbis_dec_convert (pad, format, stop, &tformat, &tstop)))
        goto convert_error;

      /* then seek with time on the peer */
      real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
          flags, cur_type, tcur, stop_type, tstop);
      gst_event_set_seqnum (real_seek, seqnum);

      res = gst_pad_push_event (dec->sinkpad, real_seek);
      break;
    }
    default:
      res = gst_pad_push_event (dec->sinkpad, event);
      break;
  }
done:
  gst_object_unref (dec);

  return res;

  /* ERRORS */
convert_error:
  {
    GST_DEBUG_OBJECT (dec, "cannot convert start/stop for seek");
    goto done;
  }
}
static gboolean
seek_mode_testing (InsanityTest * test)
{
  gboolean res;
  GstEvent *event;
  GstSeekFlags flags = GST_SEEK_FLAG_FLUSH;
  GstSeekType stop_type = GST_SEEK_TYPE_NONE;

  /* Reset global seek props */
  glob_seek_first_buf_ts = GST_CLOCK_TIME_NONE;
  glob_seek_stop_ts = GST_CLOCK_TIME_NONE;
  glob_seek_segment_seektime = 0;

  /* Set seeking arguments */
  switch (glob_in_progress) {
    case TEST_BACKWARD_PLAYBACK:
      glob_seek_rate = -1;
      glob_seek_stop_ts = glob_duration;
      stop_type = GST_SEEK_TYPE_SET;
      break;
    case TEST_FAST_FORWARD:
      glob_seek_rate = 2;
      glob_seek_stop_ts = glob_duration / 2;
      break;
    case TEST_FAST_BACKWARD:
      glob_seek_rate = -2;
      glob_seek_stop_ts = glob_duration;
      stop_type = GST_SEEK_TYPE_SET;
      break;
    default:
      return FALSE;
  }

  glob_seek_got_segment = FALSE;
  event = gst_event_new_seek (glob_seek_rate, GST_FORMAT_TIME,
      flags, GST_SEEK_TYPE_SET, glob_seek_segment_seektime,
      stop_type, glob_seek_stop_ts);

  /* We didn't find any event/message with the seqnum we previously set */
  if (glob_seqnum != 0 && glob_seqnum_found == FALSE)
    glob_wrong_seqnum = TRUE;

  glob_seqnum_found = FALSE;
  glob_seqnum = gst_util_seqnum_next ();
  gst_event_set_seqnum (event, glob_seqnum);
  res = gst_element_send_event (glob_pipeline, event);
  global_last_seek = g_get_monotonic_time ();

  if (!res) {
    validate_current_test (test, FALSE, "Could not send seek event");
    glob_seek_rate = 0;
    glob_seqnum = 0;

    /* ... Next test */
    next_test (test);
  }

  return FALSE;
}
Пример #3
0
static void
_push_eos (GstAggregator * self)
{
  GstEvent *event;
  _push_mandatory_events (self);

  self->priv->send_eos = FALSE;
  event = gst_event_new_eos ();
  gst_event_set_seqnum (event, self->priv->seqnum);
  gst_pad_push_event (self->srcpad, event);
}
Пример #4
0
static inline void
_push_mandatory_events (GstAggregator * self)
{
  GstAggregatorPrivate *priv = self->priv;

  if (g_atomic_int_get (&self->priv->send_stream_start)) {
    gchar s_id[32];

    GST_INFO_OBJECT (self, "pushing stream start");
    /* stream-start (FIXME: create id based on input ids) */
    g_snprintf (s_id, sizeof (s_id), "agg-%08x", g_random_int ());
    if (!gst_pad_push_event (self->srcpad, gst_event_new_stream_start (s_id))) {
      GST_WARNING_OBJECT (self->srcpad, "Sending stream start event failed");
    }
    g_atomic_int_set (&self->priv->send_stream_start, FALSE);
  }

  if (self->priv->srccaps) {

    GST_INFO_OBJECT (self, "pushing caps: %" GST_PTR_FORMAT,
        self->priv->srccaps);
    if (!gst_pad_push_event (self->srcpad,
            gst_event_new_caps (self->priv->srccaps))) {
      GST_WARNING_OBJECT (self->srcpad, "Sending caps event failed");
    }
    gst_caps_unref (self->priv->srccaps);
    self->priv->srccaps = NULL;
  }

  if (g_atomic_int_get (&self->priv->send_segment)) {
    if (!g_atomic_int_get (&self->priv->flush_seeking)) {
      GstEvent *segev = gst_event_new_segment (&self->segment);

      if (!self->priv->seqnum)
        self->priv->seqnum = gst_event_get_seqnum (segev);
      else
        gst_event_set_seqnum (segev, self->priv->seqnum);

      GST_DEBUG_OBJECT (self, "pushing segment %" GST_PTR_FORMAT, segev);
      gst_pad_push_event (self->srcpad, segev);
      g_atomic_int_set (&self->priv->send_segment, FALSE);
    }
  }

  if (priv->tags && priv->tags_changed) {
    gst_pad_push_event (self->srcpad,
        gst_event_new_tag (gst_tag_list_ref (priv->tags)));
    priv->tags_changed = FALSE;
  }
}
Пример #5
0
static GstEvent *
check_pending_key_unit_event (GstEvent * pending_event, GstSegment * segment,
    GstClockTime timestamp, guint flags, GstClockTime pending_key_unit_ts)
{
  GstClockTime running_time, stream_time;
  gboolean all_headers;
  guint count;
  GstEvent *event = NULL;

  g_return_val_if_fail (pending_event != NULL, NULL);
  g_return_val_if_fail (segment != NULL, NULL);

  if (pending_event == NULL)
    goto out;

  if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
      timestamp == GST_CLOCK_TIME_NONE)
    goto out;

  running_time = gst_segment_to_running_time (segment,
      GST_FORMAT_TIME, timestamp);

  GST_INFO ("now %" GST_TIME_FORMAT " wanted %" GST_TIME_FORMAT,
      GST_TIME_ARGS (running_time), GST_TIME_ARGS (pending_key_unit_ts));
  if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
      running_time < pending_key_unit_ts)
    goto out;

  if (flags & GST_BUFFER_FLAG_DELTA_UNIT) {
    GST_INFO ("pending force key unit, waiting for keyframe");
    goto out;
  }

  stream_time = gst_segment_to_stream_time (segment,
      GST_FORMAT_TIME, timestamp);

  gst_video_event_parse_upstream_force_key_unit (pending_event,
      NULL, &all_headers, &count);

  event =
      gst_video_event_new_downstream_force_key_unit (timestamp, stream_time,
      running_time, all_headers, count);
  gst_event_set_seqnum (event, gst_event_get_seqnum (pending_event));

out:
  return event;
}
/* sinkpad functions */
static gboolean
gst_stream_synchronizer_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstStreamSynchronizer *self = GST_STREAM_SYNCHRONIZER (parent);
  GstPad *opad;
  gboolean ret = FALSE;

  GST_LOG_OBJECT (pad, "Handling event %s: %" GST_PTR_FORMAT,
      GST_EVENT_TYPE_NAME (event), event);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_STREAM_START:
    {
      GstStream *stream, *ostream;
      guint32 seqnum = gst_event_get_seqnum (event);
      GList *l;
      gboolean all_wait = TRUE;
      gboolean new_stream = TRUE;

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      if (stream && stream->stream_start_seqnum != seqnum) {
        stream->is_eos = FALSE;
        stream->stream_start_seqnum = seqnum;
        stream->drop_discont = TRUE;

        /* Check if this belongs to a stream that is already there,
         * e.g. we got the visualizations for an audio stream */
        for (l = self->streams; l; l = l->next) {
          ostream = l->data;

          if (ostream != stream && ostream->stream_start_seqnum == seqnum
              && !ostream->wait) {
            new_stream = FALSE;
            break;
          }
        }

        if (!new_stream) {
          GST_DEBUG_OBJECT (pad,
              "Stream %d belongs to running stream %d, no waiting",
              stream->stream_number, ostream->stream_number);
          stream->wait = FALSE;
          stream->new_stream = FALSE;
        } else {
          GST_DEBUG_OBJECT (pad, "Stream %d changed", stream->stream_number);

          stream->wait = TRUE;
          stream->new_stream = TRUE;

          for (l = self->streams; l; l = l->next) {
            GstStream *ostream = l->data;

            all_wait = all_wait && ostream->wait;
            if (!all_wait)
              break;
          }
          if (all_wait) {
            gint64 position = 0;

            GST_DEBUG_OBJECT (self, "All streams have changed -- unblocking");

            for (l = self->streams; l; l = l->next) {
              GstStream *ostream = l->data;
              gint64 stop_running_time;
              gint64 position_running_time;

              ostream->wait = FALSE;

              if (ostream->segment.format == GST_FORMAT_TIME) {
                stop_running_time =
                    gst_segment_to_running_time (&ostream->segment,
                    GST_FORMAT_TIME, ostream->segment.stop);
                position_running_time =
                    gst_segment_to_running_time (&ostream->segment,
                    GST_FORMAT_TIME, ostream->segment.position);
                position =
                    MAX (position, MAX (stop_running_time,
                        position_running_time));
              }
            }
            position = MAX (0, position);
            self->group_start_time = MAX (self->group_start_time, position);

            GST_DEBUG_OBJECT (self, "New group start time: %" GST_TIME_FORMAT,
                GST_TIME_ARGS (self->group_start_time));

            for (l = self->streams; l; l = l->next) {
              GstStream *ostream = l->data;
              g_cond_broadcast (&ostream->stream_finish_cond);
            }
          }
        }
      } else {
        GST_DEBUG_OBJECT (self, "No stream or STREAM_START from same source");
      }

      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
    case GST_EVENT_SEGMENT:{
      GstStream *stream;
      GstSegment segment;

      gst_event_copy_segment (event, &segment);

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      if (stream) {
        if (stream->wait) {
          GST_DEBUG_OBJECT (pad, "Stream %d is waiting", stream->stream_number);
          g_cond_wait (&stream->stream_finish_cond, &self->lock);
          stream = gst_pad_get_element_private (pad);
          if (stream)
            stream->wait = FALSE;
        }
      }

      if (self->shutdown) {
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
        gst_event_unref (event);
        goto done;
      }

      if (stream && segment.format == GST_FORMAT_TIME) {
        if (stream->new_stream) {
          stream->new_stream = FALSE;
          segment.base = self->group_start_time;
        }

        GST_DEBUG_OBJECT (pad, "Segment was: %" GST_SEGMENT_FORMAT,
            &stream->segment);
        gst_segment_copy_into (&segment, &stream->segment);
        GST_DEBUG_OBJECT (pad, "Segment now is: %" GST_SEGMENT_FORMAT,
            &stream->segment);
        stream->segment_seqnum = gst_event_get_seqnum (event);

        GST_DEBUG_OBJECT (pad, "Stream start running time: %" GST_TIME_FORMAT,
            GST_TIME_ARGS (stream->segment.base));
        {
          GstEvent *tmpev;

          tmpev = gst_event_new_segment (&stream->segment);
          gst_event_set_seqnum (tmpev, stream->segment_seqnum);
          gst_event_unref (event);
          event = tmpev;
        }

      } else if (stream) {
        GST_WARNING_OBJECT (pad, "Non-TIME segment: %s",
            gst_format_get_name (segment.format));
        gst_segment_init (&stream->segment, GST_FORMAT_UNDEFINED);
        /* Since this stream is not time-based, we mark it so that
         * other streams don't wait forever on it */
        stream->wait = TRUE;
      }
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
    case GST_EVENT_FLUSH_START:{
      GstStream *stream;

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      if (stream) {
        GST_DEBUG_OBJECT (pad, "Flushing streams");
        g_cond_broadcast (&stream->stream_finish_cond);
      }
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
    case GST_EVENT_FLUSH_STOP:{
      GstStream *stream;

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      if (stream) {
        GST_DEBUG_OBJECT (pad, "Resetting segment for stream %d",
            stream->stream_number);
        gst_segment_init (&stream->segment, GST_FORMAT_UNDEFINED);

        stream->is_eos = FALSE;
        stream->wait = FALSE;
        stream->new_stream = FALSE;
        stream->drop_discont = FALSE;
        stream->seen_data = FALSE;
        g_cond_broadcast (&stream->stream_finish_cond);
      }
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
    case GST_EVENT_EOS:{
      GstStream *stream;
      GList *l;
      gboolean all_eos = TRUE;
      gboolean seen_data;
      GSList *pads = NULL;
      GstPad *srcpad;
      GstClockTime timestamp;

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      if (!stream) {
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
        GST_WARNING_OBJECT (pad, "EOS for unknown stream");
        break;
      }

      GST_DEBUG_OBJECT (pad, "Have EOS for stream %d", stream->stream_number);
      stream->is_eos = TRUE;

      seen_data = stream->seen_data;
      srcpad = gst_object_ref (stream->srcpad);

      if (seen_data && stream->segment.position != -1)
        timestamp = stream->segment.position;
      else if (stream->segment.rate < 0.0 || stream->segment.stop == -1)
        timestamp = stream->segment.start;
      else
        timestamp = stream->segment.stop;

      for (l = self->streams; l; l = l->next) {
        GstStream *ostream = l->data;

        all_eos = all_eos && ostream->is_eos;
        if (!all_eos)
          break;
      }

      if (all_eos) {
        GST_DEBUG_OBJECT (self, "All streams are EOS -- forwarding");
        for (l = self->streams; l; l = l->next) {
          GstStream *ostream = l->data;
          /* local snapshot of current pads */
          gst_object_ref (ostream->srcpad);
          pads = g_slist_prepend (pads, ostream->srcpad);
        }
      }
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      /* drop lock when sending eos, which may block in e.g. preroll */
      if (pads) {
        GstPad *pad;
        GSList *epad;

        ret = TRUE;
        epad = pads;
        while (epad) {
          pad = epad->data;
          GST_DEBUG_OBJECT (pad, "Pushing EOS");
          ret = ret && gst_pad_push_event (pad, gst_event_new_eos ());
          gst_object_unref (pad);
          epad = g_slist_next (epad);
        }
        g_slist_free (pads);
      } else {
        /* if EOS, but no data has passed, then send something to replace EOS
         * for preroll purposes */
        if (!seen_data) {
          GstEvent *gap_event;

          gap_event = gst_event_new_gap (timestamp, GST_CLOCK_TIME_NONE);
          ret = gst_pad_push_event (srcpad, gap_event);
        } else {
          GstEvent *gap_event;

          /* FIXME: Also send a GAP event to let audio sinks start their
           * clock in case they did not have enough data yet */
          gap_event = gst_event_new_gap (timestamp, GST_CLOCK_TIME_NONE);
          ret = gst_pad_push_event (srcpad, gap_event);
        }
      }
      gst_object_unref (srcpad);
      gst_event_unref (event);
      goto done;
    }
    default:
      break;
  }

  opad = gst_stream_get_other_pad_from_pad (self, pad);
  if (opad) {
    ret = gst_pad_push_event (opad, event);
    gst_object_unref (opad);
  }

done:

  return ret;
}
/* sinkpad functions */
static gboolean
gst_stream_synchronizer_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstStreamSynchronizer *self = GST_STREAM_SYNCHRONIZER (parent);
  gboolean ret = FALSE;

  GST_LOG_OBJECT (pad, "Handling event %s: %" GST_PTR_FORMAT,
      GST_EVENT_TYPE_NAME (event), event);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_STREAM_START:
    {
      GstSyncStream *stream, *ostream;
      guint32 seqnum = gst_event_get_seqnum (event);
      guint group_id;
      gboolean have_group_id;
      GList *l;
      gboolean all_wait = TRUE;
      gboolean new_stream = TRUE;

      have_group_id = gst_event_parse_group_id (event, &group_id);

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      self->have_group_id &= have_group_id;
      have_group_id = self->have_group_id;

      stream = gst_pad_get_element_private (pad);

      if (!stream) {
        GST_DEBUG_OBJECT (self, "No stream or STREAM_START from same source");
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
        break;
      }

      gst_event_parse_stream_flags (event, &stream->flags);

      if ((have_group_id && stream->group_id != group_id) || (!have_group_id
              && stream->stream_start_seqnum != seqnum)) {
        stream->is_eos = FALSE;
        stream->eos_sent = FALSE;
        stream->flushing = FALSE;
        stream->stream_start_seqnum = seqnum;
        stream->group_id = group_id;

        if (!have_group_id) {
          /* Check if this belongs to a stream that is already there,
           * e.g. we got the visualizations for an audio stream */
          for (l = self->streams; l; l = l->next) {
            ostream = l->data;

            if (ostream != stream && ostream->stream_start_seqnum == seqnum
                && !ostream->wait) {
              new_stream = FALSE;
              break;
            }
          }

          if (!new_stream) {
            GST_DEBUG_OBJECT (pad,
                "Stream %d belongs to running stream %d, no waiting",
                stream->stream_number, ostream->stream_number);
            stream->wait = FALSE;

            GST_STREAM_SYNCHRONIZER_UNLOCK (self);
            break;
          }
        } else if (group_id == self->group_id) {
          GST_DEBUG_OBJECT (pad, "Stream %d belongs to running group %d, "
              "no waiting", stream->stream_number, group_id);
          GST_STREAM_SYNCHRONIZER_UNLOCK (self);
          break;
        }

        GST_DEBUG_OBJECT (pad, "Stream %d changed", stream->stream_number);

        stream->wait = TRUE;

        for (l = self->streams; l; l = l->next) {
          GstSyncStream *ostream = l->data;

          all_wait = all_wait && ((ostream->flags & GST_STREAM_FLAG_SPARSE)
              || (ostream->wait && (!have_group_id
                      || ostream->group_id == group_id)));
          if (!all_wait)
            break;
        }

        if (all_wait) {
          gint64 position = 0;

          if (have_group_id)
            GST_DEBUG_OBJECT (self,
                "All streams have changed to group id %u -- unblocking",
                group_id);
          else
            GST_DEBUG_OBJECT (self, "All streams have changed -- unblocking");

          self->group_id = group_id;

          for (l = self->streams; l; l = l->next) {
            GstSyncStream *ostream = l->data;
            gint64 stop_running_time;
            gint64 position_running_time;

            ostream->wait = FALSE;

            if (ostream->segment.format == GST_FORMAT_TIME) {
              stop_running_time =
                  gst_segment_to_running_time (&ostream->segment,
                  GST_FORMAT_TIME, ostream->segment.stop);
              position_running_time =
                  gst_segment_to_running_time (&ostream->segment,
                  GST_FORMAT_TIME, ostream->segment.position);

              position_running_time =
                  MAX (position_running_time, stop_running_time);
              position_running_time -=
                  gst_segment_to_running_time (&ostream->segment,
                  GST_FORMAT_TIME, ostream->segment.start);
              position_running_time = MAX (0, position_running_time);

              position = MAX (position, position_running_time);
            }
          }

          self->group_start_time += position;

          GST_DEBUG_OBJECT (self, "New group start time: %" GST_TIME_FORMAT,
              GST_TIME_ARGS (self->group_start_time));

          for (l = self->streams; l; l = l->next) {
            GstSyncStream *ostream = l->data;
            ostream->wait = FALSE;
            g_cond_broadcast (&ostream->stream_finish_cond);
          }
        }
      }

      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
    case GST_EVENT_SEGMENT:{
      GstSyncStream *stream;
      GstSegment segment;

      gst_event_copy_segment (event, &segment);

      GST_STREAM_SYNCHRONIZER_LOCK (self);

      gst_stream_synchronizer_wait (self, pad);

      if (self->shutdown) {
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
        gst_event_unref (event);
        goto done;
      }

      stream = gst_pad_get_element_private (pad);
      if (stream && segment.format == GST_FORMAT_TIME) {
        GST_DEBUG_OBJECT (pad,
            "New stream, updating base from %" GST_TIME_FORMAT " to %"
            GST_TIME_FORMAT, GST_TIME_ARGS (segment.base),
            GST_TIME_ARGS (segment.base + self->group_start_time));
        segment.base += self->group_start_time;

        GST_DEBUG_OBJECT (pad, "Segment was: %" GST_SEGMENT_FORMAT,
            &stream->segment);
        gst_segment_copy_into (&segment, &stream->segment);
        GST_DEBUG_OBJECT (pad, "Segment now is: %" GST_SEGMENT_FORMAT,
            &stream->segment);
        stream->segment_seqnum = gst_event_get_seqnum (event);

        GST_DEBUG_OBJECT (pad, "Stream start running time: %" GST_TIME_FORMAT,
            GST_TIME_ARGS (stream->segment.base));
        {
          GstEvent *tmpev;

          tmpev = gst_event_new_segment (&stream->segment);
          gst_event_set_seqnum (tmpev, stream->segment_seqnum);
          gst_event_unref (event);
          event = tmpev;
        }
      } else if (stream) {
        GST_WARNING_OBJECT (pad, "Non-TIME segment: %s",
            gst_format_get_name (segment.format));
        gst_segment_init (&stream->segment, GST_FORMAT_UNDEFINED);
      }
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
    case GST_EVENT_FLUSH_START:{
      GstSyncStream *stream;

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      self->eos = FALSE;
      if (stream) {
        GST_DEBUG_OBJECT (pad, "Flushing streams");
        stream->flushing = TRUE;
        g_cond_broadcast (&stream->stream_finish_cond);
      }
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
    case GST_EVENT_FLUSH_STOP:{
      GstSyncStream *stream;
      GList *l;
      GstClockTime new_group_start_time = 0;

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      if (stream) {
        GST_DEBUG_OBJECT (pad, "Resetting segment for stream %d",
            stream->stream_number);
        gst_segment_init (&stream->segment, GST_FORMAT_UNDEFINED);

        stream->is_eos = FALSE;
        stream->eos_sent = FALSE;
        stream->flushing = FALSE;
        stream->wait = FALSE;
        g_cond_broadcast (&stream->stream_finish_cond);
      }

      for (l = self->streams; l; l = l->next) {
        GstSyncStream *ostream = l->data;
        GstClockTime start_running_time;

        if (ostream == stream || ostream->flushing)
          continue;

        if (ostream->segment.format == GST_FORMAT_TIME) {
          start_running_time =
              gst_segment_to_running_time (&ostream->segment,
              GST_FORMAT_TIME, ostream->segment.start);

          new_group_start_time = MAX (new_group_start_time, start_running_time);
        }
      }

      GST_DEBUG_OBJECT (pad,
          "Updating group start time from %" GST_TIME_FORMAT " to %"
          GST_TIME_FORMAT, GST_TIME_ARGS (self->group_start_time),
          GST_TIME_ARGS (new_group_start_time));
      self->group_start_time = new_group_start_time;
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      break;
    }
      /* unblocking EOS wait when track switch. */
    case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:{
      if (gst_event_has_name (event, "playsink-custom-video-flush")
          || gst_event_has_name (event, "playsink-custom-audio-flush")
          || gst_event_has_name (event, "playsink-custom-subtitle-flush")) {
        GstSyncStream *stream;

        GST_STREAM_SYNCHRONIZER_LOCK (self);
        stream = gst_pad_get_element_private (pad);
        if (stream) {
          stream->is_eos = FALSE;
          stream->eos_sent = FALSE;
          stream->wait = FALSE;
          g_cond_broadcast (&stream->stream_finish_cond);
        }
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      }
      break;
    }
    case GST_EVENT_EOS:{
      GstSyncStream *stream;
      GList *l;
      gboolean all_eos = TRUE;
      gboolean seen_data;
      GSList *pads = NULL;
      GstPad *srcpad;
      GstClockTime timestamp;

      GST_STREAM_SYNCHRONIZER_LOCK (self);
      stream = gst_pad_get_element_private (pad);
      if (!stream) {
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
        GST_WARNING_OBJECT (pad, "EOS for unknown stream");
        break;
      }

      GST_DEBUG_OBJECT (pad, "Have EOS for stream %d", stream->stream_number);
      stream->is_eos = TRUE;

      seen_data = stream->seen_data;
      srcpad = gst_object_ref (stream->srcpad);

      if (seen_data && stream->segment.position != -1)
        timestamp = stream->segment.position;
      else if (stream->segment.rate < 0.0 || stream->segment.stop == -1)
        timestamp = stream->segment.start;
      else
        timestamp = stream->segment.stop;

      stream->segment.position = timestamp;

      for (l = self->streams; l; l = l->next) {
        GstSyncStream *ostream = l->data;

        all_eos = all_eos && ostream->is_eos;
        if (!all_eos)
          break;
      }

      if (all_eos) {
        GST_DEBUG_OBJECT (self, "All streams are EOS -- forwarding");
        self->eos = TRUE;
        for (l = self->streams; l; l = l->next) {
          GstSyncStream *ostream = l->data;
          /* local snapshot of current pads */
          gst_object_ref (ostream->srcpad);
          pads = g_slist_prepend (pads, ostream->srcpad);
        }
      }
      if (pads) {
        GstPad *pad;
        GSList *epad;
        GstSyncStream *ostream;

        ret = TRUE;
        epad = pads;
        while (epad) {
          pad = epad->data;
          ostream = gst_pad_get_element_private (pad);
          if (ostream) {
            g_cond_broadcast (&ostream->stream_finish_cond);
          }

          gst_object_unref (pad);
          epad = g_slist_next (epad);
        }
        g_slist_free (pads);
      } else {
        if (seen_data) {
          self->send_gap_event = TRUE;
          stream->gap_duration = GST_CLOCK_TIME_NONE;
          stream->wait = TRUE;
          ret = gst_stream_synchronizer_wait (self, srcpad);
        }
      }

      /* send eos if haven't seen data. seen_data will be true if data buffer
       * of the track have received in anytime. sink is ready if seen_data is
       * true, so can send GAP event. Will send EOS if sink isn't ready. The
       * scenario for the case is one track haven't any media data and then
       * send EOS. Or no any valid media data in one track, so decoder can't
       * get valid CAPS for the track. sink can't ready without received CAPS.*/
      if (!seen_data || self->eos) {
        GST_DEBUG_OBJECT (pad, "send EOS event");
        /* drop lock when sending eos, which may block in e.g. preroll */
        GST_STREAM_SYNCHRONIZER_UNLOCK (self);
        ret = gst_pad_push_event (srcpad, gst_event_new_eos ());
        GST_STREAM_SYNCHRONIZER_LOCK (self);
        stream = gst_pad_get_element_private (pad);
        if (stream) {
          stream->eos_sent = TRUE;
        }
      }

      gst_object_unref (srcpad);
      gst_event_unref (event);
      GST_STREAM_SYNCHRONIZER_UNLOCK (self);
      goto done;
    }
    default:
      break;
  }

  ret = gst_pad_event_default (pad, parent, event);

done:

  return ret;
}
Пример #8
0
gboolean
mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad,
    GstEvent * event)
{
  MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
  GstFlowReturn ret = GST_FLOW_ERROR;
  gdouble rate;
  gboolean flush;
  GstFormat format;
  GstSeekFlags flags;
  GstSeekType start_type, stop_type;
  gint64 start, stop;
  GstEvent *flush_event = NULL;

  gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
      &stop_type, &stop);

  if (format != GST_FORMAT_TIME)
    return FALSE;

  if (GST_EVENT_SEQNUM (event) == base->last_seek_seqnum) {
    GST_DEBUG_OBJECT (base, "Skipping already handled seek");
    return TRUE;
  }

  if (base->mode == BASE_MODE_PUSHING) {
    /* First try if upstream supports seeking in TIME format */
    if (gst_pad_push_event (base->sinkpad, gst_event_ref (event))) {
      GST_DEBUG ("upstream handled SEEK event");
      return TRUE;
    }

    /* If the subclass can seek, do that */
    if (klass->seek) {
      ret = klass->seek (base, event);
      if (G_UNLIKELY (ret != GST_FLOW_OK))
        GST_WARNING ("seeking failed %s", gst_flow_get_name (ret));
      else {
        GstEvent *new_seek;

        if (GST_CLOCK_TIME_IS_VALID (base->seek_offset)) {
          base->mode = BASE_MODE_SEEKING;
          new_seek = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
              GST_SEEK_TYPE_SET, base->seek_offset, GST_SEEK_TYPE_NONE, -1);
          gst_event_set_seqnum (new_seek, GST_EVENT_SEQNUM (event));
          if (!gst_pad_push_event (base->sinkpad, new_seek))
            ret = GST_FLOW_ERROR;
          else
            base->last_seek_seqnum = GST_EVENT_SEQNUM (event);
        }
        base->mode = BASE_MODE_PUSHING;
      }
    } else {
      GST_WARNING ("subclass has no seek implementation");
    }

    return ret == GST_FLOW_OK;
  }

  if (!klass->seek) {
    GST_WARNING ("subclass has no seek implementation");
    return FALSE;
  }

  if (rate <= 0.0) {
    GST_WARNING ("Negative rate not supported");
    return FALSE;
  }

  GST_DEBUG ("seek event, rate: %f start: %" GST_TIME_FORMAT
      " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start),
      GST_TIME_ARGS (stop));

  flush = flags & GST_SEEK_FLAG_FLUSH;

  /* stop streaming, either by flushing or by pausing the task */
  base->mode = BASE_MODE_SEEKING;
  if (flush) {
    GST_DEBUG_OBJECT (base, "sending flush start");
    flush_event = gst_event_new_flush_start ();
    gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event));
    gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event));
    GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event);
  } else
    gst_pad_pause_task (base->sinkpad);

  /* wait for streaming to finish */
  GST_PAD_STREAM_LOCK (base->sinkpad);

  if (flush) {
    /* send a FLUSH_STOP for the sinkpad, since we need data for seeking */
    GST_DEBUG_OBJECT (base, "sending flush stop");
    flush_event = gst_event_new_flush_stop (TRUE);
    gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event));

    /* ref for it to be reused later */
    gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event));
    /* And actually flush our pending data but allow to preserve some info
     * to perform the seek */
    mpegts_base_flush (base, FALSE);
    mpegts_packetizer_flush (base->packetizer, FALSE);
  }

  if (flags & (GST_SEEK_FLAG_SEGMENT)) {
    GST_WARNING ("seek flags 0x%x are not supported", (int) flags);
    goto done;
  }


  /* If the subclass can seek, do that */
  ret = klass->seek (base, event);
  if (G_UNLIKELY (ret != GST_FLOW_OK))
    GST_WARNING ("seeking failed %s", gst_flow_get_name (ret));
  else
    base->last_seek_seqnum = GST_EVENT_SEQNUM (event);

  if (flush_event) {
    /* if we sent a FLUSH_START, we now send a FLUSH_STOP */
    GST_DEBUG_OBJECT (base, "sending flush stop");
    GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event);
    flush_event = NULL;
  }
done:
  if (flush_event)
    gst_event_unref (flush_event);
  gst_pad_start_task (base->sinkpad, (GstTaskFunction) mpegts_base_loop, base,
      NULL);

  GST_PAD_STREAM_UNLOCK (base->sinkpad);
  return ret == GST_FLOW_OK;
}
Пример #9
0
static gboolean
gst_midi_parse_perform_seek (GstMidiParse * midiparse, GstEvent * event)
{
  gboolean res = TRUE, tres;
  gdouble rate;
  GstFormat seek_format;
  GstSeekFlags flags;
  GstSeekType start_type, stop_type;
  gint64 start, stop;
  gboolean flush;
  gboolean update;
  GstSegment seeksegment;
  guint32 seqnum;
  GstEvent *tevent;

  GST_DEBUG_OBJECT (midiparse, "doing seek: %" GST_PTR_FORMAT, event);

  if (event) {
    gst_event_parse_seek (event, &rate, &seek_format, &flags,
        &start_type, &start, &stop_type, &stop);

    if (seek_format != GST_FORMAT_TIME)
      goto invalid_format;

    flush = flags & GST_SEEK_FLAG_FLUSH;
    seqnum = gst_event_get_seqnum (event);
  } else {
    flush = FALSE;
    /* get next seqnum */
    seqnum = gst_util_seqnum_next ();
  }

  /* send flush start */
  if (flush) {
    tevent = gst_event_new_flush_start ();
    gst_event_set_seqnum (tevent, seqnum);
    gst_pad_push_event (midiparse->srcpad, tevent);
  } else
    gst_pad_pause_task (midiparse->srcpad);

  /* grab streaming lock, this should eventually be possible, either
   * because the task is paused, our streaming thread stopped
   * or because our peer is flushing. */
  GST_PAD_STREAM_LOCK (midiparse->sinkpad);
  if (G_UNLIKELY (midiparse->seqnum == seqnum)) {
    /* we have seen this event before, issue a warning for now */
    GST_WARNING_OBJECT (midiparse, "duplicate event found %" G_GUINT32_FORMAT,
        seqnum);
  } else {
    midiparse->seqnum = seqnum;
    GST_DEBUG_OBJECT (midiparse, "seek with seqnum %" G_GUINT32_FORMAT, seqnum);
  }

  /* Copy the current segment info into the temp segment that we can actually
   * attempt the seek with. We only update the real segment if the seek succeeds. */
  memcpy (&seeksegment, &midiparse->segment, sizeof (GstSegment));

  /* now configure the final seek segment */
  if (event) {
    gst_segment_do_seek (&seeksegment, rate, seek_format, flags,
        start_type, start, stop_type, stop, &update);
  }

  /* Else, no seek event passed, so we're just (re)starting the
     current segment. */
  GST_DEBUG_OBJECT (midiparse, "segment configured from %" G_GINT64_FORMAT
      " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
      seeksegment.start, seeksegment.stop, seeksegment.position);

  /* do the seek, segment.position contains the new position. */
  res = gst_midi_parse_do_seek (midiparse, &seeksegment);

  /* and prepare to continue streaming */
  if (flush) {
    tevent = gst_event_new_flush_stop (TRUE);
    gst_event_set_seqnum (tevent, seqnum);
    /* send flush stop, peer will accept data and events again. We
     * are not yet providing data as we still have the STREAM_LOCK. */
    gst_pad_push_event (midiparse->srcpad, tevent);
  }

  /* if the seek was successful, we update our real segment and push
   * out the new segment. */
  if (res) {
    GST_OBJECT_LOCK (midiparse);
    memcpy (&midiparse->segment, &seeksegment, sizeof (GstSegment));
    GST_OBJECT_UNLOCK (midiparse);

    if (seeksegment.flags & GST_SEGMENT_FLAG_SEGMENT) {
      GstMessage *message;

      message = gst_message_new_segment_start (GST_OBJECT (midiparse),
          seeksegment.format, seeksegment.position);
      gst_message_set_seqnum (message, seqnum);

      gst_element_post_message (GST_ELEMENT (midiparse), message);
    }
    /* for deriving a stop position for the playback segment from the seek
     * segment, we must take the duration when the stop is not set */
    if ((stop = seeksegment.stop) == -1)
      stop = seeksegment.duration;

    midiparse->segment_pending = TRUE;
    midiparse->discont = TRUE;
  }

  /* and restart the task in case it got paused explicitly or by
   * the FLUSH_START event we pushed out. */
  tres =
      gst_pad_start_task (midiparse->sinkpad,
      (GstTaskFunction) gst_midi_parse_loop, midiparse->sinkpad, NULL);
  if (res && !tres)
    res = FALSE;

  /* and release the lock again so we can continue streaming */
  GST_PAD_STREAM_UNLOCK (midiparse->sinkpad);

  return res;

  /* ERROR */
invalid_format:
  {
    GST_DEBUG_OBJECT (midiparse, "Unsupported seek format %s",
        gst_format_get_name (seek_format));
    return FALSE;
  }
}
Пример #10
0
static gboolean
theora_dec_src_event (GstPad * pad, GstEvent * event)
{
  gboolean res = TRUE;
  GstTheoraDec *dec;

  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
    {
      GstFormat format, tformat;
      gdouble rate;
      GstEvent *real_seek;
      GstSeekFlags flags;
      GstSeekType cur_type, stop_type;
      gint64 cur, stop;
      gint64 tcur, tstop;
      guint32 seqnum;

      gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
          &stop_type, &stop);
      seqnum = gst_event_get_seqnum (event);
      gst_event_unref (event);

      /* we have to ask our peer to seek to time here as we know
       * nothing about how to generate a granulepos from the src
       * formats or anything.
       * 
       * First bring the requested format to time 
       */
      tformat = GST_FORMAT_TIME;
      if (!(res = theora_dec_src_convert (pad, format, cur, &tformat, &tcur)))
        goto convert_error;
      if (!(res = theora_dec_src_convert (pad, format, stop, &tformat, &tstop)))
        goto convert_error;

      /* then seek with time on the peer */
      real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
          flags, cur_type, tcur, stop_type, tstop);
      gst_event_set_seqnum (real_seek, seqnum);

      res = gst_pad_push_event (dec->sinkpad, real_seek);
      break;
    }
    case GST_EVENT_QOS:
    {
      gdouble proportion;
      GstClockTimeDiff diff;
      GstClockTime timestamp;

      gst_event_parse_qos (event, &proportion, &diff, &timestamp);

      /* we cannot randomly skip frame decoding since we don't have
       * B frames. we can however use the timestamp and diff to not
       * push late frames. This would at least save us the time to
       * crop/memcpy the data. */
      GST_OBJECT_LOCK (dec);
      dec->proportion = proportion;
      dec->earliest_time = timestamp + diff;
      GST_OBJECT_UNLOCK (dec);

      GST_DEBUG_OBJECT (dec, "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
          GST_TIME_ARGS (timestamp), diff);

      res = gst_pad_push_event (dec->sinkpad, event);
      break;
    }
    default:
      res = gst_pad_push_event (dec->sinkpad, event);
      break;
  }
done:
  gst_object_unref (dec);

  return res;

  /* ERRORS */
convert_error:
  {
    GST_DEBUG_OBJECT (dec, "could not convert format");
    goto done;
  }
}