3 * Copyright (C) 2011 Collabora Ltda
4 * Copyright (C) 2011 Texas Instruments
5 * @author: Luciana Fujii Pontello <luciana.fujii@collabora.co.uk>
6 * @author: Edward Hervey <edward@collabora.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 #include "gstpvrvideosink.h"
26 #include "gstpvrbufferpool.h"
28 #include <gst/video/gstvideosink.h>
29 #include <gst/video/videooverlay.h>
30 /* Helper functions */
31 #include <gst/video/gstvideometa.h>
33 /* Debugging category */
34 #include <gst/gstinfo.h>
40 #include <servicesext.h>
42 #define DEFAULT_QUEUE_SIZE 12
44 GST_DEBUG_CATEGORY_EXTERN (gst_debug_pvrvideosink);
45 #define GST_CAT_DEFAULT gst_debug_pvrvideosink
47 #define PVR2DMEMINFO_INITIALISE(d, s) \
49 (d)->hPrivateData = (IMG_VOID *)(s); \
50 (d)->hPrivateMapData = (IMG_VOID *)(s->hKernelMemInfo); \
51 (d)->ui32DevAddr = (IMG_UINT32) (s)->sDevVAddr.uiAddr; \
52 (d)->ui32MemSize = (s)->uAllocSize; \
53 (d)->pBase = (s)->pvLinAddr;\
54 (d)->ulFlags = (s)->ui32Flags;\
57 /* end of internal definitions */
59 static void gst_pvrvideosink_reset (GstPVRVideoSink * pvrvideosink);
60 static void gst_pvrvideosink_xwindow_draw_borders (GstPVRVideoSink *
61 pvrvideosink, GstXWindow * xwindow, GstVideoRectangle rect);
62 static void gst_pvrvideosink_expose (GstVideoOverlay * overlay);
63 static void gst_pvrvideosink_xwindow_destroy (GstPVRVideoSink * pvrvideosink,
64 GstXWindow * xwindow);
65 static void gst_pvrvideosink_dcontext_free (GstDrawContext * dcontext);
67 static void gst_pvrvideosink_videooverlay_init (GstVideoOverlayInterface *
70 #define gst_pvrvideosink_parent_class parent_class
71 G_DEFINE_TYPE_WITH_CODE (GstPVRVideoSink, gst_pvrvideosink, GST_TYPE_VIDEO_SINK,
72 G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
73 gst_pvrvideosink_videooverlay_init));
76 static GstStaticPadTemplate gst_pvrvideosink_sink_template_factory =
77 GST_STATIC_PAD_TEMPLATE ("sink",
80 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("NV12")));
85 PROP_FORCE_ASPECT_RATIO,
90 /* ============================================================= */
94 /* ============================================================= */
96 /* pvrvideo buffers */
99 gst_pvrvideosink_xwindow_update_geometry (GstPVRVideoSink * pvrvideosink)
101 XWindowAttributes attr;
103 WSEGLDrawableParams source_params;
104 PVRSRV_CLIENT_MEM_INFO *client_mem_info;
106 /* Update the window geometry */
107 g_mutex_lock (pvrvideosink->dcontext->x_lock);
108 if (G_UNLIKELY (pvrvideosink->xwindow == NULL)) {
109 g_mutex_unlock (pvrvideosink->dcontext->x_lock);
112 pvrvideosink->redraw_borders = TRUE;
114 XGetWindowAttributes (pvrvideosink->dcontext->x_display,
115 pvrvideosink->xwindow->window, &attr);
117 pvrvideosink->xwindow->width = attr.width;
118 pvrvideosink->xwindow->height = attr.height;
120 if (!pvrvideosink->have_render_rect) {
121 pvrvideosink->render_rect.x = pvrvideosink->render_rect.y = 0;
122 pvrvideosink->render_rect.w = attr.width;
123 pvrvideosink->render_rect.h = attr.height;
125 if (pvrvideosink->dcontext != NULL) {
127 pvrvideosink->dcontext->wsegl_table->
128 pfnWSEGL_DeleteDrawable (pvrvideosink->dcontext->drawable_handle);
129 if (glerror != WSEGL_SUCCESS) {
130 GST_ERROR_OBJECT (pvrvideosink, "Error destroying drawable");
134 pvrvideosink->dcontext->wsegl_table->
135 pfnWSEGL_CreateWindowDrawable (pvrvideosink->dcontext->display_handle,
136 pvrvideosink->dcontext->glconfig,
137 &pvrvideosink->dcontext->drawable_handle,
138 (NativeWindowType) pvrvideosink->xwindow->window,
139 &pvrvideosink->dcontext->rotation);
140 if (glerror != WSEGL_SUCCESS) {
141 GST_ERROR_OBJECT (pvrvideosink, "Error creating drawable");
145 pvrvideosink->dcontext->wsegl_table->
146 pfnWSEGL_GetDrawableParameters (pvrvideosink->dcontext->drawable_handle,
147 &source_params, &pvrvideosink->render_params);
148 if (glerror != WSEGL_SUCCESS) {
149 GST_ERROR_OBJECT (pvrvideosink, "Error getting Drawable params");
154 (PVRSRV_CLIENT_MEM_INFO *) pvrvideosink->render_params.hPrivateData;
155 PVR2DMEMINFO_INITIALISE (&pvrvideosink->dcontext->dst_mem, client_mem_info);
158 g_mutex_unlock (pvrvideosink->dcontext->x_lock);
161 /* This function handles XEvents that might be in the queue. It generates
162 GstEvent that will be sent upstream in the pipeline to handle interactivity
163 and navigation. It will also listen for configure events on the window to
164 trigger caps renegotiation so on the fly software scaling can work. */
166 gst_pvrvideosink_handle_xevents (GstPVRVideoSink * pvrvideosink)
169 gboolean exposed = FALSE;
170 gboolean configured = FALSE;
172 g_mutex_lock (pvrvideosink->flow_lock);
173 g_mutex_lock (pvrvideosink->dcontext->x_lock);
176 while (XCheckWindowEvent (pvrvideosink->dcontext->x_display,
177 pvrvideosink->xwindow->window, ExposureMask | StructureNotifyMask,
183 case ConfigureNotify:
184 g_mutex_unlock (pvrvideosink->dcontext->x_lock);
185 gst_pvrvideosink_xwindow_update_geometry (pvrvideosink);
186 g_mutex_lock (pvrvideosink->dcontext->x_lock);
194 if (exposed || configured) {
195 g_mutex_unlock (pvrvideosink->dcontext->x_lock);
196 g_mutex_unlock (pvrvideosink->flow_lock);
198 gst_pvrvideosink_expose (GST_VIDEO_OVERLAY (pvrvideosink));
200 g_mutex_lock (pvrvideosink->flow_lock);
201 g_mutex_lock (pvrvideosink->dcontext->x_lock);
204 /* Handle Display events */
205 while (XPending (pvrvideosink->dcontext->x_display)) {
206 XNextEvent (pvrvideosink->dcontext->x_display, &e);
212 wm_delete = XInternAtom (pvrvideosink->dcontext->x_display,
213 "WM_DELETE_WINDOW", True);
214 if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) {
215 /* Handle window deletion by posting an error on the bus */
216 GST_ELEMENT_ERROR (pvrvideosink, RESOURCE, NOT_FOUND,
217 ("Output window was closed"), (NULL));
219 g_mutex_unlock (pvrvideosink->dcontext->x_lock);
220 gst_pvrvideosink_xwindow_destroy (pvrvideosink,
221 pvrvideosink->xwindow);
222 pvrvideosink->xwindow = NULL;
223 g_mutex_lock (pvrvideosink->dcontext->x_lock);
232 g_mutex_unlock (pvrvideosink->dcontext->x_lock);
233 g_mutex_unlock (pvrvideosink->flow_lock);
237 gst_pvrvideosink_event_thread (GstPVRVideoSink * pvrvideosink)
239 GST_OBJECT_LOCK (pvrvideosink);
240 while (pvrvideosink->running) {
241 GST_OBJECT_UNLOCK (pvrvideosink);
243 if (pvrvideosink->xwindow) {
244 gst_pvrvideosink_handle_xevents (pvrvideosink);
246 g_usleep (G_USEC_PER_SEC / 20);
248 GST_OBJECT_LOCK (pvrvideosink);
250 GST_OBJECT_UNLOCK (pvrvideosink);
256 gst_pvrvideosink_manage_event_thread (GstPVRVideoSink * pvrvideosink)
258 GThread *thread = NULL;
260 /* don't start the thread too early */
261 if (pvrvideosink->dcontext == NULL) {
265 GST_OBJECT_LOCK (pvrvideosink);
266 if (!pvrvideosink->event_thread) {
267 /* Setup our event listening thread */
268 GST_DEBUG_OBJECT (pvrvideosink, "run xevent thread");
269 pvrvideosink->running = TRUE;
270 pvrvideosink->event_thread = g_thread_create (
271 (GThreadFunc) gst_pvrvideosink_event_thread, pvrvideosink, TRUE, NULL);
273 GST_OBJECT_UNLOCK (pvrvideosink);
275 /* Wait for our event thread to finish */
277 g_thread_join (thread);
281 static GstDrawContext *
282 gst_pvrvideosink_get_dcontext (GstPVRVideoSink * pvrvideosink)
284 GstDrawContext *dcontext = NULL;
285 PVR2DERROR pvr_error;
287 DRI2WSDisplay *displayImpl;
289 const WSEGLCaps *glcaps;
291 GST_DEBUG_OBJECT (pvrvideosink, "Getting draw context");
293 dcontext = g_new0 (GstDrawContext, 1);
294 dcontext->x_lock = g_mutex_new ();
296 dcontext->p_blt_info = g_new0 (PVR2D_3DBLT_EXT, 1);
297 if (!dcontext->p_blt_info)
298 goto p_blt_info_alloc_failed;
300 dcontext->p_blt2d_info = g_new0 (PVR2DBLTINFO, 1);
302 GST_LOG_OBJECT (pvrvideosink, "Opening X Display");
303 dcontext->x_display = XOpenDisplay (NULL);
305 if (dcontext->x_display == NULL)
306 goto fail_open_display;
308 GST_LOG_OBJECT (pvrvideosink, "WSEGL_GetFunctionTablePointer()");
309 dcontext->wsegl_table = WSEGL_GetFunctionTablePointer ();
311 GST_LOG_OBJECT (pvrvideosink, "pfnWSEGL_IsDisplayValid()");
312 glerror = dcontext->wsegl_table->pfnWSEGL_IsDisplayValid (
313 (NativeDisplayType) dcontext->x_display);
315 if (glerror != WSEGL_SUCCESS)
316 goto display_invalid;
318 GST_LOG_OBJECT (pvrvideosink, "pfnWSEGL_InitialiseDisplay()");
320 glerror = dcontext->wsegl_table->pfnWSEGL_InitialiseDisplay (
321 (NativeDisplayType) dcontext->x_display, &dcontext->display_handle,
322 &glcaps, &dcontext->glconfig);
323 if (glerror != WSEGL_SUCCESS)
324 goto display_init_failed;
326 displayImpl = (DRI2WSDisplay *) dcontext->display_handle;
327 dcontext->pvr_context = displayImpl->hContext;
329 GST_LOG_OBJECT (pvrvideosink, "PVR2DGetScreenMode()");
331 pvr_error = PVR2DGetScreenMode (dcontext->pvr_context,
332 &dcontext->display_format, &dcontext->display_width,
333 &dcontext->display_height, &dcontext->stride, &refresh_rate);
334 if (pvr_error != PVR2D_OK)
335 goto screen_mode_failed;
337 GST_DEBUG_OBJECT (pvrvideosink,
338 "Got format:%d, width:%d, height:%d, stride:%d, refresh_rate:%d",
339 dcontext->display_format, dcontext->display_width,
340 dcontext->display_height, dcontext->stride, refresh_rate);
342 dcontext->screen_num = DefaultScreen (dcontext->x_display);
343 dcontext->black = XBlackPixel (dcontext->x_display, dcontext->screen_num);
345 GST_DEBUG_OBJECT (pvrvideosink, "Returning dcontext %p", dcontext);
349 p_blt_info_alloc_failed:
351 GST_ERROR_OBJECT (pvrvideosink, "Alloc of bltinfo failed");
352 gst_pvrvideosink_dcontext_free (dcontext);
358 GST_ERROR_OBJECT (pvrvideosink, "Failed to open X Display");
359 gst_pvrvideosink_dcontext_free (dcontext);
365 GST_ERROR_OBJECT (pvrvideosink, "Display is not valid (glerror:%d)",
367 gst_pvrvideosink_dcontext_free (dcontext);
373 GST_ERROR_OBJECT (pvrvideosink, "Error initializing display (glerror:%d)",
375 gst_pvrvideosink_dcontext_free (dcontext);
381 GST_ERROR_OBJECT (pvrvideosink, "Failed to get screen mode. error : %s",
382 gst_pvr2d_error_get_string (pvr_error));
383 gst_pvrvideosink_dcontext_free (dcontext);
389 gst_pvrvideosink_xwindow_set_title (GstPVRVideoSink * pvrvideosink,
390 GstXWindow * xwindow, const gchar * media_title)
393 g_free (pvrvideosink->media_title);
394 pvrvideosink->media_title = g_strdup (media_title);
397 /* we have a window */
398 if (xwindow->internal) {
399 XTextProperty xproperty;
400 const gchar *app_name;
401 const gchar *title = NULL;
402 gchar *title_mem = NULL;
404 /* set application name as a title */
405 app_name = g_get_application_name ();
407 if (app_name && pvrvideosink->media_title) {
408 title = title_mem = g_strconcat (pvrvideosink->media_title, " : ",
410 } else if (app_name) {
412 } else if (pvrvideosink->media_title) {
413 title = pvrvideosink->media_title;
417 if ((XStringListToTextProperty (((char **) &title), 1,
419 XSetWMName (pvrvideosink->dcontext->x_display, xwindow->window,
421 XFree (xproperty.value);
431 gst_pvrvideosink_create_window (GstPVRVideoSink * pvrvideosink, gint width,
435 WSEGLDrawableParams source_params;
438 GstDrawContext *dcontext;
441 PVRSRV_CLIENT_MEM_INFO *client_mem_info;
443 GST_DEBUG_OBJECT (pvrvideosink, "begin");
445 dcontext = pvrvideosink->dcontext;
446 xwindow = g_new0 (GstXWindow, 1);
448 xwindow->internal = TRUE;
449 pvrvideosink->render_rect.x = pvrvideosink->render_rect.y = 0;
450 pvrvideosink->render_rect.w = width;
451 pvrvideosink->render_rect.h = height;
452 xwindow->width = width;
453 xwindow->height = height;
454 xwindow->internal = TRUE;
456 g_mutex_lock (pvrvideosink->dcontext->x_lock);
458 root = DefaultRootWindow (dcontext->x_display);
459 xwindow->window = XCreateSimpleWindow (dcontext->x_display, root, 0, 0,
460 width, height, 2, 2, pvrvideosink->dcontext->black);
461 XSelectInput (dcontext->x_display, xwindow->window,
462 ExposureMask | StructureNotifyMask);
464 /* Tell the window manager we'd like delete client messages instead of
466 wm_delete = XInternAtom (pvrvideosink->dcontext->x_display,
467 "WM_DELETE_WINDOW", True);
468 if (wm_delete != None) {
469 (void) XSetWMProtocols (pvrvideosink->dcontext->x_display, xwindow->window,
473 XMapWindow (dcontext->x_display, xwindow->window);
475 /* We have to do that to prevent X from redrawing the background on
476 * ConfigureNotify. This takes away flickering of video when resizing. */
477 XSetWindowBackgroundPixmap (pvrvideosink->dcontext->x_display,
478 xwindow->window, None);
480 gst_pvrvideosink_xwindow_set_title (pvrvideosink, xwindow, NULL);
482 xwindow->gc = XCreateGC (pvrvideosink->dcontext->x_display,
483 xwindow->window, 0, &values);
485 g_mutex_unlock (pvrvideosink->dcontext->x_lock);
488 dcontext->wsegl_table->
489 pfnWSEGL_CreateWindowDrawable (dcontext->display_handle,
490 dcontext->glconfig, &(dcontext->drawable_handle),
491 (NativeWindowType) xwindow->window, &(dcontext->rotation));
493 if (glerror != WSEGL_SUCCESS) {
494 GST_ERROR_OBJECT (pvrvideosink, "Error creating drawable");
498 dcontext->wsegl_table->
499 pfnWSEGL_GetDrawableParameters (dcontext->drawable_handle, &source_params,
500 &pvrvideosink->render_params);
502 (PVRSRV_CLIENT_MEM_INFO *) pvrvideosink->render_params.hPrivateData;
503 PVR2DMEMINFO_INITIALISE (&dcontext->dst_mem, client_mem_info);
505 GST_DEBUG_OBJECT (pvrvideosink, "end");
510 gst_pvrvideosink_blit (GstPVRVideoSink * pvrvideosink, GstBuffer * buffer)
512 PVR2DERROR pvr_error;
513 GstDrawContext *dcontext = pvrvideosink->dcontext;
516 gboolean draw_border = FALSE;
517 PPVR2D_3DBLT_EXT p_blt_3d;
518 PVR2DMEMINFO *src_mem;
519 PVR2DFORMAT pvr_format;
520 GstVideoRectangle result;
522 GstVideoCropMeta *cropmeta;
524 GST_DEBUG_OBJECT (pvrvideosink, "buffer %p", buffer);
527 GST_VIDEO_INFO_FORMAT (&pvrvideosink->info) ==
528 GST_VIDEO_FORMAT_NV12 ? PVR2D_YUV420_2PLANE : PVR2D_ARGB8888;
530 g_mutex_lock (pvrvideosink->flow_lock);
532 buffer = pvrvideosink->current_buffer;
537 meta = gst_buffer_get_pvr_meta (buffer);
538 if (G_UNLIKELY (meta == NULL))
541 src_mem = meta->src_mem;
542 p_blt_3d = dcontext->p_blt_info;
544 video_width = GST_VIDEO_SINK_WIDTH (pvrvideosink);
545 video_height = GST_VIDEO_SINK_HEIGHT (pvrvideosink);
547 g_mutex_lock (pvrvideosink->dcontext->x_lock);
549 /* Draw borders when displaying the first frame. After this
550 draw borders only on expose event or after a size change. */
551 if (!(pvrvideosink->current_buffer) || pvrvideosink->redraw_borders) {
555 /* Store a reference to the last image we put, lose the previous one */
556 if (buffer && pvrvideosink->current_buffer != buffer) {
557 if (pvrvideosink->current_buffer) {
558 GST_LOG_OBJECT (pvrvideosink, "unreffing %p",
559 pvrvideosink->current_buffer);
560 gst_buffer_unref (GST_BUFFER_CAST (pvrvideosink->current_buffer));
562 GST_LOG_OBJECT (pvrvideosink, "reffing %p as our current buffer", buffer);
563 pvrvideosink->current_buffer = gst_buffer_ref (buffer);
566 if (pvrvideosink->keep_aspect) {
567 GstVideoRectangle src, dst;
569 src.w = GST_VIDEO_SINK_WIDTH (pvrvideosink);
570 src.h = GST_VIDEO_SINK_HEIGHT (pvrvideosink);
571 dst.w = pvrvideosink->render_rect.w;
572 dst.h = pvrvideosink->render_rect.h;
573 gst_video_sink_center_rect (src, dst, &result, TRUE);
574 result.x += pvrvideosink->render_rect.x;
575 result.y += pvrvideosink->render_rect.y;
577 memcpy (&result, &pvrvideosink->render_rect, sizeof (GstVideoRectangle));
580 p_blt_3d->sDst.pSurfMemInfo = &dcontext->dst_mem;
581 p_blt_3d->sDst.SurfOffset = 0;
582 p_blt_3d->sDst.Stride = 4 * pvrvideosink->render_params.ui32Stride;
583 p_blt_3d->sDst.Format = PVR2D_ARGB8888;
584 p_blt_3d->sDst.SurfWidth = pvrvideosink->xwindow->width;
585 p_blt_3d->sDst.SurfHeight = pvrvideosink->xwindow->height;
587 p_blt_3d->rcDest.left = result.x;
588 p_blt_3d->rcDest.top = result.y;
589 p_blt_3d->rcDest.right = result.w + result.x;
590 p_blt_3d->rcDest.bottom = result.h + result.y;
592 p_blt_3d->sSrc.pSurfMemInfo = src_mem;
593 p_blt_3d->sSrc.SurfOffset = 0;
594 p_blt_3d->sSrc.Stride = GST_VIDEO_INFO_COMP_STRIDE (&pvrvideosink->info, 0);
595 p_blt_3d->sSrc.Format = pvr_format;
596 p_blt_3d->sSrc.SurfWidth = video_width;
597 p_blt_3d->sSrc.SurfHeight = video_height;
599 /* If buffer has crop information, use that */
600 if ((cropmeta = gst_buffer_get_video_crop_meta (buffer))) {
601 p_blt_3d->rcSource.left = cropmeta->x;
602 p_blt_3d->rcSource.top = cropmeta->y;
603 p_blt_3d->rcSource.right = cropmeta->x + cropmeta->width;
604 p_blt_3d->rcSource.bottom = cropmeta->y + cropmeta->height;
606 p_blt_3d->rcSource.left = 0;
607 p_blt_3d->rcSource.top = 0;
608 p_blt_3d->rcSource.right = video_width;
609 p_blt_3d->rcSource.bottom = video_height;
612 p_blt_3d->hUseCode = NULL;
614 if (GST_VIDEO_INFO_FORMAT (&pvrvideosink->info) == GST_VIDEO_FORMAT_NV12)
615 p_blt_3d->bDisableDestInput = TRUE;
617 /* blit fails for RGB without this... not sure why yet... */
618 p_blt_3d->bDisableDestInput = FALSE;
620 GST_DEBUG_OBJECT (pvrvideosink, "about to blit");
622 pvr_error = PVR2DBlt3DExt (pvrvideosink->dcontext->pvr_context,
623 dcontext->p_blt_info);
625 if (pvr_error != PVR2D_OK) {
626 GST_ERROR_OBJECT (pvrvideosink, "Failed to blit. Error : %s",
627 gst_pvr2d_error_get_string (pvr_error));
630 dcontext->wsegl_table->pfnWSEGL_SwapDrawable (dcontext->drawable_handle, 1);
633 gst_pvrvideosink_xwindow_draw_borders (pvrvideosink, pvrvideosink->xwindow,
635 pvrvideosink->redraw_borders = FALSE;
637 g_mutex_unlock (pvrvideosink->dcontext->x_lock);
640 GST_DEBUG_OBJECT (pvrvideosink, "end");
641 g_mutex_unlock (pvrvideosink->flow_lock);
648 g_mutex_unlock (pvrvideosink->flow_lock);
649 GST_ERROR_OBJECT (pvrvideosink, "Got a buffer without GstPVRMeta");
655 gst_pvrvideosink_destroy_drawable (GstPVRVideoSink * pvrvideosink)
657 GST_DEBUG_OBJECT (pvrvideosink, "dcontext : %p", pvrvideosink->dcontext);
659 if (pvrvideosink->dcontext != NULL) {
660 if (pvrvideosink->dcontext->drawable_handle) {
661 GST_DEBUG_OBJECT (pvrvideosink, "Deleting Drawable (drawable_handle:%p)",
662 pvrvideosink->dcontext->drawable_handle);
663 pvrvideosink->dcontext->wsegl_table->
664 pfnWSEGL_DeleteDrawable (pvrvideosink->dcontext->drawable_handle);
667 GST_DEBUG_OBJECT (pvrvideosink, "Closing display (display_handle:%p)",
668 pvrvideosink->dcontext->display_handle);
669 pvrvideosink->dcontext->wsegl_table->
670 pfnWSEGL_CloseDisplay (pvrvideosink->dcontext->display_handle);
674 /* We are called with the x_lock taken */
676 gst_pvrvideosink_pvrfill_rectangle (GstPVRVideoSink * pvrvideosink,
677 GstVideoRectangle rect)
679 PVR2DERROR pvr_error;
680 PPVR2DBLTINFO p_blt2d_info = 0;
681 GstDrawContext *dcontext = pvrvideosink->dcontext;
683 GST_DEBUG_OBJECT (pvrvideosink, "begin");
685 p_blt2d_info = dcontext->p_blt2d_info;
687 p_blt2d_info->pDstMemInfo = &dcontext->dst_mem;
688 p_blt2d_info->BlitFlags = PVR2D_BLIT_DISABLE_ALL;
689 p_blt2d_info->DstOffset = 0;
690 p_blt2d_info->CopyCode = PVR2DROPclear;
691 p_blt2d_info->DstStride = 4 * pvrvideosink->render_params.ui32Stride;
692 p_blt2d_info->DstFormat = PVR2D_ARGB8888;
693 p_blt2d_info->DstSurfWidth = pvrvideosink->xwindow->width;
694 p_blt2d_info->DstSurfHeight = pvrvideosink->xwindow->height;
695 p_blt2d_info->DstX = rect.x;
696 p_blt2d_info->DstY = rect.y;
697 p_blt2d_info->DSizeX = rect.w;
698 p_blt2d_info->DSizeY = rect.h;
700 pvr_error = PVR2DBlt (pvrvideosink->dcontext->pvr_context, p_blt2d_info);
702 if (pvr_error != PVR2D_OK) {
703 GST_ERROR_OBJECT (pvrvideosink, "Failed to blit. Error : %s",
704 gst_pvr2d_error_get_string (pvr_error));
707 dcontext->wsegl_table->pfnWSEGL_SwapDrawable (dcontext->drawable_handle, 1);
710 GST_DEBUG_OBJECT (pvrvideosink, "end");
713 /* We are called with the x_lock taken */
715 gst_pvrvideosink_xwindow_draw_borders (GstPVRVideoSink * pvrvideosink,
716 GstXWindow * xwindow, GstVideoRectangle rect)
719 GstVideoRectangle result;
721 g_return_if_fail (GST_IS_PVRVIDEOSINK (pvrvideosink));
722 g_return_if_fail (xwindow != NULL);
725 result.x = pvrvideosink->render_rect.x;
726 result.y = pvrvideosink->render_rect.y;
727 result.w = rect.x - pvrvideosink->render_rect.x;
728 result.h = pvrvideosink->render_rect.h;
729 if (rect.x > pvrvideosink->render_rect.x)
730 gst_pvrvideosink_pvrfill_rectangle (pvrvideosink, result);
733 t1 = rect.x + rect.w;
734 t2 = pvrvideosink->render_rect.x + pvrvideosink->render_rect.w;
736 result.y = pvrvideosink->render_rect.y;
738 result.h = pvrvideosink->render_rect.h;
740 gst_pvrvideosink_pvrfill_rectangle (pvrvideosink, result);
743 result.x = pvrvideosink->render_rect.x;
744 result.y = pvrvideosink->render_rect.y;
745 result.w = pvrvideosink->render_rect.w;
746 result.h = rect.y - pvrvideosink->render_rect.y;
747 if (rect.y > pvrvideosink->render_rect.y)
748 gst_pvrvideosink_pvrfill_rectangle (pvrvideosink, result);
751 t1 = rect.y + rect.h;
752 t2 = pvrvideosink->render_rect.y + pvrvideosink->render_rect.h;
753 result.x = pvrvideosink->render_rect.x;
755 result.w = pvrvideosink->render_rect.w;
758 gst_pvrvideosink_pvrfill_rectangle (pvrvideosink, result);
764 gst_pvrvideosink_setcaps (GstBaseSink * bsink, GstCaps * caps)
766 GstPVRVideoSink *pvrvideosink;
768 GstStructure *structure;
769 GstBufferPool *oldpool, *newpool;
771 pvrvideosink = GST_PVRVIDEOSINK (bsink);
773 GST_DEBUG_OBJECT (pvrvideosink,
774 "sinkconnect possible caps with given caps %" GST_PTR_FORMAT, caps);
776 if (!gst_video_info_from_caps (&info, caps))
779 GST_VIDEO_SINK_WIDTH (pvrvideosink) = info.width;
780 GST_VIDEO_SINK_HEIGHT (pvrvideosink) = info.height;
782 /* Notify application to set xwindow id now */
783 g_mutex_lock (pvrvideosink->flow_lock);
784 if (!pvrvideosink->xwindow) {
785 g_mutex_unlock (pvrvideosink->flow_lock);
786 gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (pvrvideosink));
788 g_mutex_unlock (pvrvideosink->flow_lock);
791 g_mutex_lock (pvrvideosink->flow_lock);
792 if (!pvrvideosink->xwindow)
793 pvrvideosink->xwindow = gst_pvrvideosink_create_window (pvrvideosink,
794 GST_VIDEO_SINK_WIDTH (pvrvideosink),
795 GST_VIDEO_SINK_HEIGHT (pvrvideosink));
796 g_mutex_unlock (pvrvideosink->flow_lock);
798 pvrvideosink->info = info;
800 /* After a resize, we want to redraw the borders in case the new frame size
801 * doesn't cover the same area */
802 pvrvideosink->redraw_borders = TRUE;
804 /* create a new pool for the new configuration */
805 newpool = gst_pvr_buffer_pool_new (GST_ELEMENT_CAST (pvrvideosink));
807 /* PVR needs at least 3 buffers */
808 structure = gst_buffer_pool_get_config (newpool);
809 gst_buffer_pool_config_set (structure, caps, GST_VIDEO_INFO_SIZE (&info), 3,
811 if (!gst_buffer_pool_set_config (newpool, structure))
814 oldpool = pvrvideosink->pool;
815 pvrvideosink->pool = newpool;
816 g_mutex_unlock (pvrvideosink->flow_lock);
818 /* unref the old sink */
820 /* we don't deactivate, some elements might still be using it, it will
821 * be deactivated when the last ref is gone */
822 gst_object_unref (oldpool);
829 GST_ERROR_OBJECT (pvrvideosink, "failed to set config.");
830 g_mutex_unlock (pvrvideosink->flow_lock);
836 GST_DEBUG_OBJECT (pvrvideosink,
837 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
843 gst_pvrvideosink_getcaps (GstBaseSink * bsink, GstCaps * filter)
845 GstPVRVideoSink *pvrvideosink;
848 GST_DEBUG_OBJECT (bsink, "filter:%" GST_PTR_FORMAT, filter);
850 pvrvideosink = GST_PVRVIDEOSINK (bsink);
852 /* FIXME : If we have curently configured caps, we should return those
853 * intersected with the filter*/
855 caps = gst_pad_get_pad_template_caps (GST_BASE_SINK (pvrvideosink)->sinkpad);
857 GstCaps *intersection;
860 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
861 gst_caps_unref (caps);
865 GST_DEBUG_OBJECT (bsink, "Returning %" GST_PTR_FORMAT, caps);
870 static GstStateChangeReturn
871 gst_pvrvideosink_change_state (GstElement * element, GstStateChange transition)
873 GstPVRVideoSink *pvrvideosink;
874 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
875 GstDrawContext *dcontext;
877 pvrvideosink = GST_PVRVIDEOSINK (element);
879 switch (transition) {
880 case GST_STATE_CHANGE_NULL_TO_READY:
881 if (pvrvideosink->dcontext == NULL) {
882 dcontext = gst_pvrvideosink_get_dcontext (pvrvideosink);
883 if (dcontext == NULL)
884 return GST_STATE_CHANGE_FAILURE;
885 GST_OBJECT_LOCK (pvrvideosink);
886 pvrvideosink->dcontext = dcontext;
887 GST_OBJECT_UNLOCK (pvrvideosink);
889 gst_pvrvideosink_manage_event_thread (pvrvideosink);
891 case GST_STATE_CHANGE_READY_TO_PAUSED:
893 case GST_STATE_CHANGE_PAUSED_TO_READY:
895 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
901 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
903 switch (transition) {
904 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
906 case GST_STATE_CHANGE_PAUSED_TO_READY:
907 GST_VIDEO_SINK_WIDTH (pvrvideosink) = 0;
908 GST_VIDEO_SINK_HEIGHT (pvrvideosink) = 0;
910 case GST_STATE_CHANGE_READY_TO_NULL:
911 gst_pvrvideosink_reset (pvrvideosink);
921 gst_pvrvideosink_get_times (GstBaseSink * bsink, GstBuffer * buf,
922 GstClockTime * start, GstClockTime * end)
924 GstPVRVideoSink *pvrvideosink;
926 pvrvideosink = GST_PVRVIDEOSINK (bsink);
928 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
929 *start = GST_BUFFER_TIMESTAMP (buf);
930 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
931 *end = *start + GST_BUFFER_DURATION (buf);
934 fps_n = GST_VIDEO_INFO_FPS_N (&pvrvideosink->info);
935 fps_d = GST_VIDEO_INFO_FPS_D (&pvrvideosink->info);
937 *end = *start + gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
944 gst_pvrvideosink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
946 GstPVRVideoSink *pvrvideosink = GST_PVRVIDEOSINK (vsink);
949 GST_DEBUG_OBJECT (pvrvideosink, "render buffer: %p", buf);
951 meta = gst_buffer_get_pvr_meta (buf);
953 if (G_UNLIKELY (meta == NULL)) {
954 meta = gst_buffer_add_pvr_meta (buf, GST_ELEMENT_CAST (pvrvideosink));
959 gst_pvrvideosink_blit (pvrvideosink, buf);
965 GST_WARNING_OBJECT (pvrvideosink, "Failed to map incoming buffer");
966 return GST_FLOW_ERROR;
971 gst_pvrvideosink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
973 GstPVRVideoSink *pvrvideosink = (GstPVRVideoSink *) bsink;
975 GstStructure *config;
980 gst_query_parse_allocation (query, &caps, &need_pool);
985 g_mutex_lock (pvrvideosink->flow_lock);
986 if ((pool = pvrvideosink->pool))
987 gst_object_ref (pool);
988 g_mutex_unlock (pvrvideosink->flow_lock);
991 const GstCaps *pcaps;
993 /* we had a pool, check caps */
994 GST_DEBUG_OBJECT (pvrvideosink, "check existing pool caps");
995 config = gst_buffer_pool_get_config (pool);
996 gst_buffer_pool_config_get (config, &pcaps, &size, NULL, NULL, NULL, NULL);
998 if (!gst_caps_is_equal (caps, pcaps)) {
999 GST_DEBUG_OBJECT (pvrvideosink, "pool has different caps");
1000 /* different caps, we can't use this pool */
1001 gst_object_unref (pool);
1006 if (pool == NULL && need_pool) {
1009 GST_DEBUG_OBJECT (pvrvideosink, "create new pool");
1010 pool = gst_pvr_buffer_pool_new (GST_ELEMENT_CAST (pvrvideosink));
1012 if (!gst_video_info_from_caps (&info, caps))
1015 /* the normal size of a frame */
1018 config = gst_buffer_pool_get_config (pool);
1019 gst_buffer_pool_config_set (config, caps, size, 0, 0, 0, 0);
1020 if (!gst_buffer_pool_set_config (pool, config))
1023 /* we need at least 3 buffers */
1024 gst_query_set_allocation_params (query, size, 3, 0, 0, 0, pool);
1026 /* we also support various metadata */
1027 gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API, NULL);
1029 gst_object_unref (pool);
1036 GST_DEBUG_OBJECT (bsink, "no caps specified");
1041 GST_DEBUG_OBJECT (bsink, "invalid caps specified");
1046 GST_DEBUG_OBJECT (bsink, "failed setting config");
1051 /* Interfaces stuff */
1053 /* This function destroys a GstXWindow */
1055 gst_pvrvideosink_xwindow_destroy (GstPVRVideoSink * pvrvideosink,
1056 GstXWindow * xwindow)
1058 g_return_if_fail (xwindow != NULL);
1060 g_mutex_lock (pvrvideosink->dcontext->x_lock);
1062 /* If we did not create that window we just free the GC and let it live */
1063 if (xwindow->internal)
1064 XDestroyWindow (pvrvideosink->dcontext->x_display, xwindow->window);
1066 XSelectInput (pvrvideosink->dcontext->x_display, xwindow->window, 0);
1068 XFreeGC (pvrvideosink->dcontext->x_display, xwindow->gc);
1070 XSync (pvrvideosink->dcontext->x_display, FALSE);
1072 g_mutex_unlock (pvrvideosink->dcontext->x_lock);
1078 gst_pvrvideosink_set_window_handle (GstVideoOverlay * overlay, guintptr id)
1080 XID window_handle = id;
1081 GstPVRVideoSink *pvrvideosink = GST_PVRVIDEOSINK (overlay);
1082 GstXWindow *xwindow = NULL;
1084 g_return_if_fail (GST_IS_PVRVIDEOSINK (pvrvideosink));
1086 g_mutex_lock (pvrvideosink->flow_lock);
1088 /* If we already use that window return */
1089 if (pvrvideosink->xwindow && (window_handle == pvrvideosink->xwindow->window)) {
1090 g_mutex_unlock (pvrvideosink->flow_lock);
1094 /* If the element has not initialized the X11 context try to do so */
1095 if (!pvrvideosink->dcontext && !(pvrvideosink->dcontext =
1096 gst_pvrvideosink_get_dcontext (pvrvideosink))) {
1097 g_mutex_unlock (pvrvideosink->flow_lock);
1098 /* we have thrown a GST_ELEMENT_ERROR now */
1102 /* If a window is there already we destroy it */
1103 if (pvrvideosink->xwindow) {
1104 gst_pvrvideosink_xwindow_destroy (pvrvideosink, pvrvideosink->xwindow);
1105 pvrvideosink->xwindow = NULL;
1108 /* If the xid is 0 we will create an internal one in buffer_alloc */
1109 if (window_handle != 0) {
1110 XWindowAttributes attr;
1112 WSEGLDrawableParams source_params;
1113 PVRSRV_CLIENT_MEM_INFO *client_mem_info;
1115 xwindow = g_new0 (GstXWindow, 1);
1116 xwindow->window = window_handle;
1118 /* Set the event we want to receive and create a GC */
1119 g_mutex_lock (pvrvideosink->dcontext->x_lock);
1121 XGetWindowAttributes (pvrvideosink->dcontext->x_display, xwindow->window,
1124 xwindow->width = attr.width;
1125 xwindow->height = attr.height;
1126 xwindow->internal = FALSE;
1127 if (!pvrvideosink->have_render_rect) {
1128 pvrvideosink->render_rect.x = pvrvideosink->render_rect.y = 0;
1129 pvrvideosink->render_rect.w = attr.width;
1130 pvrvideosink->render_rect.h = attr.height;
1132 XSelectInput (pvrvideosink->dcontext->x_display, xwindow->window,
1133 ExposureMask | StructureNotifyMask);
1135 XSetWindowBackgroundPixmap (pvrvideosink->dcontext->x_display,
1136 xwindow->window, None);
1138 XMapWindow (pvrvideosink->dcontext->x_display, xwindow->window);
1139 xwindow->gc = XCreateGC (pvrvideosink->dcontext->x_display,
1140 xwindow->window, 0, NULL);
1141 g_mutex_unlock (pvrvideosink->dcontext->x_lock);
1144 pvrvideosink->dcontext->wsegl_table->
1145 pfnWSEGL_CreateWindowDrawable (pvrvideosink->dcontext->display_handle,
1146 pvrvideosink->dcontext->glconfig,
1147 &(pvrvideosink->dcontext->drawable_handle),
1148 (NativeWindowType) xwindow->window,
1149 &(pvrvideosink->dcontext->rotation));
1151 if (glerror != WSEGL_SUCCESS) {
1152 GST_ERROR_OBJECT (pvrvideosink, "Error creating drawable");
1156 pvrvideosink->dcontext->wsegl_table->
1157 pfnWSEGL_GetDrawableParameters (pvrvideosink->dcontext->drawable_handle,
1158 &source_params, &pvrvideosink->render_params);
1161 (PVRSRV_CLIENT_MEM_INFO *) pvrvideosink->render_params.hPrivateData;
1162 PVR2DMEMINFO_INITIALISE (&pvrvideosink->dcontext->dst_mem, client_mem_info);
1166 pvrvideosink->xwindow = xwindow;
1168 g_mutex_unlock (pvrvideosink->flow_lock);
1172 gst_pvrvideosink_expose (GstVideoOverlay * overlay)
1174 GstPVRVideoSink *pvrvideosink = GST_PVRVIDEOSINK (overlay);
1176 gst_pvrvideosink_blit (pvrvideosink, NULL);
1180 gst_pvrvideosink_set_event_handling (GstVideoOverlay * overlay,
1181 gboolean handle_events)
1183 GstPVRVideoSink *pvrvideosink = GST_PVRVIDEOSINK (overlay);
1185 g_mutex_lock (pvrvideosink->flow_lock);
1187 if (G_UNLIKELY (!pvrvideosink->xwindow)) {
1188 g_mutex_unlock (pvrvideosink->flow_lock);
1192 g_mutex_lock (pvrvideosink->dcontext->x_lock);
1194 XSelectInput (pvrvideosink->dcontext->x_display,
1195 pvrvideosink->xwindow->window, ExposureMask | StructureNotifyMask);
1197 g_mutex_unlock (pvrvideosink->dcontext->x_lock);
1199 g_mutex_unlock (pvrvideosink->flow_lock);
1203 gst_pvrvideosink_set_render_rectangle (GstVideoOverlay * overlay, gint x,
1204 gint y, gint width, gint height)
1206 GstPVRVideoSink *pvrvideosink = GST_PVRVIDEOSINK (overlay);
1208 /* FIXME: how about some locking? */
1209 if (width >= 0 && height >= 0) {
1210 pvrvideosink->render_rect.x = x;
1211 pvrvideosink->render_rect.y = y;
1212 pvrvideosink->render_rect.w = width;
1213 pvrvideosink->render_rect.h = height;
1214 pvrvideosink->have_render_rect = TRUE;
1216 pvrvideosink->render_rect.x = 0;
1217 pvrvideosink->render_rect.y = 0;
1218 pvrvideosink->render_rect.w = pvrvideosink->xwindow->width;
1219 pvrvideosink->render_rect.h = pvrvideosink->xwindow->height;
1220 pvrvideosink->have_render_rect = FALSE;
1225 gst_pvrvideosink_videooverlay_init (GstVideoOverlayInterface * iface)
1227 iface->set_window_handle = gst_pvrvideosink_set_window_handle;
1228 iface->expose = gst_pvrvideosink_expose;
1229 iface->handle_events = gst_pvrvideosink_set_event_handling;
1230 iface->set_render_rectangle = gst_pvrvideosink_set_render_rectangle;
1233 /* =========================================== */
1235 /* Init & Class init */
1237 /* =========================================== */
1240 gst_pvrvideosink_set_property (GObject * object, guint prop_id,
1241 const GValue * value, GParamSpec * pspec)
1243 GstPVRVideoSink *pvrvideosink;
1245 g_return_if_fail (GST_IS_PVRVIDEOSINK (object));
1247 pvrvideosink = GST_PVRVIDEOSINK (object);
1250 case PROP_FORCE_ASPECT_RATIO:
1251 pvrvideosink->keep_aspect = g_value_get_boolean (value);
1254 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1260 gst_pvrvideosink_get_property (GObject * object, guint prop_id,
1261 GValue * value, GParamSpec * pspec)
1263 GstPVRVideoSink *pvrvideosink;
1265 g_return_if_fail (GST_IS_PVRVIDEOSINK (object));
1267 pvrvideosink = GST_PVRVIDEOSINK (object);
1270 case PROP_FORCE_ASPECT_RATIO:
1271 g_value_set_boolean (value, pvrvideosink->keep_aspect);
1274 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1280 gst_pvrvideosink_track_buffer (GstPVRVideoSink * pvrsink, GstBuffer * buffer)
1282 GST_DEBUG_OBJECT (pvrsink, "Adding buffer %p to tracked buffers", buffer);
1283 pvrsink->metabuffers = g_list_prepend (pvrsink->metabuffers, buffer);
1287 gst_pvrvideosink_untrack_buffer (GstPVRVideoSink * pvrsink, GstBuffer * buffer)
1289 GST_DEBUG_OBJECT (pvrsink, "Removing buffer %p from tracked buffers", buffer);
1290 pvrsink->metabuffers = g_list_remove_all (pvrsink->metabuffers, buffer);
1294 gst_pvrvideosink_release_pvr_metas (GstPVRVideoSink * pvrsink)
1297 GstPVRMeta *pvrmeta;
1299 GST_DEBUG_OBJECT (pvrsink, "Releasing pending PVR metas");
1301 while (pvrsink->metabuffers) {
1302 buf = (GstBuffer *) pvrsink->metabuffers->data;
1304 pvrmeta = gst_buffer_get_pvr_meta (buf);
1306 gst_buffer_remove_meta (buf, (GstMeta *) pvrmeta);
1309 GST_DEBUG_OBJECT (pvrsink, "Done");
1313 gst_pvrvideosink_dcontext_free (GstDrawContext * dcontext)
1315 GST_DEBUG ("Freeing dcontext %p", dcontext);
1317 if (dcontext->p_blt_info)
1318 g_free (dcontext->p_blt_info);
1320 if (dcontext->p_blt2d_info)
1321 g_free (dcontext->p_blt2d_info);
1323 if (dcontext->x_lock)
1324 g_mutex_lock (dcontext->x_lock);
1325 if (dcontext->x_display) {
1326 GST_LOG ("Closing display");
1327 XCloseDisplay (dcontext->x_display);
1329 if (dcontext->x_lock) {
1330 g_mutex_unlock (dcontext->x_lock);
1331 g_mutex_free (dcontext->x_lock);
1338 gst_pvrvideosink_dcontext_clear (GstPVRVideoSink * pvrvideosink)
1340 GstDrawContext *dcontext;
1342 GST_DEBUG_OBJECT (pvrvideosink, "Clearing dcontext %p",
1343 pvrvideosink->dcontext);
1345 GST_OBJECT_LOCK (pvrvideosink);
1346 if (!pvrvideosink->dcontext) {
1347 GST_OBJECT_UNLOCK (pvrvideosink);
1351 dcontext = pvrvideosink->dcontext;
1352 pvrvideosink->dcontext = NULL;
1353 GST_OBJECT_UNLOCK (pvrvideosink);
1355 gst_pvrvideosink_dcontext_free (dcontext);
1359 gst_pvrvideosink_reset (GstPVRVideoSink * pvrvideosink)
1363 GST_DEBUG_OBJECT (pvrvideosink, "Resetting");
1365 GST_OBJECT_LOCK (pvrvideosink);
1366 pvrvideosink->running = FALSE;
1367 thread = pvrvideosink->event_thread;
1368 pvrvideosink->event_thread = NULL;
1369 GST_OBJECT_UNLOCK (pvrvideosink);
1372 g_thread_join (thread);
1374 if (pvrvideosink->current_buffer) {
1375 GST_LOG_OBJECT (pvrvideosink, "Removing cached buffer");
1376 gst_buffer_unref (pvrvideosink->current_buffer);
1377 pvrvideosink->current_buffer = NULL;
1380 if (pvrvideosink->pool) {
1381 GST_LOG_OBJECT (pvrvideosink, "Unreffing pool");
1382 gst_object_unref (pvrvideosink->pool);
1383 pvrvideosink->pool = NULL;
1385 memset (&pvrvideosink->render_params, 0, sizeof (WSEGLDrawableParams));
1387 pvrvideosink->render_rect.x = pvrvideosink->render_rect.y = 0;
1388 pvrvideosink->render_rect.w = pvrvideosink->render_rect.h = 0;
1389 pvrvideosink->have_render_rect = FALSE;
1391 gst_pvrvideosink_release_pvr_metas (pvrvideosink);
1393 gst_pvrvideosink_destroy_drawable (pvrvideosink);
1395 if (pvrvideosink->xwindow) {
1396 gst_pvrvideosink_xwindow_destroy (pvrvideosink, pvrvideosink->xwindow);
1397 pvrvideosink->xwindow = NULL;
1400 gst_pvrvideosink_dcontext_clear (pvrvideosink);
1404 gst_pvrvideosink_finalize (GObject * object)
1406 GstPVRVideoSink *pvrvideosink;
1408 pvrvideosink = GST_PVRVIDEOSINK (object);
1410 gst_pvrvideosink_reset (pvrvideosink);
1412 if (pvrvideosink->flow_lock) {
1413 g_mutex_free (pvrvideosink->flow_lock);
1414 pvrvideosink->flow_lock = NULL;
1417 G_OBJECT_CLASS (parent_class)->finalize (object);
1421 gst_pvrvideosink_init (GstPVRVideoSink * pvrvideosink)
1423 pvrvideosink->running = FALSE;
1425 pvrvideosink->flow_lock = g_mutex_new ();
1426 pvrvideosink->pool = NULL;
1428 pvrvideosink->keep_aspect = FALSE;
1429 pvrvideosink->current_caps = NULL;
1430 pvrvideosink->dcontext = NULL;
1431 pvrvideosink->xwindow = NULL;
1432 pvrvideosink->redraw_borders = TRUE;
1433 pvrvideosink->current_buffer = NULL;
1434 pvrvideosink->event_thread = NULL;
1435 memset (&pvrvideosink->render_params, 0, sizeof (WSEGLDrawableParams));
1439 gst_pvrvideosink_class_init (GstPVRVideoSinkClass * klass)
1441 GObjectClass *gobject_class;
1442 GstElementClass *gstelement_class;
1443 GstBaseSinkClass *gstbasesink_class;
1444 GstVideoSinkClass *videosink_class;
1446 gobject_class = (GObjectClass *) klass;
1447 gstelement_class = (GstElementClass *) klass;
1448 gstbasesink_class = (GstBaseSinkClass *) klass;
1449 videosink_class = (GstVideoSinkClass *) klass;
1451 parent_class = g_type_class_peek_parent (klass);
1453 gobject_class->finalize = gst_pvrvideosink_finalize;
1454 gobject_class->set_property = gst_pvrvideosink_set_property;
1455 gobject_class->get_property = gst_pvrvideosink_get_property;
1457 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
1458 g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
1459 "When enabled, reverse caps negotiation (scaling) will respect "
1460 "original aspect ratio", TRUE,
1461 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1463 gst_element_class_set_details_simple (gstelement_class,
1464 "PVR Video sink", "Sink/Video",
1466 "Luciana Fujii Pontello <luciana.fujii@collabora.co.uk");
1468 gst_element_class_add_pad_template (gstelement_class,
1469 gst_static_pad_template_get (&gst_pvrvideosink_sink_template_factory));
1471 gstelement_class->change_state = gst_pvrvideosink_change_state;
1473 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_pvrvideosink_setcaps);
1474 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_pvrvideosink_getcaps);
1475 gstbasesink_class->propose_allocation =
1476 GST_DEBUG_FUNCPTR (gst_pvrvideosink_propose_allocation);
1477 gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_pvrvideosink_get_times);
1479 videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_pvrvideosink_show_frame);