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