X11: port imagesinks to new miniobjects

Remove the subbuffer from X11 sinks and use the private pointer to store a
single buffer metadata with the extra info.
This commit is contained in:
Wim Taymans 2011-02-24 11:57:53 +01:00
parent 03c710d6cd
commit e78903e662
4 changed files with 360 additions and 433 deletions

View file

@ -130,7 +130,7 @@ MotifWmHints, MwmHints;
static void gst_ximagesink_reset (GstXImageSink * ximagesink);
static void gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink,
GstXImageBuffer * ximage);
GstBuffer * ximage);
static void gst_ximagesink_xwindow_update_geometry (GstXImageSink * ximagesink);
static void gst_ximagesink_expose (GstXOverlay * overlay);
@ -165,36 +165,24 @@ static GstVideoSinkClass *parent_class = NULL;
/* ============================================================= */
/* ximage buffers */
#define GET_XDATA(buf) ((GstXImageData *) (GST_BUFFER_CAST(buf)->owner_priv))
static GstBufferClass *ximage_buffer_parent_class = NULL;
#define GST_TYPE_XIMAGE_BUFFER (gst_ximage_buffer_get_type())
#define GST_IS_XIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XIMAGE_BUFFER))
#define GST_XIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XIMAGE_BUFFER, GstXImageBuffer))
#define GST_XIMAGE_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XIMAGE_BUFFER, GstXImageBufferClass))
/* So some words about GstMiniObject, this is pretty messy...
GstMiniObject does not use the standard finalizing of GObjects, you are
supposed to call gst_buffer_unref that's going to call gst_mini_objec_unref
which will handle its own refcount system and call gst_mini_object_free.
gst_mini_object_free will call the class finalize method which is not the
one from GObject, after calling this finalize method it will free the object
instance for you if the refcount is still 0 so you should not chain up */
static void
gst_ximage_buffer_finalize (GstXImageBuffer * ximage)
gst_ximage_buffer_dispose (GstBuffer * ximage)
{
GstXImageData *data = NULL;
GstXImageSink *ximagesink = NULL;
gboolean recycled = FALSE;
gboolean running;
g_return_if_fail (ximage != NULL);
data = GET_XDATA (ximage);
g_return_if_fail (data != NULL);
ximagesink = ximage->ximagesink;
if (G_UNLIKELY (ximagesink == NULL)) {
GST_WARNING_OBJECT (ximagesink, "no sink found");
goto beach;
}
ximagesink = data->ximagesink;
if (G_UNLIKELY (ximagesink == NULL))
goto no_sink;
g_return_if_fail (GST_IS_XIMAGESINK (ximagesink));
GST_OBJECT_LOCK (ximagesink);
running = ximagesink->running;
@ -205,84 +193,44 @@ gst_ximage_buffer_finalize (GstXImageBuffer * ximage)
GST_DEBUG_OBJECT (ximagesink,
"destroy image %p because the sink is shutting down", ximage);
gst_ximagesink_ximage_destroy (ximagesink, ximage);
} else if ((ximage->width != GST_VIDEO_SINK_WIDTH (ximagesink)) ||
(ximage->height != GST_VIDEO_SINK_HEIGHT (ximagesink))) {
} else if ((data->width != GST_VIDEO_SINK_WIDTH (ximagesink)) ||
(data->height != GST_VIDEO_SINK_HEIGHT (ximagesink))) {
/* If our geometry changed we can't reuse that image. */
GST_DEBUG_OBJECT (ximagesink,
"destroy image %p as its size changed %dx%d vs current %dx%d",
ximage, ximage->width, ximage->height,
ximage, data->width, data->height,
GST_VIDEO_SINK_WIDTH (ximagesink), GST_VIDEO_SINK_HEIGHT (ximagesink));
gst_ximagesink_ximage_destroy (ximagesink, ximage);
} else {
/* In that case we can reuse the image and add it to our image pool. */
GST_LOG_OBJECT (ximagesink, "recycling image %p in pool", ximage);
/* need to increment the refcount again to recycle */
gst_buffer_ref (GST_BUFFER_CAST (ximage));
gst_buffer_ref (ximage);
g_mutex_lock (ximagesink->pool_lock);
ximagesink->buffer_pool = g_slist_prepend (ximagesink->buffer_pool, ximage);
g_mutex_unlock (ximagesink->pool_lock);
recycled = TRUE;
}
if (!recycled)
GST_MINI_OBJECT_CLASS (ximage_buffer_parent_class)->finalize
(GST_MINI_OBJECT (ximage));
beach:
return;
}
static void
gst_ximage_buffer_free (GstXImageBuffer * ximage)
{
/* make sure it is not recycled */
ximage->width = -1;
ximage->height = -1;
gst_buffer_unref (GST_BUFFER_CAST (ximage));
}
static void
gst_ximage_buffer_init (GstXImageBuffer * ximage_buffer, gpointer g_class)
{
#ifdef HAVE_XSHM
ximage_buffer->SHMInfo.shmaddr = ((void *) -1);
ximage_buffer->SHMInfo.shmid = -1;
#endif
}
static void
gst_ximage_buffer_class_init (gpointer g_class, gpointer class_data)
{
GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
ximage_buffer_parent_class = g_type_class_peek_parent (g_class);
mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
gst_ximage_buffer_finalize;
}
static GType
gst_ximage_buffer_get_type (void)
{
static GType _gst_ximage_buffer_type;
if (G_UNLIKELY (_gst_ximage_buffer_type == 0)) {
static const GTypeInfo ximage_buffer_info = {
sizeof (GstBufferClass),
NULL,
NULL,
gst_ximage_buffer_class_init,
NULL,
NULL,
sizeof (GstXImageBuffer),
0,
(GInstanceInitFunc) gst_ximage_buffer_init,
NULL
};
_gst_ximage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
"GstXImageBuffer", &ximage_buffer_info, 0);
no_sink:
{
GST_WARNING ("no sink found");
return;
}
return _gst_ximage_buffer_type;
}
static void
gst_ximage_buffer_free (GstBuffer * ximage)
{
GstXImageData *data = GET_XDATA (ximage);
g_return_if_fail (data != NULL);
/* make sure it is not recycled */
data->width = -1;
data->height = -1;
gst_buffer_unref (ximage);
}
/* X11 stuff */
@ -398,27 +346,37 @@ beach:
#endif /* HAVE_XSHM */
/* This function handles GstXImageBuffer creation depending on XShm availability */
static GstXImageBuffer *
static GstBuffer *
gst_ximagesink_ximage_new (GstXImageSink * ximagesink, GstCaps * caps)
{
GstXImageBuffer *ximage = NULL;
GstBuffer *buffer = NULL;
GstXImageData *data = NULL;
GstStructure *structure = NULL;
gboolean succeeded = FALSE;
int (*handler) (Display *, XErrorEvent *);
g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL);
ximage = (GstXImageBuffer *) gst_mini_object_new (GST_TYPE_XIMAGE_BUFFER);
data = g_slice_new0 (GstXImageData);
#ifdef HAVE_XSHM
data->SHMInfo.shmaddr = ((void *) -1);
data->SHMInfo.shmid = -1;
#endif
buffer = gst_buffer_new ();
GST_MINI_OBJECT_CAST (buffer)->dispose =
(GstMiniObjectDisposeFunction) gst_ximage_buffer_dispose;
buffer->owner_priv = data;
structure = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int (structure, "width", &ximage->width) ||
!gst_structure_get_int (structure, "height", &ximage->height)) {
if (!gst_structure_get_int (structure, "width", &data->width) ||
!gst_structure_get_int (structure, "height", &data->height)) {
GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
}
GST_DEBUG_OBJECT (ximagesink, "creating image %p (%dx%d)", ximage,
ximage->width, ximage->height);
GST_DEBUG_OBJECT (ximagesink, "creating image %p (%dx%d)", data,
data->width, data->height);
g_mutex_lock (ximagesink->x_lock);
@ -428,11 +386,11 @@ gst_ximagesink_ximage_new (GstXImageSink * ximagesink, GstCaps * caps)
#ifdef HAVE_XSHM
if (ximagesink->xcontext->use_xshm) {
ximage->ximage = XShmCreateImage (ximagesink->xcontext->disp,
data->ximage = XShmCreateImage (ximagesink->xcontext->disp,
ximagesink->xcontext->visual,
ximagesink->xcontext->depth,
ZPixmap, NULL, &ximage->SHMInfo, ximage->width, ximage->height);
if (!ximage->ximage || error_caught) {
ZPixmap, NULL, &data->SHMInfo, data->width, data->height);
if (!data->ximage || error_caught) {
g_mutex_unlock (ximagesink->x_lock);
/* Reset error handler */
error_caught = FALSE;
@ -440,53 +398,52 @@ gst_ximagesink_ximage_new (GstXImageSink * ximagesink, GstCaps * caps)
/* Push an error */
GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
ximage->width, ximage->height),
data->width, data->height),
("could not XShmCreateImage a %dx%d image",
ximage->width, ximage->height));
data->width, data->height));
goto beach;
}
/* we have to use the returned bytes_per_line for our shm size */
ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height;
data->size = data->ximage->bytes_per_line * data->ximage->height;
GST_LOG_OBJECT (ximagesink,
"XShm image size is %" G_GSIZE_FORMAT ", width %d, stride %d",
ximage->size, ximage->width, ximage->ximage->bytes_per_line);
data->size, data->width, data->ximage->bytes_per_line);
ximage->SHMInfo.shmid = shmget (IPC_PRIVATE, ximage->size,
IPC_CREAT | 0777);
if (ximage->SHMInfo.shmid == -1) {
data->SHMInfo.shmid = shmget (IPC_PRIVATE, data->size, IPC_CREAT | 0777);
if (data->SHMInfo.shmid == -1) {
g_mutex_unlock (ximagesink->x_lock);
GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
ximage->width, ximage->height),
data->width, data->height),
("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
ximage->size));
data->size));
goto beach;
}
ximage->SHMInfo.shmaddr = shmat (ximage->SHMInfo.shmid, NULL, 0);
if (ximage->SHMInfo.shmaddr == ((void *) -1)) {
data->SHMInfo.shmaddr = shmat (data->SHMInfo.shmid, NULL, 0);
if (data->SHMInfo.shmaddr == ((void *) -1)) {
g_mutex_unlock (ximagesink->x_lock);
GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
ximage->width, ximage->height),
data->width, data->height),
("Failed to shmat: %s", g_strerror (errno)));
/* Clean up the shared memory segment */
shmctl (ximage->SHMInfo.shmid, IPC_RMID, NULL);
shmctl (data->SHMInfo.shmid, IPC_RMID, NULL);
goto beach;
}
ximage->ximage->data = ximage->SHMInfo.shmaddr;
ximage->SHMInfo.readOnly = FALSE;
data->ximage->data = data->SHMInfo.shmaddr;
data->SHMInfo.readOnly = FALSE;
if (XShmAttach (ximagesink->xcontext->disp, &ximage->SHMInfo) == 0) {
if (XShmAttach (ximagesink->xcontext->disp, &data->SHMInfo) == 0) {
/* Clean up shm seg */
shmctl (ximage->SHMInfo.shmid, IPC_RMID, NULL);
shmctl (data->SHMInfo.shmid, IPC_RMID, NULL);
g_mutex_unlock (ximagesink->x_lock);
GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
ximage->width, ximage->height), ("Failed to XShmAttach"));
data->width, data->height), ("Failed to XShmAttach"));
goto beach;
}
@ -495,19 +452,19 @@ gst_ximagesink_ximage_new (GstXImageSink * ximagesink, GstCaps * caps)
/* Now that everyone has attached, we can delete the shared memory segment.
* This way, it will be deleted as soon as we detach later, and not
* leaked if we crash. */
shmctl (ximage->SHMInfo.shmid, IPC_RMID, NULL);
shmctl (data->SHMInfo.shmid, IPC_RMID, NULL);
} else
#endif /* HAVE_XSHM */
{
guint allocsize;
ximage->ximage = XCreateImage (ximagesink->xcontext->disp,
data->ximage = XCreateImage (ximagesink->xcontext->disp,
ximagesink->xcontext->visual,
ximagesink->xcontext->depth,
ZPixmap, 0, NULL,
ximage->width, ximage->height, ximagesink->xcontext->bpp, 0);
if (!ximage->ximage || error_caught) {
data->width, data->height, ximagesink->xcontext->bpp, 0);
if (!data->ximage || error_caught) {
g_mutex_unlock (ximagesink->x_lock);
/* Reset error handler */
error_caught = FALSE;
@ -515,33 +472,31 @@ gst_ximagesink_ximage_new (GstXImageSink * ximagesink, GstCaps * caps)
/* Push an error */
GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
ximage->width, ximage->height),
("could not XCreateImage a %dx%d image",
ximage->width, ximage->height));
data->width, data->height),
("could not XCreateImage a %dx%d image", data->width, data->height));
goto beach;
}
/* upstream will assume that rowstrides are multiples of 4, but this
* doesn't always seem to be the case with XCreateImage() */
if ((ximage->ximage->bytes_per_line % 4) != 0) {
if ((data->ximage->bytes_per_line % 4) != 0) {
GST_WARNING_OBJECT (ximagesink, "returned stride not a multiple of 4 as "
"usually assumed");
}
/* we have to use the returned bytes_per_line for our image size */
ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height;
data->size = data->ximage->bytes_per_line * data->ximage->height;
/* alloc a bit more for unexpected strides to avoid crashes upstream.
* FIXME: if we get an unrounded stride, the image will be displayed
* distorted, since all upstream elements assume a rounded stride */
allocsize =
GST_ROUND_UP_4 (ximage->ximage->bytes_per_line) *
ximage->ximage->height;
ximage->ximage->data = g_malloc (allocsize);
GST_ROUND_UP_4 (data->ximage->bytes_per_line) * data->ximage->height;
data->ximage->data = g_malloc (allocsize);
GST_LOG_OBJECT (ximagesink,
"non-XShm image size is %" G_GSIZE_FORMAT " (alloced: %u), width %d, "
"stride %d", ximage->size, allocsize, ximage->width,
ximage->ximage->bytes_per_line);
"stride %d", data->size, allocsize, data->width,
data->ximage->bytes_per_line);
XSync (ximagesink->xcontext->disp, FALSE);
}
@ -552,30 +507,35 @@ gst_ximagesink_ximage_new (GstXImageSink * ximagesink, GstCaps * caps)
succeeded = TRUE;
GST_BUFFER_DATA (ximage) = (guchar *) ximage->ximage->data;
GST_BUFFER_SIZE (ximage) = ximage->size;
/* Keep a ref to our sink */
ximage->ximagesink = gst_object_ref (ximagesink);
data->ximagesink = gst_object_ref (ximagesink);
GST_BUFFER_DATA (buffer) = (guchar *) data->ximage->data;
GST_BUFFER_SIZE (buffer) = data->size;
g_mutex_unlock (ximagesink->x_lock);
beach:
if (!succeeded) {
gst_ximage_buffer_free (ximage);
ximage = NULL;
gst_ximage_buffer_free (buffer);
buffer = NULL;
}
return ximage;
return buffer;
}
/* This function destroys a GstXImageBuffer handling XShm availability */
/* This function destroys a GstBuffer with GstXImageData handling XShm availability */
static void
gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink,
GstXImageBuffer * ximage)
gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink, GstBuffer * ximage)
{
GstXImageData *data;
g_return_if_fail (ximage != NULL);
g_return_if_fail (GST_IS_XIMAGESINK (ximagesink));
data = GET_XDATA (ximage);
g_return_if_fail (data != NULL);
/* Hold the object lock to ensure the XContext doesn't disappear */
GST_OBJECT_LOCK (ximagesink);
@ -588,8 +548,8 @@ gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink,
if (!ximagesink->xcontext) {
GST_DEBUG_OBJECT (ximagesink, "Destroying XImage after XContext");
#ifdef HAVE_XSHM
if (ximage->SHMInfo.shmaddr != ((void *) -1)) {
shmdt (ximage->SHMInfo.shmaddr);
if (data->SHMInfo.shmaddr != ((void *) -1)) {
shmdt (data->SHMInfo.shmaddr);
}
#endif
goto beach;
@ -599,19 +559,19 @@ gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink,
#ifdef HAVE_XSHM
if (ximagesink->xcontext->use_xshm) {
if (ximage->SHMInfo.shmaddr != ((void *) -1)) {
XShmDetach (ximagesink->xcontext->disp, &ximage->SHMInfo);
if (data->SHMInfo.shmaddr != ((void *) -1)) {
XShmDetach (ximagesink->xcontext->disp, &data->SHMInfo);
XSync (ximagesink->xcontext->disp, 0);
shmdt (ximage->SHMInfo.shmaddr);
shmdt (data->SHMInfo.shmaddr);
}
if (ximage->ximage)
XDestroyImage (ximage->ximage);
if (data->ximage)
XDestroyImage (data->ximage);
} else
#endif /* HAVE_XSHM */
{
if (ximage->ximage) {
XDestroyImage (ximage->ximage);
if (data->ximage) {
XDestroyImage (data->ximage);
}
}
@ -622,11 +582,13 @@ gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink,
beach:
GST_OBJECT_UNLOCK (ximagesink);
if (ximage->ximagesink) {
if (data->ximagesink) {
/* Release the ref to our sink */
ximage->ximagesink = NULL;
data->ximagesink = NULL;
gst_object_unref (ximagesink);
}
g_slice_free (GstXImageData, data);
ximage->owner_priv = NULL;
return;
}
@ -669,8 +631,9 @@ gst_ximagesink_xwindow_draw_borders (GstXImageSink * ximagesink,
/* This function puts a GstXImageBuffer on a GstXImageSink's window */
static gboolean
gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage)
gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstBuffer * ximage)
{
GstXImageData *data;
GstVideoRectangle src, dst, result;
gboolean draw_border = FALSE;
@ -698,8 +661,7 @@ gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage)
gst_buffer_unref (GST_BUFFER_CAST (ximagesink->cur_image));
}
GST_LOG_OBJECT (ximagesink, "reffing %p as our current image", ximage);
ximagesink->cur_image =
GST_XIMAGE_BUFFER (gst_buffer_ref (GST_BUFFER_CAST (ximage)));
ximagesink->cur_image = gst_buffer_ref (ximage);
}
/* Expose sends a NULL image, we take the latest frame */
@ -713,8 +675,9 @@ gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage)
}
}
src.w = ximage->width;
src.h = ximage->height;
data = GET_XDATA (ximage);
src.w = data->width;
src.h = data->height;
dst.w = ximagesink->xwindow->width;
dst.h = ximagesink->xwindow->height;
@ -734,7 +697,7 @@ gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage)
ximage, 0, 0, result.x, result.y, result.w, result.h,
ximagesink->xwindow->width, ximagesink->xwindow->height);
XShmPutImage (ximagesink->xcontext->disp, ximagesink->xwindow->win,
ximagesink->xwindow->gc, ximage->ximage, 0, 0, result.x, result.y,
ximagesink->xwindow->gc, data->ximage, 0, 0, result.x, result.y,
result.w, result.h, FALSE);
} else
#endif /* HAVE_XSHM */
@ -744,7 +707,7 @@ gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage)
ximage, 0, 0, result.x, result.y, result.w, result.h,
ximagesink->xwindow->width, ximagesink->xwindow->height);
XPutImage (ximagesink->xcontext->disp, ximagesink->xwindow->win,
ximagesink->xwindow->gc, ximage->ximage, 0, 0, result.x, result.y,
ximagesink->xwindow->gc, data->ximage, 0, 0, result.x, result.y,
result.w, result.h);
}
@ -853,7 +816,7 @@ gst_ximagesink_xwindow_new (GstXImageSink * ximagesink, gint width, gint height)
xwindow->win = XCreateSimpleWindow (ximagesink->xcontext->disp,
ximagesink->xcontext->root,
0, 0, xwindow->width, xwindow->height, 0, 0, ximagesink->xcontext->black);
0, 0, width, height, 0, 0, ximagesink->xcontext->black);
/* We have to do that to prevent X from redrawing the background on
ConfigureNotify. This takes away flickering of video when resizing. */
@ -1413,11 +1376,10 @@ gst_ximagesink_xcontext_clear (GstXImageSink * ximagesink)
static void
gst_ximagesink_bufferpool_clear (GstXImageSink * ximagesink)
{
g_mutex_lock (ximagesink->pool_lock);
while (ximagesink->buffer_pool) {
GstXImageBuffer *ximage = ximagesink->buffer_pool->data;
GstBuffer *ximage = ximagesink->buffer_pool->data;
ximagesink->buffer_pool = g_slist_delete_link (ximagesink->buffer_pool,
ximagesink->buffer_pool);
@ -1541,13 +1503,16 @@ gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
/* If our ximage has changed we destroy it, next chain iteration will create
a new one */
if ((ximagesink->ximage) &&
((GST_VIDEO_SINK_WIDTH (ximagesink) != ximagesink->ximage->width) ||
(GST_VIDEO_SINK_HEIGHT (ximagesink) != ximagesink->ximage->height))) {
GST_DEBUG_OBJECT (ximagesink, "our image is not usable anymore, unref %p",
ximagesink->ximage);
gst_buffer_unref (GST_BUFFER_CAST (ximagesink->ximage));
ximagesink->ximage = NULL;
if ((ximagesink->ximage)) {
GstXImageData *data = GET_XDATA (ximagesink->ximage);
if (((GST_VIDEO_SINK_WIDTH (ximagesink) != data->width) ||
(GST_VIDEO_SINK_HEIGHT (ximagesink) != data->height))) {
GST_DEBUG_OBJECT (ximagesink, "our image is not usable anymore, unref %p",
ximagesink->ximage);
gst_buffer_unref (ximagesink->ximage);
ximagesink->ximage = NULL;
}
}
return TRUE;
@ -1668,13 +1633,16 @@ gst_ximagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
if (!ximagesink->xcontext)
return GST_FLOW_ERROR;
#if 0
/* If this buffer has been allocated using our buffer management we simply
put the ximage which is in the PRIVATE pointer */
if (GST_IS_XIMAGE_BUFFER (buf)) {
GST_LOG_OBJECT (ximagesink, "buffer from our pool, writing directly");
if (!gst_ximagesink_ximage_put (ximagesink, GST_XIMAGE_BUFFER (buf)))
goto no_window;
} else {
} else
#endif
{
/* Else we have to copy the data into our private image, */
/* if we have one... */
GST_LOG_OBJECT (ximagesink, "normal buffer, copying from it");
@ -1686,10 +1654,11 @@ gst_ximagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
/* The create method should have posted an informative error */
goto no_ximage;
if (ximagesink->ximage->size < GST_BUFFER_SIZE (buf)) {
if (GST_BUFFER_SIZE (ximagesink->ximage) < GST_BUFFER_SIZE (buf)) {
GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
ximagesink->ximage->width, ximagesink->ximage->height),
GET_XDATA (ximagesink->ximage)->width,
GET_XDATA (ximagesink->ximage)->height),
("XServer allocated buffer size did not match input buffer"));
gst_ximagesink_ximage_destroy (ximagesink, ximagesink->ximage);
@ -1698,7 +1667,7 @@ gst_ximagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
}
}
memcpy (GST_BUFFER_DATA (ximagesink->ximage), GST_BUFFER_DATA (buf),
MIN (GST_BUFFER_SIZE (buf), ximagesink->ximage->size));
MIN (GST_BUFFER_SIZE (buf), GST_BUFFER_SIZE (ximagesink->ximage)));
if (!gst_ximagesink_ximage_put (ximagesink, ximagesink->ximage))
goto no_window;
}
@ -1752,7 +1721,7 @@ gst_ximagesink_event (GstBaseSink * sink, GstEvent * event)
return TRUE;
}
#if 0
/* Buffer management
*
* The buffer_alloc function must either return a buffer with given size and
@ -1938,6 +1907,7 @@ alloc:
beach:
return ret;
}
#endif
/* Interfaces stuff */
@ -2436,8 +2406,10 @@ gst_ximagesink_class_init (GstXImageSinkClass * klass)
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_ximagesink_getcaps);
gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_ximagesink_setcaps);
#if 0
gstbasesink_class->buffer_alloc =
GST_DEBUG_FUNCPTR (gst_ximagesink_buffer_alloc);
#endif
gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_ximagesink_get_times);
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_ximagesink_event);
@ -2490,11 +2462,6 @@ gst_ximagesink_get_type (void)
&navigation_info);
g_type_add_interface_static (ximagesink_type, GST_TYPE_X_OVERLAY,
&overlay_info);
/* register type and create class in a more safe place instead of at
* runtime since the type registration and class creation is not
* threadsafe. */
g_type_class_ref (gst_ximage_buffer_get_type ());
}
return ximagesink_type;

View file

@ -52,8 +52,7 @@ G_BEGIN_DECLS
typedef struct _GstXContext GstXContext;
typedef struct _GstXWindow GstXWindow;
typedef struct _GstXImageBuffer GstXImageBuffer;
typedef struct _GstXImageBufferClass GstXImageBufferClass;
typedef struct _GstXImageData GstXImageData;
typedef struct _GstXImageSink GstXImageSink;
typedef struct _GstXImageSinkClass GstXImageSinkClass;
@ -129,20 +128,19 @@ struct _GstXWindow
GC gc;
};
/**
* GstXImageBuffer:
* GstXImageData:
* @ximagesink: a reference to our #GstXImageSink
* @ximage: the XImage of this buffer
* @width: the width in pixels of XImage @ximage
* @height: the height in pixels of XImage @ximage
* @size: the size in bytes of XImage @ximage
*
* Subclass of #GstBuffer containing additional information about an XImage.
* Structure with additional information about an XImage.
*/
struct _GstXImageBuffer
struct _GstXImageData
{
GstBuffer buffer;
/* Reference to the ximagesink we belong to */
GstXImageSink *ximagesink;
@ -194,8 +192,8 @@ struct _GstXImageSink
GstXContext *xcontext;
GstXWindow *xwindow;
GstXImageBuffer *ximage;
GstXImageBuffer *cur_image;
GstBuffer *ximage;
GstBuffer *cur_image;
GThread *event_thread;
gboolean running;

View file

@ -143,10 +143,8 @@ MotifWmHints, MwmHints;
#define MWM_HINTS_DECORATIONS (1L << 1)
static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink);
static GstBufferClass *xvimage_buffer_parent_class = NULL;
static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage);
static void gst_xvimagesink_xvimage_destroy (GstXvImageSink * xvimagesink,
GstBuffer * xvimage);
static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
xvimagesink);
static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
@ -200,99 +198,19 @@ static GstVideoSinkClass *parent_class = NULL;
/* ============================================================= */
/* xvimage buffers */
#define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type())
#define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER))
#define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer))
#define GST_XVIMAGE_BUFFER_CAST(obj) ((GstXvImageBuffer *)(obj))
/* This function destroys a GstXvImage handling XShm availability */
static void
gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage)
{
GstXvImageSink *xvimagesink;
GST_DEBUG_OBJECT (xvimage, "Destroying buffer");
xvimagesink = xvimage->xvimagesink;
if (G_UNLIKELY (xvimagesink == NULL))
goto no_sink;
g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
GST_OBJECT_LOCK (xvimagesink);
/* If the destroyed image is the current one we destroy our reference too */
if (xvimagesink->cur_image == xvimage)
xvimagesink->cur_image = NULL;
/* We might have some buffers destroyed after changing state to NULL */
if (xvimagesink->xcontext == NULL) {
GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
#ifdef HAVE_XSHM
/* Need to free the shared memory segment even if the x context
* was already cleaned up */
if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
shmdt (xvimage->SHMInfo.shmaddr);
}
#endif
goto beach;
}
g_mutex_lock (xvimagesink->x_lock);
#ifdef HAVE_XSHM
if (xvimagesink->xcontext->use_xshm) {
if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo);
XSync (xvimagesink->xcontext->disp, FALSE);
shmdt (xvimage->SHMInfo.shmaddr);
}
if (xvimage->xvimage)
XFree (xvimage->xvimage);
} else
#endif /* HAVE_XSHM */
{
if (xvimage->xvimage) {
if (xvimage->xvimage->data) {
g_free (xvimage->xvimage->data);
}
XFree (xvimage->xvimage);
}
}
XSync (xvimagesink->xcontext->disp, FALSE);
g_mutex_unlock (xvimagesink->x_lock);
beach:
GST_OBJECT_UNLOCK (xvimagesink);
xvimage->xvimagesink = NULL;
gst_object_unref (xvimagesink);
GST_MINI_OBJECT_CLASS (xvimage_buffer_parent_class)->finalize (GST_MINI_OBJECT
(xvimage));
return;
no_sink:
{
GST_WARNING ("no sink found");
return;
}
}
#define GET_XVDATA(buf) ((GstXvImageData *) (GST_BUFFER_CAST(buf)->owner_priv))
static void
gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage)
gst_xvimage_buffer_dispose (GstBuffer * xvimage)
{
GstXvImageData *data = NULL;
GstXvImageSink *xvimagesink;
gboolean running;
xvimagesink = xvimage->xvimagesink;
data = GET_XVDATA (xvimage);
g_return_if_fail (data != NULL);
xvimagesink = data->xvimagesink;
if (G_UNLIKELY (xvimagesink == NULL))
goto no_sink;
@ -302,22 +220,22 @@ gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage)
running = xvimagesink->running;
GST_OBJECT_UNLOCK (xvimagesink);
/* If our geometry changed we can't reuse that image. */
if (running == FALSE) {
GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down");
gst_xvimage_buffer_destroy (xvimage);
} else if ((xvimage->width != xvimagesink->video_width) ||
(xvimage->height != xvimagesink->video_height)) {
gst_xvimagesink_xvimage_destroy (xvimagesink, xvimage);
} else if ((data->width != xvimagesink->video_width) ||
(data->height != xvimagesink->video_height)) {
/* If our geometry changed we can't reuse that image. */
GST_LOG_OBJECT (xvimage,
"destroy image as its size changed %dx%d vs current %dx%d",
xvimage->width, xvimage->height,
data->width, data->height,
xvimagesink->video_width, xvimagesink->video_height);
gst_xvimage_buffer_destroy (xvimage);
gst_xvimagesink_xvimage_destroy (xvimagesink, xvimage);
} else {
/* In that case we can reuse the image and add it to our image pool. */
GST_LOG_OBJECT (xvimage, "recycling image in pool");
/* need to increment the refcount again to recycle */
gst_buffer_ref (GST_BUFFER_CAST (xvimage));
gst_buffer_ref (xvimage);
g_mutex_lock (xvimagesink->pool_lock);
xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool,
xvimage);
@ -333,56 +251,16 @@ no_sink:
}
static void
gst_xvimage_buffer_free (GstXvImageBuffer * xvimage)
gst_xvimage_buffer_free (GstBuffer * xvimage)
{
GstXvImageData *data = GET_XVDATA (xvimage);
g_return_if_fail (data != NULL);
/* make sure it is not recycled */
xvimage->width = -1;
xvimage->height = -1;
gst_buffer_unref (GST_BUFFER (xvimage));
}
static void
gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class)
{
#ifdef HAVE_XSHM
xvimage->SHMInfo.shmaddr = ((void *) -1);
xvimage->SHMInfo.shmid = -1;
#endif
}
static void
gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data)
{
GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
xvimage_buffer_parent_class = g_type_class_peek_parent (g_class);
mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
gst_xvimage_buffer_finalize;
}
static GType
gst_xvimage_buffer_get_type (void)
{
static GType _gst_xvimage_buffer_type;
if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) {
static const GTypeInfo xvimage_buffer_info = {
sizeof (GstBufferClass),
NULL,
NULL,
gst_xvimage_buffer_class_init,
NULL,
NULL,
sizeof (GstXvImageBuffer),
0,
(GInstanceInitFunc) gst_xvimage_buffer_init,
NULL
};
_gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
"GstXvImageBuffer", &xvimage_buffer_info, 0);
}
return _gst_xvimage_buffer_type;
data->width = -1;
data->height = -1;
gst_buffer_unref (xvimage);
}
/* X11 stuff */
@ -505,10 +383,11 @@ beach:
#endif /* HAVE_XSHM */
/* This function handles GstXvImage creation depending on XShm availability */
static GstXvImageBuffer *
static GstBuffer *
gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
{
GstXvImageBuffer *xvimage = NULL;
GstBuffer *buffer = NULL;
GstXvImageData *data = NULL;
GstStructure *structure = NULL;
gboolean succeeded = FALSE;
int (*handler) (Display *, XErrorEvent *);
@ -518,29 +397,37 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
if (caps == NULL)
return NULL;
xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER);
GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer");
data = g_slice_new0 (GstXvImageData);
#ifdef HAVE_XSHM
data->SHMInfo.shmaddr = ((void *) -1);
data->SHMInfo.shmid = -1;
#endif
buffer = gst_buffer_new ();
GST_DEBUG_OBJECT (xvimagesink, "Creating new XvImageBuffer");
GST_MINI_OBJECT_CAST (buffer)->dispose =
(GstMiniObjectDisposeFunction) gst_xvimage_buffer_dispose;
buffer->owner_priv = data;
structure = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int (structure, "width", &xvimage->width) ||
!gst_structure_get_int (structure, "height", &xvimage->height)) {
if (!gst_structure_get_int (structure, "width", &data->width) ||
!gst_structure_get_int (structure, "height", &data->height)) {
GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
}
GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width,
xvimage->height);
GST_LOG_OBJECT (xvimagesink, "creating %dx%d", data->width, data->height);
xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
if (xvimage->im_format == -1) {
data->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
if (data->im_format == -1) {
GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %"
GST_PTR_FORMAT, caps);
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
xvimage->width, xvimage->height), ("Invalid input caps"));
data->width, data->height), ("Invalid input caps"));
goto beach_unlocked;
}
xvimage->xvimagesink = gst_object_ref (xvimagesink);
data->xvimagesink = gst_object_ref (xvimagesink);
g_mutex_lock (xvimagesink->x_lock);
@ -552,11 +439,10 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
if (xvimagesink->xcontext->use_xshm) {
int expected_size;
xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
data->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
xvimagesink->xcontext->xv_port_id,
xvimage->im_format, NULL,
xvimage->width, xvimage->height, &xvimage->SHMInfo);
if (!xvimage->xvimage || error_caught) {
data->im_format, NULL, data->width, data->height, &data->SHMInfo);
if (!data->xvimage || error_caught) {
g_mutex_unlock (xvimagesink->x_lock);
/* Reset error handler */
error_caught = FALSE;
@ -564,20 +450,20 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
/* Push an error */
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
xvimage->width, xvimage->height),
data->width, data->height),
("could not XvShmCreateImage a %dx%d image",
xvimage->width, xvimage->height));
data->width, data->height));
goto beach_unlocked;
}
/* we have to use the returned data_size for our shm size */
xvimage->size = xvimage->xvimage->data_size;
data->size = data->xvimage->data_size;
GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
xvimage->size);
data->size);
/* calculate the expected size. This is only for sanity checking the
* number we get from X. */
switch (xvimage->im_format) {
switch (data->im_format) {
case GST_MAKE_FOURCC ('I', '4', '2', '0'):
case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
{
@ -586,17 +472,17 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
guint plane;
offsets[0] = 0;
pitches[0] = GST_ROUND_UP_4 (xvimage->width);
offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (xvimage->height);
pitches[1] = GST_ROUND_UP_8 (xvimage->width) / 2;
pitches[0] = GST_ROUND_UP_4 (data->width);
offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (data->height);
pitches[1] = GST_ROUND_UP_8 (data->width) / 2;
offsets[2] =
offsets[1] + pitches[1] * GST_ROUND_UP_2 (xvimage->height) / 2;
offsets[1] + pitches[1] * GST_ROUND_UP_2 (data->height) / 2;
pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
expected_size =
offsets[2] + pitches[2] * GST_ROUND_UP_2 (xvimage->height) / 2;
offsets[2] + pitches[2] * GST_ROUND_UP_2 (data->height) / 2;
for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
for (plane = 0; plane < data->xvimage->num_planes; plane++) {
GST_DEBUG_OBJECT (xvimagesink,
"Plane %u has a expected pitch of %d bytes, " "offset of %d",
plane, pitches[plane], offsets[plane]);
@ -605,64 +491,63 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
}
case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2);
expected_size = data->height * GST_ROUND_UP_4 (data->width * 2);
break;
default:
expected_size = 0;
break;
}
if (expected_size != 0 && xvimage->size != expected_size) {
if (expected_size != 0 && data->size != expected_size) {
GST_WARNING_OBJECT (xvimagesink,
"unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
xvimage->size, expected_size);
data->size, expected_size);
}
/* Be verbose about our XvImage stride */
{
guint plane;
for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
for (plane = 0; plane < data->xvimage->num_planes; plane++) {
GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
"offset of %d", plane, xvimage->xvimage->pitches[plane],
xvimage->xvimage->offsets[plane]);
"offset of %d", plane, data->xvimage->pitches[plane],
data->xvimage->offsets[plane]);
}
}
xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
IPC_CREAT | 0777);
if (xvimage->SHMInfo.shmid == -1) {
data->SHMInfo.shmid = shmget (IPC_PRIVATE, data->size, IPC_CREAT | 0777);
if (data->SHMInfo.shmid == -1) {
g_mutex_unlock (xvimagesink->x_lock);
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
xvimage->width, xvimage->height),
data->width, data->height),
("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
xvimage->size));
data->size));
goto beach_unlocked;
}
xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0);
if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
data->SHMInfo.shmaddr = shmat (data->SHMInfo.shmid, NULL, 0);
if (data->SHMInfo.shmaddr == ((void *) -1)) {
g_mutex_unlock (xvimagesink->x_lock);
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
xvimage->width, xvimage->height),
data->width, data->height),
("Failed to shmat: %s", g_strerror (errno)));
/* Clean up the shared memory segment */
shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
shmctl (data->SHMInfo.shmid, IPC_RMID, NULL);
goto beach_unlocked;
}
xvimage->xvimage->data = xvimage->SHMInfo.shmaddr;
xvimage->SHMInfo.readOnly = FALSE;
data->xvimage->data = data->SHMInfo.shmaddr;
data->SHMInfo.readOnly = FALSE;
if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
if (XShmAttach (xvimagesink->xcontext->disp, &data->SHMInfo) == 0) {
/* Clean up the shared memory segment */
shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
shmctl (data->SHMInfo.shmid, IPC_RMID, NULL);
g_mutex_unlock (xvimagesink->x_lock);
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
xvimage->width, xvimage->height), ("Failed to XShmAttach"));
data->width, data->height), ("Failed to XShmAttach"));
goto beach_unlocked;
}
@ -671,17 +556,17 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
/* Delete the shared memory segment as soon as we everyone is attached.
* This way, it will be deleted as soon as we detach later, and not
* leaked if we crash. */
shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
shmctl (data->SHMInfo.shmid, IPC_RMID, NULL);
GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
data->SHMInfo.shmid, data->SHMInfo.shmseg);
} else
#endif /* HAVE_XSHM */
{
xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
data->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
xvimagesink->xcontext->xv_port_id,
xvimage->im_format, NULL, xvimage->width, xvimage->height);
if (!xvimage->xvimage || error_caught) {
data->im_format, NULL, data->width, data->height);
if (!data->xvimage || error_caught) {
g_mutex_unlock (xvimagesink->x_lock);
/* Reset error handler */
error_caught = FALSE;
@ -689,15 +574,14 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
/* Push an error */
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create outputimage buffer of %dx%d pixels",
xvimage->width, xvimage->height),
("could not XvCreateImage a %dx%d image",
xvimage->width, xvimage->height));
data->width, data->height),
("could not XvCreateImage a %dx%d image", data->width, data->height));
goto beach_unlocked;
}
/* we have to use the returned data_size for our image size */
xvimage->size = xvimage->xvimage->data_size;
xvimage->xvimage->data = g_malloc (xvimage->size);
data->size = data->xvimage->data_size;
data->xvimage->data = g_malloc (data->size);
XSync (xvimagesink->xcontext->disp, FALSE);
}
@ -708,18 +592,93 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
succeeded = TRUE;
GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data;
GST_BUFFER_SIZE (xvimage) = xvimage->size;
GST_BUFFER_DATA (buffer) = (guchar *) data->xvimage->data;
GST_BUFFER_SIZE (buffer) = data->size;
g_mutex_unlock (xvimagesink->x_lock);
beach_unlocked:
if (!succeeded) {
gst_xvimage_buffer_free (xvimage);
xvimage = NULL;
gst_xvimage_buffer_free (buffer);
buffer = NULL;
}
return xvimage;
return buffer;
}
/* This function destroys a GstXvImage handling XShm availability */
static void
gst_xvimagesink_xvimage_destroy (GstXvImageSink * xvimagesink,
GstBuffer * xvimage)
{
GstXvImageData *data = NULL;
GST_DEBUG_OBJECT (xvimage, "Destroying buffer");
g_return_if_fail (xvimage != NULL);
g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
data = GET_XVDATA (xvimage);
g_return_if_fail (data != NULL);
GST_OBJECT_LOCK (xvimagesink);
/* If the destroyed image is the current one we destroy our reference too */
if (xvimagesink->cur_image == xvimage)
xvimagesink->cur_image = NULL;
/* We might have some buffers destroyed after changing state to NULL */
if (xvimagesink->xcontext == NULL) {
GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
#ifdef HAVE_XSHM
/* Need to free the shared memory segment even if the x context
* was already cleaned up */
if (data->SHMInfo.shmaddr != ((void *) -1)) {
shmdt (data->SHMInfo.shmaddr);
}
#endif
goto beach;
}
g_mutex_lock (xvimagesink->x_lock);
#ifdef HAVE_XSHM
if (xvimagesink->xcontext->use_xshm) {
if (data->SHMInfo.shmaddr != ((void *) -1)) {
GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
data->SHMInfo.shmid, data->SHMInfo.shmseg);
XShmDetach (xvimagesink->xcontext->disp, &data->SHMInfo);
XSync (xvimagesink->xcontext->disp, FALSE);
shmdt (data->SHMInfo.shmaddr);
}
if (data->xvimage)
XFree (data->xvimage);
} else
#endif /* HAVE_XSHM */
{
if (data->xvimage) {
if (data->xvimage->data) {
g_free (data->xvimage->data);
}
XFree (data->xvimage);
}
}
XSync (xvimagesink->xcontext->disp, FALSE);
g_mutex_unlock (xvimagesink->x_lock);
beach:
GST_OBJECT_UNLOCK (xvimagesink);
data->xvimagesink = NULL;
gst_object_unref (xvimagesink);
g_slice_free (GstXvImageData, data);
xvimage->owner_priv = NULL;
return;
}
/* We are called with the x_lock taken */
@ -769,9 +728,9 @@ gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink,
/* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
* if no window was available */
static gboolean
gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
GstXvImageBuffer * xvimage)
gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage)
{
GstXvImageData *data;
GstVideoRectangle result;
gboolean draw_border = FALSE;
@ -794,11 +753,10 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
if (xvimage && xvimagesink->cur_image != xvimage) {
if (xvimagesink->cur_image) {
GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
gst_buffer_unref (xvimagesink->cur_image);
}
GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage);
xvimagesink->cur_image =
GST_XVIMAGE_BUFFER_CAST (gst_buffer_ref (GST_BUFFER_CAST (xvimage)));
xvimagesink->cur_image = gst_buffer_ref (xvimage);
}
/* Expose sends a NULL image, we take the latest frame */
@ -837,19 +795,21 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
xvimagesink->redraw_border = FALSE;
}
data = GET_XVDATA (xvimage);
/* We scale to the window's geometry */
#ifdef HAVE_XSHM
if (xvimagesink->xcontext->use_xshm) {
GST_LOG_OBJECT (xvimagesink,
"XvShmPutImage with image %dx%d and window %dx%d, from xvimage %"
GST_PTR_FORMAT,
xvimage->width, xvimage->height,
data->width, data->height,
xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage);
XvShmPutImage (xvimagesink->xcontext->disp,
xvimagesink->xcontext->xv_port_id,
xvimagesink->xwindow->win,
xvimagesink->xwindow->gc, xvimage->xvimage,
xvimagesink->xwindow->gc, data->xvimage,
xvimagesink->disp_x, xvimagesink->disp_y,
xvimagesink->disp_width, xvimagesink->disp_height,
result.x, result.y, result.w, result.h, FALSE);
@ -859,7 +819,7 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
XvPutImage (xvimagesink->xcontext->disp,
xvimagesink->xcontext->xv_port_id,
xvimagesink->xwindow->win,
xvimagesink->xwindow->gc, xvimage->xvimage,
xvimagesink->xwindow->gc, data->xvimage,
xvimagesink->disp_x, xvimagesink->disp_y,
xvimagesink->disp_width, xvimagesink->disp_height,
result.x, result.y, result.w, result.h);
@ -1734,6 +1694,7 @@ gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext)
ratio = 4.0 * 576 / (3.0 * 720);
}
GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
/* now find the one from par[][2] with the lowest delta to the real one */
delta = DELTA (0);
index = 0;
@ -2013,7 +1974,7 @@ gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
g_mutex_lock (xvimagesink->pool_lock);
while (xvimagesink->image_pool) {
GstXvImageBuffer *xvimage = xvimagesink->image_pool->data;
GstBuffer *xvimage = xvimagesink->image_pool->data;
xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
xvimagesink->image_pool);
@ -2212,17 +2173,18 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
/* We renew our xvimage only if size or format changed;
* the xvimage is the same size as the video pixel size */
if ((xvimagesink->xvimage) &&
((im_format != xvimagesink->xvimage->im_format) ||
(video_width != xvimagesink->xvimage->width) ||
(video_height != xvimagesink->xvimage->height))) {
GST_DEBUG_OBJECT (xvimagesink,
"old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
GST_FOURCC_ARGS (im_format));
GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage));
xvimagesink->xvimage = NULL;
if ((xvimagesink->xvimage)) {
GstXvImageData *data = GET_XVDATA (xvimagesink->xvimage);
if (((im_format != data->im_format) ||
(video_width != data->width) || (video_height != data->height))) {
GST_DEBUG_OBJECT (xvimagesink,
"old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (data->im_format), GST_FOURCC_ARGS (im_format));
GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
gst_buffer_unref (xvimagesink->xvimage);
xvimagesink->xvimage = NULL;
}
}
g_mutex_unlock (xvimagesink->flow_lock);
@ -2362,6 +2324,7 @@ gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
xvimagesink = GST_XVIMAGESINK (vsink);
#if 0
/* If this buffer has been allocated using our buffer management we simply
put the ximage which is in the PRIVATE pointer */
if (GST_IS_XVIMAGE_BUFFER (buf)) {
@ -2369,7 +2332,9 @@ gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
if (!gst_xvimagesink_xvimage_put (xvimagesink,
GST_XVIMAGE_BUFFER_CAST (buf)))
goto no_window;
} else {
} else
#endif
{
GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
"slow copy into bufferpool buffer %p", buf);
/* Else we have to copy the data into our private image, */
@ -2384,21 +2349,22 @@ gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
/* The create method should have posted an informative error */
goto no_image;
if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
if (GST_BUFFER_SIZE (xvimagesink->xvimage) < GST_BUFFER_SIZE (buf)) {
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
xvimagesink->xvimage->width, xvimagesink->xvimage->height),
GET_XVDATA (xvimagesink->xvimage)->width,
GET_XVDATA (xvimagesink->xvimage)->height),
("XServer allocated buffer size did not match input buffer"));
gst_xvimage_buffer_destroy (xvimagesink->xvimage);
gst_xvimagesink_xvimage_destroy (xvimagesink, xvimagesink->xvimage);
xvimagesink->xvimage = NULL;
goto no_image;
}
}
memcpy (xvimagesink->xvimage->xvimage->data,
memcpy (GST_BUFFER_DATA (xvimagesink->xvimage),
GST_BUFFER_DATA (buf),
MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
MIN (GST_BUFFER_SIZE (buf), GST_BUFFER_SIZE (xvimagesink->xvimage)));
if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
goto no_window;
@ -2452,6 +2418,7 @@ gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
return TRUE;
}
#if 0
/* Buffer management */
static GstCaps *
@ -2508,7 +2475,7 @@ gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
{
GstFlowReturn ret = GST_FLOW_OK;
GstXvImageSink *xvimagesink;
GstXvImageBuffer *xvimage = NULL;
GstXvImageData *xvimage = NULL;
GstCaps *intersection = NULL;
GstStructure *structure = NULL;
gint width, height, image_format;
@ -2709,6 +2676,7 @@ invalid_caps:
goto beach;
}
}
#endif
/* Interfaces stuff */
@ -3674,8 +3642,10 @@ gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
#if 0
gstbasesink_class->buffer_alloc =
GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
#endif
gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
@ -3749,12 +3719,6 @@ gst_xvimagesink_get_type (void)
&colorbalance_info);
g_type_add_interface_static (xvimagesink_type, GST_TYPE_PROPERTY_PROBE,
&propertyprobe_info);
/* register type and create class in a more safe place instead of at
* runtime since the type registration and class creation is not
* threadsafe. */
g_type_class_ref (gst_xvimage_buffer_get_type ());
}
return xvimagesink_type;

View file

@ -58,8 +58,7 @@ G_BEGIN_DECLS
typedef struct _GstXContext GstXContext;
typedef struct _GstXWindow GstXWindow;
typedef struct _GstXvImageFormat GstXvImageFormat;
typedef struct _GstXvImageBuffer GstXvImageBuffer;
typedef struct _GstXvImageBufferClass GstXvImageBufferClass;
typedef struct _GstXvImageData GstXvImageData;
typedef struct _GstXvImageSink GstXvImageSink;
typedef struct _GstXvImageSinkClass GstXvImageSinkClass;
@ -163,7 +162,7 @@ struct _GstXvImageFormat {
};
/**
* GstXImageBuffer:
* GstXImageData:
* @xvimagesink: a reference to our #GstXvImageSink
* @xvimage: the XvImage of this buffer
* @width: the width in pixels of XvImage @xvimage
@ -171,11 +170,9 @@ struct _GstXvImageFormat {
* @im_format: the image format of XvImage @xvimage
* @size: the size in bytes of XvImage @xvimage
*
* Subclass of #GstBuffer containing additional information about an XvImage.
* Structure with additional information about an XvImage.
*/
struct _GstXvImageBuffer {
GstBuffer buffer;
struct _GstXvImageData {
/* Reference to the xvimagesink we belong to */
GstXvImageSink *xvimagesink;
@ -234,12 +231,13 @@ struct _GstXvImageSink {
GstXContext *xcontext;
GstXWindow *xwindow;
GstXvImageBuffer *xvimage;
GstXvImageBuffer *cur_image;
GstBuffer *xvimage;
GstBuffer *cur_image;
GThread *event_thread;
gboolean running;
/* Framerate numerator and denominator */
gint fps_n;
gint fps_d;