Ejemplo n.º 1
0
void AudioFileReader::handleNewDeinterleavePad(GstPad* pad)
{
    // A new pad for a planar channel was added in deinterleave. Plug
    // in an appsink so we can pull the data from each
    // channel. Pipeline looks like:
    // ... deinterleave ! queue ! appsink.
    GstElement* queue = gst_element_factory_make("queue", 0);
    GstElement* sink = gst_element_factory_make("appsink", 0);

    GstAppSinkCallbacks callbacks;
    callbacks.eos = 0;
    callbacks.new_preroll = 0;
#ifdef GST_API_VERSION_1
    callbacks.new_sample = onAppsinkPullRequiredCallback;
#else
    callbacks.new_buffer_list = 0;
    callbacks.new_buffer = onAppsinkPullRequiredCallback;
#endif
    gst_app_sink_set_callbacks(GST_APP_SINK(sink), &callbacks, this, 0);

    g_object_set(sink, "sync", FALSE, NULL);

    gst_bin_add_many(GST_BIN(m_pipeline), queue, sink, NULL);

    GstPad* sinkPad = gst_element_get_static_pad(queue, "sink");
    gst_pad_link_full(pad, sinkPad, GST_PAD_LINK_CHECK_NOTHING);
    gst_object_unref(GST_OBJECT(sinkPad));

    gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING);

    gst_element_set_state(queue, GST_STATE_READY);
    gst_element_set_state(sink, GST_STATE_READY);
}
Ejemplo n.º 2
0
void AudioFileReader::decodeAudioForBusCreation()
{
    // Build the pipeline (giostreamsrc | filesrc) ! decodebin2
    // A deinterleave element is added once a src pad becomes available in decodebin.
    m_pipeline = gst_pipeline_new(0);

    GRefPtr<GstBus> bus = webkitGstPipelineGetBus(GST_PIPELINE(m_pipeline));
    ASSERT(bus);
    gst_bus_add_signal_watch(bus.get());
    g_signal_connect(bus.get(), "message", G_CALLBACK(messageCallback), this);

    GstElement* source;
    if (m_data) {
        ASSERT(m_dataSize);
        source = gst_element_factory_make("giostreamsrc", 0);
        GRefPtr<GInputStream> memoryStream = adoptGRef(g_memory_input_stream_new_from_data(m_data, m_dataSize, 0));
        g_object_set(source, "stream", memoryStream.get(), NULL);
    } else {
        source = gst_element_factory_make("filesrc", 0);
        g_object_set(source, "location", m_filePath, NULL);
    }

    m_decodebin = gst_element_factory_make(gDecodebinName, "decodebin");
    g_signal_connect(m_decodebin.get(), "pad-added", G_CALLBACK(onGStreamerDecodebinPadAddedCallback), this);

    gst_bin_add_many(GST_BIN(m_pipeline), source, m_decodebin.get(), NULL);
    gst_element_link_pads_full(source, "src", m_decodebin.get(), "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_set_state(m_pipeline, GST_STATE_PAUSED);
}
Ejemplo n.º 3
0
/**
 * gst_camerabin_try_add_element:
 * @bin: tries adding an element to this bin
 * @srcpad:  src pad name, or NULL for any
 * @new_elem: new element to be added
 * @dstpad:  dst pad name, or NULL for any
 *
 * Adds given element to given @bin. Looks for an unconnected src pad
 * (with name @srcpad, if specified) from the @bin and links the element to
 * it.
 *
 * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise.
 */
gboolean
gst_camerabin_try_add_element (GstBin * bin, const gchar * srcpad,
    GstElement * new_elem, const gchar * dstpad)
{
  GstPad *bin_pad;
  GstElement *bin_elem;
  gboolean ret = TRUE;

  g_return_val_if_fail (bin, FALSE);
  g_return_val_if_fail (new_elem, FALSE);

  /* Get pads for linking */
  bin_pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC);
  /* Add to bin */
  gst_bin_add (GST_BIN (bin), new_elem);
  /* Link, if unconnected pad was found, otherwise just add it to bin */
  if (bin_pad) {
    GST_DEBUG_OBJECT (bin, "linking %s to %s:%s", GST_OBJECT_NAME (new_elem),
        GST_DEBUG_PAD_NAME (bin_pad));
    bin_elem = gst_pad_get_parent_element (bin_pad);
    gst_object_unref (bin_pad);
    if (!gst_element_link_pads_full (bin_elem, srcpad, new_elem, dstpad,
            GST_PAD_LINK_CHECK_CAPS)) {
      gst_object_ref (new_elem);
      gst_bin_remove (bin, new_elem);
      ret = FALSE;
    }
    gst_object_unref (bin_elem);
  } else {
    GST_INFO_OBJECT (bin, "no unlinked source pad in bin");
  }

  return ret;
}
void
composition_pad_added_cb (GstElement * composition, GstPad * pad,
    CollectStructure * collect)
{
  fail_if (!(gst_element_link_pads_full (composition, GST_OBJECT_NAME (pad),
              collect->sink, "sink", GST_PAD_LINK_CHECK_NOTHING)));
}
void AudioDestinationGStreamer::finishBuildingPipelineAfterWavParserPadReady(GstPad* pad)
{
    ASSERT(m_wavParserAvailable);

    GRefPtr<GstElement> audioSink = gst_element_factory_make("autoaudiosink", 0);
    m_audioSinkAvailable = audioSink;

    if (!audioSink) {
        LOG_ERROR("Failed to create GStreamer autoaudiosink element");
        return;
    }

    // Autoaudiosink does the real sink detection in the GST_STATE_NULL->READY transition
    // so it's best to roll it to READY as soon as possible to ensure the underlying platform
    // audiosink was loaded correctly.
    GstStateChangeReturn stateChangeReturn = gst_element_set_state(audioSink.get(), GST_STATE_READY);
    if (stateChangeReturn == GST_STATE_CHANGE_FAILURE) {
        LOG_ERROR("Failed to change autoaudiosink element state");
        gst_element_set_state(audioSink.get(), GST_STATE_NULL);
        m_audioSinkAvailable = false;
        return;
    }

    GstElement* audioConvert = gst_element_factory_make("audioconvert", 0);
    gst_bin_add_many(GST_BIN(m_pipeline), audioConvert, audioSink.get(), NULL);

    // Link wavparse's src pad to audioconvert sink pad.
    GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(audioConvert, "sink"));
    gst_pad_link_full(pad, sinkPad.get(), GST_PAD_LINK_CHECK_NOTHING);

    // Link audioconvert to audiosink and roll states.
    gst_element_link_pads_full(audioConvert, "src", audioSink.get(), "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_sync_state_with_parent(audioConvert);
    gst_element_sync_state_with_parent(audioSink.leakRef());
}
Ejemplo n.º 6
0
AudioDestinationGStreamer::AudioDestinationGStreamer(AudioIOCallback& callback, float sampleRate)
    : m_callback(callback)
    , m_renderBus(AudioBus::create(2, framesToPull, false))
    , m_sampleRate(sampleRate)
    , m_isPlaying(false)
{
    m_pipeline = gst_pipeline_new("play");
    GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline)));
    ASSERT(bus);
    gst_bus_add_signal_watch(bus.get());
    g_signal_connect(bus.get(), "message", G_CALLBACK(messageCallback), this);

    GstElement* webkitAudioSrc = reinterpret_cast<GstElement*>(g_object_new(WEBKIT_TYPE_WEB_AUDIO_SRC,
                                                                            "rate", sampleRate,
                                                                            "bus", m_renderBus.get(),
                                                                            "provider", &m_callback,
                                                                            "frames", framesToPull, NULL));

    GRefPtr<GstElement> audioSink = gst_element_factory_make("autoaudiosink", 0);
    m_audioSinkAvailable = audioSink;
    if (!audioSink) {
        LOG_ERROR("Failed to create GStreamer autoaudiosink element");
        return;
    }

    // Autoaudiosink does the real sink detection in the GST_STATE_NULL->READY transition
    // so it's best to roll it to READY as soon as possible to ensure the underlying platform
    // audiosink was loaded correctly.
    GstStateChangeReturn stateChangeReturn = gst_element_set_state(audioSink.get(), GST_STATE_READY);
    if (stateChangeReturn == GST_STATE_CHANGE_FAILURE) {
        LOG_ERROR("Failed to change autoaudiosink element state");
        gst_element_set_state(audioSink.get(), GST_STATE_NULL);
        m_audioSinkAvailable = false;
        return;
    }

    GstElement* audioConvert = gst_element_factory_make("audioconvert", 0);
    GstElement* audioResample = gst_element_factory_make("audioresample", 0);
    gst_bin_add_many(GST_BIN(m_pipeline), webkitAudioSrc, audioConvert, audioResample, audioSink.get(), NULL);

    // Link src pads from webkitAudioSrc to audioConvert ! audioResample ! autoaudiosink.
    gst_element_link_pads_full(webkitAudioSrc, "src", audioConvert, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(audioConvert, "src", audioResample, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(audioResample, "src", audioSink.get(), "sink", GST_PAD_LINK_CHECK_NOTHING);
}
static GstElement *
ges_title_source_create_source (GESTrackElement * object)
{
  GstElement *topbin, *background, *text;
  GstPad *src, *pad;

  GESTitleSource *self = GES_TITLE_SOURCE (object);
  GESTitleSourcePrivate *priv = self->priv;
  const gchar *bg_props[] = { "pattern", "foreground-color", NULL };
  const gchar *text_props[] = { "text", "font-desc", "valignment", "halignment",
    "color", "xpos", "ypos", "outline-color", "shaded-background", NULL
  };

  topbin = gst_bin_new ("titlesrc-bin");
  background = gst_element_factory_make ("videotestsrc", "titlesrc-bg");

  text = gst_element_factory_make ("textoverlay", "titlsrc-text");
  if (priv->text) {
    g_object_set (text, "text", priv->text, NULL);
  }
  if (priv->font_desc) {
    g_object_set (text, "font-desc", priv->font_desc, NULL);
  }
  g_object_set (text, "valignment", (gint) priv->valign, "halignment",
      (gint) priv->halign, NULL);
  g_object_set (text, "color", (guint) self->priv->color, NULL);
  g_object_set (text, "xpos", (gdouble) self->priv->xpos, NULL);
  g_object_set (text, "ypos", (gdouble) self->priv->ypos, NULL);


  g_object_set (background, "pattern", (gint) GES_VIDEO_TEST_PATTERN_SOLID,
      NULL);
  g_object_set (background, "foreground-color", (guint) self->priv->background,
      NULL);

  gst_bin_add_many (GST_BIN (topbin), background, text, NULL);

  gst_element_link_pads_full (background, "src", text, "video_sink",
      GST_PAD_LINK_CHECK_NOTHING);

  pad = gst_element_get_static_pad (text, "src");
  src = gst_ghost_pad_new ("src", pad);
  gst_object_unref (pad);
  gst_element_add_pad (topbin, src);

  gst_object_ref (text);
  gst_object_ref (background);

  priv->text_el = text;
  priv->background_el = background;

  ges_track_element_add_children_props (object, text, NULL, NULL, text_props);
  ges_track_element_add_children_props (object, background, NULL, NULL,
      bg_props);

  return topbin;
}
Ejemplo n.º 8
0
static gboolean
activate_vpp (GstVaapiDecodeBin * vaapidecbin)
{
  GstElement *src;

  if (vaapidecbin->ghost_pad_src || vaapidecbin->postproc)
    return TRUE;

  if (!vaapidecbin->has_vpp || vaapidecbin->disable_vpp) {
    src = vaapidecbin->queue;
    goto connect_src_ghost_pad;
  }

  /* 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_link_pads_full (vaapidecbin->queue, "src",
          vaapidecbin->postproc, "sink", GST_PAD_LINK_CHECK_NOTHING))
    goto error_link_pad;

  GST_DEBUG_OBJECT (vaapidecbin, "Enabling VPP");
  src = vaapidecbin->postproc;

  goto connect_src_ghost_pad;

error_element_missing:
  {
    post_missing_element_message (vaapidecbin, "vaapipostproc");
    return FALSE;
  }
error_link_pad:
  {
    GST_ERROR_OBJECT (vaapidecbin, "Failed to link the child elements");
    return FALSE;
  }
connect_src_ghost_pad:
  {
    GstPad *srcpad, *ghostpad;

    srcpad = gst_element_get_static_pad (src, "src");
    ghostpad = gst_ghost_pad_new ("src", srcpad);
    vaapidecbin->ghost_pad_src = ghostpad;
    gst_object_unref (srcpad);
    gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad);
    return TRUE;
  }
}
Ejemplo n.º 9
0
void AudioFileReader::plugDeinterleave(GstPad* pad)
{
    // Ignore any additional source pads just in case.
    if (m_deInterleave)
        return;

    // A decodebin pad was added, plug in a deinterleave element to
    // separate each planar channel. Sub pipeline looks like
    // ... decodebin2 ! audioconvert ! audioresample ! capsfilter ! deinterleave.
    GstElement* audioConvert  = gst_element_factory_make("audioconvert", 0);
    GstElement* audioResample = gst_element_factory_make("audioresample", 0);
    GstElement* capsFilter = gst_element_factory_make("capsfilter", 0);
    m_deInterleave = gst_element_factory_make("deinterleave", "deinterleave");

    g_object_set(m_deInterleave.get(), "keep-positions", TRUE, NULL);
    g_signal_connect(m_deInterleave.get(), "pad-added", G_CALLBACK(onGStreamerDeinterleavePadAddedCallback), this);
    g_signal_connect(m_deInterleave.get(), "no-more-pads", G_CALLBACK(onGStreamerDeinterleaveReadyCallback), this);

    GstCaps* caps = gst_caps_new_simple("audio/x-raw",
        "rate", G_TYPE_INT, static_cast<int>(m_sampleRate),
        "channels", G_TYPE_INT, m_channels,
        "format", G_TYPE_STRING, GST_AUDIO_NE(F32),
        "layout", G_TYPE_STRING, "interleaved", nullptr);
    g_object_set(capsFilter, "caps", caps, NULL);
    gst_caps_unref(caps);

    gst_bin_add_many(GST_BIN(m_pipeline), audioConvert, audioResample, capsFilter, m_deInterleave.get(), NULL);

    GstPad* sinkPad = gst_element_get_static_pad(audioConvert, "sink");
    gst_pad_link_full(pad, sinkPad, GST_PAD_LINK_CHECK_NOTHING);
    gst_object_unref(GST_OBJECT(sinkPad));

    gst_element_link_pads_full(audioConvert, "src", audioResample, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(audioResample, "src", capsFilter, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(capsFilter, "src", m_deInterleave.get(), "sink", GST_PAD_LINK_CHECK_NOTHING);

    gst_element_sync_state_with_parent(audioConvert);
    gst_element_sync_state_with_parent(audioResample);
    gst_element_sync_state_with_parent(capsFilter);
    gst_element_sync_state_with_parent(m_deInterleave.get());
}
static GstElement *
ges_multi_file_source_create_source (GESTrackElement * track_element)
{
  GESMultiFileSource *self;
  GstElement *bin, *src, *decodebin;
  GstCaps *disc_caps;
  GstDiscovererStreamInfo *stream_info;
  GValue fps = G_VALUE_INIT;
  GstCaps *caps;
  GESUriSourceAsset *asset;
  GESMultiFileURI *uri_data;

  self = (GESMultiFileSource *) track_element;

  asset =
      GES_URI_SOURCE_ASSET (ges_extractable_get_asset (GES_EXTRACTABLE (self)));

  if (asset != NULL) {
    stream_info = ges_uri_source_asset_get_stream_info (asset);
    g_assert (stream_info);
    disc_caps = gst_discoverer_stream_info_get_caps (stream_info);
    caps = gst_caps_copy (disc_caps);
    GST_DEBUG ("Got some nice caps %s", gst_caps_to_string (disc_caps));
    gst_object_unref (stream_info);
    gst_caps_unref (disc_caps);
  } else {
    caps = gst_caps_new_empty ();
    GST_WARNING ("Could not extract asset.");
  }

  g_value_init (&fps, GST_TYPE_FRACTION);
  gst_value_set_fraction (&fps, 25, 1);
  gst_caps_set_value (caps, "framerate", &fps);

  bin = GST_ELEMENT (gst_bin_new ("multi-image-bin"));
  src = gst_element_factory_make ("multifilesrc", NULL);

  uri_data = ges_multi_file_uri_new (self->uri);
  g_object_set (src, "start-index", uri_data->start, "stop-index",
      uri_data->end, "caps", caps, "location", uri_data->location, NULL);
  g_free (uri_data);

  decodebin = gst_element_factory_make ("decodebin", NULL);

  gst_bin_add_many (GST_BIN (bin), src, decodebin, NULL);
  gst_element_link_pads_full (src, "src", decodebin, "sink",
      GST_PAD_LINK_CHECK_NOTHING);

  g_signal_connect (G_OBJECT (decodebin), "pad-added",
      G_CALLBACK (pad_added_cb), bin);

  return bin;
}
Ejemplo n.º 11
0
static gboolean
create_node (GstBin * bin, GstElement * sink, const gchar * sinkpadname,
    GstElement ** new_sink, gint children, gint flavour)
{
  GstElement *mix, *proc, *conv;

  if (children >= 1) {
    mix = gst_element_factory_make (factories[flavour][ELEM_MIX], NULL);
    if (!mix) {
      GST_WARNING ("need element '%s'", factories[flavour][ELEM_MIX]);
      return FALSE;
    }
  } else {
    mix = gst_element_factory_make ("identity", NULL);
  }
  proc = gst_element_factory_make (factories[flavour][ELEM_PROC], NULL);
  if (!proc) {
    GST_WARNING ("need element '%s'", factories[flavour][ELEM_PROC]);
    return FALSE;
  }
  conv = gst_element_factory_make (factories[flavour][ELEM_CONV], NULL);
  if (!conv) {
    GST_WARNING ("need element '%s'", factories[flavour][ELEM_CONV]);
    return FALSE;
  }
  gst_bin_add_many (bin, mix, proc, conv, NULL);
  if (!gst_element_link_pads_full (mix, "src", proc, "sink",
          GST_PAD_LINK_CHECK_NOTHING)
      || !gst_element_link_pads_full (proc, "src", conv, "sink",
          GST_PAD_LINK_CHECK_NOTHING)
      || !gst_element_link_pads_full (conv, "src", sink, sinkpadname,
          GST_PAD_LINK_CHECK_NOTHING)) {
    GST_WARNING ("can't link elements");
    return FALSE;
  }
  *new_sink = mix;
  return TRUE;
}
Ejemplo n.º 12
0
static GstElement *
ges_image_source_create_source (GESTrackElement * track_element)
{
    GstElement *bin, *source, *scale, *freeze, *iconv;
    GstPad *src, *target;

    bin = GST_ELEMENT (gst_bin_new ("still-image-bin"));
    source = gst_element_factory_make ("uridecodebin", NULL);
    scale = gst_element_factory_make ("videoscale", NULL);
    freeze = gst_element_factory_make ("imagefreeze", NULL);
    iconv = gst_element_factory_make ("videoconvert", NULL);

    g_object_set (scale, "add-borders", TRUE, NULL);

    gst_bin_add_many (GST_BIN (bin), source, scale, freeze, iconv, NULL);

    gst_element_link_pads_full (scale, "src", iconv, "sink",
                                GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full (iconv, "src", freeze, "sink",
                                GST_PAD_LINK_CHECK_NOTHING);

    /* FIXME: add capsfilter here with sink caps (see 626518) */

    target = gst_element_get_static_pad (freeze, "src");

    src = gst_ghost_pad_new ("src", target);
    gst_element_add_pad (bin, src);
    gst_object_unref (target);

    g_object_set (source, "uri", ((GESImageSource *) track_element)->uri, NULL);

    g_signal_connect (G_OBJECT (source), "pad-added",
                      G_CALLBACK (pad_added_cb), scale);

    return bin;
}
Ejemplo n.º 13
0
static gboolean
gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin)
{
  gchar *missing_factory = NULL;

  /* create the decoder */
  vaapidecbin->decoder =
      gst_element_factory_make ("vaapidecode", "vaapidecode");
  if (!vaapidecbin->decoder) {
    missing_factory = "vaapidecode";
    goto error_element_missing;
  }
  /* create the queue */
  vaapidecbin->queue = gst_element_factory_make ("queue", "queue");
  if (!vaapidecbin->queue) {
    missing_factory = "queue";
    goto error_element_missing;
  }

  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);

  gst_bin_add_many (GST_BIN (vaapidecbin),
      vaapidecbin->decoder, vaapidecbin->queue, NULL);

  if (!gst_element_link_pads_full (vaapidecbin->decoder, "src",
          vaapidecbin->queue, "sink", GST_PAD_LINK_CHECK_NOTHING))
    goto error_link_pad;

  return TRUE;

error_element_missing:
  {
    post_missing_element_message (vaapidecbin, missing_factory);
    return FALSE;
  }
error_link_pad:
  {
    GST_ERROR_OBJECT (vaapidecbin, "Failed to link the child elements");
    return FALSE;
  }
}
static GstElement *
ges_track_title_source_create_element (GESTrackObject * object)
{
  GESTrackTitleSource *self = GES_TRACK_TITLE_SOURCE (object);
  GESTrackTitleSourcePrivate *priv = self->priv;
  GstElement *topbin, *background, *text;
  GstPad *src;

  topbin = gst_bin_new ("titlesrc-bin");
  background = gst_element_factory_make ("videotestsrc", "titlesrc-bg");

  text = gst_element_factory_make ("textoverlay", "titlsrc-text");
  if (priv->text) {
    g_object_set (text, "text", priv->text, NULL);
  }
  if (priv->font_desc) {
    g_object_set (text, "font-desc", priv->font_desc, NULL);
  }
  g_object_set (text, "valignment", (gint) priv->valign, "halignment",
      (gint) priv->halign, NULL);

  g_object_set (background, "pattern", (gint) GES_VIDEO_TEST_PATTERN_BLACK,
      NULL);
  g_object_set (text, "color", (guint) self->priv->color, NULL);
  g_object_set (text, "xpos", (gdouble) self->priv->xpos, NULL);
  g_object_set (text, "ypos", (gdouble) self->priv->ypos, NULL);

  gst_bin_add_many (GST_BIN (topbin), background, text, NULL);

  gst_element_link_pads_full (background, "src", text, "video_sink",
      GST_PAD_LINK_CHECK_NOTHING);

  src = gst_ghost_pad_new ("src", gst_element_get_static_pad (text, "src"));
  gst_element_add_pad (topbin, src);

  g_object_ref (text);
  g_object_ref (background);

  priv->text_el = text;
  priv->background_el = background;

  return topbin;
}
void AudioSourceProviderGStreamer::configureAudioBin(GstElement* audioBin, GstElement* teePredecessor)
{
    m_audioSinkBin = audioBin;

    GstElement* audioTee = gst_element_factory_make("tee", "audioTee");
    GstElement* audioQueue = gst_element_factory_make("queue", 0);
    GstElement* audioConvert = gst_element_factory_make("audioconvert", 0);
    GstElement* audioConvert2 = gst_element_factory_make("audioconvert", 0);
    GstElement* audioResample = gst_element_factory_make("audioresample", 0);
    GstElement* audioResample2 = gst_element_factory_make("audioresample", 0);
    GstElement* volumeElement = gst_element_factory_make("volume", "volume");
    GstElement* audioSink = gst_element_factory_make("autoaudiosink", 0);

    gst_bin_add_many(GST_BIN(m_audioSinkBin.get()), audioTee, audioQueue, audioConvert, audioResample, volumeElement, audioConvert2, audioResample2, audioSink, nullptr);

    // In cases where the audio-sink needs elements before tee (such
    // as scaletempo) they need to be linked to tee which in this case
    // doesn't need a ghost pad. It is assumed that the teePredecessor
    // chain already configured a ghost pad.
    if (teePredecessor)
        gst_element_link_pads_full(teePredecessor, "src", audioTee, "sink", GST_PAD_LINK_CHECK_NOTHING);
    else {
        // Add a ghostpad to the bin so it can proxy to tee.
        GRefPtr<GstPad> audioTeeSinkPad = adoptGRef(gst_element_get_static_pad(audioTee, "sink"));
        gst_element_add_pad(m_audioSinkBin.get(), gst_ghost_pad_new("sink", audioTeeSinkPad.get()));
    }

    // Link a new src pad from tee to queue ! audioconvert !
    // audioresample ! volume ! audioconvert ! audioresample !
    // autoaudiosink. The audioresample and audioconvert are needed to
    // ensure the audio sink receives buffers in the correct format.
    gst_element_link_pads_full(audioTee, "src_%u", audioQueue, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(audioQueue, "src", audioConvert, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(audioConvert, "src", audioResample, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(audioResample, "src", volumeElement, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(volumeElement, "src", audioConvert2, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(audioConvert2, "src", audioResample2, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(audioResample2, "src", audioSink, "sink", GST_PAD_LINK_CHECK_NOTHING);
}
Ejemplo n.º 16
0
void AudioLiveInputPipeline::handleNewDeinterleavePad(GstPad* pad)
{
    // A new pad for a planar channel was added in deinterleave.
    // Plug in an appsink so we can pull the data from each channel.
    // Pipeline looks like:
    // ... deinterleave ! appsink.
    GstElement* queue = gst_element_factory_make("queue", nullptr);
    GstElement* sink = gst_element_factory_make("appsink", nullptr);

    gst_bin_add_many(GST_BIN(m_pipeline), queue, sink, nullptr);

    GstPad* sinkPad = gst_element_get_static_pad(queue, "sink");
    gst_pad_link_full(pad, sinkPad, GST_PAD_LINK_CHECK_NOTHING);
    gst_object_unref(GST_OBJECT(sinkPad));

    gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING);

    m_sinkList = g_slist_prepend(m_sinkList, sink);
    gst_element_sync_state_with_parent(queue);
    gst_element_sync_state_with_parent(sink);
}
GstElement *
audiotest_bin_src (const gchar * name, guint64 start,
    gint64 duration, guint priority, gboolean intaudio)
{
  GstElement *source = NULL;
  GstElement *identity = NULL;
  GstElement *audiotestsrc = NULL;
  GstElement *audioconvert = NULL;
  GstElement *bin = NULL;
  GstCaps *caps;
  GstPad *srcpad = NULL;

  audiotestsrc = gst_element_factory_make_or_warn ("audiotestsrc", NULL);
  identity = gst_element_factory_make_or_warn ("identity", NULL);
  bin = gst_bin_new (NULL);
  source = new_nle_src (name, start, duration, priority);
  audioconvert = gst_element_factory_make_or_warn ("audioconvert", NULL);

  if (intaudio)
    caps = gst_caps_from_string ("audio/x-raw,format=(string)S16LE");
  else
    caps = gst_caps_from_string ("audio/x-raw,format=(string)F32LE");

  gst_bin_add_many (GST_BIN (bin), audiotestsrc, audioconvert, identity, NULL);
  gst_element_link_pads_full (audiotestsrc, "src", audioconvert, "sink",
      GST_PAD_LINK_CHECK_NOTHING);
  fail_if ((gst_element_link_filtered (audioconvert, identity, caps)) != TRUE);

  gst_caps_unref (caps);

  gst_bin_add (GST_BIN (source), bin);

  srcpad = gst_element_get_static_pad (identity, "src");

  gst_element_add_pad (bin, gst_ghost_pad_new ("src", srcpad));

  gst_object_unref (srcpad);

  return source;
}
Ejemplo n.º 18
0
AudioDestinationGStreamer::AudioDestinationGStreamer(AudioIOCallback& callback, float sampleRate)
    : m_callback(callback)
    , m_renderBus(2, framesToPull, false)
    , m_sampleRate(sampleRate)
    , m_isPlaying(false)
{
    m_pipeline = gst_pipeline_new("play");
    GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline));
    ASSERT(bus);
    gst_bus_add_signal_watch(bus);
    g_signal_connect(bus, "message", G_CALLBACK(messageCallback), this);
    gst_object_unref(bus);

    GstElement* webkitAudioSrc = reinterpret_cast<GstElement*>(g_object_new(WEBKIT_TYPE_WEB_AUDIO_SRC,
                                                                            "rate", sampleRate,
                                                                            "bus", &m_renderBus,
                                                                            "provider", &m_callback,
                                                                            "frames", framesToPull, NULL));

    GstElement* wavParser = gst_element_factory_make("wavparse", 0);

    m_wavParserAvailable = wavParser;
    ASSERT_WITH_MESSAGE(m_wavParserAvailable, "Failed to create GStreamer wavparse element");
    if (!m_wavParserAvailable)
        return;

#ifndef GST_API_VERSION_1
    g_signal_connect(wavParser, "pad-added", G_CALLBACK(onGStreamerWavparsePadAddedCallback), this);
#endif
    gst_bin_add_many(GST_BIN(m_pipeline), webkitAudioSrc, wavParser, NULL);
    gst_element_link_pads_full(webkitAudioSrc, "src", wavParser, "sink", GST_PAD_LINK_CHECK_NOTHING);

#ifdef GST_API_VERSION_1
    GRefPtr<GstPad> srcPad = adoptGRef(gst_element_get_static_pad(wavParser, "src"));
    finishBuildingPipelineAfterWavParserPadReady(srcPad.get());
#endif
}
Ejemplo n.º 19
0
void AudioFileReader::decodeAudioForBusCreation()
{
    // Build the pipeline (giostreamsrc | filesrc) ! decodebin2
    // A deinterleave element is added once a src pad becomes available in decodebin.
    m_pipeline = gst_pipeline_new(0);

    GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline)));
    ASSERT(bus);
    gst_bus_add_signal_watch(bus.get());
    g_signal_connect(bus.get(), "message", G_CALLBACK(messageCallback), this);

    GstElement* source;
    if (m_data) {
        ASSERT(m_dataSize);
        source = gst_element_factory_make("giostreamsrc", 0);
        GRefPtr<GInputStream> memoryStream = adoptGRef(g_memory_input_stream_new_from_data(m_data, m_dataSize, 0));
        g_object_set(source, "stream", memoryStream.get(), NULL);
    } else {
        source = gst_element_factory_make("filesrc", 0);
        g_object_set(source, "location", m_filePath, NULL);
    }

    m_decodebin = gst_element_factory_make("decodebin", "decodebin");
    g_signal_connect(m_decodebin.get(), "pad-added", G_CALLBACK(onGStreamerDecodebinPadAddedCallback), this);

    gst_bin_add_many(GST_BIN(m_pipeline), source, m_decodebin.get(), NULL);
    gst_element_link_pads_full(source, "src", m_decodebin.get(), "sink", GST_PAD_LINK_CHECK_NOTHING);

    // Catch errors here immediately, there might not be an error message if
    // we're unlucky.
    if (gst_element_set_state(m_pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
        g_warning("Error: Failed to set pipeline to PAUSED");
        m_errorOccurred = true;
        g_main_loop_quit(m_loop.get());
    }
}
GstElement *
videotest_in_bin_nle_src (const gchar * name, guint64 start, gint64 duration,
    gint pattern, guint priority)
{
  GstElement *nlesource = NULL;
  GstElement *videotestsrc = NULL;
  GstElement *bin = NULL;
  GstElement *alpha = NULL;
  GstPad *srcpad = NULL;

  alpha = gst_element_factory_make ("alpha", NULL);
  if (alpha == NULL)
    return NULL;

  videotestsrc = gst_element_factory_make_or_warn ("videotestsrc", NULL);
  g_object_set (G_OBJECT (videotestsrc), "pattern", pattern, NULL);
  bin = gst_bin_new (NULL);

  nlesource = new_nle_src (name, start, duration, priority);

  gst_bin_add (GST_BIN (bin), videotestsrc);
  gst_bin_add (GST_BIN (bin), alpha);

  gst_element_link_pads_full (videotestsrc, "src", alpha, "sink",
      GST_PAD_LINK_CHECK_NOTHING);

  gst_bin_add (GST_BIN (nlesource), bin);

  srcpad = gst_element_get_static_pad (alpha, "src");

  gst_element_add_pad (bin, gst_ghost_pad_new ("src", srcpad));

  gst_object_unref (srcpad);

  return nlesource;
}
// This function creates and initializes some internal variables, and returns a
// pointer to the element that should receive the data flow first
GstElement* MediaPlayerPrivateGStreamerBase::createVideoSink(GstElement* pipeline)
{
    if (!initializeGStreamer())
        return 0;

#if USE(NATIVE_FULLSCREEN_VIDEO)
    m_gstGWorld = GStreamerGWorld::createGWorld(pipeline);
    m_webkitVideoSink = webkitVideoSinkNew(m_gstGWorld.get());
#else
    UNUSED_PARAM(pipeline);
    m_webkitVideoSink = webkitVideoSinkNew();
#endif

    m_repaintHandler = g_signal_connect(m_webkitVideoSink.get(), "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);

#if USE(NATIVE_FULLSCREEN_VIDEO)
    // Build a new video sink consisting of a bin containing a tee
    // (meant to distribute data to multiple video sinks) and our
    // internal video sink. For fullscreen we create an autovideosink
    // and initially block the data flow towards it and configure it

    m_videoSinkBin = gst_bin_new("video-sink");

    GstElement* videoTee = gst_element_factory_make("tee", "videoTee");
    GstElement* queue = gst_element_factory_make("queue", 0);

#ifdef GST_API_VERSION_1
    GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(videoTee, "sink"));
    GST_OBJECT_FLAG_SET(GST_OBJECT(sinkPad.get()), GST_PAD_FLAG_PROXY_ALLOCATION);
#endif

    gst_bin_add_many(GST_BIN(m_videoSinkBin.get()), videoTee, queue, NULL);

    // Link a new src pad from tee to queue1.
    gst_element_link_pads_full(videoTee, 0, queue, "sink", GST_PAD_LINK_CHECK_NOTHING);
#endif

    GstElement* actualVideoSink = 0;
    m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink");
    if (m_fpsSink) {
        // The verbose property has been added in -bad 0.10.22. Making
        // this whole code depend on it because we don't want
        // fpsdiplaysink to spit data on stdout.
        GstElementFactory* factory = GST_ELEMENT_FACTORY(GST_ELEMENT_GET_CLASS(m_fpsSink)->elementfactory);
        if (gst_plugin_feature_check_version(GST_PLUGIN_FEATURE(factory), 0, 10, 22)) {
            g_object_set(m_fpsSink, "silent", TRUE , NULL);

            // Turn off text overlay unless logging is enabled.
#if LOG_DISABLED
            g_object_set(m_fpsSink, "text-overlay", FALSE , NULL);
#else
            WTFLogChannel* channel = getChannelFromName("Media");
            if (channel->state != WTFLogChannelOn)
                g_object_set(m_fpsSink, "text-overlay", FALSE , NULL);
#endif // LOG_DISABLED

            if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) {
                g_object_set(m_fpsSink, "video-sink", m_webkitVideoSink.get(), NULL);
#if USE(NATIVE_FULLSCREEN_VIDEO)
                gst_bin_add(GST_BIN(m_videoSinkBin.get()), m_fpsSink);
#endif
                actualVideoSink = m_fpsSink;
            } else
                m_fpsSink = 0;
        } else
            m_fpsSink = 0;
    }

    if (!m_fpsSink) {
#if USE(NATIVE_FULLSCREEN_VIDEO)
        gst_bin_add(GST_BIN(m_videoSinkBin.get()), m_webkitVideoSink.get());
#endif
        actualVideoSink = m_webkitVideoSink.get();
    }

    ASSERT(actualVideoSink);

#if USE(NATIVE_FULLSCREEN_VIDEO)
    // Faster elements linking.
    gst_element_link_pads_full(queue, "src", actualVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING);

    // Add a ghostpad to the bin so it can proxy to tee.
    GRefPtr<GstPad> pad = adoptGRef(gst_element_get_static_pad(videoTee, "sink"));
    gst_element_add_pad(m_videoSinkBin.get(), gst_ghost_pad_new("sink", pad.get()));

    // Set the bin as video sink of playbin.
    return m_videoSinkBin.get();
#else
    return actualVideoSink;
#endif
}
Ejemplo n.º 22
0
static gboolean
gst_viewfinder_bin_create_elements (GstViewfinderBin * vfbin)
{
  GstElement *csp = NULL;
  GstElement *videoscale = NULL;
  GstPad *firstpad = NULL;
  const gchar *missing_element_name;
  gboolean newsink = FALSE;
  gboolean updated_converters = FALSE;

  GST_DEBUG_OBJECT (vfbin, "Creating internal elements");

  /* First check if we need to add/replace the internal sink */
  if (vfbin->video_sink) {
    if (vfbin->user_video_sink && vfbin->video_sink != vfbin->user_video_sink) {
      gst_bin_remove (GST_BIN_CAST (vfbin), vfbin->video_sink);
      gst_object_unref (vfbin->video_sink);
      vfbin->video_sink = NULL;
    }
  }

  if (!vfbin->video_sink) {
    if (vfbin->user_video_sink)
      vfbin->video_sink = gst_object_ref (vfbin->user_video_sink);
    else {
      vfbin->video_sink = gst_element_factory_make ("autovideosink",
          "vfbin-sink");
      if (!vfbin->video_sink) {
        missing_element_name = "autovideosink";
        goto missing_element;
      }
    }

    gst_bin_add (GST_BIN_CAST (vfbin), gst_object_ref (vfbin->video_sink));
    newsink = TRUE;
  }

  /* check if we want add/remove the conversion elements */
  if (vfbin->elements_created && vfbin->disable_converters) {
    /* remove the elements, user doesn't want them */

    gst_ghost_pad_set_target (GST_GHOST_PAD (vfbin->ghostpad), NULL);
    csp = gst_bin_get_by_name (GST_BIN_CAST (vfbin), "vfbin-csp");
    videoscale = gst_bin_get_by_name (GST_BIN_CAST (vfbin), "vfbin-videoscale");

    gst_bin_remove (GST_BIN_CAST (vfbin), csp);
    gst_bin_remove (GST_BIN_CAST (vfbin), videoscale);

    gst_object_unref (csp);
    gst_object_unref (videoscale);

    updated_converters = TRUE;
  } else if (!vfbin->elements_created && !vfbin->disable_converters) {
    gst_ghost_pad_set_target (GST_GHOST_PAD (vfbin->ghostpad), NULL);

    /* add the elements, user wants them */
    csp = gst_element_factory_make ("ffmpegcolorspace", "vfbin-csp");
    if (!csp) {
      missing_element_name = "ffmpegcolorspace";
      goto missing_element;
    }
    gst_bin_add (GST_BIN_CAST (vfbin), csp);

    videoscale = gst_element_factory_make ("videoscale", "vfbin->videoscale");
    if (!videoscale) {
      missing_element_name = "videoscale";
      goto missing_element;
    }
    gst_bin_add (GST_BIN_CAST (vfbin), videoscale);

    gst_element_link_pads_full (csp, "src", videoscale, "sink",
        GST_PAD_LINK_CHECK_NOTHING);

    vfbin->elements_created = TRUE;
    GST_DEBUG_OBJECT (vfbin, "Elements succesfully created and linked");

    updated_converters = TRUE;
  }
  /* otherwise, just leave it as is */

  /* if sink was replaced -> link it to the internal converters */
  if (newsink && !vfbin->disable_converters) {
    gboolean unref = FALSE;
    if (!videoscale) {
      videoscale = gst_bin_get_by_name (GST_BIN_CAST (vfbin),
          "vfbin-videscale");
      unref = TRUE;
    }

    if (!gst_element_link_pads_full (videoscale, "src", vfbin->video_sink,
            "sink", GST_PAD_LINK_CHECK_CAPS)) {
      GST_ELEMENT_ERROR (vfbin, CORE, NEGOTIATION, (NULL),
          ("linking videoscale and viewfindersink failed"));
    }

    if (unref)
      gst_object_unref (videoscale);
    videoscale = NULL;
  }

  /* Check if we need a new ghostpad target */
  if (updated_converters || (newsink && vfbin->disable_converters)) {
    if (vfbin->disable_converters) {
      firstpad = gst_element_get_static_pad (vfbin->video_sink, "sink");
    } else {
      /* csp should always exist at this point */
      firstpad = gst_element_get_static_pad (csp, "sink");
    }
  }

  /* need to change the ghostpad target if firstpad is set */
  if (firstpad) {
    if (!gst_ghost_pad_set_target (GST_GHOST_PAD (vfbin->ghostpad), firstpad))
      goto error;
    gst_object_unref (firstpad);
    firstpad = NULL;
  }

  return TRUE;

missing_element:
  gst_element_post_message (GST_ELEMENT_CAST (vfbin),
      gst_missing_element_message_new (GST_ELEMENT_CAST (vfbin),
          missing_element_name));
  GST_ELEMENT_ERROR (vfbin, CORE, MISSING_PLUGIN,
      (_("Missing element '%s' - check your GStreamer installation."),
          missing_element_name), (NULL));
  goto error;

error:
  GST_WARNING_OBJECT (vfbin, "Creating internal elements failed");
  if (firstpad)
    gst_object_unref (firstpad);
  return FALSE;
}
Ejemplo n.º 23
0
/**
 * ges_pipeline_set_mode:
 * @pipeline: a #GESPipeline
 * @mode: the #GESPipelineFlags to use
 *
 * switches the @pipeline to the specified @mode. The default mode when
 * creating a #GESPipeline is #GES_PIPELINE_MODE_PREVIEW.
 *
 * Note: The @pipeline will be set to #GST_STATE_NULL during this call due to
 * the internal changes that happen. The caller will therefore have to 
 * set the @pipeline to the requested state after calling this method.
 *
 * Returns: %TRUE if the mode was properly set, else %FALSE.
 **/
gboolean
ges_pipeline_set_mode (GESPipeline * pipeline, GESPipelineFlags mode)
{

  GList *tmp;
  g_return_val_if_fail (GES_IS_PIPELINE (pipeline), FALSE);

  GST_DEBUG_OBJECT (pipeline, "current mode : %d, mode : %d",
      pipeline->priv->mode, mode);

  /* fast-path, nothing to change */
  if (mode == pipeline->priv->mode)
    return TRUE;

  /* FIXME: It would be nice if we are only (de)activating preview
   * modes to not set the whole pipeline to NULL, but instead just
   * do the proper (un)linking to playsink. */

  /* Switch pipeline to NULL since we're changing the configuration */
  gst_element_set_state (GST_ELEMENT_CAST (pipeline), GST_STATE_NULL);


  if (pipeline->priv->timeline) {
    gboolean disabled =
        ! !(mode & (GES_PIPELINE_MODE_RENDER | GES_PIPELINE_MODE_SMART_RENDER));

    for (tmp = pipeline->priv->timeline->tracks; tmp; tmp = tmp->next)
      track_disable_last_gap (GES_TRACK (tmp->data), disabled);
  }

  /* remove no-longer needed components */
  if (pipeline->priv->mode & GES_PIPELINE_MODE_PREVIEW &&
      !(mode & GES_PIPELINE_MODE_PREVIEW)) {
    /* Disable playsink */
    GST_DEBUG ("Disabling playsink");
    gst_object_ref (pipeline->priv->playsink);
    gst_bin_remove (GST_BIN_CAST (pipeline), pipeline->priv->playsink);
  }
  if ((pipeline->priv->mode &
          (GES_PIPELINE_MODE_RENDER | GES_PIPELINE_MODE_SMART_RENDER)) &&
      !(mode & (GES_PIPELINE_MODE_RENDER | GES_PIPELINE_MODE_SMART_RENDER))) {
    GList *tmp;
    GstCaps *caps;

    for (tmp = pipeline->priv->timeline->tracks; tmp; tmp = tmp->next) {
      GESTrackType type = GES_TRACK (tmp->data)->type;

      if (type == GES_TRACK_TYPE_AUDIO)
        caps = gst_caps_new_empty_simple ("audio/x-raw");
      else if (type == GES_TRACK_TYPE_VIDEO)
        caps = gst_caps_new_empty_simple ("video/x-raw");
      else
        continue;

      ges_track_set_caps (GES_TRACK (tmp->data), caps);
      gst_caps_unref (caps);
    }

    /* Disable render bin */
    GST_DEBUG ("Disabling rendering bin");
    gst_object_ref (pipeline->priv->encodebin);
    gst_object_ref (pipeline->priv->urisink);
    gst_bin_remove_many (GST_BIN_CAST (pipeline),
        pipeline->priv->encodebin, pipeline->priv->urisink, NULL);
  }

  /* Add new elements */
  if (!(pipeline->priv->mode & GES_PIPELINE_MODE_PREVIEW) &&
      (mode & GES_PIPELINE_MODE_PREVIEW)) {
    /* Add playsink */
    GST_DEBUG ("Adding playsink");
    if (!gst_bin_add (GST_BIN_CAST (pipeline), pipeline->priv->playsink)) {
      GST_ERROR_OBJECT (pipeline, "Couldn't add playsink");
      return FALSE;
    }
  }
  if (!(pipeline->priv->mode &
          (GES_PIPELINE_MODE_RENDER | GES_PIPELINE_MODE_SMART_RENDER)) &&
      (mode & (GES_PIPELINE_MODE_RENDER | GES_PIPELINE_MODE_SMART_RENDER))) {
    /* Adding render bin */
    GST_DEBUG ("Adding render bin");

    if (G_UNLIKELY (pipeline->priv->urisink == NULL)) {
      GST_ERROR_OBJECT (pipeline, "Output URI not set !");
      return FALSE;
    }
    if (!gst_bin_add (GST_BIN_CAST (pipeline), pipeline->priv->encodebin)) {
      GST_ERROR_OBJECT (pipeline, "Couldn't add encodebin");
      return FALSE;
    }
    if (!gst_bin_add (GST_BIN_CAST (pipeline), pipeline->priv->urisink)) {
      GST_ERROR_OBJECT (pipeline, "Couldn't add URI sink");
      return FALSE;
    }
    g_object_set (pipeline->priv->encodebin, "avoid-reencoding",
        !(!(mode & GES_PIPELINE_MODE_SMART_RENDER)), NULL);

    gst_element_link_pads_full (pipeline->priv->encodebin, "src",
        pipeline->priv->urisink, "sink", GST_PAD_LINK_CHECK_NOTHING);
  }

  /* FIXUPS */
  /* FIXME
   * If we are rendering, set playsink to sync=False,
   * If we are NOT rendering, set playsink to sync=TRUE */

  pipeline->priv->mode = mode;

  return TRUE;
}
Ejemplo n.º 24
0
static void
_test_negotiation (const gchar * src_templ, const gchar * sink_templ,
    gint width, gint height, gint par_n, gint par_d)
{
  GstElement *pipeline;
  GstElement *src, *capsfilter1, *scale, *capsfilter2, *sink;
  GstBus *bus;
  GMainLoop *loop;
  GstCaps *caps;
  TestNegotiationData data = { 0, 0, 0, 0, FALSE, NULL };
  GstPad *pad;

  GST_DEBUG ("Running test for src templ caps '%s' and sink templ caps '%s'",
      src_templ, sink_templ);

  pipeline = gst_element_factory_make ("pipeline", "pipeline");
  fail_unless (pipeline != NULL);

  src = gst_element_factory_make ("videotestsrc", "src");
  fail_unless (src != NULL);
  g_object_set (G_OBJECT (src), "num-buffers", 1, NULL);

  capsfilter1 = gst_element_factory_make ("capsfilter", "filter1");
  fail_unless (capsfilter1 != NULL);
  caps = gst_caps_from_string (src_templ);
  fail_unless (caps != NULL);
  g_object_set (G_OBJECT (capsfilter1), "caps", caps, NULL);
  gst_caps_unref (caps);

  scale = gst_element_factory_make ("videoscale", "scale");
  fail_unless (scale != NULL);

  capsfilter2 = gst_element_factory_make ("capsfilter", "filter2");
  fail_unless (capsfilter2 != NULL);
  caps = gst_caps_from_string (sink_templ);
  fail_unless (caps != NULL);
  g_object_set (G_OBJECT (capsfilter2), "caps", caps, NULL);
  gst_caps_unref (caps);

  pad = gst_element_get_static_pad (capsfilter2, "sink");
  fail_unless (pad != NULL);
  g_signal_connect (pad, "notify::caps",
      G_CALLBACK (_test_negotiation_notify_caps), &data);
  gst_object_unref (pad);

  sink = gst_element_factory_make ("fakesink", "sink");
  fail_unless (sink != NULL);
  g_object_set (sink, "async", FALSE, NULL);

  gst_bin_add_many (GST_BIN (pipeline), src, capsfilter1, scale, capsfilter2,
      sink, NULL);

  fail_unless (gst_element_link_pads_full (src, "src", capsfilter1, "sink",
          LINK_CHECK_FLAGS));
  fail_unless (gst_element_link_pads_full (capsfilter1, "src", scale, "sink",
          LINK_CHECK_FLAGS));
  fail_unless (gst_element_link_pads_full (scale, "src", capsfilter2, "sink",
          LINK_CHECK_FLAGS));
  fail_unless (gst_element_link_pads_full (capsfilter2, "src", sink, "sink",
          LINK_CHECK_FLAGS));

  loop = g_main_loop_new (NULL, FALSE);

  bus = gst_element_get_bus (pipeline);
  fail_unless (bus != NULL);
  gst_bus_add_signal_watch (bus);

  data.loop = loop;
  data.width = width;
  data.height = height;
  data.par_n = par_n;
  data.par_d = par_d;
  data.ok = FALSE;

  g_signal_connect (bus, "message", G_CALLBACK (_test_negotiation_message),
      &data);

  gst_object_unref (bus);

  fail_unless (gst_element_set_state (pipeline,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);

  g_main_loop_run (loop);

  fail_unless (data.ok == TRUE);

  fail_unless (gst_element_set_state (pipeline,
          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);

  gst_object_unref (pipeline);
  g_main_loop_unref (loop);
}
static GstElement *
ges_track_video_transition_create_element (GESTrackObject * object)
{
  GstElement *topbin, *iconva, *iconvb, *scalea, *scaleb, *capsfilt, *oconv;
  GstObject *target = NULL;
  const gchar *propname = NULL;
  GstElement *mixer = NULL;
  GstPad *sinka_target, *sinkb_target, *src_target, *sinka, *sinkb, *src,
      *srca_pad;
  GESTrackVideoTransition *self;
  GESTrackVideoTransitionPrivate *priv;

  self = GES_TRACK_VIDEO_TRANSITION (object);
  priv = self->priv;

  GST_LOG ("creating a video bin");

  topbin = gst_bin_new ("transition-bin");
  iconva = gst_element_factory_make ("videoconvert", "tr-csp-a");
  iconvb = gst_element_factory_make ("videoconvert", "tr-csp-b");
  scalea = gst_element_factory_make ("videoscale", "vs-a");
  scaleb = gst_element_factory_make ("videoscale", "vs-b");
  capsfilt = gst_element_factory_make ("capsfilter", "capsfilt");
  oconv = gst_element_factory_make ("videoconvert", "tr-csp-output");

  gst_bin_add_many (GST_BIN (topbin), iconva, iconvb, scalea, scaleb, capsfilt,
      oconv, NULL);

  mixer = gst_element_factory_make ("videomixer", NULL);
  g_assert (mixer);
  g_object_set (G_OBJECT (mixer), "background", 1, NULL);
  gst_bin_add (GST_BIN (topbin), mixer);

  if (priv->pending_type != GES_VIDEO_STANDARD_TRANSITION_TYPE_CROSSFADE) {
    priv->sinka =
        (GstPad *) link_element_to_mixer_with_smpte (GST_BIN (topbin), iconva,
        mixer, priv->pending_type, NULL);
    priv->sinkb =
        (GstPad *) link_element_to_mixer_with_smpte (GST_BIN (topbin), iconvb,
        mixer, priv->pending_type, &priv->smpte);
    target = GST_OBJECT (priv->smpte);
    propname = "position";
    priv->start_value = 1.0;
    priv->end_value = 0.0;
  } else {
    gst_element_link_pads_full (iconva, "src", scalea, "sink",
        GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full (iconvb, "src", scaleb, "sink",
        GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full (scaleb, "src", capsfilt, "sink",
        GST_PAD_LINK_CHECK_NOTHING);

    priv->sinka = (GstPad *) link_element_to_mixer (scalea, mixer);
    priv->sinkb = (GstPad *) link_element_to_mixer (capsfilt, mixer);
    target = GST_OBJECT (priv->sinkb);
    propname = "alpha";
    priv->start_value = 0.0;
    priv->end_value = 1.0;
  }

  priv->mixer = gst_object_ref (mixer);

  fast_element_link (mixer, oconv);

  sinka_target = gst_element_get_static_pad (iconva, "sink");
  sinkb_target = gst_element_get_static_pad (iconvb, "sink");
  src_target = gst_element_get_static_pad (oconv, "src");

  sinka = gst_ghost_pad_new ("sinka", sinka_target);
  sinkb = gst_ghost_pad_new ("sinkb", sinkb_target);
  src = gst_ghost_pad_new ("src", src_target);

  gst_element_add_pad (topbin, src);
  gst_element_add_pad (topbin, sinka);
  gst_element_add_pad (topbin, sinkb);

  srca_pad = gst_element_get_static_pad (scalea, "src");
  g_signal_connect (srca_pad, "notify::caps", G_CALLBACK (on_caps_set),
      (GstElement *) capsfilt);

  gst_object_unref (sinka_target);
  gst_object_unref (sinkb_target);
  gst_object_unref (src_target);
  gst_object_unref (srca_pad);

  /* set up interpolation */

  set_interpolation (target, priv, propname);

  priv->topbin = topbin;
  priv->type = priv->pending_type;

  return topbin;
}
/**
 * ges_timeline_pipeline_set_mode:
 * @pipeline: a #GESTimelinePipeline
 * @mode: the #GESPipelineFlags to use
 *
 * switches the @pipeline to the specified @mode. The default mode when
 * creating a #GESTimelinePipeline is #TIMELINE_MODE_PREVIEW.
 *
 * Note: The @pipeline will be set to #GST_STATE_NULL during this call due to
 * the internal changes that happen. The caller will therefore have to 
 * set the @pipeline to the requested state after calling this method.
 *
 * Returns: %TRUE if the mode was properly set, else %FALSE.
 **/
gboolean
ges_timeline_pipeline_set_mode (GESTimelinePipeline * pipeline,
    GESPipelineFlags mode)
{
  GST_DEBUG_OBJECT (pipeline, "current mode : %d, mode : %d",
      pipeline->priv->mode, mode);

  /* fast-path, nothing to change */
  if (mode == pipeline->priv->mode)
    return TRUE;

  /* FIXME: It would be nice if we are only (de)activating preview
   * modes to not set the whole pipeline to NULL, but instead just
   * do the proper (un)linking to playsink. */

  /* Switch pipeline to NULL since we're changing the configuration */
  gst_element_set_state (GST_ELEMENT_CAST (pipeline), GST_STATE_NULL);

  /* remove no-longer needed components */
  if (pipeline->priv->mode & TIMELINE_MODE_PREVIEW &&
      !(mode & TIMELINE_MODE_PREVIEW)) {
    /* Disable playsink */
    GST_DEBUG ("Disabling playsink");
    g_object_ref (pipeline->priv->playsink);
    gst_bin_remove (GST_BIN_CAST (pipeline), pipeline->priv->playsink);
  }
  if ((pipeline->priv->mode &
          (TIMELINE_MODE_RENDER | TIMELINE_MODE_SMART_RENDER)) &&
      !(mode & (TIMELINE_MODE_RENDER | TIMELINE_MODE_SMART_RENDER))) {
    /* Disable render bin */
    GST_DEBUG ("Disabling rendering bin");
    g_object_ref (pipeline->priv->encodebin);
    g_object_ref (pipeline->priv->urisink);
    gst_bin_remove_many (GST_BIN_CAST (pipeline),
        pipeline->priv->encodebin, pipeline->priv->urisink, NULL);
  }

  /* Add new elements */
  if (!(pipeline->priv->mode & TIMELINE_MODE_PREVIEW) &&
      (mode & TIMELINE_MODE_PREVIEW)) {
    /* Add playsink */
    GST_DEBUG ("Adding playsink");

    if (!gst_bin_add (GST_BIN_CAST (pipeline), pipeline->priv->playsink)) {
      GST_ERROR_OBJECT (pipeline, "Couldn't add playsink");
      return FALSE;
    }
  }
  if (!(pipeline->priv->mode &
          (TIMELINE_MODE_RENDER | TIMELINE_MODE_SMART_RENDER)) &&
      (mode & (TIMELINE_MODE_RENDER | TIMELINE_MODE_SMART_RENDER))) {
    /* Adding render bin */
    GST_DEBUG ("Adding render bin");

    if (G_UNLIKELY (pipeline->priv->urisink == NULL)) {
      GST_ERROR_OBJECT (pipeline, "Output URI not set !");
      return FALSE;
    }
    if (!gst_bin_add (GST_BIN_CAST (pipeline), pipeline->priv->encodebin)) {
      GST_ERROR_OBJECT (pipeline, "Couldn't add encodebin");
      return FALSE;
    }
    if (!gst_bin_add (GST_BIN_CAST (pipeline), pipeline->priv->urisink)) {
      GST_ERROR_OBJECT (pipeline, "Couldn't add URI sink");
      return FALSE;
    }
    g_object_set (pipeline->priv->encodebin, "avoid-reencoding",
        !(!(mode & TIMELINE_MODE_SMART_RENDER)), NULL);

    gst_element_link_pads_full (pipeline->priv->encodebin, "src",
        pipeline->priv->urisink, "sink", GST_PAD_LINK_CHECK_NOTHING);
  }

  /* FIXUPS */
  /* FIXME
   * If we are rendering, set playsink to sync=False,
   * If we are NOT rendering, set playsink to sync=TRUE */

  pipeline->priv->mode = mode;

  return TRUE;
}
bool GStreamerGWorld::enterFullscreen()
{
    if (m_dynamicPadName)
        return false;

    if (!m_videoWindow)
        m_videoWindow = PlatformVideoWindow::createWindow();

    GstElement* platformVideoSink = gst_element_factory_make("autovideosink", "platformVideoSink");
    GstElement* colorspace = gst_element_factory_make(gVideoConvertName, "colorspace");
    GstElement* queue = gst_element_factory_make("queue", "queue");
    GstElement* videoScale = gst_element_factory_make("videoscale", "videoScale");

    // Get video sink bin and the tee inside.
    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"));

    gst_bin_add_many(GST_BIN(videoSink.get()), platformVideoSink, videoScale, colorspace, queue, NULL);

    // Faster elements linking.
    gst_element_link_pads_full(queue, "src", colorspace, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(colorspace, "src", videoScale, "sink", GST_PAD_LINK_CHECK_NOTHING);
    gst_element_link_pads_full(videoScale, "src", platformVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING);

    // Link a new src pad from tee to queue.
#ifndef GST_API_VERSION_1
    GRefPtr<GstPad> srcPad = adoptGRef(gst_element_get_request_pad(tee.get(), "src%d"));
#else
    GRefPtr<GstPad> srcPad = adoptGRef(gst_element_get_request_pad(tee.get(), "src_%u"));
#endif
    GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(queue, "sink"));
    gst_pad_link(srcPad.get(), sinkPad.get());

    m_dynamicPadName.set(gst_pad_get_name(srcPad.get()));

    // Synchronize the new elements with pipeline state. If it's
    // paused limit the state change to pre-rolling.
    GstState state;
    gst_element_get_state(m_pipeline, &state, 0, 0);
    if (state < GST_STATE_PLAYING)
        state = GST_STATE_READY;

    gst_element_set_state(platformVideoSink, state);
    gst_element_set_state(videoScale, state);
    gst_element_set_state(colorspace, state);
    gst_element_set_state(queue, state);

#ifndef GST_API_VERSION_1
    // Query the current media segment informations and send them towards
    // the new tee branch downstream.
    GstQuery* query = gst_query_new_segment(GST_FORMAT_TIME);
    gboolean queryResult = gst_element_query(m_pipeline, query);

    if (!queryResult) {
        gst_query_unref(query);
        return true;
    }

    gint64 position;
    GstFormat format;
    if (!gst_element_query_position(m_pipeline, &format, &position))
        position = 0;

    gdouble rate;
    gint64 startValue, stopValue;
    gst_query_parse_segment(query, &rate, &format, &startValue, &stopValue);

    GstEvent* event = gst_event_new_new_segment(FALSE, rate, format, startValue, stopValue, position);
    gst_pad_push_event(srcPad.get(), event);

    gst_query_unref(query);
#endif
    return true;
}
static void
uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad,
    GstDiscoverer * dc)
{
  PrivateStream *ps;
  GstPad *sinkpad = NULL;
  GstCaps *caps;
  static GstCaps *subs_caps = NULL;

  if (!subs_caps) {
    subs_caps = gst_caps_from_string ("text/plain; text/x-pango-markup; "
        "subpicture/x-pgs; subpicture/x-dvb; application/x-subtitle-unknown; "
        "application/x-ssa; application/x-ass; subtitle/x-kate; "
        "video/x-dvd-subpicture; ");
  }

  GST_DEBUG_OBJECT (dc, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));

  ps = g_slice_new0 (PrivateStream);

  ps->dc = dc;
  ps->pad = pad;
  ps->queue = gst_element_factory_make ("queue", NULL);
  ps->sink = gst_element_factory_make ("fakesink", NULL);

  if (G_UNLIKELY (ps->queue == NULL || ps->sink == NULL))
    goto error;

  g_object_set (ps->sink, "silent", TRUE, NULL);
  g_object_set (ps->queue, "max-size-buffers", 1, "silent", TRUE, NULL);

  caps = gst_pad_get_caps_reffed (pad);

  if (gst_caps_can_intersect (caps, subs_caps)) {
    /* Subtitle streams are sparse and don't provide any information - don't
     * wait for data to preroll */
    g_object_set (ps->sink, "async", FALSE, NULL);
  }

  gst_caps_unref (caps);

  gst_bin_add_many (dc->priv->pipeline, ps->queue, ps->sink, NULL);

  if (!gst_element_link_pads_full (ps->queue, "src", ps->sink, "sink",
          GST_PAD_LINK_CHECK_NOTHING))
    goto error;
  if (!gst_element_sync_state_with_parent (ps->sink))
    goto error;
  if (!gst_element_sync_state_with_parent (ps->queue))
    goto error;

  sinkpad = gst_element_get_static_pad (ps->queue, "sink");
  if (sinkpad == NULL)
    goto error;
  if (gst_pad_link_full (pad, sinkpad,
          GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)
    goto error;
  gst_object_unref (sinkpad);

  /* Add an event probe */
  gst_pad_add_event_probe (pad, G_CALLBACK (_event_probe), ps);

  DISCO_LOCK (dc);
  dc->priv->streams = g_list_append (dc->priv->streams, ps);
  DISCO_UNLOCK (dc);

  GST_DEBUG_OBJECT (dc, "Done handling pad");

  return;

error:
  GST_ERROR_OBJECT (dc, "Error while handling pad");
  if (sinkpad)
    gst_object_unref (sinkpad);
  if (ps->queue)
    gst_object_unref (ps->queue);
  if (ps->sink)
    gst_object_unref (ps->sink);
  g_slice_free (PrivateStream, ps);
  return;
}
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;
    }
}
Ejemplo n.º 30
0
static void
run_test (const GstCaps * caps, gint src_width, gint src_height,
    gint dest_width, gint dest_height, gint method,
    GCallback src_handoff, gpointer src_handoff_user_data,
    GCallback sink_handoff, gpointer sink_handoff_user_data)
{
  GstElement *pipeline;
  GstElement *src, *videoconvert, *capsfilter1, *identity, *scale,
      *capsfilter2, *sink;
  GstMessage *msg;
  GstBus *bus;
  GstCaps *copy;
  guint n_buffers = 0;

  /* skip formats that videoconvert can't handle */
  if (!videoconvert_supports_caps (caps))
    return;

  pipeline = gst_element_factory_make ("pipeline", "pipeline");
  fail_unless (pipeline != NULL);

  src = gst_element_factory_make ("videotestsrc", "src");
  fail_unless (src != NULL);
  g_object_set (G_OBJECT (src), "num-buffers", 1, NULL);

  videoconvert = gst_element_factory_make ("videoconvert", "csp");
  fail_unless (videoconvert != NULL);

  capsfilter1 = gst_element_factory_make ("capsfilter", "filter1");
  fail_unless (capsfilter1 != NULL);
  copy = gst_caps_copy (caps);
  gst_caps_set_simple (copy, "width", G_TYPE_INT, src_width, "height",
      G_TYPE_INT, src_height, "framerate", GST_TYPE_FRACTION, 30, 1, NULL);
  g_object_set (G_OBJECT (capsfilter1), "caps", copy, NULL);
  gst_caps_unref (copy);

  identity = gst_element_factory_make ("identity", "identity");
  fail_unless (identity != NULL);
  if (src_handoff) {
    g_object_set (G_OBJECT (identity), "signal-handoffs", TRUE, NULL);
    g_signal_connect (identity, "handoff", G_CALLBACK (src_handoff),
        src_handoff_user_data);
  }

  scale = gst_element_factory_make ("videoscale", "scale");
  fail_unless (scale != NULL);
  g_object_set (G_OBJECT (scale), "method", method, NULL);

  capsfilter2 = gst_element_factory_make ("capsfilter", "filter2");
  fail_unless (capsfilter2 != NULL);
  copy = gst_caps_copy (caps);
  gst_caps_set_simple (copy, "width", G_TYPE_INT, dest_width, "height",
      G_TYPE_INT, dest_height, NULL);
  g_object_set (G_OBJECT (capsfilter2), "caps", copy, NULL);
  gst_caps_unref (copy);

  sink = gst_element_factory_make ("fakesink", "sink");
  fail_unless (sink != NULL);
  g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, "async", FALSE, NULL);
  g_signal_connect (sink, "handoff", G_CALLBACK (on_sink_handoff), &n_buffers);
  if (sink_handoff) {
    g_signal_connect (sink, "handoff", G_CALLBACK (sink_handoff),
        sink_handoff_user_data);
  }

  gst_bin_add_many (GST_BIN (pipeline), src, videoconvert, capsfilter1,
      identity, scale, capsfilter2, sink, NULL);

  fail_unless (gst_element_link_pads_full (src, "src", videoconvert, "sink",
          LINK_CHECK_FLAGS));
  fail_unless (gst_element_link_pads_full (videoconvert, "src", capsfilter1,
          "sink", LINK_CHECK_FLAGS));
  fail_unless (gst_element_link_pads_full (capsfilter1, "src", identity, "sink",
          LINK_CHECK_FLAGS));
  fail_unless (gst_element_link_pads_full (identity, "src", scale, "sink",
          LINK_CHECK_FLAGS));
  fail_unless (gst_element_link_pads_full (scale, "src", capsfilter2, "sink",
          LINK_CHECK_FLAGS));
  fail_unless (gst_element_link_pads_full (capsfilter2, "src", sink, "sink",
          LINK_CHECK_FLAGS));

  bus = gst_element_get_bus (pipeline);
  fail_unless (bus != NULL);

  fail_unless (gst_element_set_state (pipeline,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);

  msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
      GST_MESSAGE_EOS | GST_MESSAGE_ERROR | GST_MESSAGE_WARNING);

  fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_EOS);

  fail_unless (gst_element_set_state (pipeline,
          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);

  fail_unless (n_buffers == 1);

  gst_object_unref (pipeline);
  gst_message_unref (msg);
  gst_object_unref (bus);
}