h264encoder: add rate-control attribute
[profile/ivi/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
28 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_encoder_debug);
29 #define GST_CAT_DEFAULT gst_vaapi_encoder_debug
30
31
32 G_DEFINE_TYPE(GstVaapiEncoder, gst_vaapi_encoder, G_TYPE_OBJECT)
33
34 gboolean
35 gst_vaapi_encoder_set_display(
36     GstVaapiEncoder* encoder,
37     GstVaapiDisplay *display
38 )
39 {
40   GstVaapiEncoderPrivate *priv = encoder->priv;
41   if (display == priv->display) {
42     return TRUE;
43   }
44
45   if (VAAPI_ENC_INIT < priv->state) {
46     return FALSE;
47   }
48   if (priv->display) {
49     g_object_unref(priv->display);
50     priv->display = NULL;
51     priv->va_display = NULL;
52   }
53   if (display) {
54     priv->display = g_object_ref(display);
55     priv->va_display = gst_vaapi_display_get_display(display);
56   }
57   return TRUE;
58 }
59
60 GstVaapiDisplay *
61 gst_vaapi_encoder_get_display(GstVaapiEncoder* encoder)
62 {
63   GstVaapiEncoderPrivate *priv = encoder->priv;
64   return (priv->display ? g_object_ref(priv->display) : NULL);
65 }
66
67 GstVaapiContext *
68 gst_vaapi_encoder_get_context(GstVaapiEncoder* encoder)
69 {
70   GstVaapiEncoderPrivate *priv = encoder->priv;
71   return (priv->context ? g_object_ref(priv->context) : NULL);
72 }
73
74
75 VAAPI_Encode_State
76 gst_vaapi_encoder_get_state(GstVaapiEncoder* encoder)
77 {
78   GstVaapiEncoderPrivate *priv = encoder->priv;
79   return priv->state;
80 }
81
82
83 EncoderStatus
84 gst_vaapi_encoder_initialize(GstVaapiEncoder* encoder)
85 {
86   EncoderStatus ret = ENCODER_NO_ERROR;
87   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
88   GstVaapiEncoderPrivate *priv = encoder->priv;
89
90   /* check state */
91   if (VAAPI_ENC_INIT == priv->state) {
92     return ENCODER_NO_ERROR;
93   }
94   ENCODER_ASSERT(VAAPI_ENC_NULL == priv->state);
95   if (VAAPI_ENC_NULL != priv->state) {
96     return ENCODER_STATE_ERR;
97   }
98
99   /* create va_dpy*/
100   if (!priv->display) {
101     priv->display = gst_vaapi_display_x11_new(NULL);
102     ENCODER_CHECK_STATUS(priv->display,
103                          ENCODER_DISPLAY_ERR,
104                          "gst_vaapi_display_x11_new failed.");
105     priv->va_display = gst_vaapi_display_get_display(priv->display);
106   }
107
108   if (encoder_class->initialize) {
109     ret = encoder_class->initialize(encoder);
110     ENCODER_CHECK_STATUS (ENCODER_NO_ERROR == ret,
111                           ret,
112                           "encoder <initialize> failed.");
113   }
114   priv->state = VAAPI_ENC_INIT;
115
116 end:
117   return ret;
118 }
119
120 EncoderStatus
121 gst_vaapi_encoder_open(GstVaapiEncoder* encoder)
122 {
123   EncoderStatus ret = ENCODER_NO_ERROR;
124   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
125   GstVaapiEncoderPrivate *priv = encoder->priv;
126
127   /* check state */
128   if (VAAPI_ENC_OPENED == priv->state) {
129     return ENCODER_NO_ERROR;
130   }
131   ENCODER_ASSERT(VAAPI_ENC_INIT == priv->state);
132   if (VAAPI_ENC_INIT != priv->state) {
133     return ENCODER_STATE_ERR;
134   }
135   ENCODER_ASSERT(!priv->context);
136
137   ENCODER_CHECK_STATUS(encoder_class->open,
138                        ENCODER_FUNC_PTR_ERR,
139                        "encoder <open> function pointer empty.");
140   ret = encoder_class->open(encoder, &priv->context);
141   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
142                        ret,
143                        "encoder <open> failed.");
144   ENCODER_CHECK_STATUS(priv->context,
145                        ENCODER_CONTEXT_ERR,
146                        "encoder <open> context failed.");
147   priv->va_context = gst_vaapi_context_get_id(priv->context);
148   priv->state = VAAPI_ENC_OPENED;
149
150 end:
151   return ret;
152 }
153
154 EncoderStatus
155 gst_vaapi_encoder_encode(
156     GstVaapiEncoder* encoder,
157     GstBuffer *raw_pic,
158     GList **coded_pics
159 )
160 {
161   EncoderStatus ret = ENCODER_NO_ERROR;
162   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
163   GstVaapiEncoderPrivate *priv = encoder->priv;
164
165   ENCODER_CHECK_STATUS(priv->state >= VAAPI_ENC_OPENED,
166                        ENCODER_STATE_ERR,
167                        "encoder was not opened before <encode>.");
168   ENCODER_CHECK_STATUS(encoder_class->encode,
169                        ENCODER_FUNC_PTR_ERR,
170                        "encoder <encode> function pointer empty.");
171   ret = encoder_class->encode(encoder, raw_pic, coded_pics);
172   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
173                        ret,
174                        "encoder <encode> failed.");
175   if (priv->state < VAAPI_ENC_ENCODING) {
176     priv->state = VAAPI_ENC_ENCODING;
177   }
178 end:
179   return ret;
180 }
181
182 EncoderStatus
183 gst_vaapi_encoder_get_codec_data(
184     GstVaapiEncoder* encoder,
185     GstBuffer **codec_data
186 )
187 {
188   EncoderStatus ret = ENCODER_NO_ERROR;
189   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
190   GstVaapiEncoderPrivate *priv = encoder->priv;
191
192   ENCODER_CHECK_STATUS(priv->state >= VAAPI_ENC_OPENED,
193                        ENCODER_STATE_ERR,
194                        "encoder was not opened before <get_codec_data>.");
195   if (!encoder_class->get_codec_data) {
196     *codec_data = NULL;
197     ENCODER_LOG_INFO("There's no codec_data");
198     return ret;
199   }
200   ret = encoder_class->get_codec_data(encoder, codec_data);
201
202 end:
203   return ret;
204 }
205
206 EncoderStatus
207 gst_vaapi_encoder_flush(
208     GstVaapiEncoder* encoder,
209     GList **coded_pics
210 )
211 {
212   EncoderStatus ret = ENCODER_NO_ERROR;
213   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
214   GstVaapiEncoderPrivate *priv = encoder->priv;
215
216   if (priv->state < VAAPI_ENC_OPENED) {
217     return ENCODER_STATE_ERR;
218   }
219   ENCODER_CHECK_STATUS(encoder_class->flush,
220                        ENCODER_FUNC_PTR_ERR,
221                        "encoder <flush> function pointer empty.");
222   ret = encoder_class->flush(encoder, coded_pics);
223   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
224                        ret,
225                        "encoder <flush> failed.");
226   if (priv->state > VAAPI_ENC_OPENED) {
227     priv->state = VAAPI_ENC_OPENED;
228   }
229 end:
230   return ret;
231 }
232
233 EncoderStatus
234 gst_vaapi_encoder_close(GstVaapiEncoder* encoder)
235 {
236   EncoderStatus ret = ENCODER_NO_ERROR;
237   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
238   GstVaapiEncoderPrivate *priv = encoder->priv;
239
240   if (VAAPI_ENC_INIT >= priv->state) {
241     return ENCODER_NO_ERROR;
242   }
243   ENCODER_CHECK_STATUS(encoder_class->close,
244                        ENCODER_FUNC_PTR_ERR,
245                        "encoder <close> function pointers empty.");
246   ret = encoder_class->close(encoder);
247   ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
248                        ret,
249                        "encoder <close> failed.");
250 end:
251   if (priv->context) {
252     g_object_unref(priv->context);
253     priv->context = NULL;
254     priv->va_context = VA_INVALID_ID;
255   }
256
257   priv->state = VAAPI_ENC_INIT;
258   return ret;
259 }
260
261 EncoderStatus
262 gst_vaapi_encoder_uninitialize(GstVaapiEncoder* encoder)
263 {
264   EncoderStatus ret = ENCODER_NO_ERROR;
265   GstVaapiEncoderClass *encoder_class = GST_VAAPI_ENCODER_GET_CLASS(encoder);
266   GstVaapiEncoderPrivate *priv = encoder->priv;
267
268   if (VAAPI_ENC_NULL == priv->state) {
269     return ENCODER_NO_ERROR;
270   }
271
272   if (VAAPI_ENC_INIT < priv->state) {
273     ret = gst_vaapi_encoder_close(encoder);
274   }
275   ENCODER_ASSERT(VAAPI_ENC_INIT == priv->state);
276   if (encoder_class->uninitialize) {
277     ret = encoder_class->uninitialize(encoder);
278     ENCODER_CHECK_STATUS(ENCODER_NO_ERROR == ret,
279                          ret,
280                          "encoder <uninitialize> failed.");
281   }
282
283 end:
284   if (priv->display) {
285     g_object_unref(priv->display);
286     priv->display = NULL;
287     priv->va_display = NULL;
288   }
289   priv->state = VAAPI_ENC_NULL;
290   return ret;
291
292 }
293
294 char *
295 vaapi_encoder_dump_bytes(const guint8 *buf, guint32 num)
296 {
297   static char tmp[1024];
298   guint32 i = 0;
299   memset(tmp, 0, sizeof(tmp));
300
301   char *p = tmp;
302   for (i = 0; i < num; i++) {
303     snprintf(p, 1024-(p-tmp), "%02x", (guint8)buf[i]);
304     p += strlen(p);
305   }
306   return tmp;
307 }
308
309 static void
310 gst_vaapi_encoder_init(GstVaapiEncoder *encoder)
311 {
312   GstVaapiEncoderPrivate *priv;
313
314   encoder->priv = GST_VAAPI_ENCODER_GET_PRIVATE(encoder);
315   priv = encoder->priv;
316   ENCODER_ASSERT(priv);
317
318   priv->display = NULL;
319   priv->va_display = NULL;
320   priv->context = NULL;
321   priv->va_context = VA_INVALID_ID;
322   priv->state = VAAPI_ENC_NULL;
323
324   encoder->width = 0;
325   encoder->height = 0;
326   encoder->frame_rate = 0;
327   encoder->rate_control = GST_VAAPI_RATECONTROL_NONE;
328 }
329
330 static void
331 gst_vaapi_encoder_finalize(GObject *object)
332 {
333   GstVaapiEncoder* encoder = GST_VAAPI_ENCODER(object);
334   GstVaapiEncoderPrivate *priv = encoder->priv;
335   if (VAAPI_ENC_NULL != priv->state) {
336     gst_vaapi_encoder_uninitialize(encoder);
337   }
338
339   if (priv->context) {
340     g_object_unref(priv->context);
341     priv->context = NULL;
342     priv->va_context = VA_INVALID_ID;
343   }
344
345   if (priv->display) {
346     g_object_unref(priv->display);
347     priv->display = NULL;
348     priv->va_display = NULL;
349   }
350
351   G_OBJECT_CLASS (gst_vaapi_encoder_parent_class)->finalize (object);
352 }
353
354 static void
355 gst_vaapi_encoder_class_init(GstVaapiEncoderClass *kclass)
356 {
357   GObjectClass * const object_class = G_OBJECT_CLASS(kclass);
358   g_type_class_add_private(kclass, sizeof(GstVaapiEncoderPrivate));
359
360
361   GST_DEBUG_CATEGORY_INIT (gst_vaapi_encoder_debug,
362                            "gst_va_encoder",
363                            0,
364                            "gst_va_encoder element");
365
366   object_class->finalize = gst_vaapi_encoder_finalize;
367 }