encoder: fix subclassing process.
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapiencoder.c
1 /*
2  *  gstvaapiencoder.c - VA encoder abstraction
3  *
4  *  Copyright (C) 2013 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 #include "sysdeps.h"
22 #include "gstvaapicompat.h"
23 #include "gstvaapiencoder.h"
24 #include "gstvaapiencoder_priv.h"
25 #include "gstvaapicontext.h"
26 #include "gstvaapidisplay_priv.h"
27
28 #define DEBUG 1
29 #include "gstvaapidebug.h"
30
31 #define GST_VAAPI_ENCODER_LOCK(encoder)                         \
32   G_STMT_START {                                                \
33     g_mutex_lock (&(GST_VAAPI_ENCODER_CAST(encoder))->lock);    \
34   } G_STMT_END
35
36 #define GST_VAAPI_ENCODER_UNLOCK(encoder)                               \
37   G_STMT_START {                                                        \
38     g_mutex_unlock (&(GST_VAAPI_ENCODER_CAST(encoder))->lock);          \
39   } G_STMT_END
40
41 #define GST_VAAPI_ENCODER_BUF_FREE_WAIT(encoder)                        \
42   G_STMT_START {                                                        \
43     g_cond_wait (&(GST_VAAPI_ENCODER_CAST(encoder))->codedbuf_free,     \
44                  &(GST_VAAPI_ENCODER_CAST(encoder))->lock);             \
45   } G_STMT_END
46
47 #define GST_VAAPI_ENCODER_BUF_FREE_SIGNAL(encoder)                      \
48   G_STMT_START {                                                        \
49     g_cond_signal (&(GST_VAAPI_ENCODER_CAST(encoder))->codedbuf_free);  \
50   } G_STMT_END
51
52 #define GST_VAAPI_ENCODER_FREE_SURFACE_WAIT(encoder)                    \
53   G_STMT_START {                                                        \
54     g_cond_wait (&(GST_VAAPI_ENCODER_CAST(encoder))->surface_free,      \
55                  &(GST_VAAPI_ENCODER_CAST(encoder))->lock);             \
56   } G_STMT_END
57
58 #define GST_VAAPI_ENCODER_FREE_SURFACE_SIGNAL(encoder)                  \
59   G_STMT_START {                                                        \
60     g_cond_signal (&(GST_VAAPI_ENCODER_CAST(encoder))->surface_free);   \
61   } G_STMT_END
62
63 #define GST_VAAPI_ENCODER_SYNC_SIGNAL(encoder)                          \
64   G_STMT_START {                                                        \
65     g_cond_signal (&(GST_VAAPI_ENCODER_CAST(encoder))->sync_ready);     \
66   } G_STMT_END
67
68 static inline gboolean
69 GST_VAAPI_ENCODER_SYNC_WAIT_TIMEOUT (GstVaapiEncoder * encoder, gint64 timeout)
70 {
71   gint64 end_time = g_get_monotonic_time () + timeout;
72   return g_cond_wait_until (&encoder->sync_ready, &encoder->lock, end_time);
73 }
74
75 typedef struct
76 {
77   GstVaapiEncPicture *picture;
78   GstVaapiCodedBufferProxy *buf;
79 } GstVaapiEncoderSyncPic;
80
81 GstVaapiEncoder *
82 gst_vaapi_encoder_ref (GstVaapiEncoder * encoder)
83 {
84   return gst_vaapi_object_ref (encoder);
85 }
86
87 void
88 gst_vaapi_encoder_unref (GstVaapiEncoder * encoder)
89 {
90   gst_vaapi_object_unref (encoder);
91 }
92
93 void
94 gst_vaapi_encoder_replace (GstVaapiEncoder ** old_encoder_ptr,
95     GstVaapiEncoder * new_encoder)
96 {
97   gst_vaapi_object_replace (old_encoder_ptr, new_encoder);
98 }
99
100 static void
101 _coded_buffer_proxy_released_notify (GstVaapiEncoder * encoder)
102 {
103   GST_VAAPI_ENCODER_LOCK (encoder);
104   GST_VAAPI_ENCODER_BUF_FREE_SIGNAL (encoder);
105   GST_VAAPI_ENCODER_UNLOCK (encoder);
106 }
107
108 static GstVaapiCodedBufferProxy *
109 gst_vaapi_encoder_create_coded_buffer (GstVaapiEncoder * encoder)
110 {
111   GstVaapiCodedBufferPool *const pool =
112     GST_VAAPI_CODED_BUFFER_POOL (encoder->codedbuf_pool);
113   GstVaapiCodedBufferProxy *codedbuf_proxy;
114
115   GST_VAAPI_ENCODER_LOCK (encoder);
116   do {
117     codedbuf_proxy = gst_vaapi_coded_buffer_proxy_new_from_pool (pool);
118     if (codedbuf_proxy)
119       break;
120
121     /* Wait for a free coded buffer to become available */
122     GST_VAAPI_ENCODER_BUF_FREE_WAIT (encoder);
123     codedbuf_proxy = gst_vaapi_coded_buffer_proxy_new_from_pool (pool);
124   } while (0);
125   GST_VAAPI_ENCODER_UNLOCK (encoder);
126   if (!codedbuf_proxy)
127     return NULL;
128
129   gst_vaapi_coded_buffer_proxy_set_destroy_notify (codedbuf_proxy,
130       (GDestroyNotify)_coded_buffer_proxy_released_notify, encoder);
131   return codedbuf_proxy;
132 }
133
134 static void
135 _surface_proxy_released_notify (GstVaapiEncoder * encoder)
136 {
137   GST_VAAPI_ENCODER_FREE_SURFACE_SIGNAL (encoder);
138 }
139
140 GstVaapiSurfaceProxy *
141 gst_vaapi_encoder_create_surface (GstVaapiEncoder * encoder)
142 {
143   GstVaapiSurfaceProxy *proxy;
144
145   g_assert (encoder && encoder->context);
146   g_return_val_if_fail (encoder->context, NULL);
147
148   GST_VAAPI_ENCODER_LOCK (encoder);
149   while (!gst_vaapi_context_get_surface_count (encoder->context)) {
150     GST_VAAPI_ENCODER_FREE_SURFACE_WAIT (encoder);
151   }
152   proxy = gst_vaapi_context_get_surface_proxy (encoder->context);
153   GST_VAAPI_ENCODER_UNLOCK (encoder);
154
155   gst_vaapi_surface_proxy_set_destroy_notify (proxy,
156       (GDestroyNotify) _surface_proxy_released_notify, encoder);
157
158   return proxy;
159 }
160
161 void
162 gst_vaapi_encoder_release_surface (GstVaapiEncoder * encoder,
163     GstVaapiSurfaceProxy * surface)
164 {
165   GST_VAAPI_ENCODER_LOCK (encoder);
166   gst_vaapi_surface_proxy_unref (surface);
167   GST_VAAPI_ENCODER_UNLOCK (encoder);
168 }
169
170 static GstVaapiEncoderSyncPic *
171 _create_sync_picture (GstVaapiEncPicture * picture,
172     GstVaapiCodedBufferProxy * coded_buf)
173 {
174   GstVaapiEncoderSyncPic *sync = g_slice_new0 (GstVaapiEncoderSyncPic);
175
176   g_assert (picture && coded_buf);
177   sync->picture = gst_vaapi_enc_picture_ref (picture);
178   sync->buf = gst_vaapi_coded_buffer_proxy_ref (coded_buf);
179   return sync;
180 }
181
182 static void
183 _free_sync_picture (GstVaapiEncoder * encoder,
184     GstVaapiEncoderSyncPic * sync_pic)
185 {
186   g_assert (sync_pic);
187
188   if (sync_pic->picture)
189     gst_vaapi_enc_picture_unref (sync_pic->picture);
190   if (sync_pic->buf)
191     gst_vaapi_coded_buffer_proxy_unref (sync_pic->buf);
192   g_slice_free (GstVaapiEncoderSyncPic, sync_pic);
193 }
194
195 static void
196 gst_vaapi_encoder_free_sync_pictures (GstVaapiEncoder * encoder)
197 {
198   GstVaapiEncoderSyncPic *sync;
199
200   GST_VAAPI_ENCODER_LOCK (encoder);
201   while (!g_queue_is_empty (&encoder->sync_pictures)) {
202     sync =
203         (GstVaapiEncoderSyncPic *) g_queue_pop_head (&encoder->sync_pictures);
204     GST_VAAPI_ENCODER_UNLOCK (encoder);
205     _free_sync_picture (encoder, sync);
206     GST_VAAPI_ENCODER_LOCK (encoder);
207   }
208   GST_VAAPI_ENCODER_UNLOCK (encoder);
209 }
210
211 static gboolean
212 gst_vaapi_encoder_push_sync_picture (GstVaapiEncoder * encoder,
213     GstVaapiEncoderSyncPic * sync_pic)
214 {
215   GST_VAAPI_ENCODER_LOCK (encoder);
216   g_queue_push_tail (&encoder->sync_pictures, sync_pic);
217   GST_VAAPI_ENCODER_SYNC_SIGNAL (encoder);
218   GST_VAAPI_ENCODER_UNLOCK (encoder);
219   return TRUE;
220 }
221
222 static GstVaapiEncoderStatus
223 gst_vaapi_encoder_pop_sync_picture (GstVaapiEncoder * encoder,
224     GstVaapiEncoderSyncPic ** sync_pic, guint64 timeout)
225 {
226   GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
227
228   *sync_pic = NULL;
229
230   GST_VAAPI_ENCODER_LOCK (encoder);
231   if (g_queue_is_empty (&encoder->sync_pictures) &&
232       !GST_VAAPI_ENCODER_SYNC_WAIT_TIMEOUT (encoder, timeout))
233     goto timeout;
234
235   if (g_queue_is_empty (&encoder->sync_pictures)) {
236     ret = GST_VAAPI_ENCODER_STATUS_UNKNOWN_ERR;
237     goto end;
238   }
239
240   *sync_pic =
241       (GstVaapiEncoderSyncPic *) g_queue_pop_head (&encoder->sync_pictures);
242   g_assert (*sync_pic);
243   ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
244   goto end;
245
246 timeout:
247   ret = GST_VAAPI_ENCODER_STATUS_TIMEOUT;
248
249 end:
250   GST_VAAPI_ENCODER_UNLOCK (encoder);
251   return ret;
252 }
253
254 GstVaapiEncoderStatus
255 gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder,
256     GstVideoCodecFrame * frame)
257 {
258   GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
259   GstVaapiEncoderClass *klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
260   GstVaapiEncPicture *picture = NULL;
261   GstVaapiCodedBufferProxy *coded_buf = NULL;
262   GstVaapiEncoderSyncPic *sync_pic = NULL;
263
264 again:
265   picture = NULL;
266   sync_pic = NULL;
267   ret = klass->reordering (encoder, frame, FALSE, &picture);
268
269   if (ret == GST_VAAPI_ENCODER_STATUS_FRAME_NOT_READY)
270     return GST_VAAPI_ENCODER_STATUS_SUCCESS;
271
272   g_assert (picture);
273   if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
274     goto error;
275   if (!picture) {
276     ret = GST_VAAPI_ENCODER_STATUS_PICTURE_ERR;
277     goto error;
278   }
279
280   coded_buf = gst_vaapi_encoder_create_coded_buffer (encoder);
281   if (!coded_buf) {
282     ret = GST_VAAPI_ENCODER_STATUS_OBJECT_ERR;
283     goto error;
284   }
285
286   ret = klass->encode (encoder, picture, coded_buf);
287   if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
288     goto error;
289
290   /* another thread would sync and get coded buffer */
291   sync_pic = _create_sync_picture (picture, coded_buf);
292   gst_vaapi_coded_buffer_proxy_replace (&coded_buf, NULL);
293   gst_vaapi_enc_picture_replace (&picture, NULL);
294
295   if (!gst_vaapi_encoder_push_sync_picture (encoder, sync_pic)) {
296     ret = GST_VAAPI_ENCODER_STATUS_THREAD_ERR;
297     goto error;
298   }
299
300   frame = NULL;
301   goto again;
302
303 error:
304   gst_vaapi_enc_picture_replace (&picture, NULL);
305   gst_vaapi_coded_buffer_proxy_replace (&coded_buf, NULL);
306   if (sync_pic)
307     _free_sync_picture (encoder, sync_pic);
308   GST_ERROR ("encoding failed, error:%d", ret);
309   return ret;
310 }
311
312 GstVaapiEncoderStatus
313 gst_vaapi_encoder_get_buffer (GstVaapiEncoder * encoder,
314     GstVideoCodecFrame ** frame,
315     GstVaapiCodedBufferProxy ** codedbuf, gint64 us_of_timeout)
316 {
317   GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
318   GstVaapiEncoderSyncPic *sync_pic = NULL;
319   GstVaapiSurfaceStatus surface_status;
320   GstVaapiEncPicture *picture;
321
322   ret = gst_vaapi_encoder_pop_sync_picture (encoder, &sync_pic, us_of_timeout);
323   if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
324     goto end;
325
326   picture = sync_pic->picture;
327
328   if (!picture->surface || !gst_vaapi_surface_sync (picture->surface)) {
329     ret = GST_VAAPI_ENCODER_STATUS_PARAM_ERR;
330     goto end;
331   }
332   if (!gst_vaapi_surface_query_status (picture->surface, &surface_status)) {
333     ret = GST_VAAPI_ENCODER_STATUS_PICTURE_ERR;
334     goto end;
335   }
336   if (frame)
337     *frame = gst_video_codec_frame_ref (picture->frame);
338   if (codedbuf)
339     *codedbuf = gst_vaapi_coded_buffer_proxy_ref (sync_pic->buf);
340
341 end:
342   if (sync_pic)
343     _free_sync_picture (encoder, sync_pic);
344   return ret;
345 }
346
347 GstVaapiEncoderStatus
348 gst_vaapi_encoder_flush (GstVaapiEncoder * encoder)
349 {
350   GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
351
352   return klass->flush (encoder);
353 }
354
355 GstVaapiEncoderStatus
356 gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder,
357     GstBuffer ** codec_data)
358 {
359   GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
360   GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
361
362   *codec_data = NULL;
363   if (!klass->get_codec_data)
364     return GST_VAAPI_ENCODER_STATUS_SUCCESS;
365
366   ret = klass->get_codec_data (encoder, codec_data);
367   return ret;
368 }
369
370 static gboolean
371 gst_vaapi_encoder_ensure_context (GstVaapiEncoder * encoder)
372 {
373   GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
374   GstVaapiContextInfo info;
375   GstVaapiContext *context;
376
377   if (GST_VAAPI_ENCODER_CONTEXT (encoder))
378     return TRUE;
379
380   memset (&info, 0, sizeof (info));
381   if (!klass->get_context_info (encoder, &info))
382     return FALSE;
383
384   context = gst_vaapi_context_new_full (GST_VAAPI_ENCODER_DISPLAY (encoder),
385       &info);
386   if (!context)
387     return FALSE;
388
389   GST_VAAPI_ENCODER_CONTEXT (encoder) = context;
390   GST_VAAPI_ENCODER_VA_CONTEXT (encoder) = gst_vaapi_context_get_id (context);
391   return TRUE;
392 }
393
394 GstCaps *
395 gst_vaapi_encoder_set_format (GstVaapiEncoder * encoder,
396     GstVideoCodecState * in_state, GstCaps * ref_caps)
397 {
398   GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
399   GstCaps *out_caps = NULL;
400
401   if (!GST_VIDEO_INFO_WIDTH (&in_state->info) ||
402       !GST_VIDEO_INFO_HEIGHT (&in_state->info)) {
403     GST_WARNING ("encoder set format failed, width or height equal to 0.");
404     return NULL;
405   }
406   GST_VAAPI_ENCODER_VIDEO_INFO (encoder) = in_state->info;
407
408   out_caps = klass->set_format (encoder, in_state, ref_caps);
409   if (!out_caps)
410     goto error;
411
412   if (GST_VAAPI_ENCODER_CAPS (encoder) &&
413       gst_caps_is_equal (out_caps, GST_VAAPI_ENCODER_CAPS (encoder))) {
414     gst_caps_unref (out_caps);
415     return GST_VAAPI_ENCODER_CAPS (encoder);
416   }
417   gst_caps_replace (&GST_VAAPI_ENCODER_CAPS (encoder), out_caps);
418   g_assert (GST_VAAPI_ENCODER_CONTEXT (encoder) == NULL);
419   gst_vaapi_object_replace (&GST_VAAPI_ENCODER_CONTEXT (encoder), NULL);
420
421   if (!gst_vaapi_encoder_ensure_context (encoder))
422     goto error;
423
424   encoder->codedbuf_size = (GST_VAAPI_ENCODER_WIDTH (encoder) *
425       GST_VAAPI_ENCODER_HEIGHT (encoder) * 400) / (16 * 16);
426
427   encoder->codedbuf_pool = gst_vaapi_coded_buffer_pool_new (encoder,
428       encoder->codedbuf_size);
429   if (!encoder->codedbuf_pool) {
430     GST_ERROR ("failed to initialized coded buffer pool");
431     goto error;
432   }
433   gst_vaapi_video_pool_set_capacity (encoder->codedbuf_pool, 5);
434
435   return out_caps;
436
437 error:
438   gst_caps_replace (&GST_VAAPI_ENCODER_CAPS (encoder), NULL);
439   gst_caps_replace (&out_caps, NULL);
440   GST_ERROR ("encoder set format failed");
441   return NULL;
442 }
443
444 static gboolean
445 gst_vaapi_encoder_init (GstVaapiEncoder * encoder, GstVaapiDisplay * display)
446 {
447   GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
448
449   g_return_val_if_fail (display != NULL, FALSE);
450
451 #define CHECK_VTABLE_HOOK(FUNC) do {            \
452     if (!klass->FUNC)                           \
453       goto error_invalid_vtable;                \
454   } while (0)
455
456   CHECK_VTABLE_HOOK (init);
457   CHECK_VTABLE_HOOK (finalize);
458   CHECK_VTABLE_HOOK (encode);
459   CHECK_VTABLE_HOOK (reordering);
460   CHECK_VTABLE_HOOK (flush);
461   CHECK_VTABLE_HOOK (get_context_info);
462   CHECK_VTABLE_HOOK (set_format);
463
464 #undef CHECK_VTABLE_HOOK
465
466   encoder->display = gst_vaapi_display_ref (display);
467   encoder->va_display = gst_vaapi_display_get_display (display);
468   encoder->va_context = VA_INVALID_ID;
469
470   gst_video_info_init (&encoder->video_info);
471
472   g_mutex_init (&encoder->lock);
473   g_cond_init (&encoder->codedbuf_free);
474   g_cond_init (&encoder->surface_free);
475   g_queue_init (&encoder->sync_pictures);
476   g_cond_init (&encoder->sync_ready);
477
478   return klass->init (encoder);
479
480   /* ERRORS */
481 error_invalid_vtable:
482   {
483     GST_ERROR ("invalid subclass hook (internal error)");
484     return FALSE;
485   }
486 }
487
488 void
489 gst_vaapi_encoder_finalize (GstVaapiEncoder * encoder)
490 {
491   GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
492
493   klass->finalize (encoder);
494
495   gst_vaapi_encoder_free_sync_pictures (encoder);
496   gst_vaapi_video_pool_replace (&encoder->codedbuf_pool, NULL);
497
498   gst_vaapi_object_replace (&encoder->context, NULL);
499   gst_vaapi_display_replace (&encoder->display, NULL);
500   encoder->va_display = NULL;
501   g_mutex_clear (&encoder->lock);
502   g_cond_clear (&encoder->codedbuf_free);
503   g_cond_clear (&encoder->surface_free);
504   g_queue_clear (&encoder->sync_pictures);
505   g_cond_clear (&encoder->sync_ready);
506 }
507
508 GstVaapiEncoder *
509 gst_vaapi_encoder_new (const GstVaapiEncoderClass * klass,
510     GstVaapiDisplay * display)
511 {
512   GstVaapiEncoder *encoder;
513
514   encoder = (GstVaapiEncoder *)
515       gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS (klass));
516   if (!encoder)
517     return NULL;
518
519   if (!gst_vaapi_encoder_init (encoder, display))
520     goto error;
521   return encoder;
522
523 error:
524   gst_vaapi_encoder_unref (encoder);
525   return NULL;
526 }