static void gst_sdlvideosink_xoverlay_set_window_handle (GstXOverlay * overlay, guintptr handle) { GstSDLVideoSink *sdlvideosink = GST_SDLVIDEOSINK (overlay); unsigned long parent = (unsigned long) handle; if (sdlvideosink->xwindow_id == parent) return; sdlvideosink->xwindow_id = parent; /* are we running yet? */ if (sdlvideosink->init) { gboolean negotiated; g_mutex_lock (sdlvideosink->lock); negotiated = (sdlvideosink->overlay != NULL); if (negotiated) gst_sdlvideosink_destroy (sdlvideosink); /* Call initsdl to set the WINDOWID env var urk */ gst_sdlvideosink_initsdl (sdlvideosink); if (negotiated) gst_sdlvideosink_create (sdlvideosink); g_mutex_unlock (sdlvideosink->lock); } }
static gboolean gst_sdlvideosink_setcaps (GstBaseSink * bsink, GstCaps * vscapslist) { GstSDLVideoSink *sdlvideosink; GstStructure *structure; gboolean res = TRUE; sdlvideosink = GST_SDLVIDEOSINK (bsink); structure = gst_caps_get_structure (vscapslist, 0); gst_structure_get_fourcc (structure, "format", &sdlvideosink->fourcc); sdlvideosink->format = gst_sdlvideosink_get_sdl_from_fourcc (sdlvideosink, sdlvideosink->fourcc); gst_structure_get_int (structure, "width", &sdlvideosink->width); gst_structure_get_int (structure, "height", &sdlvideosink->height); gst_structure_get_fraction (structure, "framerate", &sdlvideosink->framerate_n, &sdlvideosink->framerate_d); g_mutex_lock (sdlvideosink->lock); if (!sdlvideosink->format || !gst_sdlvideosink_create (sdlvideosink)) res = FALSE; g_mutex_unlock (sdlvideosink->lock); return res; }
/* FIXME */ static GstBuffer * gst_sdlvideosink_buffer_new (GstBufferPool * pool, gint64 location, guint size, gpointer user_data) { GstSDLVideoSink *sdlvideosink = GST_SDLVIDEOSINK (user_data); GstBuffer *buffer; if (!sdlvideosink->overlay) return NULL; if (!gst_sdlvideosink_lock (sdlvideosink)) { return NULL; } /* this protects the buffer from being written over multiple times */ g_mutex_lock (sdlvideosink->lock); buffer = gst_buffer_new (); GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DONTFREE); GST_BUFFER_DATA (buffer) = sdlvideosink->overlay->pixels[0]; if (sdlvideosink->format == SDL_YV12_OVERLAY || sdlvideosink->format == SDL_IYUV_OVERLAY) { GST_BUFFER_SIZE (buffer) = sdlvideosink->width * sdlvideosink->height * 3 / 2; } else { GST_BUFFER_SIZE (buffer) = sdlvideosink->width * sdlvideosink->height * 2; } GST_BUFFER_MAXSIZE (buffer) = GST_BUFFER_SIZE (buffer); return buffer; }
static gboolean gst_sdlvideosink_supported (GstImplementsInterface * interface, GType iface_type) { GstSDLVideoSink *sdlvideosink = GST_SDLVIDEOSINK (interface); gboolean result = FALSE; /* check SDL for whether it was compiled against X, FB, etc. */ if (iface_type == GST_TYPE_X_OVERLAY) { gchar tmp[4]; if (!sdlvideosink->init) { g_mutex_lock (sdlvideosink->lock); SDL_Init (SDL_INIT_VIDEO); /* True if the video driver is X11 */ result = (strcmp ("x11", SDL_VideoDriverName (tmp, 4)) == 0); SDL_QuitSubSystem (SDL_INIT_VIDEO); g_mutex_unlock (sdlvideosink->lock); } else result = sdlvideosink->is_xwindows; } else if (iface_type == GST_TYPE_NAVIGATION) result = TRUE; return result; }
static void gst_sdlvideosink_finalize (GObject * obj) { g_mutex_free (GST_SDLVIDEOSINK (obj)->lock); G_OBJECT_CLASS (parent_class)->finalize (obj); }
static void gst_sdlvideosink_navigation_send_event (GstNavigation * navigation, GstStructure * structure) { GstSDLVideoSink *sdlvideosink = GST_SDLVIDEOSINK (navigation); GstEvent *event; GstVideoRectangle dst = { 0, }; GstVideoRectangle src = { 0, }; GstVideoRectangle result; double x, y, old_x, old_y; GstPad *pad = NULL; src.w = GST_VIDEO_SINK_WIDTH (sdlvideosink); src.h = GST_VIDEO_SINK_HEIGHT (sdlvideosink); dst.w = sdlvideosink->width; dst.h = sdlvideosink->height; gst_video_sink_center_rect (src, dst, &result, FALSE); event = gst_event_new_navigation (structure); /* Our coordinates can be wrong here if we centered the video */ /* Converting pointer coordinates to the non scaled geometry */ if (gst_structure_get_double (structure, "pointer_x", &old_x)) { x = old_x; if (x >= result.x && x <= (result.x + result.w)) { x -= result.x; x *= sdlvideosink->width; x /= result.w; } else { x = 0; } GST_DEBUG_OBJECT (sdlvideosink, "translated navigation event x " "coordinate from %f to %f", old_x, x); gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x, NULL); } if (gst_structure_get_double (structure, "pointer_y", &old_y)) { y = old_y; if (y >= result.y && y <= (result.y + result.h)) { y -= result.y; y *= sdlvideosink->height; y /= result.h; } else { y = 0; } GST_DEBUG_OBJECT (sdlvideosink, "translated navigation event y " "coordinate from %f to %f", old_y, y); gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, y, NULL); } pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sdlvideosink)); if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) { gst_pad_send_event (pad, event); gst_object_unref (pad); } }
static GstBufferPool * gst_sdlvideosink_get_bufferpool (GstPad * pad) { GstSDLVideoSink *sdlvideosink = GST_SDLVIDEOSINK (gst_pad_get_parent (pad)); if (sdlvideosink->overlay) return sdlvideosink->bufferpool; return NULL; }
static void gst_sdlvideosink_buffer_free (GstBufferPool * pool, GstBuffer * buffer, gpointer user_data) { GstSDLVideoSink *sdlvideosink = GST_SDLVIDEOSINK (user_data); g_mutex_unlock (sdlvideosink->lock); gst_sdlvideosink_unlock (sdlvideosink); gst_buffer_default_free (buffer); }
static GstStateChangeReturn gst_sdlvideosink_change_state (GstElement * element, GstStateChange transition) { GstSDLVideoSink *sdlvideosink; GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; g_return_val_if_fail (GST_IS_SDLVIDEOSINK (element), GST_STATE_CHANGE_FAILURE); sdlvideosink = GST_SDLVIDEOSINK (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: sdlvideosink->is_xwindows = GST_IS_X_OVERLAY (sdlvideosink); g_mutex_lock (sdlvideosink->lock); if (!gst_sdlvideosink_initsdl (sdlvideosink)) { g_mutex_unlock (sdlvideosink->lock); goto init_failed; } GST_OBJECT_FLAG_SET (sdlvideosink, GST_SDLVIDEOSINK_OPEN); g_mutex_unlock (sdlvideosink->lock); break; default: /* do nothing */ break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: sdlvideosink->framerate_n = 0; sdlvideosink->framerate_d = 1; g_mutex_lock (sdlvideosink->lock); gst_sdlvideosink_destroy (sdlvideosink); g_mutex_unlock (sdlvideosink->lock); break; case GST_STATE_CHANGE_READY_TO_NULL: g_mutex_lock (sdlvideosink->lock); gst_sdlvideosink_deinitsdl (sdlvideosink); GST_OBJECT_FLAG_UNSET (sdlvideosink, GST_SDLVIDEOSINK_OPEN); g_mutex_unlock (sdlvideosink->lock); break; default: /* do nothing */ break; } return ret; init_failed: { /* method posted detailed error message */ GST_DEBUG_OBJECT (sdlvideosink, "init failed"); return GST_STATE_CHANGE_FAILURE; } }
static void gst_sdlvideosink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstSDLVideoSink *sdlvideosink; sdlvideosink = GST_SDLVIDEOSINK (object); switch (prop_id) { case PROP_FULLSCREEN: g_value_set_boolean (value, sdlvideosink->full_screen); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_sdlvideosink_get_times (GstBaseSink * basesink, GstBuffer * buffer, GstClockTime * start, GstClockTime * end) { GstSDLVideoSink *sdlvideosink = GST_SDLVIDEOSINK (basesink); GstClockTime timestamp, duration; timestamp = GST_BUFFER_TIMESTAMP (buffer); if (GST_CLOCK_TIME_IS_VALID (timestamp)) { *start = timestamp; duration = GST_BUFFER_DURATION (buffer); if (GST_CLOCK_TIME_IS_VALID (duration)) { *end = timestamp + duration; } else { if (sdlvideosink->framerate_n > 0) { *end = timestamp + gst_util_uint64_scale_int (GST_SECOND, sdlvideosink->framerate_d, sdlvideosink->framerate_n); } } } }
static GstFlowReturn gst_sdlvideosink_show_frame (GstBaseSink * bsink, GstBuffer * buf) { GstSDLVideoSink *sdlvideosink; sdlvideosink = GST_SDLVIDEOSINK (bsink); g_mutex_lock (sdlvideosink->lock); if (!sdlvideosink->init || !sdlvideosink->overlay || !sdlvideosink->overlay->pixels) goto not_init; /* if (GST_BUFFER_DATA (buf) != sdlvideosink->overlay->pixels[0]) */ if (TRUE) { guint8 *out; gint l; if (!gst_sdlvideosink_lock (sdlvideosink)) goto cannot_lock; /* buf->yuv - FIXME: bufferpool! */ if (sdlvideosink->format == SDL_YV12_OVERLAY) { guint8 *y, *u, *v; switch (sdlvideosink->fourcc) { case GST_MAKE_FOURCC ('I', '4', '2', '0'): y = GST_BUFFER_DATA (buf); /* I420 is YV12 with switched colour planes and different offsets */ v = y + I420_U_OFFSET (sdlvideosink->width, sdlvideosink->height); u = y + I420_V_OFFSET (sdlvideosink->width, sdlvideosink->height); break; case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): y = GST_BUFFER_DATA (buf); u = y + I420_U_OFFSET (sdlvideosink->width, sdlvideosink->height); v = y + I420_V_OFFSET (sdlvideosink->width, sdlvideosink->height); break; default: gst_sdlvideosink_unlock (sdlvideosink); g_mutex_unlock (sdlvideosink->lock); g_return_val_if_reached (GST_FLOW_ERROR); } /* Y Plane */ out = sdlvideosink->overlay->pixels[0]; for (l = 0; l < sdlvideosink->height; l++) { memcpy (out, y, I420_Y_ROWSTRIDE (sdlvideosink->width)); out += sdlvideosink->overlay->pitches[0]; y += I420_Y_ROWSTRIDE (sdlvideosink->width); } /* U plane */ out = sdlvideosink->overlay->pixels[1]; for (l = 0; l < (sdlvideosink->height / 2); l++) { memcpy (out, u, I420_U_ROWSTRIDE (sdlvideosink->width)); out += sdlvideosink->overlay->pitches[1]; u += I420_U_ROWSTRIDE (sdlvideosink->width); } /* V plane */ out = sdlvideosink->overlay->pixels[2]; for (l = 0; l < (sdlvideosink->height / 2); l++) { memcpy (out, v, I420_V_ROWSTRIDE (sdlvideosink->width)); out += sdlvideosink->overlay->pitches[2]; v += I420_V_ROWSTRIDE (sdlvideosink->width); } } else { guint8 *in = GST_BUFFER_DATA (buf); gint in_stride = sdlvideosink->width * 2; out = sdlvideosink->overlay->pixels[0]; for (l = 0; l < sdlvideosink->height; l++) { memcpy (out, in, in_stride); out += sdlvideosink->overlay->pitches[0]; in += in_stride; } } gst_sdlvideosink_unlock (sdlvideosink); } /* Show, baby, show! */ SDL_DisplayYUVOverlay (sdlvideosink->overlay, &(sdlvideosink->rect)); /* Handle any resize */ gst_sdlv_process_events (sdlvideosink); g_mutex_unlock (sdlvideosink->lock); return GST_FLOW_OK; /* ERRORS */ not_init: { GST_ELEMENT_ERROR (sdlvideosink, CORE, NEGOTIATION, (NULL), ("not negotiated.")); g_mutex_unlock (sdlvideosink->lock); return GST_FLOW_NOT_NEGOTIATED; } cannot_lock: { /* lock function posted detailed message */ g_mutex_unlock (sdlvideosink->lock); return GST_FLOW_ERROR; } }