static gboolean
gst_play_sink_convert_bin_sink_setcaps (GstPlaySinkConvertBin * self,
    GstCaps * caps)
{
  GstStructure *s;
  const gchar *name;
  gboolean reconfigure = FALSE;
  gboolean raw;

  GST_DEBUG_OBJECT (self, "setcaps");
  GST_PLAY_SINK_CONVERT_BIN_LOCK (self);
  s = gst_caps_get_structure (caps, 0);
  name = gst_structure_get_name (s);

  if (self->audio) {
    raw = g_str_equal (name, "audio/x-raw");
  } else {
    raw = g_str_equal (name, "video/x-raw");
  }

  GST_DEBUG_OBJECT (self, "raw %d, self->raw %d, blocked %d",
      raw, self->raw, gst_pad_is_blocked (self->sink_proxypad));

  if (raw) {
    if (!gst_pad_is_blocked (self->sink_proxypad)) {
      GstPad *target = gst_ghost_pad_get_target (GST_GHOST_PAD (self->sinkpad));

      if (!self->raw || (target && !gst_pad_query_accept_caps (target, caps))) {
        if (!self->raw)
          GST_DEBUG_OBJECT (self, "Changing caps from non-raw to raw");
        else
          GST_DEBUG_OBJECT (self, "Changing caps in an incompatible way");

        reconfigure = TRUE;
        block_proxypad (self);
      }

      if (target)
        gst_object_unref (target);
    }
  } else {
    if (self->raw && !gst_pad_is_blocked (self->sink_proxypad)) {
      GST_DEBUG_OBJECT (self, "Changing caps from raw to non-raw");
      reconfigure = TRUE;
      block_proxypad (self);
    }
  }

  /* Otherwise the setcaps below fails */
  if (reconfigure) {
    gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
    gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);
  }

  GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self);

  GST_DEBUG_OBJECT (self, "Setting sink caps %" GST_PTR_FORMAT, caps);

  return TRUE;
}
static gboolean
gst_auto_video_convert_add_autoconvert (GstAutoVideoConvert * autovideoconvert)
{
  GstPad *pad;

  if (autovideoconvert->autoconvert)
    return TRUE;

  autovideoconvert->autoconvert =
      gst_element_factory_make ("autoconvert", "autoconvertchild");
  if (!autovideoconvert->autoconvert) {
    GST_ERROR_OBJECT (autovideoconvert,
        "Could not create autoconvert instance");
    return FALSE;
  }

  /* first add autoconvert in bin */
  gst_bin_add (GST_BIN (autovideoconvert),
      gst_object_ref (autovideoconvert->autoconvert));

  /* get sinkpad and link it to ghost sink pad */
  pad = gst_element_get_static_pad (autovideoconvert->autoconvert, "sink");
  gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (autovideoconvert->sinkpad),
      pad);
  gst_object_unref (pad);

  /* get srcpad and link it to ghost src pad */
  pad = gst_element_get_static_pad (autovideoconvert->autoconvert, "src");
  gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (autovideoconvert->srcpad), pad);
  gst_object_unref (pad);

  return TRUE;
}
static GstPadProbeReturn
pad_blocked_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
  GstPlaySinkConvertBin *self = user_data;
  GstPad *peer;
  GstCaps *caps;
  gboolean raw;

  if (GST_IS_EVENT (info->data) && !GST_EVENT_IS_SERIALIZED (info->data)) {
    GST_DEBUG_OBJECT (self, "Letting non-serialized event %s pass",
        GST_EVENT_TYPE_NAME (info->data));
    return GST_PAD_PROBE_PASS;
  }

  GST_PLAY_SINK_CONVERT_BIN_LOCK (self);
  GST_DEBUG_OBJECT (self, "Pad blocked");

  /* There must be a peer at this point */
  peer = gst_pad_get_peer (self->sinkpad);
  caps = gst_pad_get_current_caps (peer);
  if (!caps)
    caps = gst_pad_query_caps (peer, NULL);
  gst_object_unref (peer);

  raw = is_raw_caps (caps, self->audio);
  GST_DEBUG_OBJECT (self, "Caps %" GST_PTR_FORMAT " are raw: %d", caps, raw);
  gst_caps_unref (caps);

  if (raw == self->raw)
    goto unblock;
  self->raw = raw;

  gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
  gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);

  if (raw) {
    GST_DEBUG_OBJECT (self, "Switching to raw conversion pipeline");

    if (self->conversion_elements)
      g_list_foreach (self->conversion_elements,
          (GFunc) gst_play_sink_convert_bin_on_element_added, self);
  } else {

    GST_DEBUG_OBJECT (self, "Switch to passthrough pipeline");

    gst_play_sink_convert_bin_on_element_added (self->identity, self);
  }

  gst_play_sink_convert_bin_set_targets (self, !raw);

unblock:
  self->sink_proxypad_block_id = 0;
  GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self);

  return GST_PAD_PROBE_REMOVE;
}
static gboolean
gst_play_sink_video_convert_sink_setcaps (GstPad * pad, GstCaps * caps)
{
    GstPlaySinkVideoConvert *self =
        GST_PLAY_SINK_VIDEO_CONVERT (gst_pad_get_parent (pad));
    gboolean ret;
    GstStructure *s;
    const gchar *name;
    gboolean reconfigure = FALSE;

    GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
    s = gst_caps_get_structure (caps, 0);
    name = gst_structure_get_name (s);

    if (g_str_has_prefix (name, "video/x-raw-")) {
        if (!self->raw && !gst_pad_is_blocked (self->sink_proxypad)) {
            GST_DEBUG_OBJECT (self, "Changing caps from non-raw to raw");
            reconfigure = TRUE;
            gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
                                            (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
                                            (GDestroyNotify) gst_object_unref);
        }
    } else {
        if (self->raw && !gst_pad_is_blocked (self->sink_proxypad)) {
            GST_DEBUG_OBJECT (self, "Changing caps from raw to non-raw");
            reconfigure = TRUE;
            gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
                                            (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
                                            (GDestroyNotify) gst_object_unref);
        }
    }

    /* Otherwise the setcaps below fails */
    if (reconfigure) {
        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);
    }
    GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);

    ret = gst_ghost_pad_setcaps_default (pad, caps);

    GST_DEBUG_OBJECT (self, "Setting sink caps %" GST_PTR_FORMAT ": %d", caps,
                      ret);

    gst_object_unref (self);

    return ret;
}
Example #5
0
static GstCaps *
gst_play_sink_audio_convert_getcaps (GstPad * pad)
{
  GstPlaySinkAudioConvert *self =
      GST_PLAY_SINK_AUDIO_CONVERT (gst_pad_get_parent (pad));
  GstCaps *ret;
  GstPad *otherpad, *peer = NULL;

  GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
  otherpad = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (pad));
  GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);

  if (otherpad) {
    peer = gst_pad_get_peer (otherpad);
    gst_object_unref (otherpad);
    otherpad = NULL;
  }

  if (peer) {
    ret = gst_pad_get_caps_reffed (peer);
    gst_object_unref (peer);
  } else {
    ret = gst_caps_new_any ();
  }

  gst_object_unref (self);

  return ret;
}
static void
gst_play_sink_video_convert_init (GstPlaySinkVideoConvert * self)
{
    GstPadTemplate *templ;

    self->lock = g_mutex_new ();
    gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);

    templ = gst_static_pad_template_get (&sinktemplate);
    self->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink", templ);
    gst_pad_set_event_function (self->sinkpad,
                                GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_sink_event));
    gst_pad_set_setcaps_function (self->sinkpad,
                                  GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_sink_setcaps));
    gst_pad_set_getcaps_function (self->sinkpad,
                                  GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_getcaps));

    self->sink_proxypad =
        GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (self->sinkpad)));

    gst_element_add_pad (GST_ELEMENT_CAST (self), self->sinkpad);
    gst_object_unref (templ);

    templ = gst_static_pad_template_get (&srctemplate);
    self->srcpad = gst_ghost_pad_new_no_target_from_template ("src", templ);
    gst_pad_set_getcaps_function (self->srcpad,
                                  GST_DEBUG_FUNCPTR (gst_play_sink_video_convert_getcaps));
    gst_element_add_pad (GST_ELEMENT_CAST (self), self->srcpad);
    gst_object_unref (templ);

    gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
                              self->sink_proxypad);
}
static void
gst_auto_video_convert_remove_autoconvert (GstAutoVideoConvert *
    autovideoconvert)
{
  if (!autovideoconvert->autoconvert)
    return;

  gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (autovideoconvert->srcpad),
      NULL);
  gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (autovideoconvert->sinkpad),
      NULL);

  gst_bin_remove (GST_BIN (autovideoconvert), autovideoconvert->autoconvert);
  gst_object_unref (autovideoconvert->autoconvert);
  autovideoconvert->autoconvert = NULL;
}
Example #8
0
GstPad *
gst_ghost_pad_new_from_template (const gchar * name, GstPad * target,
    GstPadTemplate * templ)
{
  GstPad *ret;

  g_return_val_if_fail (GST_IS_PAD (target), NULL);
  g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
  g_return_val_if_fail (templ != NULL, NULL);
  g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) ==
      GST_PAD_DIRECTION (target), NULL);

  GST_LOG ("name:%s, target:%s:%s, templ:%p", GST_STR_NULL (name),
      GST_DEBUG_PAD_NAME (target), templ);

  if ((ret = gst_ghost_pad_new_full (name, GST_PAD_DIRECTION (target), templ)))
    if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
      goto set_target_failed;

  return ret;

  /* ERRORS */
set_target_failed:
  {
    GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
        GST_DEBUG_PAD_NAME (target));
    gst_object_unref (ret);
    return NULL;
  }
}
Example #9
0
EXPORT_C
#endif

GstPad *
gst_ghost_pad_new (const gchar * name, GstPad * target)
{
  GstPad *ret;

  g_return_val_if_fail (GST_IS_PAD (target), NULL);
  g_return_val_if_fail (!gst_pad_is_linked (target), NULL);

  GST_LOG ("name:%s, target:%s:%s", GST_STR_NULL (name),
      GST_DEBUG_PAD_NAME (target));

  if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target))))
    if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
      goto set_target_failed;

  return ret;

  /* ERRORS */
set_target_failed:
  {
    GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
        GST_DEBUG_PAD_NAME (target));
    gst_object_unref (ret);
    return NULL;
  }
}
static GstStateChangeReturn
gst_play_sink_video_convert_change_state (GstElement * element,
        GstStateChange transition)
{
    GstStateChangeReturn ret;
    GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (element);

    switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
        GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
        if (gst_pad_is_blocked (self->sink_proxypad))
            gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
                                            (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
                                            (GDestroyNotify) gst_object_unref);
        GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
        break;
    default:
        break;
    }

    ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
    if (ret == GST_STATE_CHANGE_FAILURE)
        return ret;

    switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
        GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
        gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
        if (self->conv) {
            gst_element_set_state (self->conv, GST_STATE_NULL);
            gst_bin_remove (GST_BIN_CAST (self), self->conv);
            self->conv = NULL;
        }
        if (self->scale) {
            gst_element_set_state (self->scale, GST_STATE_NULL);
            gst_bin_remove (GST_BIN_CAST (self), self->scale);
            self->scale = NULL;
        }
        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
                                  self->sink_proxypad);
        self->raw = FALSE;
        GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
        break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
        GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
        if (!gst_pad_is_blocked (self->sink_proxypad))
            gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE,
                                            (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
                                            (GDestroyNotify) gst_object_unref);
        GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
    default:
        break;
    }

    return ret;
}
Example #11
0
static void
rsn_dec_init (RsnDec * self, RsnDecClass * klass)
{
  GstPadTemplate *templ;

  templ =
      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink");
  g_assert (templ != NULL);
  self->sinkpad =
      GST_GHOST_PAD_CAST (gst_ghost_pad_new_no_target_from_template ("sink",
          templ));
  self->sink_event_func = GST_PAD_EVENTFUNC (self->sinkpad);
  gst_pad_set_event_function (GST_PAD_CAST (self->sinkpad),
      GST_DEBUG_FUNCPTR (rsn_dec_sink_event));

  templ = gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "src");
  g_assert (templ != NULL);
  self->srcpad =
      GST_GHOST_PAD_CAST (gst_ghost_pad_new_no_target_from_template ("src",
          templ));
  gst_element_add_pad (GST_ELEMENT (self), GST_PAD_CAST (self->sinkpad));
  gst_element_add_pad (GST_ELEMENT (self), GST_PAD_CAST (self->srcpad));
}
static void
gst_play_sink_convert_bin_set_targets (GstPlaySinkConvertBin * self,
    gboolean passthrough)
{
  GstPad *pad;
  GstElement *head, *tail;

  GST_DEBUG_OBJECT (self, "Setting pad targets with passthrough %d",
      passthrough);
  if (self->conversion_elements == NULL || passthrough) {
    GST_DEBUG_OBJECT (self, "no conversion elements, using identity (%p) as "
        "head/tail", self->identity);
    if (!passthrough) {
      GST_WARNING_OBJECT (self,
          "Doing passthrough as no converter elements were added");
    }
    head = tail = self->identity;
  } else {
    head = GST_ELEMENT (g_list_first (self->conversion_elements)->data);
    tail = GST_ELEMENT (g_list_last (self->conversion_elements)->data);
    GST_DEBUG_OBJECT (self, "conversion elements in use, picking "
        "head:%s and tail:%s", GST_OBJECT_NAME (head), GST_OBJECT_NAME (tail));
  }

  g_return_if_fail (head != NULL);
  g_return_if_fail (tail != NULL);

  pad = gst_element_get_static_pad (head, "sink");
  GST_DEBUG_OBJECT (self, "Ghosting bin sink pad to %" GST_PTR_FORMAT, pad);
  gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad);
  gst_object_unref (pad);

  pad = gst_element_get_static_pad (tail, "src");
  GST_DEBUG_OBJECT (self, "Ghosting bin src pad to %" GST_PTR_FORMAT, pad);
  gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad);
  gst_object_unref (pad);
}
Example #13
0
static gboolean
make_encodebin (GstTranscodeBin * self)
{
  GstPad *pad;
  GST_INFO_OBJECT (self, "making new encodebin");

  if (!self->profile)
    goto no_profile;

  self->encodebin = gst_element_factory_make ("encodebin", NULL);
  if (!self->encodebin)
    goto no_decodebin;

  g_object_set (self->encodebin, "profile", self->profile, NULL);

  gst_bin_add (GST_BIN (self), self->encodebin);

  pad = gst_element_get_static_pad (self->encodebin, "src");
  if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad)) {

    gst_object_unref (pad);
    GST_ERROR_OBJECT (self, "Could not ghost %" GST_PTR_FORMAT " srcpad",
        self->encodebin);

    return FALSE;
  }
  gst_object_unref (pad);

  return gst_element_sync_state_with_parent (self->encodebin);

  /* ERRORS */
no_decodebin:
  {
    post_missing_plugin_error (GST_ELEMENT_CAST (self), "encodebin");

    GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, (NULL),
        ("No encodebin element, check your installation"));

    return FALSE;
  }
  /* ERRORS */
no_profile:
  {
    GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, (NULL),
        ("No GstEncodingProfile set, can not run."));

    return FALSE;
  }
}
Example #14
0
static void
gst_play_sink_audio_convert_init (GstPlaySinkAudioConvert * self)
{
  GstPadTemplate *templ;

  self->lock = g_mutex_new ();
  gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);

  templ = gst_static_pad_template_get (&sinktemplate);
  self->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink", templ);
  gst_pad_set_event_function (self->sinkpad,
      GST_DEBUG_FUNCPTR (gst_play_sink_audio_convert_sink_event));
  gst_pad_set_setcaps_function (self->sinkpad,
      GST_DEBUG_FUNCPTR (gst_play_sink_audio_convert_sink_setcaps));
  gst_pad_set_getcaps_function (self->sinkpad,
      GST_DEBUG_FUNCPTR (gst_play_sink_audio_convert_getcaps));

  self->sink_proxypad =
      GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (self->sinkpad)));

  gst_element_add_pad (GST_ELEMENT_CAST (self), self->sinkpad);
  gst_object_unref (templ);

  templ = gst_static_pad_template_get (&srctemplate);
  self->srcpad = gst_ghost_pad_new_no_target_from_template ("src", templ);
  gst_pad_set_getcaps_function (self->srcpad,
      GST_DEBUG_FUNCPTR (gst_play_sink_audio_convert_getcaps));
  gst_element_add_pad (GST_ELEMENT_CAST (self), self->srcpad);
  gst_object_unref (templ);

  gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
      self->sink_proxypad);

  /* FIXME: Only create this on demand but for now we need
   * it to always exist because of playsink's volume proxying
   * logic.
   */
  self->volume = gst_element_factory_make ("volume", "volume");
  if (self->volume)
    gst_object_ref_sink (self->volume);
}
Example #15
0
static void
gst_ghost_pad_dispose (GObject * object)
{
  GstPad *pad;
  GstPad *internal;
  GstPad *intpeer;

  pad = GST_PAD (object);

  GST_DEBUG_OBJECT (pad, "dispose");

  GST_PROXY_LOCK (pad);
  internal = GST_PROXY_PAD_INTERNAL (pad);

  gst_pad_set_activatepull_function (internal, NULL);
  gst_pad_set_activatepush_function (internal, NULL);

  g_signal_handler_disconnect (internal, GST_GHOST_PAD_CAST (pad)->notify_id);

  intpeer = gst_pad_get_peer (internal);
  if (intpeer) {
    if (GST_PAD_IS_SRC (internal))
      gst_pad_unlink (internal, intpeer);
    else
      gst_pad_unlink (intpeer, internal);

    gst_object_unref (intpeer);
  }

  GST_PROXY_PAD_INTERNAL (internal) = NULL;

  /* disposes of the internal pad, since the ghostpad is the only possible object
   * that has a refcount on the internal pad. */
  gst_object_unparent (GST_OBJECT_CAST (internal));

  GST_PROXY_UNLOCK (pad);

  G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
}
Example #16
0
static gboolean
make_decodebin (GstTranscodeBin * self)
{
  GstPad *pad;
  GST_INFO_OBJECT (self, "making new decodebin");

  self->decodebin = gst_element_factory_make ("decodebin", NULL);

  if (!self->decodebin)
    goto no_decodebin;

  g_signal_connect (self->decodebin, "pad-added", G_CALLBACK (pad_added_cb),
      self);

  gst_bin_add (GST_BIN (self), self->decodebin);
  pad = gst_element_get_static_pad (self->decodebin, "sink");
  if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad)) {

    gst_object_unref (pad);
    GST_ERROR_OBJECT (self, "Could not ghost %" GST_PTR_FORMAT " sinkpad",
        self->decodebin);

    return FALSE;
  }

  gst_object_unref (pad);
  return TRUE;

  /* ERRORS */
no_decodebin:
  {
    post_missing_plugin_error (GST_ELEMENT_CAST (self), "decodebin");
    GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, (NULL),
        ("No decodebin element, check your installation"));

    return FALSE;
  }
}
static void
pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self)
{
    GstPad *peer;
    GstCaps *caps;
    gboolean raw;

    GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
    self->sink_proxypad_blocked = blocked;
    GST_DEBUG_OBJECT (self, "Pad blocked: %d", blocked);
    if (!blocked)
        goto done;

    /* There must be a peer at this point */
    peer = gst_pad_get_peer (self->sinkpad);
    caps = gst_pad_get_negotiated_caps (peer);
    if (!caps)
        caps = gst_pad_get_caps_reffed (peer);
    gst_object_unref (peer);

    raw = is_raw_caps (caps);
    GST_DEBUG_OBJECT (self, "Caps %" GST_PTR_FORMAT " are raw: %d", caps, raw);
    gst_caps_unref (caps);

    if (raw == self->raw)
        goto unblock;
    self->raw = raw;

    if (raw) {
        GstBin *bin = GST_BIN_CAST (self);
        GstElement *head = NULL, *prev = NULL;
        GstPad *pad;

        GST_DEBUG_OBJECT (self, "Creating raw conversion pipeline");

        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);

        self->conv = gst_element_factory_make ("ffmpegcolorspace", "conv");
        if (self->conv == NULL) {
            post_missing_element_message (self, "ffmpegcolorspace");
            GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN,
                                 (_("Missing element '%s' - check your GStreamer installation."),
                                  "ffmpegcolorspace"), ("video rendering might fail"));
        } else {
            gst_bin_add (bin, self->conv);
            gst_element_sync_state_with_parent (self->conv);
            distribute_running_time (self->conv, &self->segment);
            prev = head = self->conv;
        }

        self->scale = gst_element_factory_make ("videoscale", "scale");
        if (self->scale == NULL) {
            post_missing_element_message (self, "videoscale");
            GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN,
                                 (_("Missing element '%s' - check your GStreamer installation."),
                                  "videoscale"), ("possibly a liboil version mismatch?"));
        } else {
            /* Add black borders if necessary to keep the DAR */
            g_object_set (self->scale, "add-borders", TRUE, NULL);
            gst_bin_add (bin, self->scale);
            gst_element_sync_state_with_parent (self->scale);
            distribute_running_time (self->scale, &self->segment);
            if (prev) {
                if (!gst_element_link_pads_full (prev, "src", self->scale, "sink",
                                                 GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
                    goto link_failed;
            } else {
                head = self->scale;
            }
            prev = self->scale;
        }

        if (head) {
            pad = gst_element_get_static_pad (head, "sink");
            gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad);
            gst_object_unref (pad);
        }

        if (prev) {
            pad = gst_element_get_static_pad (prev, "src");
            gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad);
            gst_object_unref (pad);
        }

        if (!head && !prev) {
            gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
                                      self->sink_proxypad);
        }

        GST_DEBUG_OBJECT (self, "Raw conversion pipeline created");
    } else {
        GstBin *bin = GST_BIN_CAST (self);

        GST_DEBUG_OBJECT (self, "Removing raw conversion pipeline");

        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);

        if (self->conv) {
            gst_element_set_state (self->conv, GST_STATE_NULL);
            gst_bin_remove (bin, self->conv);
            self->conv = NULL;
        }
        if (self->scale) {
            gst_element_set_state (self->scale, GST_STATE_NULL);
            gst_bin_remove (bin, self->scale);
            self->scale = NULL;
        }

        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
                                  self->sink_proxypad);

        GST_DEBUG_OBJECT (self, "Raw conversion pipeline removed");
    }

unblock:
    gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
                                    (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
                                    (GDestroyNotify) gst_object_unref);

done:
    GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
    return;

link_failed:
    {
        GST_ELEMENT_ERROR (self, CORE, PAD,
                           (NULL), ("Failed to configure the video converter."));
        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
                                  self->sink_proxypad);
        gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
                                        (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
                                        (GDestroyNotify) gst_object_unref);
        return;
    }
}
Example #18
0
static GstPad *
gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir,
    GstPadTemplate * templ)
{
  GstPad *ret;
  GstPad *internal;
  GstPadDirection otherdir;

  g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);

  /* OBJECT CREATION */
  if (templ) {
    ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
        "direction", dir, "template", templ, NULL);
  } else {
    ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
        "direction", dir, NULL);
  }

  /* Set directional padfunctions for ghostpad */
  if (dir == GST_PAD_SINK) {
    gst_pad_set_bufferalloc_function (ret,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
    gst_pad_set_chain_function (ret,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
  } else {
    gst_pad_set_getrange_function (ret,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
    gst_pad_set_checkgetrange_function (ret,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
  }

  /* link/unlink functions */
  gst_pad_set_link_function (ret, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_link));
  gst_pad_set_unlink_function (ret,
      GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink));


  /* INTERNAL PAD, it always exists and is child of the ghostpad */
  otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC;
  if (templ) {
    internal =
        g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
        "direction", otherdir, "template", templ, NULL);
  } else {
    internal =
        g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
        "direction", otherdir, NULL);
  }
  GST_PAD_UNSET_FLUSHING (internal);

  /* Set directional padfunctions for internal pad */
  if (dir == GST_PAD_SRC) {
    gst_pad_set_bufferalloc_function (internal,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
    gst_pad_set_chain_function (internal,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
  } else {
    gst_pad_set_getrange_function (internal,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
    gst_pad_set_checkgetrange_function (internal,
        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
  }

  GST_PROXY_LOCK (ret);

  /* now make the ghostpad a parent of the internal pad */
  if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
          GST_OBJECT_CAST (ret)))
    goto parent_failed;

  /* The ghostpad is the parent of the internal pad and is the only object that
   * can have a refcount on the internal pad.
   * At this point, the GstGhostPad has a refcount of 1, and the internal pad has
   * a refcount of 1.
   * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
   * it's refcount on the internal pad in the dispose method by un-parenting it.
   * This is why we don't take extra refcounts in the assignments below
   */
  GST_PROXY_PAD_INTERNAL (ret) = internal;
  GST_PROXY_PAD_INTERNAL (internal) = ret;

  /* could be more general here, iterating over all writable properties...
   * taking the short road for now tho */
  GST_GHOST_PAD_CAST (ret)->notify_id =
      g_signal_connect (internal, "notify::caps", G_CALLBACK (on_int_notify),
      ret);

  /* call function to init values of the pad caps */
  on_int_notify (internal, NULL, GST_GHOST_PAD_CAST (ret));

  /* special activation functions for the internal pad */
  gst_pad_set_activatepull_function (internal,
      GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_pull));
  gst_pad_set_activatepush_function (internal,
      GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_push));

  GST_PROXY_UNLOCK (ret);

  return ret;

  /* ERRORS */
parent_failed:
  {
    GST_WARNING_OBJECT (ret, "Could not set internal pad %s:%s",
        GST_DEBUG_PAD_NAME (internal));
    g_critical ("Could not set internal pad %s:%s",
        GST_DEBUG_PAD_NAME (internal));
    GST_PROXY_UNLOCK (ret);
    gst_object_unref (ret);
    gst_object_unref (internal);
    return NULL;
  }
}
static gboolean
gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin)
{
  GstElement *capsfilter;
  GstCaps *caps;
  GstPad *queue_srcpad, *bin_srcpad, *capsfilter_sinkpad, *vpp_srcpad;
  gboolean res;
  gboolean has_vpp;

  g_object_set (G_OBJECT (vaapidecbin->queue),
      "max-size-bytes", vaapidecbin->max_size_bytes,
      "max-size-buffers", vaapidecbin->max_size_buffers,
      "max-size-time", vaapidecbin->max_size_time, NULL);

  if (vaapidecbin->disable_vpp || vaapidecbin->configured)
    return TRUE;

  has_vpp = _gst_vaapi_has_video_processing;

  if (!has_vpp && (vaapidecbin->deinterlace_method ==
          GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE
          || vaapidecbin->deinterlace_method ==
          GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED)) {
    GST_ERROR_OBJECT (vaapidecbin,
        "Don't have VPP support but advanced deinterlacing selected");
    return FALSE;
  }

  GST_INFO_OBJECT (vaapidecbin, "enabling VPP");

  /* capsfilter to avoid negotiation with vaapidecode */
  caps = gst_caps_from_string
      ("video/x-raw(memory:VASurface), format=(string)NV12");
  if (!caps)
    goto error_cannot_set_caps;
  capsfilter = gst_element_factory_make ("capsfilter", NULL);
  g_object_set (capsfilter, "caps", caps, NULL);
  gst_caps_unref (caps);

  /* create the postproc */
  vaapidecbin->postproc = gst_element_factory_make ("vaapipostproc", NULL);
  if (!vaapidecbin->postproc)
    goto error_vpp_missing;
  g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method",
      vaapidecbin->deinterlace_method, NULL);

  gst_bin_add_many (GST_BIN (vaapidecbin), capsfilter, vaapidecbin->postproc,
      NULL);

  if (!gst_element_link (capsfilter, vaapidecbin->postproc))
    goto error_sync_state;

  if (!gst_element_sync_state_with_parent (capsfilter))
    goto error_sync_state;
  if (!gst_element_sync_state_with_parent (vaapidecbin->postproc))
    goto error_sync_state;

  /* break source ghost pad target */
  bin_srcpad =
      gst_element_get_static_pad (GST_ELEMENT_CAST (vaapidecbin), "src");
  if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (bin_srcpad), NULL))
    goto error_link_pad;

  /* link decoder and queue */
  queue_srcpad = gst_element_get_static_pad (vaapidecbin->queue, "src");
  capsfilter_sinkpad = gst_element_get_static_pad (capsfilter, "sink");
  res = (gst_pad_link (queue_srcpad, capsfilter_sinkpad) == GST_PAD_LINK_OK);
  gst_object_unref (capsfilter_sinkpad);
  gst_object_unref (queue_srcpad);
  if (!res)
    goto error_link_pad;

  /* set vpp source pad as source ghost pad target */
  vpp_srcpad = gst_element_get_static_pad (vaapidecbin->postproc, "src");
  res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (bin_srcpad), vpp_srcpad);
  gst_object_unref (vpp_srcpad);
  if (!res)
    goto error_link_pad;

  gst_object_unref (bin_srcpad);
  vaapidecbin->configured = TRUE;

  return TRUE;

  /* ERRORS */
error_cannot_set_caps:
  {
    GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD,
        ("Failed to configure caps for VA Surfaces."), (NULL));
    return FALSE;
  }
error_vpp_missing:
  {
    post_missing_element_message (vaapidecbin, "vaapipostproc");
    return FALSE;
  }
error_sync_state:
  {
    GST_ELEMENT_ERROR (vaapidecbin, CORE, STATE_CHANGE,
        ("Failed to sync state of vaapipostproc"), (NULL));
    return FALSE;
  }
error_link_pad:
  {
    gst_object_unref (bin_srcpad);
    GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD,
        ("Failed to configure the vaapidecodebin."), (NULL));
    return FALSE;
  }
}
Example #20
0
static void
do_element_stats (GstStatsTracer * self, GstPad * pad, GstClockTime elapsed1,
    GstClockTime elapsed2)
{
  GstClockTimeDiff elapsed = GST_CLOCK_DIFF (elapsed1, elapsed2);
  GstObject *parent = GST_OBJECT_PARENT (pad);
  GstElement *this =
      GST_ELEMENT_CAST (GST_IS_PAD (parent) ? GST_OBJECT_PARENT (parent) :
      parent);
  GstElementStats *this_stats = get_element_stats (self, this);
  GstPad *peer_pad = GST_PAD_PEER (pad);
  GstElementStats *peer_stats;

  if (!peer_pad)
    return;

  /* walk the ghost pad chain downstream to get the real pad */
  /* if parent of peer_pad is a ghost-pad, then peer_pad is a proxy_pad */
  parent = GST_OBJECT_PARENT (peer_pad);
  if (parent && GST_IS_GHOST_PAD (parent)) {
    peer_pad = GST_PAD_CAST (parent);
    /* if this is now the ghost pad, get the peer of this */
    get_pad_stats (self, peer_pad);
    if ((parent = GST_OBJECT_PARENT (peer_pad))) {
      get_element_stats (self, GST_ELEMENT_CAST (parent));
    }
    peer_pad = GST_PAD_PEER (GST_GHOST_PAD_CAST (peer_pad));
    parent = peer_pad ? GST_OBJECT_PARENT (peer_pad) : NULL;
  }
  /* walk the ghost pad chain upstream to get the real pad */
  /* if peer_pad is a ghost-pad, then parent is a bin and it is the parent of
   * a proxy_pad */
  while (peer_pad && GST_IS_GHOST_PAD (peer_pad)) {
    get_pad_stats (self, peer_pad);
    get_element_stats (self, GST_ELEMENT_CAST (parent));
    peer_pad = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (peer_pad));
    parent = peer_pad ? GST_OBJECT_PARENT (peer_pad) : NULL;
  }

  if (!parent) {
    printf ("%" GST_TIME_FORMAT
        " transmission on unparented target pad %s_%s -> %s_%s\n",
        GST_TIME_ARGS (elapsed), GST_DEBUG_PAD_NAME (pad),
        GST_DEBUG_PAD_NAME (peer_pad));
    return;
  }
  peer_stats = get_element_stats (self, GST_ELEMENT_CAST (parent));

  /* we'd like to gather time spend in each element, but this does not make too
   * much sense yet
   * pure push/pull-based:
   *   - the time spend in the push/pull_range is accounted for the peer and
   *     removed from the current element
   *   - this works for chains
   *   - drawback is sink elements that block to sync have a high time usage
   *     - we could rerun the ests with sync=false
   * both:
   *   - a.g. demuxers both push and pull. thus we subtract time for the pull
   *     and the push operations, but never add anything.
   *   - can we start a counter after push/pull in such elements and add then
   *     time to the element upon next pad activity?
   */
#if 1
  /* this does not make sense for demuxers */
  this_stats->treal -= elapsed;
  peer_stats->treal += elapsed;
#else
  /* this creates several >100% figures */
  this_stats->treal += GST_CLOCK_DIFF (this_stats->last_ts, elapsed2) - elapsed;
  peer_stats->treal += elapsed;
  this_stats->last_ts = elapsed2;
  peer_stats->last_ts = elapsed2;
#endif
}
static gboolean
activate_vpp (GstVaapiDecodeBin * vaapidecbin)
{
  GstPad *queue_srcpad, *srcpad, *vpp_sinkpad, *vpp_srcpad;
  gboolean res;

  if (vaapidecbin->postproc)
    return TRUE;

  if (vaapidecbin->has_vpp != HAS_VPP_YES || vaapidecbin->disable_vpp)
    return TRUE;

  GST_DEBUG_OBJECT (vaapidecbin, "Enabling VPP");

  /* create the postproc */
  vaapidecbin->postproc =
      gst_element_factory_make ("vaapipostproc", "vaapipostproc");
  if (!vaapidecbin->postproc)
    goto error_element_missing;

  g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method",
      vaapidecbin->deinterlace_method, NULL);

  gst_bin_add (GST_BIN (vaapidecbin), vaapidecbin->postproc);

  if (!gst_element_sync_state_with_parent (vaapidecbin->postproc))
    goto error_sync_state;

  srcpad = gst_element_get_static_pad (GST_ELEMENT_CAST (vaapidecbin), "src");
  if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (srcpad), NULL))
    goto error_link_pad;

  queue_srcpad = gst_element_get_static_pad (vaapidecbin->queue, "src");
  vpp_sinkpad = gst_element_get_static_pad (vaapidecbin->postproc, "sink");
  res = (gst_pad_link (queue_srcpad, vpp_sinkpad) == GST_PAD_LINK_OK);
  gst_object_unref (vpp_sinkpad);
  gst_object_unref (queue_srcpad);
  if (!res)
    goto error_link_pad;

  vpp_srcpad = gst_element_get_static_pad (vaapidecbin->postproc, "src");
  res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (srcpad), vpp_srcpad);
  gst_object_unref (vpp_srcpad);
  if (!res)
    goto error_link_pad;

  gst_object_unref (srcpad);

  return TRUE;

error_element_missing:
  {
    post_missing_element_message (vaapidecbin, "vaapipostproc");
    return FALSE;
  }
error_sync_state:
  {
    GST_ERROR_OBJECT (vaapidecbin, "Failed to sync VPP state");
    return FALSE;
  }
error_link_pad:
  {
    gst_object_unref (srcpad);
    GST_ERROR_OBJECT (vaapidecbin, "Failed to link the child elements");
    return FALSE;
  }
}