Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / sys / vdpau / gstvdp / gstvdpoutputbuffer.c
1 /* 
2  * GStreamer
3  * Copyright (C) 2009 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gstvdpoutputbuffer.h"
26
27 GST_DEBUG_CATEGORY_STATIC (gst_vdp_output_buffer_debug);
28 #define GST_CAT_DEFAULT gst_vdp_output_buffer_debug
29
30 #define DEBUG_INIT(bla) \
31 GST_DEBUG_CATEGORY_INIT (gst_vdp_output_buffer_debug, "vdpoutputbuffer", 0, "VDPAU output buffer");
32
33 GstVdpOutputBuffer *
34 gst_vdp_output_buffer_new (GstVdpDevice * device, VdpRGBAFormat rgba_format,
35     gint width, gint height, GError ** error)
36 {
37   GstVdpOutputBuffer *buffer;
38   VdpStatus status;
39   VdpOutputSurface surface;
40
41   status =
42       device->vdp_output_surface_create (device->device, rgba_format, width,
43       height, &surface);
44   if (status != VDP_STATUS_OK)
45     goto create_error;
46
47   buffer =
48       (GstVdpOutputBuffer *) gst_mini_object_new (GST_TYPE_VDP_OUTPUT_BUFFER);
49
50   buffer->device = g_object_ref (device);
51   buffer->rgba_format = rgba_format;
52   buffer->width = width;
53   buffer->height = height;
54
55   buffer->surface = surface;
56
57   return buffer;
58
59 create_error:
60   g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ,
61       "Couldn't create a VdpOutputSurface, error returned from vdpau was: %s",
62       device->vdp_get_error_string (status));
63   return NULL;
64 }
65
66 static GObjectClass *gst_vdp_output_buffer_parent_class;
67
68 static void
69 gst_vdp_output_buffer_finalize (GstVdpOutputBuffer * buffer)
70 {
71   GstVdpDevice *device;
72   VdpStatus status;
73
74   if (gst_vdp_buffer_revive (GST_VDP_BUFFER_CAST (buffer)))
75     return;
76
77   device = buffer->device;
78
79   status = device->vdp_output_surface_destroy (buffer->surface);
80   if (status != VDP_STATUS_OK)
81     GST_ERROR
82         ("Couldn't destroy the buffers VdpOutputSurface, error returned was: %s",
83         device->vdp_get_error_string (status));
84
85   g_object_unref (buffer->device);
86
87   GST_MINI_OBJECT_CLASS (gst_vdp_output_buffer_parent_class)->finalize
88       (GST_MINI_OBJECT (buffer));
89 }
90
91 static void
92 gst_vdp_output_buffer_init (GstVdpOutputBuffer * buffer, gpointer g_class)
93 {
94   buffer->device = NULL;
95   buffer->surface = VDP_INVALID_HANDLE;
96 }
97
98 static void
99 gst_vdp_output_buffer_class_init (gpointer g_class, gpointer class_data)
100 {
101   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
102
103   gst_vdp_output_buffer_parent_class = g_type_class_peek_parent (g_class);
104
105   mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
106       gst_vdp_output_buffer_finalize;
107 }
108
109
110 GType
111 gst_vdp_output_buffer_get_type (void)
112 {
113   static GType _gst_vdp_output_buffer_type;
114
115   if (G_UNLIKELY (_gst_vdp_output_buffer_type == 0)) {
116     static const GTypeInfo info = {
117       sizeof (GstBufferClass),
118       NULL,
119       NULL,
120       gst_vdp_output_buffer_class_init,
121       NULL,
122       NULL,
123       sizeof (GstVdpOutputBuffer),
124       0,
125       (GInstanceInitFunc) gst_vdp_output_buffer_init,
126       NULL
127     };
128     _gst_vdp_output_buffer_type = g_type_register_static (GST_TYPE_VDP_BUFFER,
129         "GstVdpOutputBuffer", &info, 0);
130
131     DEBUG_INIT ();
132   }
133   return _gst_vdp_output_buffer_type;
134 }
135
136 typedef struct
137 {
138   VdpRGBAFormat format;
139   GstStaticCaps caps;
140 } GstVdpOutputBufferFormats;
141
142 GstVdpOutputBufferFormats rgba_formats[] = {
143   {VDP_RGBA_FORMAT_A8,
144       GST_STATIC_CAPS ("video/x-raw-rgb, "
145             "bpp = (int)8, "
146             "depth = (int)8, "
147             "endianness = (int)4321, "
148             "red_mask = (int)0x00, "
149             "green_mask = (int)0x00, "
150             "blue_mask = (int)0x00, " "alpha_mask = (int)0xff")},
151   {VDP_RGBA_FORMAT_B10G10R10A2,
152       GST_STATIC_CAPS ("video/x-raw-rgb, "
153             "bpp = (int)32, "
154             "depth = (int)30, "
155             "endianness = (int)4321, "
156             "red_mask = (int)0x000003fc, "
157             "green_mask = (int)0x003ff000, "
158             "blue_mask = (int)0xffc00000, " "alpha_mask = (int)0x00000003")},
159   {VDP_RGBA_FORMAT_B8G8R8A8,
160       GST_STATIC_CAPS ("video/x-raw-rgb, "
161             "bpp = (int)32, "
162             "depth = (int)24, "
163             "endianness = (int)4321, "
164             "red_mask = (int)0x0000ff00, "
165             "green_mask = (int)0x00ff0000, "
166             "blue_mask = (int)0xff000000, " "alpha_mask = (int)0x000000ff")},
167   {VDP_RGBA_FORMAT_R10G10B10A2,
168       GST_STATIC_CAPS ("video/x-raw-rgb, "
169             "bpp = (int)32, "
170             "depth = (int)30, "
171             "endianness = (int)4321, "
172             "red_mask = (int)0xffc00000, "
173             "green_mask = (int)0x003ff000, "
174             "blue_mask = (int)0x000003fc, " "alpha_mask = (int)0x00000003")},
175   {VDP_RGBA_FORMAT_R8G8B8A8,
176       GST_STATIC_CAPS ("video/x-raw-rgb, "
177             "bpp = (int)32, "
178             "depth = (int)24, "
179             "endianness = (int)4321, "
180             "red_mask = (int)0xff000000, "
181             "green_mask = (int)0x00ff0000, "
182             "blue_mask = (int)0x0000ff00, " "alpha_mask = (int)0x000000ff")},
183 };
184
185
186 GstCaps *
187 gst_vdp_output_buffer_get_template_caps (void)
188 {
189   GstCaps *caps, *rgb_caps;
190   gint i;
191
192   caps = gst_caps_new_empty ();
193   rgb_caps = gst_caps_new_empty ();
194
195   for (i = 0; i < G_N_ELEMENTS (rgba_formats); i++) {
196     GstCaps *format_caps;
197
198     format_caps = gst_caps_new_simple ("video/x-vdpau-output",
199         "rgba-format", G_TYPE_INT, rgba_formats[i].format,
200         "width", GST_TYPE_INT_RANGE, 1, 8192,
201         "height", GST_TYPE_INT_RANGE, 1, 8192, NULL);
202     gst_caps_append (caps, format_caps);
203
204     format_caps = gst_static_caps_get (&rgba_formats[i].caps);
205     format_caps = gst_caps_copy (format_caps);
206     gst_caps_set_simple (format_caps,
207         "width", GST_TYPE_INT_RANGE, 1, 8192,
208         "height", GST_TYPE_INT_RANGE, 1, 8192, NULL);
209     gst_caps_append (rgb_caps, format_caps);
210
211   }
212
213   gst_caps_append (caps, rgb_caps);
214
215   return caps;
216 }
217
218 GstCaps *
219 gst_vdp_output_buffer_get_allowed_caps (GstVdpDevice * device)
220 {
221   GstCaps *caps, *rgb_caps;
222   gint i;
223
224   g_return_val_if_fail (GST_IS_VDP_DEVICE (device), NULL);
225
226   caps = gst_caps_new_empty ();
227   rgb_caps = gst_caps_new_empty ();
228
229   for (i = 0; i < G_N_ELEMENTS (rgba_formats); i++) {
230     VdpStatus status;
231     VdpBool is_supported;
232     guint max_w, max_h;
233
234     status = device->vdp_output_surface_query_capabilities (device->device,
235         rgba_formats[i].format, &is_supported, &max_w, &max_h);
236     if (status != VDP_STATUS_OK && status != VDP_STATUS_INVALID_RGBA_FORMAT) {
237       GST_ERROR_OBJECT (device,
238           "Could not get query VDPAU output surface capabilites, "
239           "Error returned from vdpau was: %s",
240           device->vdp_get_error_string (status));
241
242       goto error;
243     }
244
245     if (is_supported) {
246       GstCaps *format_caps;
247
248       format_caps = gst_caps_new_simple ("video/x-vdpau-output",
249           "rgba-format", G_TYPE_INT, rgba_formats[i].format,
250           "width", GST_TYPE_INT_RANGE, 1, max_w,
251           "height", GST_TYPE_INT_RANGE, 1, max_h, NULL);
252       gst_caps_append (caps, format_caps);
253
254       format_caps = gst_static_caps_get (&rgba_formats[i].caps);
255       format_caps = gst_caps_copy (format_caps);
256       gst_caps_set_simple (format_caps,
257           "width", GST_TYPE_INT_RANGE, 1, 8192,
258           "height", GST_TYPE_INT_RANGE, 1, 8192, NULL);
259       gst_caps_append (rgb_caps, format_caps);
260     }
261   }
262
263   gst_caps_append (caps, rgb_caps);
264
265 error:
266
267   return caps;
268 }
269
270 gboolean
271 gst_vdp_caps_to_rgba_format (GstCaps * caps, VdpRGBAFormat * rgba_format)
272 {
273   GstStructure *structure;
274   gint c_bpp, c_depth, c_endianness, c_red_mask, c_green_mask, c_blue_mask,
275       c_alpha_mask;
276
277   gint i;
278
279   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
280
281   if (!gst_caps_is_fixed (caps))
282     return FALSE;
283
284   structure = gst_caps_get_structure (caps, 0);
285   if (!gst_structure_has_name (structure, "video/x-raw-rgb"))
286     return FALSE;
287
288   if (!gst_structure_get_int (structure, "bpp", &c_bpp) ||
289       !gst_structure_get_int (structure, "depth", &c_depth) ||
290       !gst_structure_get_int (structure, "endianness", &c_endianness) ||
291       !gst_structure_get_int (structure, "red_mask", &c_red_mask) ||
292       !gst_structure_get_int (structure, "green_mask", &c_green_mask) ||
293       !gst_structure_get_int (structure, "blue_mask", &c_blue_mask) ||
294       !gst_structure_get_int (structure, "alpha_mask", &c_alpha_mask))
295     return FALSE;
296
297   for (i = 0; i < G_N_ELEMENTS (rgba_formats); i++) {
298     gint bpp, depth, endianness, red_mask, green_mask, blue_mask, alpha_mask;
299
300     GstCaps *rgb_caps = gst_static_caps_get (&rgba_formats[i].caps);
301     structure = gst_caps_get_structure (rgb_caps, 0);
302
303     gst_structure_get_int (structure, "bpp", &bpp);
304     gst_structure_get_int (structure, "depth", &depth);
305     gst_structure_get_int (structure, "endianness", &endianness);
306     gst_structure_get_int (structure, "red_mask", &red_mask);
307     gst_structure_get_int (structure, "green_mask", &green_mask);
308     gst_structure_get_int (structure, "blue_mask", &blue_mask);
309     gst_structure_get_int (structure, "alpha_mask", &alpha_mask);
310
311     if (c_bpp == bpp && c_depth == depth && c_endianness == endianness &&
312         c_red_mask == red_mask && c_green_mask == green_mask &&
313         c_blue_mask == blue_mask && c_alpha_mask == alpha_mask) {
314       gst_caps_unref (rgb_caps);
315       *rgba_format = rgba_formats[i].format;
316       return TRUE;
317     }
318
319     gst_caps_unref (rgb_caps);
320   }
321
322   return FALSE;
323 }
324
325 gboolean
326 gst_vdp_output_buffer_calculate_size (GstVdpOutputBuffer * output_buf,
327     guint * size)
328 {
329   g_return_val_if_fail (GST_IS_VDP_OUTPUT_BUFFER (output_buf), FALSE);
330
331   switch (output_buf->rgba_format) {
332     case VDP_RGBA_FORMAT_A8:
333     {
334       *size = output_buf->width * output_buf->height;
335       break;
336     }
337
338     case VDP_RGBA_FORMAT_B10G10R10A2:
339     case VDP_RGBA_FORMAT_B8G8R8A8:
340     case VDP_RGBA_FORMAT_R10G10B10A2:
341     case VDP_RGBA_FORMAT_R8G8B8A8:
342     {
343       *size = output_buf->width * output_buf->height * 4;
344       break;
345     }
346
347     default:
348       g_assert_not_reached ();
349       return FALSE;
350   }
351
352   return TRUE;
353 }
354
355 gboolean
356 gst_vdp_output_buffer_download (GstVdpOutputBuffer * output_buf,
357     GstBuffer * outbuf, GError ** error)
358 {
359   guint8 *data[1];
360   guint32 stride[1];
361   GstVdpDevice *device;
362   VdpOutputSurface surface;
363   VdpStatus status;
364
365   g_return_val_if_fail (GST_IS_VDP_OUTPUT_BUFFER (output_buf), FALSE);
366
367   switch (output_buf->rgba_format) {
368     case VDP_RGBA_FORMAT_A8:
369     {
370       stride[0] = output_buf->width;
371       break;
372     }
373
374     case VDP_RGBA_FORMAT_B10G10R10A2:
375     case VDP_RGBA_FORMAT_B8G8R8A8:
376     case VDP_RGBA_FORMAT_R10G10B10A2:
377     case VDP_RGBA_FORMAT_R8G8B8A8:
378     {
379       stride[0] = output_buf->width * 4;
380       break;
381     }
382
383     default:
384       return FALSE;
385   }
386
387   device = output_buf->device;
388   surface = output_buf->surface;
389   data[0] = GST_BUFFER_DATA (outbuf);
390
391   GST_LOG_OBJECT (output_buf, "Entering vdp_output_surface_get_bits_native");
392   status =
393       device->vdp_output_surface_get_bits_native (surface, NULL, (void *) data,
394       stride);
395   GST_LOG_OBJECT (output_buf,
396       "Got status %d from vdp_output_get_bits_native", status);
397
398   if (G_UNLIKELY (status != VDP_STATUS_OK)) {
399     g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ,
400         "Couldn't get data from vdpau, error returned from vdpau was: %s",
401         device->vdp_get_error_string (status));
402     return FALSE;
403   }
404
405   return TRUE;
406 }