~ubuntu-branches/ubuntu/quantal/gstreamer-vaapi/quantal

« back to all changes in this revision

Viewing changes to gst/vaapi/gstvaapisink.c

  • Committer: Package Import Robot
  • Author(s): Timo Aaltonen
  • Date: 2012-02-10 14:35:09 UTC
  • Revision ID: package-import@ubuntu.com-20120210143509-wq9j8uqb5leu1iik
Tags: upstream-0.3.4
ImportĀ upstreamĀ versionĀ 0.3.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  gstvaapisink.c - VA-API video sink
 
3
 *
 
4
 *  Copyright (C) 2010-2011 Splitted-Desktop Systems
 
5
 *  Copyright (C) 2011-2012 Intel Corporation
 
6
 *
 
7
 *  This library is free software; you can redistribute it and/or
 
8
 *  modify it under the terms of the GNU Lesser General Public License
 
9
 *  as published by the Free Software Foundation; either version 2.1
 
10
 *  of the License, or (at your option) any later version.
 
11
 *
 
12
 *  This library is distributed in the hope that it will be useful,
 
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 *  Lesser General Public License for more details.
 
16
 *
 
17
 *  You should have received a copy of the GNU Lesser General Public
 
18
 *  License along with this library; if not, write to the Free
 
19
 *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
20
 *  Boston, MA 02110-1301 USA
 
21
 */
 
22
 
 
23
/**
 
24
 * SECTION:gstvaapisink
 
25
 * @short_description: A VA-API based videosink
 
26
 *
 
27
 * vaapisink renders video frames to a drawable (X #Window) on a local
 
28
 * display using the Video Acceleration (VA) API. The element will
 
29
 * create its own internal window and render into it.
 
30
 */
 
31
 
 
32
#include "config.h"
 
33
#include <gst/gst.h>
 
34
#include <gst/gstutils_version.h>
 
35
#include <gst/video/video.h>
 
36
#include <gst/video/videocontext.h>
 
37
#include <gst/vaapi/gstvaapivideobuffer.h>
 
38
#include <gst/vaapi/gstvaapivideosink.h>
 
39
#include <gst/vaapi/gstvaapidisplay_x11.h>
 
40
#include <gst/vaapi/gstvaapiwindow_x11.h>
 
41
#if USE_VAAPISINK_GLX
 
42
#include <gst/vaapi/gstvaapidisplay_glx.h>
 
43
#include <gst/vaapi/gstvaapiwindow_glx.h>
 
44
#endif
 
45
 
 
46
/* Supported interfaces */
 
47
#include <gst/interfaces/xoverlay.h>
 
48
 
 
49
#include "gstvaapisink.h"
 
50
#include "gstvaapipluginutil.h"
 
51
 
 
52
#define HAVE_GST_XOVERLAY_SET_WINDOW_HANDLE \
 
53
    GST_PLUGINS_BASE_CHECK_VERSION(0,10,31)
 
54
 
 
55
#define HAVE_GST_XOVERLAY_SET_RENDER_RECTANGLE \
 
56
    GST_PLUGINS_BASE_CHECK_VERSION(0,10,29)
 
57
 
 
58
#define GST_PLUGIN_NAME "vaapisink"
 
59
#define GST_PLUGIN_DESC "A VA-API based videosink"
 
60
 
 
61
GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapisink);
 
62
#define GST_CAT_DEFAULT gst_debug_vaapisink
 
63
 
 
64
/* ElementFactory information */
 
65
static const GstElementDetails gst_vaapisink_details =
 
66
    GST_ELEMENT_DETAILS(
 
67
        "VA-API sink",
 
68
        "Sink/Video",
 
69
        GST_PLUGIN_DESC,
 
70
        "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
 
71
 
 
72
/* Default template */
 
73
static GstStaticPadTemplate gst_vaapisink_sink_factory =
 
74
    GST_STATIC_PAD_TEMPLATE(
 
75
        "sink",
 
76
        GST_PAD_SINK,
 
77
        GST_PAD_ALWAYS,
 
78
        GST_STATIC_CAPS(GST_VAAPI_SURFACE_CAPS));
 
79
 
 
80
static void gst_vaapisink_iface_init(GType type);
 
81
 
 
82
GST_BOILERPLATE_FULL(
 
83
    GstVaapiSink,
 
84
    gst_vaapisink,
 
85
    GstVideoSink,
 
86
    GST_TYPE_VIDEO_SINK,
 
87
    gst_vaapisink_iface_init);
 
88
 
 
89
enum {
 
90
    PROP_0,
 
91
 
 
92
    PROP_USE_GLX,
 
93
    PROP_FULLSCREEN,
 
94
    PROP_SYNCHRONOUS,
 
95
    PROP_USE_REFLECTION
 
96
};
 
97
 
 
98
/* GstImplementsInterface interface */
 
99
 
 
100
static gboolean
 
101
gst_vaapisink_implements_interface_supported(
 
102
    GstImplementsInterface *iface,
 
103
    GType                   type
 
104
)
 
105
{
 
106
    return (type == GST_TYPE_VIDEO_CONTEXT ||
 
107
            type == GST_TYPE_X_OVERLAY);
 
108
}
 
109
 
 
110
static void
 
111
gst_vaapisink_implements_iface_init(GstImplementsInterfaceClass *iface)
 
112
{
 
113
    iface->supported = gst_vaapisink_implements_interface_supported;
 
114
}
 
115
 
 
116
/* GstVaapiVideoSink interface */
 
117
 
 
118
static void
 
119
gst_vaapisink_set_video_context(GstVideoContext *context, const gchar *type,
 
120
    const GValue *value)
 
121
{
 
122
  GstVaapiSink *sink = GST_VAAPISINK (context);
 
123
  gst_vaapi_set_display (type, value, &sink->display);
 
124
}
 
125
 
 
126
static void
 
127
gst_vaapisink_video_context_iface_init(GstVideoContextInterface *iface)
 
128
{
 
129
    iface->set_context = gst_vaapisink_set_video_context;
 
130
}
 
131
 
 
132
/* GstXOverlay interface */
 
133
 
 
134
static gboolean
 
135
gst_vaapisink_ensure_window_xid(GstVaapiSink *sink, guintptr window_id);
 
136
 
 
137
static GstFlowReturn
 
138
gst_vaapisink_show_frame(GstBaseSink *base_sink, GstBuffer *buffer);
 
139
 
 
140
static inline void
 
141
_gst_vaapisink_xoverlay_set_xid(GstXOverlay *overlay, guintptr window_id)
 
142
{
 
143
    GstVaapiSink * const sink = GST_VAAPISINK(overlay);
 
144
 
 
145
    /* Disable GLX rendering when vaapisink is using a foreign X
 
146
       window. It's pretty much useless */
 
147
    sink->use_glx = FALSE;
 
148
 
 
149
    sink->foreign_window = TRUE;
 
150
    gst_vaapisink_ensure_window_xid(sink, window_id);
 
151
}
 
152
 
 
153
#if HAVE_GST_XOVERLAY_SET_WINDOW_HANDLE
 
154
static void
 
155
gst_vaapisink_xoverlay_set_window_handle(GstXOverlay *overlay, guintptr window_id)
 
156
{
 
157
    _gst_vaapisink_xoverlay_set_xid(overlay, window_id);
 
158
}
 
159
#else
 
160
static void
 
161
gst_vaapisink_xoverlay_set_xid(GstXOverlay *overlay, XID xid)
 
162
{
 
163
    _gst_vaapisink_xoverlay_set_xid(overlay, xid);
 
164
}
 
165
#endif
 
166
 
 
167
#if HAVE_GST_XOVERLAY_SET_RENDER_RECTANGLE
 
168
static void
 
169
gst_vaapisink_xoverlay_set_render_rectangle(
 
170
    GstXOverlay *overlay,
 
171
    gint         x,
 
172
    gint         y,
 
173
    gint         width,
 
174
    gint         height
 
175
)
 
176
{
 
177
    GstVaapiSink * const sink = GST_VAAPISINK(overlay);
 
178
    GstVaapiRectangle * const display_rect = &sink->display_rect;
 
179
 
 
180
    display_rect->x      = x;
 
181
    display_rect->y      = y;
 
182
    display_rect->width  = width;
 
183
    display_rect->height = height;
 
184
    
 
185
    GST_DEBUG("render rect (%d,%d):%ux%u",
 
186
              display_rect->x, display_rect->y,
 
187
              display_rect->width, display_rect->height);
 
188
}
 
189
#endif
 
190
 
 
191
static void
 
192
gst_vaapisink_xoverlay_expose(GstXOverlay *overlay)
 
193
{
 
194
    GstBaseSink * const base_sink = GST_BASE_SINK(overlay);
 
195
    GstBuffer *buffer;
 
196
 
 
197
    buffer = gst_base_sink_get_last_buffer(base_sink);
 
198
    if (buffer) {
 
199
        gst_vaapisink_show_frame(base_sink, buffer);
 
200
        gst_buffer_unref(buffer);
 
201
    }
 
202
}
 
203
 
 
204
static void
 
205
gst_vaapisink_xoverlay_iface_init(GstXOverlayClass *iface)
 
206
{
 
207
#if HAVE_GST_XOVERLAY_SET_WINDOW_HANDLE
 
208
    iface->set_window_handle    = gst_vaapisink_xoverlay_set_window_handle;
 
209
#else
 
210
    iface->set_xwindow_id       = gst_vaapisink_xoverlay_set_xid;
 
211
#endif
 
212
#if HAVE_GST_XOVERLAY_SET_RENDER_RECTANGLE
 
213
    iface->set_render_rectangle = gst_vaapisink_xoverlay_set_render_rectangle;
 
214
#endif
 
215
    iface->expose               = gst_vaapisink_xoverlay_expose;
 
216
}
 
217
 
 
218
static void
 
219
gst_vaapisink_iface_init(GType type)
 
220
{
 
221
    const GType g_define_type_id = type;
 
222
 
 
223
    G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
 
224
                          gst_vaapisink_implements_iface_init);
 
225
    G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
 
226
                          gst_vaapisink_video_context_iface_init);
 
227
    G_IMPLEMENT_INTERFACE(GST_TYPE_X_OVERLAY,
 
228
                          gst_vaapisink_xoverlay_iface_init);
 
229
}
 
230
 
 
231
static void
 
232
gst_vaapisink_destroy(GstVaapiSink *sink)
 
233
{
 
234
    if (sink->texture) {
 
235
        g_object_unref(sink->texture);
 
236
        sink->texture = NULL;
 
237
    }
 
238
 
 
239
    if (sink->display) {
 
240
        g_object_unref(sink->display);
 
241
        sink->display = NULL;
 
242
    }
 
243
}
 
244
 
 
245
/* Checks whether a ConfigureNotify event is in the queue */
 
246
typedef struct _ConfigureNotifyEventPendingArgs ConfigureNotifyEventPendingArgs;
 
247
struct _ConfigureNotifyEventPendingArgs {
 
248
    Window      window;
 
249
    guint       width;
 
250
    guint       height;
 
251
    gboolean    match;
 
252
};
 
253
 
 
254
static Bool
 
255
configure_notify_event_pending_cb(Display *dpy, XEvent *xev, XPointer arg)
 
256
{
 
257
    ConfigureNotifyEventPendingArgs * const args =
 
258
        (ConfigureNotifyEventPendingArgs *)arg;
 
259
 
 
260
    if (xev->type == ConfigureNotify &&
 
261
        xev->xconfigure.window == args->window &&
 
262
        xev->xconfigure.width  == args->width  &&
 
263
        xev->xconfigure.height == args->height)
 
264
        args->match = TRUE;
 
265
 
 
266
    /* XXX: this is a hack to traverse the whole queue because we
 
267
       can't use XPeekIfEvent() since it could block */
 
268
    return False;
 
269
}
 
270
 
 
271
static gboolean
 
272
configure_notify_event_pending(
 
273
    GstVaapiSink *sink,
 
274
    Window        window,
 
275
    guint         width,
 
276
    guint         height
 
277
)
 
278
{
 
279
    ConfigureNotifyEventPendingArgs args;
 
280
    XEvent xev;
 
281
 
 
282
    args.window = window;
 
283
    args.width  = width;
 
284
    args.height = height;
 
285
    args.match  = FALSE;
 
286
 
 
287
    /* XXX: don't use XPeekIfEvent() because it might block */
 
288
    XCheckIfEvent(
 
289
        gst_vaapi_display_x11_get_display(GST_VAAPI_DISPLAY_X11(sink->display)),
 
290
        &xev,
 
291
        configure_notify_event_pending_cb, (XPointer)&args
 
292
    );
 
293
    return args.match;
 
294
}
 
295
 
 
296
static gboolean
 
297
gst_vaapisink_ensure_render_rect(GstVaapiSink *sink, guint width, guint height)
 
298
{
 
299
    GstVaapiRectangle * const display_rect = &sink->display_rect;
 
300
    guint num, den, display_par_n, display_par_d;
 
301
    gboolean success;
 
302
 
 
303
    GST_DEBUG("ensure render rect within %ux%u bounds", width, height);
 
304
 
 
305
    gst_vaapi_display_get_pixel_aspect_ratio(
 
306
        sink->display,
 
307
        &display_par_n, &display_par_d
 
308
    );
 
309
    GST_DEBUG("display pixel-aspect-ratio %d/%d",
 
310
              display_par_n, display_par_d);
 
311
 
 
312
    success = gst_video_calculate_display_ratio(
 
313
        &num, &den,
 
314
        sink->video_width, sink->video_height,
 
315
        sink->video_par_n, sink->video_par_d,
 
316
        display_par_n, display_par_d
 
317
    );
 
318
    if (!success)
 
319
        return FALSE;
 
320
    GST_DEBUG("video size %dx%d, calculated ratio %d/%d",
 
321
              sink->video_width, sink->video_height, num, den);
 
322
 
 
323
    display_rect->width = gst_util_uint64_scale_int(height, num, den);
 
324
    if (display_rect->width <= width) {
 
325
        GST_DEBUG("keeping window height");
 
326
        display_rect->height = height;
 
327
    }
 
328
    else {
 
329
        GST_DEBUG("keeping window width");
 
330
        display_rect->width  = width;
 
331
        display_rect->height =
 
332
            gst_util_uint64_scale_int(width, den, num);
 
333
    }
 
334
    GST_DEBUG("scaling video to %ux%u", display_rect->width, display_rect->height);
 
335
 
 
336
    g_assert(display_rect->width  <= width);
 
337
    g_assert(display_rect->height <= height);
 
338
 
 
339
    display_rect->x = (width  - display_rect->width)  / 2;
 
340
    display_rect->y = (height - display_rect->height) / 2;
 
341
 
 
342
    GST_DEBUG("render rect (%d,%d):%ux%u",
 
343
              display_rect->x, display_rect->y,
 
344
              display_rect->width, display_rect->height);
 
345
    return TRUE;
 
346
}
 
347
 
 
348
static inline gboolean
 
349
gst_vaapisink_ensure_window(GstVaapiSink *sink, guint width, guint height)
 
350
{
 
351
    GstVaapiDisplay * const display = sink->display;
 
352
 
 
353
    if (!sink->window) {
 
354
#if USE_VAAPISINK_GLX
 
355
        if (sink->use_glx)
 
356
            sink->window = gst_vaapi_window_glx_new(display, width, height);
 
357
        else
 
358
#endif
 
359
            sink->window = gst_vaapi_window_x11_new(display, width, height);
 
360
        if (sink->window)
 
361
            gst_x_overlay_got_xwindow_id(
 
362
                GST_X_OVERLAY(sink),
 
363
                gst_vaapi_window_x11_get_xid(GST_VAAPI_WINDOW_X11(sink->window))
 
364
            );
 
365
    }
 
366
    return sink->window != NULL;
 
367
}
 
368
 
 
369
static gboolean
 
370
gst_vaapisink_ensure_window_xid(GstVaapiSink *sink, guintptr window_id)
 
371
{
 
372
    Window rootwin;
 
373
    unsigned int width, height, border_width, depth;
 
374
    int x, y;
 
375
    XID xid = window_id;
 
376
 
 
377
    if (!gst_vaapi_ensure_display(sink, &sink->display))
 
378
        return FALSE;
 
379
 
 
380
    gst_vaapi_display_lock(sink->display);
 
381
    XGetGeometry(
 
382
        gst_vaapi_display_x11_get_display(GST_VAAPI_DISPLAY_X11(sink->display)),
 
383
        xid,
 
384
        &rootwin,
 
385
        &x, &y, &width, &height, &border_width, &depth
 
386
    );
 
387
    gst_vaapi_display_unlock(sink->display);
 
388
 
 
389
    if ((width != sink->window_width || height != sink->window_height) &&
 
390
        !configure_notify_event_pending(sink, xid, width, height)) {
 
391
        if (!gst_vaapisink_ensure_render_rect(sink, width, height))
 
392
            return FALSE;
 
393
        sink->window_width  = width;
 
394
        sink->window_height = height;
 
395
    }
 
396
 
 
397
    if (sink->window &&
 
398
        gst_vaapi_window_x11_get_xid(GST_VAAPI_WINDOW_X11(sink->window)) == xid)
 
399
        return TRUE;
 
400
 
 
401
    if (sink->window) {
 
402
        g_object_unref(sink->window);
 
403
        sink->window = NULL;
 
404
    }
 
405
 
 
406
#if USE_VAAPISINK_GLX
 
407
    if (sink->use_glx)
 
408
        sink->window = gst_vaapi_window_glx_new_with_xid(sink->display, xid);
 
409
    else
 
410
#endif
 
411
        sink->window = gst_vaapi_window_x11_new_with_xid(sink->display, xid);
 
412
    return sink->window != NULL;
 
413
}
 
414
 
 
415
static gboolean
 
416
gst_vaapisink_start(GstBaseSink *base_sink)
 
417
{
 
418
    GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
 
419
 
 
420
    return gst_vaapi_ensure_display(sink, &sink->display);
 
421
}
 
422
 
 
423
static gboolean
 
424
gst_vaapisink_stop(GstBaseSink *base_sink)
 
425
{
 
426
    GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
 
427
 
 
428
    if (sink->window) {
 
429
        g_object_unref(sink->window);
 
430
        sink->window = NULL;
 
431
    }
 
432
 
 
433
    if (sink->display) {
 
434
        g_object_unref(sink->display);
 
435
        sink->display = NULL;
 
436
    }
 
437
    return TRUE;
 
438
}
 
439
 
 
440
static gboolean
 
441
gst_vaapisink_set_caps(GstBaseSink *base_sink, GstCaps *caps)
 
442
{
 
443
    GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
 
444
    GstStructure * const structure = gst_caps_get_structure(caps, 0);
 
445
    guint win_width, win_height, display_width, display_height;
 
446
    gint video_width, video_height, video_par_n = 1, video_par_d = 1;
 
447
 
 
448
    if (!structure)
 
449
        return FALSE;
 
450
    if (!gst_structure_get_int(structure, "width",  &video_width))
 
451
        return FALSE;
 
452
    if (!gst_structure_get_int(structure, "height", &video_height))
 
453
        return FALSE;
 
454
    sink->video_width  = video_width;
 
455
    sink->video_height = video_height;
 
456
 
 
457
    gst_video_parse_caps_pixel_aspect_ratio(caps, &video_par_n, &video_par_d);
 
458
    sink->video_par_n  = video_par_n;
 
459
    sink->video_par_d  = video_par_d;
 
460
    GST_DEBUG("video pixel-aspect-ratio %d/%d", video_par_n, video_par_d);
 
461
 
 
462
    if (!gst_vaapi_ensure_display(sink, &sink->display))
 
463
        return FALSE;
 
464
 
 
465
    gst_vaapi_display_get_size(sink->display, &display_width, &display_height);
 
466
    if (sink->fullscreen ||
 
467
        video_width > display_width || video_height > display_height) {
 
468
        win_width  = display_width;
 
469
        win_height = display_height;
 
470
    }
 
471
    else {
 
472
        win_width  = video_width;
 
473
        win_height = video_height;
 
474
    }
 
475
 
 
476
    if (sink->window)
 
477
        gst_vaapi_window_set_size(sink->window, win_width, win_height);
 
478
    else {
 
479
        gst_vaapi_display_lock(sink->display);
 
480
        gst_x_overlay_prepare_xwindow_id(GST_X_OVERLAY(sink));
 
481
        gst_vaapi_display_unlock(sink->display);
 
482
        if (sink->window)
 
483
            return TRUE;
 
484
        if (!gst_vaapisink_ensure_window(sink, win_width, win_height))
 
485
            return FALSE;
 
486
        gst_vaapi_window_set_fullscreen(sink->window, sink->fullscreen);
 
487
        gst_vaapi_window_show(sink->window);
 
488
        gst_vaapi_window_get_size(sink->window, &win_width, &win_height);
 
489
    }
 
490
    sink->window_width  = win_width;
 
491
    sink->window_height = win_height;
 
492
    GST_DEBUG("window size %ux%u", win_width, win_height);
 
493
 
 
494
    return gst_vaapisink_ensure_render_rect(sink, win_width, win_height);
 
495
}
 
496
 
 
497
#if USE_VAAPISINK_GLX
 
498
static void
 
499
render_background(GstVaapiSink *sink)
 
500
{
 
501
    /* Original code from Mirco Muller (MacSlow):
 
502
       <http://cgit.freedesktop.org/~macslow/gl-gst-player/> */
 
503
    GLfloat fStartX = 0.0f;
 
504
    GLfloat fStartY = 0.0f;
 
505
    GLfloat fWidth  = (GLfloat)sink->window_width;
 
506
    GLfloat fHeight = (GLfloat)sink->window_height;
 
507
 
 
508
    glClear(GL_COLOR_BUFFER_BIT);
 
509
    glBegin(GL_QUADS);
 
510
    {
 
511
        /* top third, darker grey to white */
 
512
        glColor3f(0.85f, 0.85f, 0.85f);
 
513
        glVertex3f(fStartX, fStartY, 0.0f);
 
514
        glColor3f(0.85f, 0.85f, 0.85f);
 
515
        glVertex3f(fStartX + fWidth, fStartY, 0.0f);
 
516
        glColor3f(1.0f, 1.0f, 1.0f);
 
517
        glVertex3f(fStartX + fWidth, fStartY + fHeight / 3.0f, 0.0f);
 
518
        glColor3f(1.0f, 1.0f, 1.0f);
 
519
        glVertex3f(fStartX, fStartY + fHeight / 3.0f, 0.0f);
 
520
 
 
521
        /* middle third, just plain white */
 
522
        glColor3f(1.0f, 1.0f, 1.0f);
 
523
        glVertex3f(fStartX, fStartY + fHeight / 3.0f, 0.0f);
 
524
        glVertex3f(fStartX + fWidth, fStartY + fHeight / 3.0f, 0.0f);
 
525
        glVertex3f(fStartX + fWidth, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
 
526
        glVertex3f(fStartX, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
 
527
 
 
528
        /* bottom third, white to lighter grey */
 
529
        glColor3f(1.0f, 1.0f, 1.0f);
 
530
        glVertex3f(fStartX, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
 
531
        glColor3f(1.0f, 1.0f, 1.0f);
 
532
        glVertex3f(fStartX + fWidth, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
 
533
        glColor3f(0.62f, 0.66f, 0.69f);
 
534
        glVertex3f(fStartX + fWidth, fStartY + fHeight, 0.0f);
 
535
        glColor3f(0.62f, 0.66f, 0.69f);
 
536
        glVertex3f(fStartX, fStartY + fHeight, 0.0f);
 
537
    }
 
538
    glEnd();
 
539
}
 
540
 
 
541
static void
 
542
render_frame(GstVaapiSink *sink)
 
543
{
 
544
    const guint x1 = sink->display_rect.x;
 
545
    const guint x2 = sink->display_rect.x + sink->display_rect.width;
 
546
    const guint y1 = sink->display_rect.y;
 
547
    const guint y2 = sink->display_rect.y + sink->display_rect.height;
 
548
 
 
549
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
 
550
    glBegin(GL_QUADS);
 
551
    {
 
552
        glTexCoord2f(0.0f, 0.0f); glVertex2i(x1, y1);
 
553
        glTexCoord2f(0.0f, 1.0f); glVertex2i(x1, y2);
 
554
        glTexCoord2f(1.0f, 1.0f); glVertex2i(x2, y2);
 
555
        glTexCoord2f(1.0f, 0.0f); glVertex2i(x2, y1);
 
556
    }
 
557
    glEnd();
 
558
}
 
559
 
 
560
static void
 
561
render_reflection(GstVaapiSink *sink)
 
562
{
 
563
    const guint x1 = sink->display_rect.x;
 
564
    const guint x2 = sink->display_rect.x + sink->display_rect.width;
 
565
    const guint y1 = sink->display_rect.y;
 
566
    const guint rh = sink->display_rect.height / 5;
 
567
    GLfloat     ry = 1.0f - (GLfloat)rh / (GLfloat)sink->display_rect.height;
 
568
 
 
569
    glBegin(GL_QUADS);
 
570
    {
 
571
        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
 
572
        glTexCoord2f(0.0f, 1.0f); glVertex2i(x1, y1);
 
573
        glTexCoord2f(1.0f, 1.0f); glVertex2i(x2, y1);
 
574
 
 
575
        glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
 
576
        glTexCoord2f(1.0f, ry); glVertex2i(x2, y1 + rh);
 
577
        glTexCoord2f(0.0f, ry); glVertex2i(x1, y1 + rh);
 
578
    }
 
579
    glEnd();
 
580
}
 
581
 
 
582
static gboolean
 
583
gst_vaapisink_show_frame_glx(
 
584
    GstVaapiSink    *sink,
 
585
    GstVaapiSurface *surface,
 
586
    guint            flags
 
587
)
 
588
{
 
589
    GstVaapiWindowGLX * const window = GST_VAAPI_WINDOW_GLX(sink->window);
 
590
    GLenum target;
 
591
    GLuint texture;
 
592
 
 
593
    gst_vaapi_window_glx_make_current(window);
 
594
    if (!sink->texture) {
 
595
        sink->texture = gst_vaapi_texture_new(
 
596
            sink->display,
 
597
            GL_TEXTURE_2D,
 
598
            GL_BGRA,
 
599
            sink->video_width,
 
600
            sink->video_height
 
601
        );
 
602
        if (!sink->texture)
 
603
            goto error_create_texture;
 
604
    }
 
605
    if (!gst_vaapi_texture_put_surface(sink->texture, surface, flags))
 
606
        goto error_transfer_surface;
 
607
 
 
608
    target  = gst_vaapi_texture_get_target(sink->texture);
 
609
    texture = gst_vaapi_texture_get_id(sink->texture);
 
610
    if (target != GL_TEXTURE_2D || !texture)
 
611
        return FALSE;
 
612
 
 
613
    if (sink->use_reflection)
 
614
        render_background(sink);
 
615
 
 
616
    glEnable(target);
 
617
    glBindTexture(target, texture);
 
618
    {
 
619
        if (sink->use_reflection) {
 
620
            glPushMatrix();
 
621
            glRotatef(20.0f, 0.0f, 1.0f, 0.0f);
 
622
            glTranslatef(50.0f, 0.0f, 0.0f);
 
623
        }
 
624
        render_frame(sink);
 
625
        if (sink->use_reflection) {
 
626
            glPushMatrix();
 
627
            glTranslatef(0.0, (GLfloat)sink->display_rect.height + 5.0f, 0.0f);
 
628
            render_reflection(sink);
 
629
            glPopMatrix();
 
630
            glPopMatrix();
 
631
        }
 
632
    }
 
633
    glBindTexture(target, 0);
 
634
    glDisable(target);
 
635
    gst_vaapi_window_glx_swap_buffers(window);
 
636
    return TRUE;
 
637
 
 
638
    /* ERRORS */
 
639
error_create_texture:
 
640
    {
 
641
        GST_DEBUG("could not create VA/GLX texture");
 
642
        return FALSE;
 
643
    }
 
644
error_transfer_surface:
 
645
    {
 
646
        GST_DEBUG("could not transfer VA surface to texture");
 
647
        return FALSE;
 
648
    }
 
649
}
 
650
#endif
 
651
 
 
652
static inline gboolean
 
653
gst_vaapisink_show_frame_x11(
 
654
    GstVaapiSink    *sink,
 
655
    GstVaapiSurface *surface,
 
656
    guint            flags
 
657
)
 
658
{
 
659
    if (!gst_vaapi_window_put_surface(sink->window, surface,
 
660
                NULL, &sink->display_rect, flags)) {
 
661
        GST_DEBUG("could not render VA surface");
 
662
        return FALSE;
 
663
    }
 
664
    return TRUE;
 
665
}
 
666
 
 
667
static GstFlowReturn
 
668
gst_vaapisink_show_frame(GstBaseSink *base_sink, GstBuffer *buffer)
 
669
{
 
670
    GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
 
671
    GstVaapiVideoBuffer * const vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
 
672
    GstVaapiSurface *surface;
 
673
    guint flags;
 
674
    gboolean success;
 
675
    GstVideoOverlayComposition * const composition =
 
676
        gst_video_buffer_get_overlay_composition(buffer);
 
677
 
 
678
    if (sink->display != gst_vaapi_video_buffer_get_display (vbuffer)) {
 
679
      if (sink->display)
 
680
        g_object_unref (sink->display);
 
681
      sink->display = g_object_ref (gst_vaapi_video_buffer_get_display (vbuffer));
 
682
    }
 
683
 
 
684
    if (!sink->window)
 
685
        return GST_FLOW_UNEXPECTED;
 
686
 
 
687
    surface = gst_vaapi_video_buffer_get_surface(vbuffer);
 
688
    if (!surface)
 
689
        return GST_FLOW_UNEXPECTED;
 
690
 
 
691
    GST_DEBUG("render surface %" GST_VAAPI_ID_FORMAT,
 
692
              GST_VAAPI_ID_ARGS(gst_vaapi_surface_get_id(surface)));
 
693
 
 
694
    flags = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
 
695
 
 
696
    if (!gst_vaapi_surface_set_subpictures_from_composition(surface,
 
697
             composition, TRUE))
 
698
        GST_WARNING("could not update subtitles");
 
699
 
 
700
#if USE_VAAPISINK_GLX
 
701
    if (sink->use_glx)
 
702
        success = gst_vaapisink_show_frame_glx(sink, surface, flags);
 
703
    else
 
704
#endif
 
705
        success = gst_vaapisink_show_frame_x11(sink, surface, flags);
 
706
    return success ? GST_FLOW_OK : GST_FLOW_UNEXPECTED;
 
707
}
 
708
 
 
709
static gboolean
 
710
gst_vaapisink_query(GstBaseSink *base_sink, GstQuery *query)
 
711
{
 
712
    GstVaapiSink *sink = GST_VAAPISINK(base_sink);
 
713
    GST_DEBUG ("sharing display %p", sink->display);
 
714
    return gst_vaapi_reply_to_query (query, sink->display);
 
715
}
 
716
 
 
717
static void
 
718
gst_vaapisink_finalize(GObject *object)
 
719
{
 
720
    gst_vaapisink_destroy(GST_VAAPISINK(object));
 
721
 
 
722
    G_OBJECT_CLASS(parent_class)->finalize(object);
 
723
}
 
724
 
 
725
static void
 
726
gst_vaapisink_set_property(
 
727
    GObject      *object,
 
728
    guint         prop_id,
 
729
    const GValue *value,
 
730
    GParamSpec   *pspec
 
731
)
 
732
{
 
733
    GstVaapiSink * const sink = GST_VAAPISINK(object);
 
734
 
 
735
    switch (prop_id) {
 
736
    case PROP_USE_GLX:
 
737
        sink->use_glx = g_value_get_boolean(value);
 
738
        break;
 
739
    case PROP_FULLSCREEN:
 
740
        sink->fullscreen = g_value_get_boolean(value);
 
741
        break;
 
742
    case PROP_SYNCHRONOUS:
 
743
        sink->synchronous = g_value_get_boolean(value);
 
744
        break;
 
745
    case PROP_USE_REFLECTION:
 
746
        sink->use_reflection = g_value_get_boolean(value);
 
747
        break;
 
748
    default:
 
749
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
 
750
        break;
 
751
    }
 
752
}
 
753
 
 
754
static void
 
755
gst_vaapisink_get_property(
 
756
    GObject    *object,
 
757
    guint       prop_id,
 
758
    GValue     *value,
 
759
    GParamSpec *pspec
 
760
)
 
761
{
 
762
    GstVaapiSink * const sink = GST_VAAPISINK(object);
 
763
 
 
764
    switch (prop_id) {
 
765
    case PROP_USE_GLX:
 
766
        g_value_set_boolean(value, sink->use_glx);
 
767
        break;
 
768
    case PROP_FULLSCREEN:
 
769
        g_value_set_boolean(value, sink->fullscreen);
 
770
        break;
 
771
    case PROP_SYNCHRONOUS:
 
772
        g_value_set_boolean(value, sink->synchronous);
 
773
        break;
 
774
    case PROP_USE_REFLECTION:
 
775
        g_value_set_boolean(value, sink->use_reflection);
 
776
        break;
 
777
    default:
 
778
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
 
779
        break;
 
780
    }
 
781
}
 
782
 
 
783
static void
 
784
gst_vaapisink_base_init(gpointer klass)
 
785
{
 
786
    GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
 
787
 
 
788
    gst_element_class_set_details(element_class, &gst_vaapisink_details);
 
789
 
 
790
    gst_element_class_add_pad_template(
 
791
        element_class,
 
792
        gst_static_pad_template_get(&gst_vaapisink_sink_factory)
 
793
    );
 
794
}
 
795
 
 
796
static void
 
797
gst_vaapisink_class_init(GstVaapiSinkClass *klass)
 
798
{
 
799
    GObjectClass * const     object_class   = G_OBJECT_CLASS(klass);
 
800
    GstBaseSinkClass * const basesink_class = GST_BASE_SINK_CLASS(klass);
 
801
 
 
802
    GST_DEBUG_CATEGORY_INIT(gst_debug_vaapisink,
 
803
                            GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
 
804
 
 
805
    object_class->finalize       = gst_vaapisink_finalize;
 
806
    object_class->set_property   = gst_vaapisink_set_property;
 
807
    object_class->get_property   = gst_vaapisink_get_property;
 
808
 
 
809
    basesink_class->start        = gst_vaapisink_start;
 
810
    basesink_class->stop         = gst_vaapisink_stop;
 
811
    basesink_class->set_caps     = gst_vaapisink_set_caps;
 
812
    basesink_class->preroll      = gst_vaapisink_show_frame;
 
813
    basesink_class->render       = gst_vaapisink_show_frame;
 
814
    basesink_class->query        = gst_vaapisink_query;
 
815
 
 
816
#if USE_VAAPISINK_GLX
 
817
    g_object_class_install_property
 
818
        (object_class,
 
819
         PROP_USE_GLX,
 
820
         g_param_spec_boolean("use-glx",
 
821
                              "GLX rendering",
 
822
                              "Enables GLX rendering",
 
823
                              TRUE,
 
824
                              G_PARAM_READWRITE));
 
825
 
 
826
    g_object_class_install_property
 
827
        (object_class,
 
828
         PROP_USE_REFLECTION,
 
829
         g_param_spec_boolean("use-reflection",
 
830
                              "Reflection effect",
 
831
                              "Enables OpenGL reflection effect",
 
832
                              FALSE,
 
833
                              G_PARAM_READWRITE));
 
834
#endif
 
835
 
 
836
    g_object_class_install_property
 
837
        (object_class,
 
838
         PROP_FULLSCREEN,
 
839
         g_param_spec_boolean("fullscreen",
 
840
                              "Fullscreen",
 
841
                              "Requests window in fullscreen state",
 
842
                              FALSE,
 
843
                              G_PARAM_READWRITE));
 
844
 
 
845
    /**
 
846
     * GstVaapiSink:synchronous:
 
847
     *
 
848
     * When enabled, runs the X display in synchronous mode. Note that
 
849
     * this is used only for debugging.
 
850
     */
 
851
    g_object_class_install_property
 
852
        (object_class,
 
853
         PROP_SYNCHRONOUS,
 
854
         g_param_spec_boolean("synchronous",
 
855
                              "Synchronous mode",
 
856
                              "Toggles X display synchronous mode",
 
857
                              FALSE,
 
858
                              G_PARAM_READWRITE));
 
859
}
 
860
 
 
861
static void
 
862
gst_vaapisink_init(GstVaapiSink *sink, GstVaapiSinkClass *klass)
 
863
{
 
864
    sink->display        = NULL;
 
865
    sink->window         = NULL;
 
866
    sink->window_width   = 0;
 
867
    sink->window_height  = 0;
 
868
    sink->texture        = NULL;
 
869
    sink->video_width    = 0;
 
870
    sink->video_height   = 0;
 
871
    sink->video_par_n    = 1;
 
872
    sink->video_par_d    = 1;
 
873
    sink->foreign_window = FALSE;
 
874
    sink->fullscreen     = FALSE;
 
875
    sink->synchronous    = FALSE;
 
876
    sink->use_glx        = USE_VAAPISINK_GLX;
 
877
    sink->use_reflection = FALSE;
 
878
}