예제 #1
0
static gboolean
mpegts_base_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  gboolean res = TRUE;
  gboolean hard;
  MpegTSBase *base = GST_MPEGTS_BASE (parent);

  GST_DEBUG_OBJECT (base, "Got event %s",
      gst_event_type_get_name (GST_EVENT_TYPE (event)));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEGMENT:
      gst_event_copy_segment (event, &base->segment);
      GST_DEBUG_OBJECT (base, "Received segment %" GST_SEGMENT_FORMAT,
          &base->segment);
      /* Check if we need to switch PCR/PTS handling */
      if (base->segment.format == GST_FORMAT_TIME) {
        base->packetizer->calculate_offset = FALSE;
        base->packetizer->calculate_skew = TRUE;
      } else {
        base->packetizer->calculate_offset = TRUE;
        base->packetizer->calculate_skew = FALSE;
      }
      res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event);
      break;
    case GST_EVENT_STREAM_START:
      gst_event_unref (event);
      break;
    case GST_EVENT_EOS:
      res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event);
      res = gst_mpegts_base_handle_eos (base);
      break;
    case GST_EVENT_CAPS:
      /* FIXME, do something */
      gst_event_unref (event);
      break;
    case GST_EVENT_FLUSH_STOP:
      res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event);
      hard = (base->mode != BASE_MODE_SEEKING);
      mpegts_packetizer_flush (base->packetizer, hard);
      mpegts_base_flush (base, hard);
      gst_segment_init (&base->segment, GST_FORMAT_UNDEFINED);
      base->seen_pat = FALSE;
      break;
    default:
      res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event);
  }

  /* Always return TRUE for sticky events */
  if (GST_EVENT_IS_STICKY (event))
    res = TRUE;

  return res;
}
예제 #2
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;
}
예제 #3
0
static GstFlowReturn
mpegts_base_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
  GstFlowReturn res = GST_FLOW_OK;
  MpegTSBase *base;
  MpegTSPacketizerPacketReturn pret;
  MpegTSPacketizer2 *packetizer;
  MpegTSPacketizerPacket packet;
  MpegTSBaseClass *klass;

  base = GST_MPEGTS_BASE (parent);
  klass = GST_MPEGTS_BASE_GET_CLASS (base);

  packetizer = base->packetizer;

  if (klass->input_done)
    gst_buffer_ref (buf);

  if (GST_BUFFER_IS_DISCONT (buf)) {
    GST_DEBUG_OBJECT (base, "Got DISCONT buffer, flushing");
    res = mpegts_base_drain (base);
    if (G_UNLIKELY (res != GST_FLOW_OK))
      return res;

    mpegts_base_flush (base, FALSE);
    /* In the case of discontinuities in push-mode with TIME segment
     * we want to drop all previous observations (hard:TRUE) from
     * the packetizer */
    if (base->mode == BASE_MODE_PUSHING
        && base->segment.format == GST_FORMAT_TIME)
      mpegts_packetizer_flush (base->packetizer, TRUE);
    else
      mpegts_packetizer_flush (base->packetizer, FALSE);
  }

  mpegts_packetizer_push (base->packetizer, buf);

  while (res == GST_FLOW_OK) {
    pret = mpegts_packetizer_next_packet (base->packetizer, &packet);

    /* If we don't have enough data, return */
    if (G_UNLIKELY (pret == PACKET_NEED_MORE))
      break;

    if (G_UNLIKELY (pret == PACKET_BAD)) {
      /* bad header, skip the packet */
      GST_DEBUG_OBJECT (base, "bad packet, skipping");
      goto next;
    }

    if (klass->inspect_packet)
      klass->inspect_packet (base, &packet);

    /* If it's a known PES, push it */
    if (MPEGTS_BIT_IS_SET (base->is_pes, packet.pid)) {
      /* push the packet downstream */
      if (base->push_data)
        res = klass->push (base, &packet, NULL);
    } else if (packet.payload
        && MPEGTS_BIT_IS_SET (base->known_psi, packet.pid)) {
      /* base PSI data */
      GList *others, *tmp;
      GstMpegtsSection *section;

      section = mpegts_packetizer_push_section (packetizer, &packet, &others);
      if (section)
        mpegts_base_handle_psi (base, section);
      if (G_UNLIKELY (others)) {
        for (tmp = others; tmp; tmp = tmp->next)
          mpegts_base_handle_psi (base, (GstMpegtsSection *) tmp->data);
        g_list_free (others);
      }

      /* we need to push section packet downstream */
      if (base->push_section)
        res = klass->push (base, &packet, section);

    } else if (packet.payload && packet.pid != 0x1fff)
      GST_LOG ("PID 0x%04x Saw packet on a pid we don't handle", packet.pid);

  next:
    mpegts_packetizer_clear_packet (base->packetizer, &packet);
  }

  if (klass->input_done) {
    if (res == GST_FLOW_OK)
      res = klass->input_done (base, buf);
    else
      gst_buffer_unref (buf);
  }

  return res;
}