diff --git a/sys/ximage/ximagesink.c b/sys/ximage/ximagesink.c index d1780fcf51..8c5dc7933b 100644 --- a/sys/ximage/ximagesink.c +++ b/sys/ximage/ximagesink.c @@ -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; diff --git a/sys/ximage/ximagesink.h b/sys/ximage/ximagesink.h index 83e973fa1c..a8ae8396e7 100644 --- a/sys/ximage/ximagesink.h +++ b/sys/ximage/ximagesink.h @@ -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; diff --git a/sys/xvimage/xvimagesink.c b/sys/xvimage/xvimagesink.c index f5ee8666c2..d8c8bd2930 100644 --- a/sys/xvimage/xvimagesink.c +++ b/sys/xvimage/xvimagesink.c @@ -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; diff --git a/sys/xvimage/xvimagesink.h b/sys/xvimage/xvimagesink.h index 0181018487..c4baf6696d 100644 --- a/sys/xvimage/xvimagesink.h +++ b/sys/xvimage/xvimagesink.h @@ -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;