void GStreamerGWorld::exitFullscreen()
{
    if (!m_dynamicPadName)
        return;

    GstElement* sinkPtr = 0;
    g_object_get(m_pipeline, "video-sink", &sinkPtr, NULL);
    GRefPtr<GstElement> videoSink = adoptGRef(sinkPtr);

    GRefPtr<GstElement> tee = adoptGRef(gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoTee"));
    GRefPtr<GstPad> srcPad = adoptGRef(gst_element_get_static_pad(tee.get(), m_dynamicPadName.get()));

    // Block data flow towards the pipeline branch to remove. No need
    // for pad blocking if the pipeline is paused.
    GstState state;
    gst_element_get_state(m_pipeline, &state, 0, 0);
#ifdef GST_API_VERSION_1
    if (state >= GST_STATE_PLAYING)
        gst_pad_add_probe(srcPad.get(), GST_PAD_PROBE_TYPE_IDLE, reinterpret_cast<GstPadProbeCallback>(gstGWorldPadProbeCallback), this, 0);
    else
#else
    if (state < GST_STATE_PLAYING || gst_pad_set_blocked(srcPad.get(), true))
#endif
        removePlatformVideoSink();

    m_videoWindow = 0;
}
void GStreamerGWorld::exitFullscreen()
{
    if (!m_dynamicPadName)
        return;

    // Get video sink bin and the elements to remove.
    GOwnPtr<GstElement> videoSink;
    g_object_get(m_pipeline, "video-sink", &videoSink.outPtr(), NULL);
    GstElement* tee = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoTee");
    GstElement* platformVideoSink = gst_bin_get_by_name(GST_BIN(videoSink.get()), "platformVideoSink");
    GstElement* queue = gst_bin_get_by_name(GST_BIN(videoSink.get()), "queue");
    GstElement* colorspace = gst_bin_get_by_name(GST_BIN(videoSink.get()), "colorspace");
    GstElement* videoScale = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoScale");

    // Get pads to unlink and remove.
    GstPad* srcPad = gst_element_get_static_pad(tee, m_dynamicPadName);
    GstPad* sinkPad = gst_element_get_static_pad(queue, "sink");

    // Block data flow towards the pipeline branch to remove. No need
    // for pad blocking if the pipeline is paused.
    GstState state;
    gst_element_get_state(m_pipeline, &state, 0, 0);
    if (state < GST_STATE_PLAYING || gst_pad_set_blocked(srcPad, true)) {

        // Unlink and release request pad.
        gst_pad_unlink(srcPad, sinkPad);
        gst_element_release_request_pad(tee, srcPad);

        // Unlink, remove and cleanup queue, ffmpegcolorspace, videoScale and sink.
        gst_element_unlink_many(queue, colorspace, videoScale, platformVideoSink, NULL);
        gst_bin_remove_many(GST_BIN(videoSink.get()), queue, colorspace, videoScale, platformVideoSink, NULL);
        gst_element_set_state(platformVideoSink, GST_STATE_NULL);
        gst_element_set_state(videoScale, GST_STATE_NULL);
        gst_element_set_state(colorspace, GST_STATE_NULL);
        gst_element_set_state(queue, GST_STATE_NULL);
    }

    gst_object_unref(GST_OBJECT(srcPad));
    gst_object_unref(GST_OBJECT(sinkPad));

    gst_object_unref(queue);
    gst_object_unref(colorspace);
    gst_object_unref(videoScale);
    gst_object_unref(platformVideoSink);

    gst_object_unref(tee);
    m_dynamicPadName = 0;
}
void GStreamerGWorld::exitFullscreen()
{
    if (!m_dynamicPadName)
        return;

    // Get video sink bin and the elements to remove.
    GRefPtr<GstElement> videoSink;
    GstElement* sinkPtr = 0;

    g_object_get(m_pipeline, "video-sink", &sinkPtr, NULL);
    videoSink = adoptGRef(sinkPtr);

    GRefPtr<GstElement> tee = adoptGRef(gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoTee"));
    GRefPtr<GstElement> platformVideoSink = adoptGRef(gst_bin_get_by_name(GST_BIN(videoSink.get()), "platformVideoSink"));
    GRefPtr<GstElement> queue = adoptGRef(gst_bin_get_by_name(GST_BIN(videoSink.get()), "queue"));
    GRefPtr<GstElement> colorspace = adoptGRef(gst_bin_get_by_name(GST_BIN(videoSink.get()), "colorspace"));
    GRefPtr<GstElement> videoScale = adoptGRef(gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoScale"));

    // Get pads to unlink and remove.
    GRefPtr<GstPad> srcPad = adoptGRef(gst_element_get_static_pad(tee.get(), m_dynamicPadName.get()));
    GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(queue.get(), "sink"));

    // Block data flow towards the pipeline branch to remove. No need
    // for pad blocking if the pipeline is paused.
    GstState state;
    gst_element_get_state(m_pipeline, &state, 0, 0);
    if (state < GST_STATE_PLAYING || gst_pad_set_blocked(srcPad.get(), true)) {

        // Unlink and release request pad.
        gst_pad_unlink(srcPad.get(), sinkPad.get());
        gst_element_release_request_pad(tee.get(), srcPad.get());

        // Unlink, remove and cleanup queue, ffmpegcolorspace, videoScale and sink.
        gst_element_unlink_many(queue.get(), colorspace.get(), videoScale.get(), platformVideoSink.get(), NULL);
        gst_bin_remove_many(GST_BIN(videoSink.get()), queue.get(), colorspace.get(), videoScale.get(), platformVideoSink.get(), NULL);
        gst_element_set_state(platformVideoSink.get(), GST_STATE_NULL);
        gst_element_set_state(videoScale.get(), GST_STATE_NULL);
        gst_element_set_state(colorspace.get(), GST_STATE_NULL);
        gst_element_set_state(queue.get(), GST_STATE_NULL);
    }

    m_dynamicPadName.clear();
}
Beispiel #4
0
static void
test_with_caps (GstElement * src, GstElement * videocrop, GstCaps * caps)
{
    GstClockTime time_run;
    GstElement *pipeline;
    GTimer *timer;
    GstBus *bus;
    GstPad *pad;
    guint hcrop;
    guint vcrop;

    /* caps must be writable, we can't check that here though */
    g_assert (GST_CAPS_REFCOUNT_VALUE (caps) == 1);

    timer = g_timer_new ();
    vcrop = 0;
    hcrop = 0;

    pipeline = GST_ELEMENT (gst_element_get_parent (videocrop));
    g_assert (GST_IS_PIPELINE (pipeline));

    /* at this point the pipeline is in PLAYING state; we only want to capture
     * errors resulting from our on-the-fly changing of the filtercaps */
    bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));

    /* pad to block */
    pad = gst_element_get_static_pad (src, "src");

    time_run = 0;
    do {
        GstClockTime wait_time, waited_for_block;

        if (check_bus_for_errors (bus, 0))
            break;

        wait_time = GST_SECOND / FRAMERATE;

        GST_LOG ("hcrop = %3d, vcrop = %3d", vcrop, hcrop);

        g_timer_reset (timer);

        /* need to block the streaming thread while changing these properties,
         * otherwise we might get random not-negotiated errors (when caps are
         * changed in between upstream calling pad_alloc_buffer() and pushing
         * the processed buffer?) */
        gst_pad_set_blocked (pad, TRUE);
        g_object_set (videocrop, "left", hcrop, "top", vcrop, NULL);
        gst_pad_set_blocked (pad, FALSE);

        waited_for_block = g_timer_elapsed (timer, NULL) * (double) GST_SECOND;
        /* GST_LOG ("waited: %" GST_TIME_FORMAT ", frame len: %" GST_TIME_FORMAT,
           GST_TIME_ARGS (waited_for_block), GST_TIME_ARGS (wait_time)); */
        ++vcrop;
        ++hcrop;

        if (wait_time > waited_for_block) {
            g_usleep ((wait_time - waited_for_block) / GST_MSECOND);
        }

        time_run += wait_time;
    }
    while (time_run < (TIME_PER_TEST * GST_SECOND));

    g_timer_destroy (timer);
    gst_object_unref (bus);
    gst_object_unref (pad);
}
Beispiel #5
0
static gboolean
gst_switch_commit_new_kid (GstSwitchSink * sink)
{
  GstPad *targetpad;
  GstState kid_state;
  GstElement *new_kid, *old_kid;
  gboolean is_fakesink = FALSE;
  GstBus *bus;

  /* need locking around member accesses */
  GST_OBJECT_LOCK (sink);
  /* If we're currently changing state, set the child to the next state
   * we're transitioning too, rather than our current state which is 
   * about to change */
  if (GST_STATE_NEXT (sink) != GST_STATE_VOID_PENDING)
    kid_state = GST_STATE_NEXT (sink);
  else
    kid_state = GST_STATE (sink);

  new_kid = sink->new_kid;
  sink->new_kid = NULL;
  GST_OBJECT_UNLOCK (sink);

  /* Fakesink by default if NULL is passed as the new child */
  if (new_kid == NULL) {
    GST_DEBUG_OBJECT (sink, "Replacing kid with fakesink");
    new_kid = gst_element_factory_make ("fakesink", "testsink");
    if (new_kid == NULL) {
      GST_ERROR_OBJECT (sink, "Failed to create fakesink");
      return FALSE;
    }
    /* Add a reference, as it would if the element came from sink->new_kid */
    gst_object_ref (new_kid);
    g_object_set (new_kid, "sync", TRUE, NULL);
    is_fakesink = TRUE;
  } else {
    GST_DEBUG_OBJECT (sink, "Setting new kid");
  }

  /* set temporary bus of our own to catch error messages from the child
   * (could we just set our own bus on it, or would the state change messages
   * from the not-yet-added element confuse the state change algorithm? Let's
   * play it safe for now) */
  bus = gst_bus_new ();
  gst_element_set_bus (new_kid, bus);
  gst_object_unref (bus);

  if (gst_element_set_state (new_kid, kid_state) == GST_STATE_CHANGE_FAILURE) {
    GstMessage *msg;

    /* check if child posted an error message and if so re-post it on our bus
     * so that the application gets to see a decent error and not our generic
     * fallback error message which is completely indecipherable to the user */
    msg = gst_bus_pop_filtered (GST_ELEMENT_BUS (new_kid), GST_MESSAGE_ERROR);
    if (msg) {
      GST_INFO_OBJECT (sink, "Forwarding kid error: %" GST_PTR_FORMAT, msg);
      gst_element_post_message (GST_ELEMENT (sink), msg);
    }
    /* FIXME: need a translated error message that tells the user to check
     * her GConf audio/video settings */
    GST_ELEMENT_ERROR (sink, CORE, STATE_CHANGE, (NULL),
        ("Failed to set state on new child."));
    gst_element_set_bus (new_kid, NULL);
    gst_object_unref (new_kid);
    return FALSE;
  }
  gst_element_set_bus (new_kid, NULL);
  gst_bin_add (GST_BIN (sink), new_kid);

  /* Now, replace the existing child */
  GST_OBJECT_LOCK (sink);
  old_kid = sink->kid;
  sink->kid = new_kid;
  /* Mark whether a custom kid or fakesink has been installed */
  sink->have_kid = !is_fakesink;
  GST_OBJECT_UNLOCK (sink);

  /* kill old element */
  if (old_kid) {
    GST_DEBUG_OBJECT (sink, "Removing old kid %" GST_PTR_FORMAT, old_kid);
    gst_element_set_state (old_kid, GST_STATE_NULL);
    gst_bin_remove (GST_BIN (sink), old_kid);
    gst_object_unref (old_kid);
  }

  /* re-attach ghostpad */
  GST_DEBUG_OBJECT (sink, "Creating new ghostpad");
  targetpad = gst_element_get_static_pad (sink->kid, "sink");
  gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
  gst_object_unref (targetpad);
  GST_DEBUG_OBJECT (sink, "done changing child of switchsink");

  /* FIXME: Push new-segment info and pre-roll buffer(s) into the kid */

  /* Unblock the target pad if necessary */
  if (sink->awaiting_block) {
    gst_pad_set_blocked (sink->pad, FALSE);
    sink->awaiting_block = FALSE;
  }

  return TRUE;
}