GstPadProbeReturn GstEnginePipeline::EventHandoffCallback(GstPad*,
                                                          GstPadProbeInfo* info,
                                                          gpointer self) {
  GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
  GstEvent* e = gst_pad_probe_info_get_event(info);

  qLog(Debug) << instance->id() << "event" << GST_EVENT_TYPE_NAME(e);

  if (GST_EVENT_TYPE(e) == GST_EVENT_SEGMENT &&
      !instance->segment_start_received_) {
    // The segment start time is used to calculate the proper offset of data
    // buffers from the start of the stream
    const GstSegment* segment = nullptr;
    gst_event_parse_segment(e, &segment);
    instance->segment_start_ = segment->start;
    instance->segment_start_received_ = true;

    if (instance->emit_track_ended_on_segment_start_) {
      qLog(Debug) << "New segment started, EOS will signal on next buffer "
                     "discontinuity";
      instance->emit_track_ended_on_segment_start_ = false;
      instance->emit_track_ended_on_time_discontinuity_ = true;
    }
  }

  return GST_PAD_PROBE_OK;
}
Example #2
0
static GstPadProbeReturn encoder_appsink_event_probe (GstPad *pad, GstPadProbeInfo *info, gpointer data)
{
        GstEvent *event = gst_pad_probe_info_get_event (info);
        Encoder *encoder = data;
        GstClockTime timestamp, running_time, stream_time;
        gboolean all_headers;
        guint count;

        if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
                GST_ERROR ("End of Stream of encoder %s", encoder->name);
                *(encoder->output->eos) = TRUE;
                return GST_PAD_PROBE_OK;
        }

        if (!gst_video_event_is_force_key_unit (event)) {
                return GST_PAD_PROBE_OK;
        }

        /* force key unit event */
        gst_video_event_parse_downstream_force_key_unit (event, &timestamp, &stream_time, &running_time, &all_headers, &count);
        if (encoder->last_segment_duration != 0) {
                encoder->last_running_time = timestamp;
        }

        return GST_PAD_PROBE_OK;
}
GstPadProbeReturn GstEnginePipeline::EventHandoffCallback(GstPad*,
        GstPadProbeInfo* info,
        gpointer self) {
    GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
    GstEvent* e = gst_pad_probe_info_get_event(info);

    qLog(Debug) << instance->id() << "event" << GST_EVENT_TYPE_NAME(e);

    switch (GST_EVENT_TYPE(e)) {
    case GST_EVENT_SEGMENT:
        if (!instance->segment_start_received_) {
            // The segment start time is used to calculate the proper offset of data
            // buffers from the start of the stream
            const GstSegment* segment = nullptr;
            gst_event_parse_segment(e, &segment);
            instance->segment_start_ = segment->start;
            instance->segment_start_received_ = true;
        }
        break;

    default:
        break;
    }

    return GST_PAD_PROBE_OK;
}
Example #4
0
static GstPadProbeReturn
accept_eos_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
{
  GstEvent *event = gst_pad_probe_info_get_event (info);
  GstEventType type = GST_EVENT_TYPE (event);

  if (type == GST_EVENT_EOS || type == GST_EVENT_FLUSH_START
      || type == GST_EVENT_FLUSH_STOP) {
    KmsElement *self;
    gboolean accept;

    self = KMS_ELEMENT (data);
    KMS_ELEMENT_LOCK (self);
    accept = self->priv->accept_eos;
    KMS_ELEMENT_UNLOCK (self);

    if (!accept) {
      GST_DEBUG_OBJECT (pad, "Event %s dropped",
          gst_event_type_get_name (type));
    }

    return (accept) ? GST_PAD_PROBE_OK : GST_PAD_PROBE_DROP;
  }

  return GST_PAD_PROBE_OK;
}
Example #5
0
static GstPadProbeReturn
kms_agnostic_bin2_src_reconfigure_probe (GstPad * pad, GstPadProbeInfo * info,
    gpointer user_data)
{
  KmsAgnosticBin2 *self = KMS_AGNOSTIC_BIN2 (gst_pad_get_parent_element (pad));
  GstPadProbeReturn ret = GST_PAD_PROBE_OK;
  GstEvent *event;

  if (self == NULL) {
    return GST_PAD_PROBE_OK;
  }

  if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_EVENT_BOTH) {
    event = gst_pad_probe_info_get_event (info);

    if (GST_EVENT_TYPE (event) == GST_EVENT_RECONFIGURE) {
      KmsAgnosticBin2 *self = user_data;

      GST_DEBUG_OBJECT (pad, "Received reconfigure event");

      KMS_AGNOSTIC_BIN2_LOCK (self);
      kms_agnostic_bin2_process_pad (self, pad);
      ret = GST_PAD_PROBE_DROP;
      KMS_AGNOSTIC_BIN2_UNLOCK (self);

      goto end;
    }
  }

end:
  g_object_unref (self);

  return ret;
}
Example #6
0
static GstPadProbeReturn
caps_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
{
  GstEvent *event = gst_pad_probe_info_get_event (info);

  if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
    GstCaps *caps;
    GstStructure *st;
    gint width;

    GST_DEBUG ("Received event: %" GST_PTR_FORMAT, event);

    gst_event_parse_caps (event, &caps);
    st = gst_caps_get_structure (caps, 0);

    if (gst_structure_get_int (st, "width", &width)) {
      if (width == 320) {
        GstCaps *new_caps =
            gst_caps_from_string ("video/x-raw,width=640,height=480");
        GST_DEBUG ("Changing caps");
        g_object_set (G_OBJECT (data), "caps", new_caps, NULL);
        gst_caps_unref (new_caps);
      } else {
        GST_DEBUG ("Re negotiated OK");
      }
    }
  }

  return GST_PAD_PROBE_OK;
}
Example #7
0
static GstPadProbeReturn
kms_agnostic_bin2_sink_caps_probe (GstPad * pad, GstPadProbeInfo * info,
    gpointer user_data)
{
  KmsAgnosticBin2 *self;
  GstCaps *current_caps;
  GstCaps *new_caps = NULL;
  GstEvent *event = gst_pad_probe_info_get_event (info);

  if (GST_EVENT_TYPE (event) != GST_EVENT_CAPS) {
    return GST_PAD_PROBE_OK;
  }

  GST_TRACE_OBJECT (pad, "Event: %" GST_PTR_FORMAT, event);

  self = KMS_AGNOSTIC_BIN2 (user_data);

  gst_event_parse_caps (event, &new_caps);

  if (new_caps == NULL) {
    GST_ERROR_OBJECT (self, "Unexpected NULL caps");
    return GST_PAD_PROBE_OK;
  }

  KMS_AGNOSTIC_BIN2_LOCK (self);
  current_caps = self->priv->input_caps;
  self->priv->input_caps = gst_caps_copy (new_caps);
  KMS_AGNOSTIC_BIN2_UNLOCK (self);

  GST_TRACE_OBJECT (user_data, "New caps event: %" GST_PTR_FORMAT, event);

  if (current_caps != NULL) {
    GstStructure *st;

    GST_TRACE_OBJECT (user_data, "Current caps: %" GST_PTR_FORMAT,
        current_caps);

    st = gst_caps_get_structure (current_caps, 0);
    // Remove famerate, width, height, streamheader that make unecessary
    // agnostic reconstruction happen

    gst_structure_remove_fields (st, "width", "height", "framerate",
        "streamheader", "codec_data", NULL);

    if (!gst_caps_can_intersect (new_caps, current_caps) &&
        !is_raw_caps (current_caps) && !is_raw_caps (new_caps)) {
      GST_DEBUG_OBJECT (user_data, "Caps differ caps: %" GST_PTR_FORMAT,
          new_caps);
      kms_agnostic_bin2_configure_input (self, new_caps);
    }

    gst_caps_unref (current_caps);
  } else {
    GST_DEBUG_OBJECT (user_data, "No previous caps, starting");
    kms_agnostic_bin2_configure_input (self, new_caps);
  }

  return GST_PAD_PROBE_OK;
}
static GstPadProbeReturn textTrackPrivateEventCallback(GstPad*, GstPadProbeInfo* info, InbandTextTrackPrivateGStreamer* track)
{
    GstEvent* event = gst_pad_probe_info_get_event(info);
    switch (GST_EVENT_TYPE(event)) {
    case GST_EVENT_STREAM_START:
        track->streamChanged();
        break;
    default:
        break;
    }
    return GST_PAD_PROBE_OK;
}
static GstPadProbeReturn
handle_output (GstPad * pad, GstPadProbeInfo * info, StreamInfo * si)
{
  GstClockTime start, end;
  GstBuffer *buf;

  GST_LOG_OBJECT (pad, "Fired probe type 0x%x", info->type);

  if (info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST) {
    g_warning ("Buffer list handling not implemented");
    return GST_PAD_PROBE_DROP;
  }

  if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
    GstEvent *event = gst_pad_probe_info_get_event (info);
    switch (GST_EVENT_TYPE (event)) {
      case GST_EVENT_SEGMENT:
        gst_event_copy_segment (event, &si->seg);
        break;
      case GST_EVENT_EOS:
        dump_times (si);
        break;
      default:
        break;
    }
    return GST_PAD_PROBE_PASS;
  }

  buf = gst_pad_probe_info_get_buffer (info);
  if (!GST_BUFFER_PTS_IS_VALID (buf))
    goto done;
  end = start = GST_BUFFER_PTS (buf);

  if (GST_BUFFER_DURATION_IS_VALID (buf))
    end += GST_BUFFER_DURATION (buf);

  gst_segment_clip (&si->seg, GST_FORMAT_TIME, start, end, &start, &end);
  start = gst_segment_to_stream_time (&si->seg, GST_FORMAT_TIME, start);
  end = gst_segment_to_stream_time (&si->seg, GST_FORMAT_TIME, end);

  GST_DEBUG_OBJECT (pad, "new buffer %" GST_TIME_FORMAT
      " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));

  /* Now extend measured time range to include new times */
  extend_times (si, start, end);

done:
  return GST_PAD_PROBE_PASS;
}
Example #10
0
static GstPadProbeReturn
tee_src_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
  if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_EVENT_UPSTREAM) {
    GstEvent *event = gst_pad_probe_info_get_event (info);

    if (GST_EVENT_TYPE (event) == GST_EVENT_RECONFIGURE) {
      // Request key frame to upstream elements
      kms_utils_drop_until_keyframe (pad, TRUE);
      return GST_PAD_PROBE_DROP;
    }
  }

  return GST_PAD_PROBE_OK;
}
Example #11
0
/*
 * FIXME: This is a hack to make x264 work.
 *
 * We have notice that x264 doesn't work if width or height is odd,
 * so we force a rescale increasing one pixel that dimension
 * when we detect this situation.
 */
static GstPadProbeReturn
check_caps_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
{
  int width, height;
  GstCaps *filter_caps, *caps;
  GstElement *element;
  GstStructure *st;
  gboolean needs_filter = FALSE;
  GstEvent *event = gst_pad_probe_info_get_event (info);

  if (GST_EVENT_TYPE (event) != GST_EVENT_CAPS) {
    return GST_PAD_PROBE_OK;
  }

  gst_event_parse_caps (event, &caps);

  st = gst_caps_get_structure (caps, 0);

  gst_structure_get (st, "width", G_TYPE_INT, &width, NULL);
  gst_structure_get (st, "height", G_TYPE_INT, &height, NULL);

  if (width % 2) {
    GST_WARNING ("Width is odd");
    needs_filter = TRUE;
    width--;
  }

  if (height % 2) {
    GST_WARNING ("Height is odd");
    needs_filter = TRUE;
    height--;
  }

  if (!needs_filter)
    return GST_PAD_PROBE_OK;

  filter_caps = gst_caps_from_string ("video/x-raw,format=I420");

  gst_caps_set_simple (filter_caps, "width", G_TYPE_INT, width, NULL);
  gst_caps_set_simple (filter_caps, "height", G_TYPE_INT, height, NULL);

  element = gst_pad_get_parent_element (pad);
  g_object_set (element, "caps", filter_caps, NULL);
  gst_caps_unref (filter_caps);
  g_object_unref (element);

  return GST_PAD_PROBE_OK;
}
Example #12
0
InbandTextTrackPrivateGStreamer::InbandTextTrackPrivateGStreamer(gint index, GRefPtr<GstPad> pad)
    : InbandTextTrackPrivate(WebVTT), TrackPrivateBaseGStreamer(this, index, pad)
{
    m_eventProbe = gst_pad_add_probe(m_pad.get(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, [] (GstPad*, GstPadProbeInfo* info, gpointer userData) -> GstPadProbeReturn {
        auto* track = static_cast<InbandTextTrackPrivateGStreamer*>(userData);
        switch (GST_EVENT_TYPE(gst_pad_probe_info_get_event(info))) {
        case GST_EVENT_STREAM_START:
            track->streamChanged();
            break;
        default:
            break;
        }
        return GST_PAD_PROBE_OK;
    }, this, nullptr);

    notifyTrackOfStreamChanged();
}
static GstPadProbeReturn
set_caps (GstPad * pad, GstPadProbeInfo * info, gpointer data)
{
  GstEvent *event = gst_pad_probe_info_get_event (info);
  GstElement *appsrc = data;
  GstCaps *caps;

  if (GST_EVENT_TYPE (event) != GST_EVENT_CAPS)
    return GST_PAD_PROBE_OK;

  gst_event_parse_caps (event, &caps);

  GST_DEBUG_OBJECT (appsrc, "Setting caps to: %" GST_PTR_FORMAT, caps);

  g_object_set (appsrc, "caps", caps, NULL);

  return GST_PAD_PROBE_OK;
}
Example #14
0
static GstPadProbeReturn
remb_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
  RembEventManager *manager = user_data;
  GstEvent *event = gst_pad_probe_info_get_event (info);
  guint bitrate, ssrc;

  if (!kms_utils_remb_event_upstream_parse (event, &bitrate, &ssrc)) {
    return GST_PAD_PROBE_OK;
  }

  GST_TRACE_OBJECT (pad, "<%" G_GUINT32_FORMAT ", %" G_GUINT32_FORMAT ">", ssrc,
      bitrate);

  remb_event_manager_update_min (manager, bitrate, ssrc);

  return GST_PAD_PROBE_DROP;
}
Example #15
0
static GstPadProbeReturn
tag_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
{
  GstEvent *event = gst_pad_probe_info_get_event (info);

  if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) {
    KmsEncTreeBin *self = data;
    GstTagList *taglist;
    guint bitrate;

    gst_event_parse_tag (event, &taglist);
    if (gst_tag_list_get_uint (taglist, "bitrate", &bitrate)) {

      self->priv->tag_bitrate = bitrate;
      kms_enc_tree_bin_set_target_bitrate (self);
    }
  }

  return GST_PAD_PROBE_OK;
}
Example #16
0
static GstPadProbeReturn
input_bin_src_caps_probe (GstPad * pad, GstPadProbeInfo * info, gpointer bin)
{
  KmsAgnosticBin2 *self = KMS_AGNOSTIC_BIN2 (GST_OBJECT_PARENT (bin));
  GstEvent *event = gst_pad_probe_info_get_event (info);
  GstCaps *current_caps;

  if (self == NULL) {
    GST_WARNING_OBJECT (bin, "Parent agnosticbin seems to be released");
    return GST_PAD_PROBE_OK;
  }

  GST_TRACE_OBJECT (self, "Event in parser pad: %" GST_PTR_FORMAT, event);

  if (GST_EVENT_TYPE (event) != GST_EVENT_CAPS) {
    return GST_PAD_PROBE_OK;
  }

  KMS_AGNOSTIC_BIN2_LOCK (self);

  self->priv->started = TRUE;
  if (self->priv->input_bin_src_caps != NULL) {
    gst_caps_unref (self->priv->input_bin_src_caps);
  }

  gst_event_parse_caps (event, &current_caps);
  self->priv->input_bin_src_caps = gst_caps_copy (current_caps);
  kms_agnostic_bin2_insert_bin (self, GST_BIN (bin));

  GST_INFO_OBJECT (self, "Setting current caps to: %" GST_PTR_FORMAT,
      current_caps);

  kms_element_for_each_src_pad (GST_ELEMENT (self),
      (KmsPadIterationAction) add_linked_pads, self);

  KMS_AGNOSTIC_BIN2_UNLOCK (self);

  return GST_PAD_PROBE_REMOVE;
}
Example #17
0
static GstPadProbeReturn
accept_eos_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
{
  GstEvent *event = gst_pad_probe_info_get_event (info);

  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
    KmsElement *self;
    gboolean accept;

    self = KMS_ELEMENT (data);
    KMS_ELEMENT_LOCK (self);
    accept = self->priv->accept_eos;
    KMS_ELEMENT_UNLOCK (self);

    if (!accept)
      GST_DEBUG_OBJECT (pad, "Eos dropped");

    return (accept) ? GST_PAD_PROBE_OK : GST_PAD_PROBE_DROP;
  }

  return GST_PAD_PROBE_OK;
}
Example #18
0
static GstPadProbeReturn
gst_hls_sink_ghost_event_probe (GstPad * pad, GstPadProbeInfo * info,
    gpointer data)
{
  GstHlsSink *sink = GST_HLS_SINK_CAST (data);
  GstEvent *event = gst_pad_probe_info_get_event (info);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEGMENT:
    {
      gst_event_copy_segment (event, &sink->segment);
      break;
    }
    case GST_EVENT_FLUSH_STOP:
      gst_segment_init (&sink->segment, GST_FORMAT_UNDEFINED);
      break;
    case GST_EVENT_CUSTOM_DOWNSTREAM:
    {
      GstClockTime timestamp;
      GstClockTime running_time, stream_time;
      gboolean all_headers;
      guint count;

      if (!gst_video_event_is_force_key_unit (event))
        break;

      gst_event_replace (&sink->force_key_unit_event, event);
      gst_video_event_parse_downstream_force_key_unit (event,
          &timestamp, &stream_time, &running_time, &all_headers, &count);
      GST_INFO_OBJECT (sink, "setting index %d", count);
      sink->index = count;
      break;
    }
    default:
      break;
  }

  return GST_PAD_PROBE_OK;
}
static GstPadProbeReturn
configure_pipeline_capabilities (GstPad * pad, GstPadProbeInfo * info,
    gpointer user_data)
{
  GstEvent *event = gst_pad_probe_info_get_event (info);
  DataEvtProbe *data = user_data;
  GstElement *appsrc = data->appsrc;
  GstElement *appsink;
  GstCaps *caps;

  if (GST_EVENT_TYPE (event) != GST_EVENT_CAPS)
    return GST_PAD_PROBE_OK;

  gst_event_parse_caps (event, &caps);

  GST_DEBUG_OBJECT (appsrc, "Processing caps event %" GST_PTR_FORMAT, caps);

  if (gst_caps_get_size (caps) == 0) {
    GST_ERROR_OBJECT (pad, "Invalid event %" GST_PTR_FORMAT, event);

    return GST_PAD_PROBE_OK;
  }

  if (!gst_caps_is_fixed (caps)) {
    GST_WARNING_OBJECT (pad, "Not fixed caps in event %" GST_PTR_FORMAT, event);
  }

  set_appsrc_caps (appsrc, caps);

  appsink = gst_pad_get_parent_element (pad);

  if (appsink) {
    set_appsink_caps (appsink, caps, data->profile);
    g_object_unref (appsink);
  }

  return GST_PAD_PROBE_OK;
}
static GstPadProbeReturn
handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
{
  GstSplitMuxSink *splitmux = ctx->splitmux;
  MqStreamBuf *buf_info = NULL;

  GST_LOG_OBJECT (pad, "Fired probe type 0x%x\n", info->type);

  /* FIXME: Handle buffer lists, until then make it clear they won't work */
  if (info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST) {
    g_warning ("Buffer list handling not implemented");
    return GST_PAD_PROBE_DROP;
  }
  if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
    GstEvent *event = gst_pad_probe_info_get_event (info);

    GST_LOG_OBJECT (pad, "Event %" GST_PTR_FORMAT, event);

    switch (GST_EVENT_TYPE (event)) {
      case GST_EVENT_SEGMENT:
        gst_event_copy_segment (event, &ctx->out_segment);
        break;
      case GST_EVENT_FLUSH_STOP:
        GST_SPLITMUX_LOCK (splitmux);
        gst_segment_init (&ctx->out_segment, GST_FORMAT_UNDEFINED);
        g_queue_foreach (&ctx->queued_bufs, (GFunc) mq_stream_buf_free, NULL);
        g_queue_clear (&ctx->queued_bufs);
        ctx->flushing = FALSE;
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      case GST_EVENT_FLUSH_START:
        GST_SPLITMUX_LOCK (splitmux);
        GST_LOG_OBJECT (pad, "Flush start");
        ctx->flushing = TRUE;
        GST_SPLITMUX_BROADCAST (splitmux);
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      case GST_EVENT_EOS:
        GST_SPLITMUX_LOCK (splitmux);
        if (splitmux->state == SPLITMUX_STATE_STOPPED)
          goto beach;
        ctx->out_eos = TRUE;
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      case GST_EVENT_GAP:{
        GstClockTime gap_ts;

        gst_event_parse_gap (event, &gap_ts, NULL);
        if (gap_ts == GST_CLOCK_TIME_NONE)
          break;

        GST_SPLITMUX_LOCK (splitmux);

        gap_ts = gst_segment_to_running_time (&ctx->out_segment,
            GST_FORMAT_TIME, gap_ts);

        GST_LOG_OBJECT (pad, "Have GAP w/ ts %" GST_TIME_FORMAT,
            GST_TIME_ARGS (gap_ts));

        if (splitmux->state == SPLITMUX_STATE_STOPPED)
          goto beach;
        ctx->out_running_time = gap_ts;
        complete_or_wait_on_out (splitmux, ctx);
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      }
      default:
        break;
    }
    return GST_PAD_PROBE_PASS;
  }

  /* Allow everything through until the configured next stopping point */
  GST_SPLITMUX_LOCK (splitmux);

  buf_info = g_queue_pop_tail (&ctx->queued_bufs);
  if (buf_info == NULL)
    /* Can only happen due to a poorly timed flush */
    goto beach;

  /* If we have popped a keyframe, decrement the queued_gop count */
  if (buf_info->keyframe && splitmux->queued_gops > 0)
    splitmux->queued_gops--;

  ctx->out_running_time = buf_info->run_ts;

  GST_LOG_OBJECT (splitmux,
      "Pad %" GST_PTR_FORMAT " buffer with TS %" GST_TIME_FORMAT
      " size %" G_GSIZE_FORMAT,
      pad, GST_TIME_ARGS (ctx->out_running_time), buf_info->buf_size);

  complete_or_wait_on_out (splitmux, ctx);

  if (splitmux->muxed_out_time == GST_CLOCK_TIME_NONE ||
      splitmux->muxed_out_time < buf_info->run_ts)
    splitmux->muxed_out_time = buf_info->run_ts;

  splitmux->muxed_out_bytes += buf_info->buf_size;

#ifndef GST_DISABLE_GST_DEBUG
  {
    GstBuffer *buf = gst_pad_probe_info_get_buffer (info);
    GST_LOG_OBJECT (pad, "Returning to pass buffer %" GST_PTR_FORMAT
        " run ts %" GST_TIME_FORMAT, buf,
        GST_TIME_ARGS (ctx->out_running_time));
  }
#endif

  GST_SPLITMUX_UNLOCK (splitmux);

  mq_stream_buf_free (buf_info);

  return GST_PAD_PROBE_PASS;

beach:
  GST_SPLITMUX_UNLOCK (splitmux);
  return GST_PAD_PROBE_DROP;
}
Example #21
0
static GstPadProbeReturn
link_to_videomixer (GstPad * pad, GstPadProbeInfo * info,
    KmsAlphaBlendingData * data)
{
  GstPadTemplate *sink_pad_template;
  KmsAlphaBlending *mixer = data->mixer;

  if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_EVENT (info)) != GST_EVENT_CAPS) {
    return GST_PAD_PROBE_PASS;
  }

  GST_DEBUG ("stream start detected");

  KMS_ALPHA_BLENDING_LOCK (mixer);

  data->link_probe_id = 0;

  sink_pad_template =
      gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (mixer->
          priv->videomixer), "sink_%u");

  if (G_UNLIKELY (sink_pad_template == NULL)) {
    GST_ERROR_OBJECT (mixer, "Error taking a new pad from videomixer");
    KMS_ALPHA_BLENDING_UNLOCK (mixer);
    return GST_PAD_PROBE_DROP;
  }

  if (mixer->priv->master_port == data->id) {
    //master_port, reconfigurate the output_width and heigth_width
    //and all the ports already created
    GstEvent *event;
    GstCaps *caps;
    gint width, height;
    const GstStructure *str;

    event = gst_pad_probe_info_get_event (info);
    gst_event_parse_caps (event, &caps);

    GST_DEBUG ("caps %" GST_PTR_FORMAT, caps);
    if (caps != NULL) {
      str = gst_caps_get_structure (caps, 0);
      if (gst_structure_get_int (str, "width", &width) &&
          gst_structure_get_int (str, "height", &height)) {
        mixer->priv->output_height = height;
        mixer->priv->output_width = width;
      }
    }
  }

  if (mixer->priv->videotestsrc == NULL) {
    GstCaps *filtercaps;
    GstPad *pad;

    mixer->priv->videotestsrc = gst_element_factory_make ("videotestsrc", NULL);
    mixer->priv->videotestsrc_capsfilter =
        gst_element_factory_make ("capsfilter", NULL);

    g_object_set (mixer->priv->videotestsrc, "is-live", TRUE, "pattern",
        /*black */ 2, NULL);

    filtercaps =
        gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "AYUV",
        "width", G_TYPE_INT, mixer->priv->output_width,
        "height", G_TYPE_INT, mixer->priv->output_height,
        "framerate", GST_TYPE_FRACTION, 15, 1, NULL);
    g_object_set (G_OBJECT (mixer->priv->videotestsrc_capsfilter), "caps",
        filtercaps, NULL);
    gst_caps_unref (filtercaps);

    gst_bin_add_many (GST_BIN (mixer), mixer->priv->videotestsrc,
        mixer->priv->videotestsrc_capsfilter, NULL);

    gst_element_link (mixer->priv->videotestsrc,
        mixer->priv->videotestsrc_capsfilter);

    /*link capsfilter -> videomixer */
    pad = gst_element_request_pad (mixer->priv->videomixer,
        sink_pad_template, NULL, NULL);
    gst_element_link_pads (mixer->priv->videotestsrc_capsfilter, NULL,
        mixer->priv->videomixer, GST_OBJECT_NAME (pad));
    g_object_set (pad, "xpos", 0, "ypos", 0, "alpha", 0.0, "zorder", 0, NULL);
    g_object_unref (pad);

    gst_element_sync_state_with_parent (mixer->priv->videotestsrc_capsfilter);
    gst_element_sync_state_with_parent (mixer->priv->videotestsrc);
  }

  data->videoscale = gst_element_factory_make ("videoscale", NULL);
  data->capsfilter = gst_element_factory_make ("capsfilter", NULL);
  data->videorate = gst_element_factory_make ("videorate", NULL);
  data->queue = gst_element_factory_make ("queue", NULL);
  data->videobox = gst_element_factory_make ("videobox", NULL);
  data->input = TRUE;

  gst_bin_add_many (GST_BIN (mixer), data->queue, data->videorate,
      data->videoscale, data->capsfilter, data->videobox, NULL);

  g_object_set (data->videorate, "average-period", 200 * GST_MSECOND, NULL);
  g_object_set (data->queue, "flush-on-eos", TRUE, NULL);

  gst_element_link_many (data->videorate, data->queue, data->videoscale,
      data->capsfilter, data->videobox, NULL);

  /*link capsfilter -> videomixer */
  data->video_mixer_pad =
      gst_element_request_pad (mixer->priv->videomixer,
      sink_pad_template, NULL, NULL);

  gst_element_link_pads (data->videobox, NULL,
      mixer->priv->videomixer, GST_OBJECT_NAME (data->video_mixer_pad));

  gst_element_link (data->videoconvert, data->videorate);

  data->probe_id = gst_pad_add_probe (data->video_mixer_pad,
      GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
      (GstPadProbeCallback) cb_EOS_received,
      KMS_ALPHA_BLENDING_REF (data), (GDestroyNotify) kms_ref_struct_unref);

  gst_element_sync_state_with_parent (data->videoscale);
  gst_element_sync_state_with_parent (data->capsfilter);
  gst_element_sync_state_with_parent (data->videorate);
  gst_element_sync_state_with_parent (data->queue);
  gst_element_sync_state_with_parent (data->videobox);

  /* configure videomixer pad */
  mixer->priv->n_elems++;

  if (mixer->priv->master_port == data->id) {
    kms_alpha_blending_reconfigure_ports (mixer);
  } else {
    configure_port (data);
  }

  KMS_ALPHA_BLENDING_UNLOCK (mixer);

  return GST_PAD_PROBE_REMOVE;
}
static GstPadProbeReturn
handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
{
  GstSplitMuxSink *splitmux = ctx->splitmux;
  GstBuffer *buf;
  MqStreamBuf *buf_info = NULL;
  GstClockTime ts;
  gboolean loop_again;
  gboolean keyframe = FALSE;

  GST_LOG_OBJECT (pad, "Fired probe type 0x%x\n", info->type);

  /* FIXME: Handle buffer lists, until then make it clear they won't work */
  if (info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST) {
    g_warning ("Buffer list handling not implemented");
    return GST_PAD_PROBE_DROP;
  }
  if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
    GstEvent *event = gst_pad_probe_info_get_event (info);
    switch (GST_EVENT_TYPE (event)) {
      case GST_EVENT_SEGMENT:
        gst_event_copy_segment (event, &ctx->in_segment);
        break;
      case GST_EVENT_FLUSH_STOP:
        GST_SPLITMUX_LOCK (splitmux);
        gst_segment_init (&ctx->in_segment, GST_FORMAT_UNDEFINED);
        ctx->in_eos = FALSE;
        ctx->in_bytes = 0;
        ctx->in_running_time = 0;
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      case GST_EVENT_EOS:
        GST_SPLITMUX_LOCK (splitmux);
        ctx->in_eos = TRUE;

        if (splitmux->state == SPLITMUX_STATE_STOPPED)
          goto beach;

        if (ctx->is_video) {
          GST_INFO_OBJECT (splitmux, "Got Video EOS. Finishing up");
          /* Act as if this is a new keyframe with infinite timestamp */
          splitmux->max_in_running_time = GST_CLOCK_TIME_NONE;
          splitmux->state = SPLITMUX_STATE_WAITING_GOP_COMPLETE;
          /* Wake up other input pads to collect this GOP */
          GST_SPLITMUX_BROADCAST (splitmux);
          check_completed_gop (splitmux, ctx);
        } else if (splitmux->state == SPLITMUX_STATE_WAITING_GOP_COMPLETE) {
          /* If we are waiting for a GOP to be completed (ie, for aux
           * pads to catch up), then this pad is complete, so check
           * if the whole GOP is.
           */
          check_completed_gop (splitmux, ctx);
        }
        GST_SPLITMUX_UNLOCK (splitmux);
        break;
      default:
        break;
    }
    return GST_PAD_PROBE_PASS;
  }

  buf = gst_pad_probe_info_get_buffer (info);
  ctx->in_running_time = gst_segment_to_running_time (&ctx->in_segment,
      GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf));
  buf_info = mq_stream_buf_new ();

  if (GST_BUFFER_PTS_IS_VALID (buf))
    ts = GST_BUFFER_PTS (buf);
  else
    ts = GST_BUFFER_DTS (buf);

  GST_SPLITMUX_LOCK (splitmux);

  if (splitmux->state == SPLITMUX_STATE_STOPPED)
    goto beach;

  /* If this buffer has a timestamp, advance the input timestamp of the
   * stream */
  if (GST_CLOCK_TIME_IS_VALID (ts)) {
    GstClockTime running_time =
        gst_segment_to_running_time (&ctx->in_segment, GST_FORMAT_TIME,
        GST_BUFFER_TIMESTAMP (buf));

    if (GST_CLOCK_TIME_IS_VALID (running_time) &&
        (ctx->in_running_time == GST_CLOCK_TIME_NONE
            || running_time > ctx->in_running_time))
      ctx->in_running_time = running_time;
  }

  /* Try to make sure we have a valid running time */
  if (!GST_CLOCK_TIME_IS_VALID (ctx->in_running_time)) {
    ctx->in_running_time =
        gst_segment_to_running_time (&ctx->in_segment, GST_FORMAT_TIME,
        ctx->in_segment.start);
  }

  buf_info->run_ts = ctx->in_running_time;
  buf_info->buf_size = gst_buffer_get_size (buf);

  /* Update total input byte counter for overflow detect */
  ctx->in_bytes += buf_info->buf_size;

  GST_DEBUG_OBJECT (pad, "Buf TS %" GST_TIME_FORMAT
      " total in_bytes %" G_GSIZE_FORMAT,
      GST_TIME_ARGS (buf_info->run_ts), ctx->in_bytes);

  loop_again = TRUE;
  do {
    if (ctx->flushing)
      break;

    switch (splitmux->state) {
      case SPLITMUX_STATE_COLLECTING_GOP_START:
        if (ctx->is_video) {
          /* If a keyframe, we have a complete GOP */
          if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ||
              !GST_CLOCK_TIME_IS_VALID (ctx->in_running_time) ||
              splitmux->max_in_running_time >= ctx->in_running_time) {
            /* Pass this buffer through */
            loop_again = FALSE;
            break;
          }
          GST_INFO_OBJECT (pad,
              "Have keyframe with running time %" GST_TIME_FORMAT,
              GST_TIME_ARGS (ctx->in_running_time));
          keyframe = TRUE;
          splitmux->state = SPLITMUX_STATE_WAITING_GOP_COMPLETE;
          splitmux->max_in_running_time = ctx->in_running_time;
          /* Wake up other input pads to collect this GOP */
          GST_SPLITMUX_BROADCAST (splitmux);
          check_completed_gop (splitmux, ctx);
        } else {
          /* We're still waiting for a keyframe on the video pad, sleep */
          GST_LOG_OBJECT (pad, "Sleeping for GOP start");
          GST_SPLITMUX_WAIT (splitmux);
          GST_LOG_OBJECT (pad, "Done sleeping for GOP start state now %d",
              splitmux->state);
        }
        break;
      case SPLITMUX_STATE_WAITING_GOP_COMPLETE:
        /* After a GOP start is found, this buffer might complete the GOP */
        /* If we overran the target timestamp, it might be time to process
         * the GOP, otherwise bail out for more data
         */
        GST_LOG_OBJECT (pad,
            "Checking TS %" GST_TIME_FORMAT " against max %" GST_TIME_FORMAT,
            GST_TIME_ARGS (ctx->in_running_time),
            GST_TIME_ARGS (splitmux->max_in_running_time));

        if (ctx->in_running_time < splitmux->max_in_running_time) {
          loop_again = FALSE;
          break;
        }

        GST_LOG_OBJECT (pad,
            "Collected last packet of GOP. Checking other pads");
        check_completed_gop (splitmux, ctx);
        break;
      case SPLITMUX_STATE_ENDING_FILE:
      case SPLITMUX_STATE_START_NEXT_FRAGMENT:
        /* A fragment is ending, wait until that's done before continuing */
        GST_DEBUG_OBJECT (pad, "Sleeping for fragment restart");
        GST_SPLITMUX_WAIT (splitmux);
        GST_DEBUG_OBJECT (pad,
            "Done sleeping for fragment restart state now %d", splitmux->state);
        break;
      default:
        loop_again = FALSE;
        break;
    }
  } while (loop_again);

  if (keyframe) {
    splitmux->queued_gops++;
    buf_info->keyframe = TRUE;
  }

  /* Now add this buffer to the queue just before returning */
  g_queue_push_head (&ctx->queued_bufs, buf_info);

  /* Check the buffer will fit in the mq */
  check_queue_length (splitmux, ctx);

  GST_LOG_OBJECT (pad, "Returning to queue buffer %" GST_PTR_FORMAT
      " run ts %" GST_TIME_FORMAT, buf, GST_TIME_ARGS (ctx->in_running_time));

  GST_SPLITMUX_UNLOCK (splitmux);
  return GST_PAD_PROBE_PASS;

beach:
  GST_SPLITMUX_UNLOCK (splitmux);
  if (buf_info)
    mq_stream_buf_free (buf_info);
  return GST_PAD_PROBE_PASS;
}