static GstCaps * gst_decklink_audio_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) { GstDecklinkAudioSink *self = GST_DECKLINK_AUDIO_SINK_CAST (bsink); GstCaps *caps; if ((caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (bsink)))) return caps; caps = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink)); GST_OBJECT_LOCK (self); if (self->output && self->output->attributes) { int64_t max_channels = 0; HRESULT ret; GstStructure *s; GValue arr = G_VALUE_INIT; GValue v = G_VALUE_INIT; ret = self->output->attributes->GetInt (BMDDeckLinkMaximumAudioChannels, &max_channels); /* 2 should always be supported */ if (ret != S_OK) { max_channels = 2; } caps = gst_caps_make_writable (caps); s = gst_caps_get_structure (caps, 0); g_value_init (&arr, GST_TYPE_LIST); g_value_init (&v, G_TYPE_INT); if (max_channels >= 16) { g_value_set_int (&v, 16); gst_value_list_append_value (&arr, &v); } if (max_channels >= 8) { g_value_set_int (&v, 8); gst_value_list_append_value (&arr, &v); } g_value_set_int (&v, 2); gst_value_list_append_value (&arr, &v); gst_structure_set_value (s, "channels", &arr); g_value_unset (&v); g_value_unset (&arr); } GST_OBJECT_UNLOCK (self); if (filter) { GstCaps *intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (caps); caps = intersection; } return caps; }
GstCaps * gst_edt_pdv_sink_get_caps (GstBaseSink * basesink, GstCaps * filter_caps) { GstEdtPdvSink *pdvsink = GST_EDT_PDV_SINK (basesink); gint width, height, depth; GstVideoFormat format; GstVideoInfo vinfo; if (!pdvsink->dev) { return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (pdvsink))); } gst_video_info_init (&vinfo); width = pdv_get_width (pdvsink->dev); height = pdv_get_height (pdvsink->dev); depth = pdv_get_depth (pdvsink->dev); switch (depth) { case 8: format = GST_VIDEO_FORMAT_GRAY8; break; case 16: /* TODO: will this be host order or always one of BE/LE? */ format = GST_VIDEO_FORMAT_GRAY16_BE; break; default: format = GST_VIDEO_FORMAT_UNKNOWN; } gst_video_info_set_format (&vinfo, format, width, height); /* TODO: handle filter_caps */ return gst_video_info_to_caps (&vinfo); }
static gboolean gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) { GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); const GstStructure *structure; GstCaps *allowed_caps; gboolean ret = TRUE; GST_LOG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps); allowed_caps = gst_pad_get_caps (GST_BASE_SINK_PAD (bsink)); if (!gst_caps_can_intersect (allowed_caps, caps)) return FALSE; structure = gst_caps_get_structure (caps, 0); ret &= gst_structure_get_int (structure, "width", &sink->video_width); ret &= gst_structure_get_int (structure, "height", &sink->video_height); if (!ret) return FALSE; gst_caps_replace (&sink->caps, caps); return TRUE; }
static void gst_shout2send_init (GstShout2send * shout2send) { gst_base_sink_set_sync (GST_BASE_SINK (shout2send), FALSE); gst_pad_set_setcaps_function (GST_BASE_SINK_PAD (shout2send), GST_DEBUG_FUNCPTR (gst_shout2send_setcaps)); shout2send->timer = gst_poll_new_timer (); shout2send->ip = g_strdup (DEFAULT_IP); shout2send->port = DEFAULT_PORT; shout2send->password = g_strdup (DEFAULT_PASSWORD); shout2send->username = g_strdup (DEFAULT_USERNAME); shout2send->streamname = g_strdup (DEFAULT_STREAMNAME); shout2send->description = g_strdup (DEFAULT_DESCRIPTION); shout2send->genre = g_strdup (DEFAULT_GENRE); shout2send->mount = g_strdup (DEFAULT_MOUNT); shout2send->url = g_strdup (DEFAULT_URL); shout2send->protocol = DEFAULT_PROTOCOL; shout2send->ispublic = DEFAULT_PUBLIC; shout2send->tags = gst_tag_list_new (); shout2send->conn = NULL; shout2send->audio_format = SHOUT_FORMAT_VORBIS; shout2send->connected = FALSE; shout2send->songmetadata = NULL; shout2send->songartist = NULL; shout2send->songtitle = NULL; }
static GstCaps * gst_oss_sink_getcaps (GstBaseSink * bsink, GstCaps * filter) { GstOssSink *osssink; GstCaps *caps; osssink = GST_OSSSINK (bsink); if (osssink->fd == -1) { caps = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink)); } else if (osssink->probed_caps) { caps = gst_caps_ref (osssink->probed_caps); } else { caps = gst_oss_helper_probe_caps (osssink->fd); if (caps && !gst_caps_is_empty (caps)) { osssink->probed_caps = gst_caps_ref (caps); } } if (filter && caps) { GstCaps *intersection; intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (caps); return intersection; } else { return caps; } }
static GstCaps * gst_openal_sink_getcaps (GstBaseSink * bsink) { GstOpenALSink *sink = GST_OPENAL_SINK (bsink); GstCaps *caps; if (sink->device == NULL) { GstPad *pad = GST_BASE_SINK_PAD (bsink); caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); } else if (sink->probed_caps) caps = gst_caps_copy (sink->probed_caps); else { if (sink->context) caps = gst_openal_helper_probe_caps (sink->context); else if (sink->custom_ctx) caps = gst_openal_helper_probe_caps (sink->custom_ctx); else { ALCcontext *ctx = alcCreateContext (sink->device, NULL); if (ctx) { caps = gst_openal_helper_probe_caps (ctx); alcDestroyContext (ctx); } else { GST_ELEMENT_WARNING (sink, RESOURCE, FAILED, ("Could not create temporary context."), GST_ALC_ERROR (sink->device)); caps = NULL; } } if (caps && !gst_caps_is_empty (caps)) sink->probed_caps = gst_caps_copy (caps); } return caps; }
static GstCaps * gst_v4l2sink_get_caps (GstBaseSink * bsink) { GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink); GstCaps *ret; GSList *walk; GSList *formats; if (!GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) { /* FIXME: copy? */ GST_DEBUG_OBJECT (v4l2sink, "device is not open"); return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (v4l2sink))); } if (v4l2sink->probed_caps) { LOG_CAPS (v4l2sink, v4l2sink->probed_caps); return gst_caps_ref (v4l2sink->probed_caps); } formats = gst_v4l2_object_get_format_list (v4l2sink->v4l2object); ret = gst_caps_new_empty (); for (walk = v4l2sink->v4l2object->formats; walk; walk = walk->next) { struct v4l2_fmtdesc *format; GstStructure *template;
/* GstBaseSink vmethod implementations */ static GstCaps * gst_osx_audio_sink_getcaps (GstBaseSink * sink) { GstCaps *caps; GstOsxAudioSink *osxsink; OSStatus status; AudioValueRange rates[10]; UInt32 propertySize; int i; propertySize = sizeof (AudioValueRange) * 9; osxsink = GST_OSX_AUDIO_SINK (sink); caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (sink))); status = AudioDeviceGetProperty (osxsink->ringbuffer->device_id, 0, FALSE, kAudioDevicePropertyAvailableNominalSampleRates, &propertySize, &rates); GST_DEBUG ("Getting available sample rates: Status: %ld number of ranges: %lu", status, propertySize / sizeof (AudioValueRange)); for (i = 0; i < propertySize / sizeof (AudioValueRange); i++) { GST_LOG_OBJECT (osxsink, "Range from %f to %f", rates[i].mMinimum, rates[i].mMaximum); } return caps; }
static GstFlowReturn gst_test_reverse_negotiation_sink_render (GstBaseSink * bsink, GstBuffer * buffer) { GstTestReverseNegotiationSink *sink = GST_TEST_REVERSE_NEGOTIATION_SINK (bsink); GstCaps *caps; GstVideoInfo info; caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (bsink)); fail_unless (caps != NULL); fail_unless (gst_video_info_from_caps (&info, caps)); sink->nbuffers++; /* The third buffer is still in the old size * because the videoconverts can't convert * the frame sizes */ if (sink->nbuffers > 3) { fail_unless_equals_int (GST_VIDEO_INFO_WIDTH (&info), 512); fail_unless_equals_int (GST_VIDEO_INFO_HEIGHT (&info), 128); } gst_caps_unref (caps); return GST_FLOW_OK; }
static void gst_gio_base_sink_init (GstGioBaseSink * sink, GstGioBaseSinkClass * gclass) { gst_pad_set_query_function (GST_BASE_SINK_PAD (sink), GST_DEBUG_FUNCPTR (gst_gio_base_sink_query)); gst_base_sink_set_sync (GST_BASE_SINK (sink), FALSE); sink->cancel = g_cancellable_new (); }
static GstCaps * gst_v4l2sink_get_caps (GstBaseSink * bsink, GstCaps * filter) { GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink); if (!GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) { /* FIXME: copy? */ GST_DEBUG_OBJECT (v4l2sink, "device is not open"); return gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (v4l2sink)); } return gst_v4l2_object_get_caps (v4l2sink->v4l2object, filter); }
static void gst_gnome_vfs_sink_init (GstGnomeVFSSink * sink, GstGnomeVFSSinkClass * klass) { gst_pad_set_query_function (GST_BASE_SINK_PAD (sink), GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_query)); sink->uri = NULL; sink->uri_name = NULL; sink->handle = NULL; sink->own_handle = FALSE; sink->current_pos = 0; GST_BASE_SINK (sink)->sync = FALSE; }
static void gst_fd_sink_init (GstFdSink * fdsink, GstFdSinkClass * klass) { GstPad *pad; pad = GST_BASE_SINK_PAD (fdsink); gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_fd_sink_query)); fdsink->fd = 1; fdsink->uri = g_strdup_printf ("fd://%d", fdsink->fd); fdsink->bytes_written = 0; fdsink->current_pos = 0; gst_base_sink_set_sync (GST_BASE_SINK (fdsink), FALSE); }
const gchar * get_mime_type (GstAnalyzerSink * sink) { GstCaps *caps = NULL; GstStructure *structure; const gchar *name; caps = gst_pad_get_allowed_caps (GST_BASE_SINK_PAD (sink)); if (caps) { caps = gst_caps_truncate (caps); structure = gst_caps_get_structure (caps, 0); name = g_strdup (gst_structure_get_name (structure)); gst_caps_unref (caps); return name; } return NULL; }
static GstCaps * gst_openal_sink_getcaps (GstBaseSink * basesink, GstCaps * filter) { GstOpenALSink *sink = GST_OPENAL_SINK (basesink); GstCaps *caps; if (sink->default_device == NULL) { GstPad *pad = GST_BASE_SINK_PAD (basesink); GstCaps *tcaps = gst_pad_get_pad_template_caps (pad); caps = gst_caps_copy (tcaps); gst_caps_unref (tcaps); } else if (sink->probed_caps) caps = gst_caps_copy (sink->probed_caps); else { if (sink->default_context) caps = gst_openal_helper_probe_caps (sink->default_context); else if (sink->user_context) caps = gst_openal_helper_probe_caps (sink->user_context); else { ALCcontext *context = alcCreateContext (sink->default_device, NULL); if (context) { caps = gst_openal_helper_probe_caps (context); alcDestroyContext (context); } else { GST_ELEMENT_WARNING (sink, RESOURCE, FAILED, ("Could not create temporary context."), GST_ALC_ERROR (sink->default_device)); caps = NULL; } } if (caps && !gst_caps_is_empty (caps)) sink->probed_caps = gst_caps_copy (caps); } if (filter) { GstCaps *intersection; intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); return intersection; } else { return caps; } }
static void gst_file_sink_init (GstFileSink * filesink, GstFileSinkClass * g_class) { GstPad *pad; pad = GST_BASE_SINK_PAD (filesink); gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_file_sink_query)); filesink->filename = NULL; filesink->file = NULL; filesink->buffer_mode = DEFAULT_BUFFER_MODE; filesink->buffer_size = DEFAULT_BUFFER_SIZE; filesink->buffer = NULL; filesink->append = FALSE; gst_base_sink_set_sync (GST_BASE_SINK (filesink), FALSE); }
static GstCaps * gst_eglglessink_getcaps (GstBaseSink * bsink) { GstEglGlesSink *eglglessink; GstCaps *ret = NULL; eglglessink = GST_EGLGLESSINK (bsink); GST_OBJECT_LOCK (eglglessink); if (eglglessink->sinkcaps) { ret = gst_caps_ref (eglglessink->sinkcaps); } else { ret = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink))); } GST_OBJECT_UNLOCK (eglglessink); return ret; }
static void type_instance_init (GTypeInstance * instance, gpointer g_class) { GstOmxBaseSink *self; self = GST_OMX_BASE_SINK (instance); GST_LOG_OBJECT (self, "begin"); self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (g_class)); self->in_port = g_omx_core_new_port (self->gomx, 0); { GstPad *sinkpad; self->sinkpad = sinkpad = GST_BASE_SINK_PAD (self); self->base_activatepush = GST_PAD_ACTIVATEPUSHFUNC (sinkpad); gst_pad_set_activatepush_function (sinkpad, activate_push); gst_pad_set_link_function (sinkpad, pad_sink_link); } GST_LOG_OBJECT (self, "end"); }
static void gst_aasink_init (GstAASink * aasink) { GstPad *pad; pad = GST_BASE_SINK_PAD (aasink); gst_pad_set_fixatecaps_function (pad, gst_aasink_fixate); memcpy (&aasink->ascii_surf, &aa_defparams, sizeof (struct aa_hardware_params)); aasink->ascii_parms.bright = 0; aasink->ascii_parms.contrast = 16; aasink->ascii_parms.gamma = 1.0; aasink->ascii_parms.dither = 0; aasink->ascii_parms.inversion = 0; aasink->ascii_parms.randomval = 0; aasink->aa_driver = 0; aasink->width = -1; aasink->height = -1; }
static GstCaps * gst_oss_sink_getcaps (GstBaseSink * bsink) { GstOssSink *osssink; GstCaps *caps; osssink = GST_OSSSINK (bsink); if (osssink->fd == -1) { caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink))); } else if (osssink->probed_caps) { caps = gst_caps_copy (osssink->probed_caps); } else { caps = gst_oss_helper_probe_caps (osssink->fd); if (caps && !gst_caps_is_empty (caps)) { osssink->probed_caps = gst_caps_copy (caps); } } return caps; }
static GstCaps * gst_audioflinger_sink_getcaps (GstBaseSink * bsink) { GstAudioFlingerSink *audioflinger_sink; GstCaps *caps; audioflinger_sink = GST_AUDIOFLINGERSINK (bsink); GST_DEBUG_OBJECT (audioflinger_sink, "enter,%p", audioflinger_sink->audioflinger_device); if (audioflinger_sink->audioflinger_device == NULL || audioflinger_sink->m_init == FALSE) { caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink))); } else if (audioflinger_sink->probed_caps) { caps = gst_caps_copy (audioflinger_sink->probed_caps); } else { caps = gst_caps_new_any (); if (caps && !gst_caps_is_empty (caps)) { audioflinger_sink->probed_caps = gst_caps_copy (caps); } } return caps; }
static void type_instance_init (GTypeInstance *instance, gpointer g_class) { GstOmxBaseSink *self; self = GST_OMX_BASE_SINK (instance); GST_LOG_OBJECT (self, "begin"); /* GOmx */ { GOmxCore *gomx; self->gomx = gomx = g_omx_core_new (); gomx->object = self; } { const char *tmp; tmp = g_type_get_qdata (G_OBJECT_CLASS_TYPE (g_class), g_quark_from_static_string ("library-name")); self->omx_library = g_strdup (tmp); tmp = g_type_get_qdata (G_OBJECT_CLASS_TYPE (g_class), g_quark_from_static_string ("component-name")); self->omx_component = g_strdup (tmp); } { GstPad *sinkpad; self->sinkpad = sinkpad = GST_BASE_SINK_PAD (self); self->base_activatepush = GST_PAD_ACTIVATEPUSHFUNC (sinkpad); gst_pad_set_activatepush_function (sinkpad, activate_push); gst_pad_set_link_function (sinkpad, pad_sink_link); } GST_LOG_OBJECT (self, "end"); }
static GstCaps * gst_gtk_gl_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) { GstCaps *tmp = NULL; GstCaps *result = NULL; tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink)); if (filter) { GST_DEBUG_OBJECT (bsink, "intersecting with filter caps %" GST_PTR_FORMAT, filter); result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (tmp); } else { result = tmp; } result = gst_gl_overlay_compositor_add_caps (result); GST_DEBUG_OBJECT (bsink, "returning caps: %" GST_PTR_FORMAT, result); return result; }
static CoglBool cogl_gst_source_dispatch (GSource *source, GSourceFunc callback, void *user_data) { CoglGstSource *gst_source= (CoglGstSource*) source; CoglGstVideoSinkPrivate *priv = gst_source->sink->priv; GstBuffer *buffer; g_mutex_lock (&gst_source->buffer_lock); if (G_UNLIKELY (gst_source->has_new_caps)) { GstCaps *caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD ((GST_BASE_SINK (gst_source->sink)))); if (!cogl_gst_video_sink_parse_caps (caps, gst_source->sink, TRUE)) goto negotiation_fail; gst_source->has_new_caps = FALSE; priv->free_layer = priv->custom_start + priv->renderer->n_layers; dirty_default_pipeline (gst_source->sink); /* We are now in a state where we could generate the pipeline if * the application requests it so we can emit the signal. * However we'll actually generate the pipeline lazily only if * the application actually asks for it. */ g_signal_emit (gst_source->sink, video_sink_signals[PIPELINE_READY_SIGNAL], 0 /* detail */); } buffer = gst_source->buffer; gst_source->buffer = NULL; g_mutex_unlock (&gst_source->buffer_lock); if (buffer) { if (!priv->renderer->upload (gst_source->sink, buffer)) goto fail_upload; g_signal_emit (gst_source->sink, video_sink_signals[NEW_FRAME_SIGNAL], 0, NULL); gst_buffer_unref (buffer); } else GST_WARNING_OBJECT (gst_source->sink, "No buffers available for display"); return TRUE; negotiation_fail: { GST_WARNING_OBJECT (gst_source->sink, "Failed to handle caps. Stopping GSource"); priv->flow_return = GST_FLOW_NOT_NEGOTIATED; g_mutex_unlock (&gst_source->buffer_lock); return FALSE; } fail_upload: { GST_WARNING_OBJECT (gst_source->sink, "Failed to upload buffer"); priv->flow_return = GST_FLOW_ERROR; gst_buffer_unref (buffer); return FALSE; } }
static GstFlowReturn gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer) { GstFlowReturn ret; GstAppSink *appsink = GST_APP_SINK_CAST (psink); GstAppSinkPrivate *priv = appsink->priv; gboolean emit; restart: g_mutex_lock (&priv->mutex); if (priv->flushing) goto flushing; /* queue holding caps event might have been FLUSHed, * but caps state still present in pad caps */ if (G_UNLIKELY (!priv->last_caps && gst_pad_has_current_caps (GST_BASE_SINK_PAD (psink)))) { priv->last_caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (psink)); GST_DEBUG_OBJECT (appsink, "activating pad caps %" GST_PTR_FORMAT, priv->last_caps); } GST_DEBUG_OBJECT (appsink, "pushing render buffer %p on queue (%d)", buffer, priv->num_buffers); while (priv->max_buffers > 0 && priv->num_buffers >= priv->max_buffers) { if (priv->drop) { GstBuffer *old; /* we need to drop the oldest buffer and try again */ if ((old = dequeue_buffer (appsink))) { GST_DEBUG_OBJECT (appsink, "dropping old buffer %p", old); gst_buffer_unref (old); } } else { GST_DEBUG_OBJECT (appsink, "waiting for free space, length %d >= %d", priv->num_buffers, priv->max_buffers); if (priv->unlock) { /* we are asked to unlock, call the wait_preroll method */ g_mutex_unlock (&priv->mutex); if ((ret = gst_base_sink_wait_preroll (psink)) != GST_FLOW_OK) goto stopping; /* we are allowed to continue now */ goto restart; } /* wait for a buffer to be removed or flush */ g_cond_wait (&priv->cond, &priv->mutex); if (priv->flushing) goto flushing; } } /* we need to ref the buffer when pushing it in the queue */ g_queue_push_tail (priv->queue, gst_buffer_ref (buffer)); priv->num_buffers++; g_cond_signal (&priv->cond); emit = priv->emit_signals; g_mutex_unlock (&priv->mutex); if (priv->callbacks.new_sample) { ret = priv->callbacks.new_sample (appsink, priv->user_data); } else { ret = GST_FLOW_OK; if (emit) g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_SAMPLE], 0, &ret); } return ret; flushing: { GST_DEBUG_OBJECT (appsink, "we are flushing"); g_mutex_unlock (&priv->mutex); return GST_FLOW_FLUSHING; } stopping: { GST_DEBUG_OBJECT (appsink, "we are stopping"); return ret; } }
/* Buffer management * * The buffer_alloc function must either return a buffer with given size and * caps or create a buffer with different caps attached to the buffer. This * last option is called reverse negotiation, ie, where the sink suggests a * different format from the upstream peer. * * We try to do reverse negotiation when our geometry changes and we like a * resized buffer. */ static GstFlowReturn gst_vdp_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf) { VdpSink *vdp_sink; GstStructure *structure = NULL; GstFlowReturn ret = GST_FLOW_OK; gint width, height; GstCaps *alloc_caps; gint w_width, w_height; GError *err; vdp_sink = GST_VDP_SINK (bsink); GST_LOG_OBJECT (vdp_sink, "a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT " and offset %" G_GUINT64_FORMAT, size, caps, offset); /* get struct to see what is requested */ structure = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (structure, "width", &width) || !gst_structure_get_int (structure, "height", &height)) { GST_WARNING_OBJECT (vdp_sink, "invalid caps for buffer allocation %" GST_PTR_FORMAT, caps); ret = GST_FLOW_NOT_NEGOTIATED; goto beach; } alloc_caps = gst_caps_ref (caps); /* We take the flow_lock because the window might go away */ g_mutex_lock (vdp_sink->flow_lock); if (!vdp_sink->window) { g_mutex_unlock (vdp_sink->flow_lock); goto alloc; } /* What is our geometry */ gst_vdp_sink_window_update_geometry (vdp_sink, vdp_sink->window); w_width = vdp_sink->window->width; w_height = vdp_sink->window->height; g_mutex_unlock (vdp_sink->flow_lock); /* We would like another geometry */ if (width != w_width || height != w_height) { GstCaps *new_caps, *allowed_caps, *desired_caps; GstStructure *desired_struct; /* make a copy of the incomming caps to create the new * suggestion. We can't use make_writable because we might * then destroy the original caps which we still need when the * peer does not accept the suggestion. */ new_caps = gst_caps_copy (caps); desired_struct = gst_caps_get_structure (new_caps, 0); GST_DEBUG ("we would love to receive a %dx%d video", w_width, w_height); gst_structure_set (desired_struct, "width", G_TYPE_INT, w_width, NULL); gst_structure_set (desired_struct, "height", G_TYPE_INT, w_height, NULL); allowed_caps = gst_pad_get_caps (GST_BASE_SINK_PAD (vdp_sink)); desired_caps = gst_caps_intersect (new_caps, allowed_caps); gst_caps_unref (new_caps); gst_caps_unref (allowed_caps); /* see if peer accepts our new suggestion, if there is no peer, this * function returns true. */ if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (vdp_sink), desired_caps)) { /* we will not alloc a buffer of the new suggested caps. Make sure * we also unref this new caps after we set it on the buffer. */ GST_DEBUG ("peer pad accepts our desired caps %" GST_PTR_FORMAT, desired_caps); gst_caps_unref (alloc_caps); alloc_caps = desired_caps; } else { GST_DEBUG ("peer pad does not accept our desired caps %" GST_PTR_FORMAT, desired_caps); /* we alloc a buffer with the original incomming caps already in the * width and height variables */ gst_caps_unref (desired_caps); } } alloc: gst_vdp_buffer_pool_set_caps (vdp_sink->bpool, alloc_caps); gst_caps_unref (alloc_caps); err = NULL; *buf = GST_BUFFER_CAST (gst_vdp_buffer_pool_get_buffer (vdp_sink->bpool, &err)); if (!*buf) { gst_vdp_sink_post_error (vdp_sink, err); return GST_FLOW_ERROR; } beach: return ret; }
static gboolean gst_vdp_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) { VdpSink *vdp_sink; GstCaps *allowed_caps; gboolean ret = TRUE; GstStructure *structure; GstCaps *intersection; gint new_width, new_height; const GValue *fps; vdp_sink = GST_VDP_SINK (bsink); GST_OBJECT_LOCK (vdp_sink); if (!vdp_sink->device) return FALSE; GST_OBJECT_UNLOCK (vdp_sink); allowed_caps = gst_pad_get_caps (GST_BASE_SINK_PAD (bsink)); GST_DEBUG_OBJECT (vdp_sink, "sinkconnect possible caps %" GST_PTR_FORMAT " with given caps %" GST_PTR_FORMAT, allowed_caps, caps); /* We intersect those caps with our template to make sure they are correct */ intersection = gst_caps_intersect (allowed_caps, caps); gst_caps_unref (allowed_caps); GST_DEBUG_OBJECT (vdp_sink, "intersection returned %" GST_PTR_FORMAT, intersection); if (gst_caps_is_empty (intersection)) { gst_caps_unref (intersection); return FALSE; } gst_caps_unref (intersection); structure = gst_caps_get_structure (caps, 0); ret &= gst_structure_get_int (structure, "width", &new_width); ret &= gst_structure_get_int (structure, "height", &new_height); fps = gst_structure_get_value (structure, "framerate"); ret &= (fps != NULL); if (!ret) return FALSE; GST_VIDEO_SINK_WIDTH (vdp_sink) = new_width; GST_VIDEO_SINK_HEIGHT (vdp_sink) = new_height; vdp_sink->fps_n = gst_value_get_fraction_numerator (fps); vdp_sink->fps_d = gst_value_get_fraction_denominator (fps); gst_vdp_buffer_pool_set_caps (vdp_sink->bpool, caps); /* Notify application to set xwindow id now */ g_mutex_lock (vdp_sink->flow_lock); if (!vdp_sink->window) { g_mutex_unlock (vdp_sink->flow_lock); gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (vdp_sink)); } else { g_mutex_unlock (vdp_sink->flow_lock); } /* Creating our window and our image */ if (GST_VIDEO_SINK_WIDTH (vdp_sink) <= 0 || GST_VIDEO_SINK_HEIGHT (vdp_sink) <= 0) { GST_ELEMENT_ERROR (vdp_sink, CORE, NEGOTIATION, (NULL), ("Invalid image size.")); return FALSE; } g_mutex_lock (vdp_sink->flow_lock); if (!vdp_sink->window) { vdp_sink->window = gst_vdp_sink_window_new (vdp_sink, GST_VIDEO_SINK_WIDTH (vdp_sink), GST_VIDEO_SINK_HEIGHT (vdp_sink)); } g_mutex_unlock (vdp_sink->flow_lock); return TRUE; }
static GstFlowReturn webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer) { WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink); WebKitVideoSinkPrivate* priv = sink->priv; g_mutex_lock(priv->buffer_mutex); if (priv->unlocked) { g_mutex_unlock(priv->buffer_mutex); return GST_FLOW_OK; } // Ignore buffers if the video is already in fullscreen using // another sink. if (priv->gstGWorld->isFullscreen()) { g_mutex_unlock(priv->buffer_mutex); return GST_FLOW_OK; } priv->buffer = gst_buffer_ref(buffer); // For the unlikely case where the buffer has no caps, the caps // are implicitely the caps of the pad. This shouldn't happen. if (G_UNLIKELY(!GST_BUFFER_CAPS(buffer))) { buffer = priv->buffer = gst_buffer_make_metadata_writable(priv->buffer); gst_buffer_set_caps(priv->buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(bsink))); } GstCaps *caps = GST_BUFFER_CAPS(buffer); GstVideoFormat format; int width, height; if (G_UNLIKELY(!gst_video_format_parse_caps(caps, &format, &width, &height))) { gst_buffer_unref(buffer); g_mutex_unlock(priv->buffer_mutex); return GST_FLOW_ERROR; } // Cairo's ARGB has pre-multiplied alpha while GStreamer's doesn't. // Here we convert to Cairo's ARGB. if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) { // Because GstBaseSink::render() only owns the buffer reference in the // method scope we can't use gst_buffer_make_writable() here. Also // The buffer content should not be changed here because the same buffer // could be passed multiple times to this method (in theory) GstBuffer *newBuffer = gst_buffer_try_new_and_alloc(GST_BUFFER_SIZE(buffer)); // Check if allocation failed if (G_UNLIKELY(!newBuffer)) { gst_buffer_unref(buffer); g_mutex_unlock(priv->buffer_mutex); return GST_FLOW_ERROR; } gst_buffer_copy_metadata(newBuffer, buffer, (GstBufferCopyFlags) GST_BUFFER_COPY_ALL); // We don't use Color::premultipliedARGBFromColor() here because // one function call per video pixel is just too expensive: // For 720p/PAL for example this means 1280*720*25=23040000 // function calls per second! unsigned short alpha; const guint8 *source = GST_BUFFER_DATA(buffer); guint8 *destination = GST_BUFFER_DATA(newBuffer); for (int x = 0; x < height; x++) { for (int y = 0; y < width; y++) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN alpha = source[3]; destination[0] = (source[0] * alpha + 128) / 255; destination[1] = (source[1] * alpha + 128) / 255; destination[2] = (source[2] * alpha + 128) / 255; destination[3] = alpha; #else alpha = source[0]; destination[0] = alpha; destination[1] = (source[1] * alpha + 128) / 255; destination[2] = (source[2] * alpha + 128) / 255; destination[3] = (source[3] * alpha + 128) / 255; #endif source += 4; destination += 4; } } gst_buffer_unref(buffer); buffer = priv->buffer = newBuffer; } // This should likely use a lower priority, but glib currently starves // lower priority sources. // See: https://bugzilla.gnome.org/show_bug.cgi?id=610830. priv->timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, webkit_video_sink_timeout_func, gst_object_ref(sink), (GDestroyNotify)gst_object_unref); g_cond_wait(priv->data_cond, priv->buffer_mutex); g_mutex_unlock(priv->buffer_mutex); return GST_FLOW_OK; }
static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buffer) { WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(baseSink); WebKitVideoSinkPrivate* priv = sink->priv; g_mutex_lock(priv->bufferMutex); if (priv->unlocked) { g_mutex_unlock(priv->bufferMutex); return GST_FLOW_OK; } #if USE(NATIVE_FULLSCREEN_VIDEO) // Ignore buffers if the video is already in fullscreen using // another sink. if (priv->gstGWorld->isFullscreen()) { g_mutex_unlock(priv->bufferMutex); return GST_FLOW_OK; } #endif priv->buffer = gst_buffer_ref(buffer); #ifndef GST_API_VERSION_1 // For the unlikely case where the buffer has no caps, the caps // are implicitely the caps of the pad. This shouldn't happen. if (UNLIKELY(!GST_BUFFER_CAPS(buffer))) { buffer = priv->buffer = gst_buffer_make_metadata_writable(priv->buffer); gst_buffer_set_caps(priv->buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(baseSink))); } GRefPtr<GstCaps> caps = GST_BUFFER_CAPS(buffer); #else GRefPtr<GstCaps> caps; // The video info structure is valid only if the sink handled an allocation query. if (GST_VIDEO_INFO_FORMAT(&priv->info) != GST_VIDEO_FORMAT_UNKNOWN) caps = adoptGRef(gst_video_info_to_caps(&priv->info)); else caps = priv->currentCaps; #endif GstVideoFormat format; WebCore::IntSize size; int pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride; if (!getVideoSizeAndFormatFromCaps(caps.get(), size, format, pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride)) { gst_buffer_unref(buffer); g_mutex_unlock(priv->bufferMutex); return GST_FLOW_ERROR; } // Cairo's ARGB has pre-multiplied alpha while GStreamer's doesn't. // Here we convert to Cairo's ARGB. if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) { // Because GstBaseSink::render() only owns the buffer reference in the // method scope we can't use gst_buffer_make_writable() here. Also // The buffer content should not be changed here because the same buffer // could be passed multiple times to this method (in theory). GstBuffer* newBuffer = createGstBuffer(buffer); // Check if allocation failed. if (UNLIKELY(!newBuffer)) { g_mutex_unlock(priv->bufferMutex); return GST_FLOW_ERROR; } // We don't use Color::premultipliedARGBFromColor() here because // one function call per video pixel is just too expensive: // For 720p/PAL for example this means 1280*720*25=23040000 // function calls per second! #ifndef GST_API_VERSION_1 const guint8* source = GST_BUFFER_DATA(buffer); guint8* destination = GST_BUFFER_DATA(newBuffer); #else GstMapInfo sourceInfo; GstMapInfo destinationInfo; gst_buffer_map(buffer, &sourceInfo, GST_MAP_READ); const guint8* source = const_cast<guint8*>(sourceInfo.data); gst_buffer_map(newBuffer, &destinationInfo, GST_MAP_WRITE); guint8* destination = static_cast<guint8*>(destinationInfo.data); #endif for (int x = 0; x < size.height(); x++) { for (int y = 0; y < size.width(); y++) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN unsigned short alpha = source[3]; destination[0] = (source[0] * alpha + 128) / 255; destination[1] = (source[1] * alpha + 128) / 255; destination[2] = (source[2] * alpha + 128) / 255; destination[3] = alpha; #else unsigned short alpha = source[0]; destination[0] = alpha; destination[1] = (source[1] * alpha + 128) / 255; destination[2] = (source[2] * alpha + 128) / 255; destination[3] = (source[3] * alpha + 128) / 255; #endif source += 4; destination += 4; } } #ifdef GST_API_VERSION_1 gst_buffer_unmap(buffer, &sourceInfo); gst_buffer_unmap(newBuffer, &destinationInfo); #endif gst_buffer_unref(buffer); buffer = priv->buffer = newBuffer; } // This should likely use a lower priority, but glib currently starves // lower priority sources. // See: https://bugzilla.gnome.org/show_bug.cgi?id=610830. priv->timeoutId = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, webkitVideoSinkTimeoutCallback, gst_object_ref(sink), reinterpret_cast<GDestroyNotify>(gst_object_unref)); g_cond_wait(priv->dataCondition, priv->bufferMutex); g_mutex_unlock(priv->bufferMutex); return GST_FLOW_OK; }
static GstCaps * gst_tinyalsa_sink_getcaps (GstBaseSink * bsink, GstCaps * filter) { GstTinyalsaSink *sink = GST_TINYALSA_SINK (bsink); GstCaps *caps = NULL; GValue formats = { 0, }; GValue format = { 0, }; struct pcm_params *params = NULL; struct pcm_mask *mask; int rate_min, rate_max, channels_min, channels_max; guint16 m; GST_DEBUG_OBJECT (sink, "Querying caps"); GST_OBJECT_LOCK (sink); if (sink->cached_caps) { GST_DEBUG_OBJECT (sink, "Returning cached caps"); caps = gst_caps_ref (sink->cached_caps); goto done; } if (sink->pcm) { /* We can't query the device while it's open, so return current caps */ caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (bsink)); goto done; } params = pcm_params_get (sink->card, sink->device, PCM_OUT); if (!params) { GST_ERROR_OBJECT (sink, "Could not get PCM params"); goto done; } mask = pcm_params_get_mask (params, PCM_PARAM_FORMAT); m = (mask->bits[1] << 8) | mask->bits[0]; if (!(m & SNDRV_PCM_FORMAT_ANY)) { GST_ERROR_OBJECT (sink, "Could not find any supported format"); goto done; } caps = gst_caps_new_empty_simple ("audio/x-raw"); g_value_init (&formats, GST_TYPE_LIST); g_value_init (&format, G_TYPE_STRING); if (m & (1 << SNDRV_PCM_FORMAT_S8)) { g_value_set_static_string (&format, "S8"); gst_value_list_prepend_value (&formats, &format); } if (m & (1 << SNDRV_PCM_FORMAT_S16_LE)) { g_value_set_static_string (&format, "S16LE"); gst_value_list_prepend_value (&formats, &format); } if (m & (1 << SNDRV_PCM_FORMAT_S24_LE)) { g_value_set_static_string (&format, "S24_32LE"); gst_value_list_prepend_value (&formats, &format); } if (m & (1 << SNDRV_PCM_FORMAT_S32_LE)) { g_value_set_static_string (&format, "S32LE"); gst_value_list_prepend_value (&formats, &format); } gst_caps_set_value (caps, "format", &formats); g_value_unset (&format); g_value_unset (&formats); /* This is a bit of a lie, since the device likely only supports some * standard rates in this range. We should probably filter the range to * those, standard audio rates but even that isn't guaranteed to be accurate. */ rate_min = pcm_params_get_min (params, PCM_PARAM_RATE); rate_max = pcm_params_get_max (params, PCM_PARAM_RATE); if (rate_min == rate_max) gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate_min, NULL); else gst_caps_set_simple (caps, "rate", GST_TYPE_INT_RANGE, rate_min, rate_max, NULL); channels_min = pcm_params_get_min (params, PCM_PARAM_CHANNELS); channels_max = pcm_params_get_max (params, PCM_PARAM_CHANNELS); if (channels_min == channels_max) gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels_min, NULL); else gst_caps_set_simple (caps, "channels", GST_TYPE_INT_RANGE, channels_min, channels_max, NULL); gst_caps_replace (&sink->cached_caps, caps); done: GST_OBJECT_UNLOCK (sink); GST_DEBUG_OBJECT (sink, "Got caps %" GST_PTR_FORMAT, caps); if (caps && filter) { GstCaps *intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (caps); caps = intersection; } if (params) pcm_params_free (params); return caps; }