Tizen 2.0 Release
[framework/multimedia/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapiencoder.c
1 /*
2  *  gstvaapiencoder.c - VA-API encoder interface
3  *
4  *  Copyright (C) 2011 Intel Corporation
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public License
8  *  as published by the Free Software Foundation; either version 2.1
9  *  of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free
18  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301 USA
20  */
21
22 #include "gstvaapiencoder.h"
23
24 #include <string.h>
25
26 #include "gstvaapidisplay_x11.h"
27 #include "gstvaapiobject_priv.h"
28 #include "gstvaapidisplay_priv.h"
29
30 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encoder_debug);
31 #define GST_CAT_DEFAULT gst_vaapi_encoder_debug
32
33
34 G_DEFINE_TYPE(GstVaapiEncoder, gst_vaapi_encoder, G_TYPE_OBJECT)
35
36 gboolean
37 gst_vaapi_encoder_set_display(
38     GstVaapiEncoder* encoder,
39     GstVaapiDisplay *display
40 )
41 {
42   GstVaapiEncoderPrivate *priv = encoder->priv;
43   if (display == priv->display) {
44     return TRUE;
45   }
46
47   if (VAAPI_ENC_INIT < priv->state) {
48     return FALSE;
49   }
50   if (priv->display) {
51     g_object_unref(priv->display);
52     priv->display = NULL;
53     priv->va_display = NULL;
54   }
55   if (display) {
56     priv->display = g_object_ref(display);
57     priv->va_display = gst_vaapi_display_get_display(display);
58   }
59   return TRUE;
60 }
61
62 GstVaapiDisplay *
63 gst_vaapi_encoder_get_display(GstVaapiEncoder* encoder)
64 {
65   GstVaapiEncoderPrivate *priv = encoder->priv;
66   return (priv->display ? g_object_ref(priv->display) : NULL);
67 }
68
69 GstVaapiContext *
70 gst_vaapi_encoder_get_context(GstVaapiEncoder* encoder)
71 {
72   GstVaapiEncoderPrivate *priv = encoder->priv;
73   return (priv->context ? g_object_ref(priv->context) : NULL);
74 }
75
76
77 VAAPI_Encode_State
78 gst_vaapi_encoder_get_state(GstVaapiEncoder* encoder)
79 {
80   GstVaapiEncoderPrivate *priv = encoder->priv;
81   return priv->state;
82 }
83
84
85 EncoderStatus
86 gst_vaapi_encoder_initialize(GstVaapiEncoder* encoder)
87 {
88   EncoderStatus ret = ENCODER_NO_ERROR;
89   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
90   GstVaapiEncoderPrivate *priv = encoder->priv;
91
92   /* check state */
93   if (VAAPI_ENC_INIT == priv->state) {
94     return ENCODER_NO_ERROR;
95   }
96   ENCODER_ASSERT(VAAPI_ENC_NULL == priv->state);
97   if (VAAPI_ENC_NULL != priv->state) {
98     return ENCODER_STATE_ERR;
99   }
100
101   /* create va_dpy*/
102   if (!priv->display) {
103     priv->display = gst_vaapi_display_x11_new(NULL);
104     ENCODER_CHECK_STATUS(priv->display,
105                          ENCODER_DISPLAY_ERR,
106                          "gst_vaapi_display_x11_new failed.");
107   }
108   priv->va_display = gst_vaapi_display_get_display(priv->display);
109
110   if (encoder_class->initialize) {
111     ret = encoder_class->initialize(encoder);
112     ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == ret,
113                           ret,
114                           "encoder <initialize> failed.");
115   }
116   priv->state = VAAPI_ENC_INIT;
117
118 end:
119   return ret;
120 }
121
122 EncoderStatus
123 gst_vaapi_encoder_open(GstVaapiEncoder* encoder)
124 {
125   EncoderStatus ret = ENCODER_NO_ERROR;
126   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
127   GstVaapiEncoderPrivate *priv = encoder->priv;
128
129   /* check state */
130   if (VAAPI_ENC_OPENED == priv->state) {
131     return ENCODER_NO_ERROR;
132   }
133   ENCODER_ASSERT(VAAPI_ENC_INIT == priv->state);
134   if (VAAPI_ENC_INIT != priv->state) {
135     return ENCODER_STATE_ERR;
136   }
137   ENCODER_ASSERT(!priv->context);
138
139   ENCODER_CHECK_STATUS(encoder_class->open,
140                        ENCODER_FUNC_PTR_ERR,
141                        "encoder <open> function pointer empty.");
142   ret = encoder_class->open(encoder, &priv->context);
143   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
144                        ret,
145                        "encoder <open> failed.");
146   ENCODER_CHECK_STATUS(priv->context,
147                        ENCODER_CONTEXT_ERR,
148                        "encoder <open> context failed.");
149   priv->va_context = gst_vaapi_context_get_id(priv->context);
150   priv->state = VAAPI_ENC_OPENED;
151
152 end:
153   return ret;
154 }
155
156 EncoderStatus
157 gst_vaapi_encoder_encode(
158     GstVaapiEncoder* encoder,
159     GstBuffer *pic
160 )
161 {
162   EncoderStatus ret = ENCODER_NO_ERROR;
163   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
164   GstVaapiEncoderPrivate *priv = encoder->priv;
165
166   ENCODER_CHECK_STATUS(priv->state >= VAAPI_ENC_OPENED,
167                        ENCODER_STATE_ERR,
168                        "encoder was not opened before <encode>.");
169   ENCODER_CHECK_STATUS(encoder_class->encode,
170                        ENCODER_FUNC_PTR_ERR,
171                        "encoder <encode> function pointer empty.");
172   ret = encoder_class->encode(encoder, pic);
173   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR <= ret,
174                        ret,
175                        "encoder <encode> failed.");
176   if (priv->state < VAAPI_ENC_ENCODING) {
177     priv->state = VAAPI_ENC_ENCODING;
178   }
179 end:
180   return ret;
181 }
182
183 EncoderStatus
184 gst_vaapi_encoder_get_encoded_buffer(
185     GstVaapiEncoder* encoder,
186     GstBuffer **buf
187 )
188 {
189   EncoderStatus ret = ENCODER_NO_ERROR;
190   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
191   GstVaapiEncoderPrivate *priv = encoder->priv;
192
193   ENCODER_CHECK_STATUS(priv->state >= VAAPI_ENC_OPENED,
194                        ENCODER_STATE_ERR,
195                        "encoder was not encoding <encode>.");
196   ENCODER_CHECK_STATUS(encoder_class->get_buf,
197                        ENCODER_FUNC_PTR_ERR,
198                        "encoder <get_buf> function pointer empty.");
199   ret = encoder_class->get_buf(encoder, buf);
200   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR <= ret,
201                        ret,
202                        "encoder <get_buf> failed.");
203 end:
204   return ret;
205 }
206
207
208 EncoderStatus
209 gst_vaapi_encoder_get_codec_data(
210     GstVaapiEncoder* encoder,
211     GstBuffer **codec_data
212 )
213 {
214   EncoderStatus ret = ENCODER_NO_ERROR;
215   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
216   GstVaapiEncoderPrivate *priv = encoder->priv;
217
218   ENCODER_CHECK_STATUS(priv->state >= VAAPI_ENC_OPENED,
219                        ENCODER_STATE_ERR,
220                        "encoder was not opened before <get_codec_data>.");
221   if (!encoder_class->get_codec_data) {
222     *codec_data = NULL;
223     ENCODER_LOG_INFO("There's no codec_data");
224     return ret;
225   }
226   ret = encoder_class->get_codec_data(encoder, codec_data);
227
228 end:
229   return ret;
230 }
231
232 EncoderStatus
233 gst_vaapi_encoder_flush(
234     GstVaapiEncoder* encoder
235 )
236 {
237   EncoderStatus ret = ENCODER_NO_ERROR;
238   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
239   GstVaapiEncoderPrivate *priv = encoder->priv;
240
241   if (priv->state < VAAPI_ENC_OPENED) {
242     return ENCODER_STATE_ERR;
243   }
244   ENCODER_CHECK_STATUS(encoder_class->flush,
245                        ENCODER_FUNC_PTR_ERR,
246                        "encoder <flush> function pointer empty.");
247   ret = encoder_class->flush(encoder);
248   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
249                        ret,
250                        "encoder <flush> failed.");
251 end:
252   return ret;
253 }
254
255 EncoderStatus
256 gst_vaapi_encoder_close(GstVaapiEncoder* encoder)
257 {
258   EncoderStatus ret = ENCODER_NO_ERROR;
259   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
260   GstVaapiEncoderPrivate *priv = encoder->priv;
261
262   if (VAAPI_ENC_INIT >= priv->state) {
263     return ENCODER_NO_ERROR;
264   }
265   ENCODER_CHECK_STATUS(encoder_class->close,
266                        ENCODER_FUNC_PTR_ERR,
267                        "encoder <close> function pointers empty.");
268   ret = encoder_class->close(encoder);
269   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
270                        ret,
271                        "encoder <close> failed.");
272 end:
273   if (priv->context) {
274     g_object_unref(priv->context);
275     priv->context = NULL;
276     priv->va_context = VA_INVALID_ID;
277   }
278
279   priv->state = VAAPI_ENC_INIT;
280   return ret;
281 }
282
283 EncoderStatus
284 gst_vaapi_encoder_render_picture(
285     GstVaapiEncoder *encoder,
286     GstVaapiSurface *surface,
287     VABufferID *bufs,
288     guint num
289 )
290 {
291   GstVaapiDisplay *display;
292   VASurfaceID  surface_id;
293   VAContextID context_id;
294   VADisplay   va_display;
295   VAStatus    va_status;
296   gboolean is_locked = FALSE;
297   EncoderStatus ret = ENCODER_NO_ERROR;
298
299   display = ENCODER_DISPLAY(encoder);
300
301   g_return_val_if_fail(surface, ENCODER_PARAMETER_ERR);
302   g_return_val_if_fail(ENCODER_CONTEXT(encoder), ENCODER_PARAMETER_ERR);
303
304   surface_id = (VASurfaceID)GST_VAAPI_OBJECT_ID(surface);
305   context_id = ENCODER_VA_CONTEXT(encoder);
306   va_display = ENCODER_VA_DISPLAY(encoder);
307   g_return_val_if_fail(surface_id != VA_INVALID_SURFACE, ENCODER_PARAMETER_ERR);
308
309   /* begin surface*/
310   ENCODER_ACQUIRE_DISPLAY_LOCK(display);
311   va_status = vaBeginPicture(va_display, context_id, surface_id);
312   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
313                        ENCODER_PARAMETER_ERR,
314                                            "vaBeginPicture failed");
315
316   va_status = vaRenderPicture(va_display,
317                               context_id,
318                               bufs,
319                               num);
320   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
321                        ENCODER_PARAMETER_ERR,
322                                            "vaRenderPicture failed");
323
324   va_status = vaEndPicture(va_display, context_id);
325   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
326                        ENCODER_PARAMETER_ERR,
327                                            "vaRenderPicture failed");
328
329 end:
330   ENCODER_RELEASE_DISPLAY_LOCK(display);
331   return ret;
332 }
333
334 EncoderStatus
335 gst_vaapi_encoder_uninitialize(GstVaapiEncoder* encoder)
336 {
337   EncoderStatus ret = ENCODER_NO_ERROR;
338   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
339   GstVaapiEncoderPrivate *priv = encoder->priv;
340
341   if (VAAPI_ENC_NULL == priv->state) {
342     return ENCODER_NO_ERROR;
343   }
344
345   if (VAAPI_ENC_INIT < priv->state) {
346     ret = gst_vaapi_encoder_close(encoder);
347   }
348   ENCODER_ASSERT(VAAPI_ENC_INIT == priv->state);
349   if (encoder_class->uninitialize) {
350     ret = encoder_class->uninitialize(encoder);
351     ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
352                          ret,
353                          "encoder <uninitialize> failed.");
354   }
355
356 end:
357   if (priv->display) {
358     g_object_unref(priv->display);
359     priv->display = NULL;
360     priv->va_display = NULL;
361   }
362   priv->state = VAAPI_ENC_NULL;
363   return ret;
364
365 }
366
367 char *
368 vaapi_encoder_dump_bytes(const guint8 *buf, guint32 num)
369 {
370   static char tmp[1024];
371   guint32 i = 0;
372   memset(tmp, 0, sizeof(tmp));
373
374   char *p = tmp;
375   for (i = 0; i < num; i++) {
376     snprintf(p, 1024-(p-tmp), "%02x", (guint8)buf[i]);
377     p += strlen(p);
378   }
379   return tmp;
380 }
381
382 static void
383 gst_vaapi_encoder_init(GstVaapiEncoder *encoder)
384 {
385   GstVaapiEncoderPrivate *priv;
386
387   encoder->priv = GST_VAAPI_ENCODER_GET_PRIVATE(encoder);
388   priv = encoder->priv;
389   ENCODER_ASSERT(priv);
390
391   priv->display = NULL;
392   priv->va_display = NULL;
393   priv->context = NULL;
394   priv->va_context = VA_INVALID_ID;
395   priv->state = VAAPI_ENC_NULL;
396
397   encoder->width = 0;
398   encoder->height = 0;
399   encoder->frame_rate = 0;
400   encoder->rate_control = GST_VAAPI_RATECONTROL_NONE;
401 }
402
403 static void
404 gst_vaapi_encoder_finalize(GObject *object)
405 {
406   GstVaapiEncoder* encoder = GST_VAAPI_ENCODER(object);
407   GstVaapiEncoderPrivate *priv = encoder->priv;
408   if (VAAPI_ENC_NULL != priv->state) {
409     gst_vaapi_encoder_uninitialize(encoder);
410   }
411
412   if (priv->context) {
413     g_object_unref(priv->context);
414     priv->context = NULL;
415     priv->va_context = VA_INVALID_ID;
416   }
417
418   if (priv->display) {
419     g_object_unref(priv->display);
420     priv->display = NULL;
421     priv->va_display = NULL;
422   }
423
424   G_OBJECT_CLASS (gst_vaapi_encoder_parent_class)->finalize (object);
425 }
426
427 static void
428 gst_vaapi_encoder_class_init(GstVaapiEncoderClass *kclass)
429 {
430   GObjectClass * const object_class = G_OBJECT_CLASS(kclass);
431   g_type_class_add_private(kclass, sizeof(GstVaapiEncoderPrivate));
432
433
434   GST_DEBUG_CATEGORY_INIT (gst_vaapi_encoder_debug,
435                            "gst_va_encoder",
436                            0,
437                            "gst_va_encoder element");
438
439   object_class->finalize = gst_vaapi_encoder_finalize;
440 }