Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / sys / vdpau / gstvdp / gstvdpdecoder.c
1 /* GStreamer
2 *
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 "gstvdpvideosrcpad.h"
26
27 #include "gstvdpdecoder.h"
28
29 GST_DEBUG_CATEGORY_STATIC (gst_vdp_decoder_debug);
30 #define GST_CAT_DEFAULT gst_vdp_decoder_debug
31
32 #define DEBUG_INIT(bla) \
33     GST_DEBUG_CATEGORY_INIT (gst_vdp_decoder_debug, "vdpdecoder", 0, \
34     "VDPAU decoder base class");
35
36 GST_BOILERPLATE_FULL (GstVdpDecoder, gst_vdp_decoder, GstBaseVideoDecoder,
37     GST_TYPE_BASE_VIDEO_DECODER, DEBUG_INIT);
38
39 enum
40 {
41   PROP_0,
42   PROP_DISPLAY
43 };
44
45 static GstFlowReturn
46 gst_vdp_decoder_shape_output (GstBaseVideoDecoder * base_video_decoder,
47     GstBuffer * buf)
48 {
49   GstVdpVideoSrcPad *vdp_pad;
50
51   vdp_pad =
52       (GstVdpVideoSrcPad *) GST_BASE_VIDEO_DECODER_SRC_PAD (base_video_decoder);
53
54   return gst_vdp_video_src_pad_push (vdp_pad, GST_VDP_VIDEO_BUFFER (buf));
55 }
56
57 static GstPad *
58 gst_vdp_decoder_create_srcpad (GstBaseVideoDecoder * base_video_decoder,
59     GstBaseVideoDecoderClass * base_video_decoder_class)
60 {
61   GstPadTemplate *pad_template;
62   GstVdpVideoSrcPad *vdp_pad;
63
64   pad_template = gst_element_class_get_pad_template
65       (GST_ELEMENT_CLASS (base_video_decoder_class),
66       GST_BASE_VIDEO_DECODER_SRC_NAME);
67
68   vdp_pad = gst_vdp_video_src_pad_new (pad_template,
69       GST_BASE_VIDEO_DECODER_SRC_NAME);
70
71   return GST_PAD (vdp_pad);
72 }
73
74 void
75 gst_vdp_decoder_post_error (GstVdpDecoder * decoder, GError * error)
76 {
77   GstMessage *message;
78
79   g_return_if_fail (GST_IS_VDP_DECODER (decoder));
80   g_return_if_fail (decoder != NULL);
81
82   message = gst_message_new_error (GST_OBJECT (decoder), error, NULL);
83   gst_element_post_message (GST_ELEMENT (decoder), message);
84   g_error_free (error);
85 }
86
87 static GstFlowReturn
88 gst_vdp_decoder_alloc_buffer (GstVdpDecoder * vdp_decoder,
89     GstVdpVideoBuffer ** video_buf)
90 {
91   GstVdpVideoSrcPad *vdp_pad;
92
93   GstFlowReturn ret;
94   GError *err = NULL;
95
96   vdp_pad = (GstVdpVideoSrcPad *) GST_BASE_VIDEO_DECODER_SRC_PAD (vdp_decoder);
97
98   ret = gst_vdp_video_src_pad_alloc_buffer (vdp_pad, video_buf, &err);
99   if (ret == GST_FLOW_ERROR)
100     gst_vdp_decoder_post_error (vdp_decoder, err);
101
102   return ret;
103 }
104
105 GstFlowReturn
106 gst_vdp_decoder_render (GstVdpDecoder * vdp_decoder, VdpPictureInfo * info,
107     guint n_bufs, VdpBitstreamBuffer * bufs, GstVdpVideoBuffer ** video_buf)
108 {
109   GstFlowReturn ret;
110
111   GstVdpDevice *device;
112   VdpVideoSurface surface;
113   VdpStatus status;
114
115   ret = gst_vdp_decoder_alloc_buffer (vdp_decoder, video_buf);
116   if (ret != GST_FLOW_OK)
117     return ret;
118
119   device = (*video_buf)->device;
120   surface = (*video_buf)->surface;
121
122   status = device->vdp_decoder_render (vdp_decoder->decoder, surface,
123       info, n_bufs, bufs);
124   if (status != VDP_STATUS_OK)
125     goto decode_error;
126
127   return GST_FLOW_OK;
128
129 decode_error:
130   GST_ELEMENT_ERROR (vdp_decoder, RESOURCE, READ,
131       ("Could not decode"),
132       ("Error returned from vdpau was: %s",
133           device->vdp_get_error_string (status)));
134
135   gst_buffer_unref (GST_BUFFER_CAST (*video_buf));
136
137   return GST_FLOW_ERROR;
138 }
139
140 GstFlowReturn
141 gst_vdp_decoder_init_decoder (GstVdpDecoder * vdp_decoder,
142     VdpDecoderProfile profile, guint32 max_references)
143 {
144   GstVdpDevice *device;
145
146   VdpStatus status;
147   GstVideoState state;
148
149   device = vdp_decoder->device;
150
151   if (vdp_decoder->decoder != VDP_INVALID_HANDLE) {
152     status = device->vdp_decoder_destroy (vdp_decoder->decoder);
153     if (status != VDP_STATUS_OK)
154       goto destroy_decoder_error;
155   }
156
157   if (!gst_base_video_decoder_set_src_caps (GST_BASE_VIDEO_DECODER
158           (vdp_decoder)))
159     return GST_FLOW_NOT_NEGOTIATED;
160
161   state =
162       gst_base_video_decoder_get_state (GST_BASE_VIDEO_DECODER (vdp_decoder));
163
164   status = device->vdp_decoder_create (device->device, profile,
165       state.width, state.height, max_references, &vdp_decoder->decoder);
166   if (status != VDP_STATUS_OK)
167     goto create_decoder_error;
168
169   return GST_FLOW_OK;
170
171 destroy_decoder_error:
172   GST_ELEMENT_ERROR (vdp_decoder, RESOURCE, READ,
173       ("Could not destroy vdpau decoder"),
174       ("Error returned from vdpau was: %s",
175           device->vdp_get_error_string (status)));
176
177   return GST_FLOW_ERROR;
178
179 create_decoder_error:
180   GST_ELEMENT_ERROR (vdp_decoder, RESOURCE, READ,
181       ("Could not create vdpau decoder"),
182       ("Error returned from vdpau was: %s",
183           device->vdp_get_error_string (status)));
184
185   return GST_FLOW_ERROR;
186 }
187
188 static gboolean
189 gst_vdp_decoder_start (GstBaseVideoDecoder * base_video_decoder)
190 {
191   GstVdpDecoder *vdp_decoder = GST_VDP_DECODER (base_video_decoder);
192
193   GError *err;
194   GstVdpVideoSrcPad *vdp_pad;
195
196   err = NULL;
197   vdp_decoder->device = gst_vdp_get_device (vdp_decoder->display, &err);
198   if (G_UNLIKELY (!vdp_decoder->device))
199     goto device_error;
200
201   vdp_pad =
202       (GstVdpVideoSrcPad *) GST_BASE_VIDEO_DECODER_SRC_PAD (base_video_decoder);
203   g_object_set (G_OBJECT (vdp_pad), "device", vdp_decoder->device, NULL);
204
205   vdp_decoder->decoder = VDP_INVALID_HANDLE;
206
207   return TRUE;
208
209 device_error:
210   gst_vdp_decoder_post_error (vdp_decoder, err);
211   return FALSE;
212 }
213
214 static gboolean
215 gst_vdp_decoder_stop (GstBaseVideoDecoder * base_video_decoder)
216 {
217   GstVdpDecoder *vdp_decoder = GST_VDP_DECODER (base_video_decoder);
218
219   if (vdp_decoder->decoder != VDP_INVALID_HANDLE) {
220     GstVdpDevice *device = vdp_decoder->device;
221     VdpStatus status;
222
223     status = device->vdp_decoder_destroy (vdp_decoder->decoder);
224     if (status != VDP_STATUS_OK) {
225       GST_ELEMENT_ERROR (vdp_decoder, RESOURCE, READ,
226           ("Could not destroy vdpau decoder"),
227           ("Error returned from vdpau was: %s",
228               device->vdp_get_error_string (status)));
229       return FALSE;
230     }
231   }
232
233   g_object_unref (vdp_decoder->device);
234
235   return TRUE;
236 }
237
238 static void
239 gst_vdp_decoder_get_property (GObject * object, guint prop_id,
240     GValue * value, GParamSpec * pspec)
241 {
242   GstVdpDecoder *vdp_decoder = GST_VDP_DECODER (object);
243
244   switch (prop_id) {
245     case PROP_DISPLAY:
246       g_value_set_string (value, vdp_decoder->display);
247       break;
248
249     default:
250       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
251       break;
252   }
253 }
254
255 static void
256 gst_vdp_decoder_set_property (GObject * object, guint prop_id,
257     const GValue * value, GParamSpec * pspec)
258 {
259   GstVdpDecoder *vdp_decoder = GST_VDP_DECODER (object);
260
261   switch (prop_id) {
262     case PROP_DISPLAY:
263       g_free (vdp_decoder->display);
264       vdp_decoder->display = g_value_dup_string (value);
265       break;
266
267     default:
268       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
269       break;
270   }
271 }
272
273 static void
274 gst_vdp_decoder_finalize (GObject * object)
275 {
276   GstVdpDecoder *vdp_decoder = GST_VDP_DECODER (object);
277
278   g_free (vdp_decoder->display);
279
280   G_OBJECT_CLASS (parent_class)->finalize (object);
281 }
282
283 static void
284 gst_vdp_decoder_base_init (gpointer g_class)
285 {
286   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
287
288   GstCaps *src_caps;
289   GstPadTemplate *src_template;
290
291   src_caps = gst_vdp_video_buffer_get_caps (TRUE, VDP_CHROMA_TYPE_420);
292   src_template = gst_pad_template_new (GST_BASE_VIDEO_DECODER_SRC_NAME,
293       GST_PAD_SRC, GST_PAD_ALWAYS, src_caps);
294
295   gst_element_class_add_pad_template (element_class, src_template);
296   gst_object_unref (src_template);
297 }
298
299 static void
300 gst_vdp_decoder_init (GstVdpDecoder * vdp_decoder, GstVdpDecoderClass * klass)
301 {
302   vdp_decoder->display = NULL;
303 }
304
305 static void
306 gst_vdp_decoder_class_init (GstVdpDecoderClass * klass)
307 {
308   GObjectClass *object_class;
309   GstBaseVideoDecoderClass *base_video_decoder_class;
310
311   object_class = G_OBJECT_CLASS (klass);
312   base_video_decoder_class = GST_BASE_VIDEO_DECODER_CLASS (klass);
313
314   object_class->get_property = gst_vdp_decoder_get_property;
315   object_class->set_property = gst_vdp_decoder_set_property;
316   object_class->finalize = gst_vdp_decoder_finalize;
317
318   base_video_decoder_class->start = gst_vdp_decoder_start;
319   base_video_decoder_class->stop = gst_vdp_decoder_stop;
320
321   base_video_decoder_class->create_srcpad = gst_vdp_decoder_create_srcpad;
322   base_video_decoder_class->shape_output = gst_vdp_decoder_shape_output;
323
324   g_object_class_install_property (object_class,
325       PROP_DISPLAY, g_param_spec_string ("display", "Display", "X Display name",
326           NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
327 }