61f063a625b6960c528e8632227234d08989aa84
[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   if (!klass->reordering || !klass->encode)
265     goto error;
266
267 again:
268   picture = NULL;
269   sync_pic = NULL;
270   ret = klass->reordering (encoder, frame, FALSE, &picture);
271
272   if (ret == GST_VAAPI_ENCODER_STATUS_FRAME_NOT_READY)
273     return GST_VAAPI_ENCODER_STATUS_SUCCESS;
274
275   g_assert (picture);
276   if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
277     goto error;
278   if (!picture) {
279     ret = GST_VAAPI_ENCODER_STATUS_PICTURE_ERR;
280     goto error;
281   }
282
283   coded_buf = gst_vaapi_encoder_create_coded_buffer (encoder);
284   if (!coded_buf) {
285     ret = GST_VAAPI_ENCODER_STATUS_OBJECT_ERR;
286     goto error;
287   }
288
289   ret = klass->encode (encoder, picture, coded_buf);
290   if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
291     goto error;
292
293   /* another thread would sync and get coded buffer */
294   sync_pic = _create_sync_picture (picture, coded_buf);
295   gst_vaapi_coded_buffer_proxy_replace (&coded_buf, NULL);
296   gst_vaapi_enc_picture_replace (&picture, NULL);
297
298   if (!gst_vaapi_encoder_push_sync_picture (encoder, sync_pic)) {
299     ret = GST_VAAPI_ENCODER_STATUS_THREAD_ERR;
300     goto error;
301   }
302
303   frame = NULL;
304   goto again;
305
306 error:
307   gst_vaapi_enc_picture_replace (&picture, NULL);
308   gst_vaapi_coded_buffer_proxy_replace (&coded_buf, NULL);
309   if (sync_pic)
310     _free_sync_picture (encoder, sync_pic);
311   GST_ERROR ("encoding failed, error:%d", ret);
312   return ret;
313 }
314
315 GstVaapiEncoderStatus
316 gst_vaapi_encoder_get_buffer (GstVaapiEncoder * encoder,
317     GstVideoCodecFrame ** frame,
318     GstVaapiCodedBufferProxy ** codedbuf, gint64 us_of_timeout)
319 {
320   GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
321   GstVaapiEncoderSyncPic *sync_pic = NULL;
322   GstVaapiSurfaceStatus surface_status;
323   GstVaapiEncPicture *picture;
324
325   ret = gst_vaapi_encoder_pop_sync_picture (encoder, &sync_pic, us_of_timeout);
326   if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
327     goto end;
328
329   picture = sync_pic->picture;
330
331   if (!picture->surface || !gst_vaapi_surface_sync (picture->surface)) {
332     ret = GST_VAAPI_ENCODER_STATUS_PARAM_ERR;
333     goto end;
334   }
335   if (!gst_vaapi_surface_query_status (picture->surface, &surface_status)) {
336     ret = GST_VAAPI_ENCODER_STATUS_PICTURE_ERR;
337     goto end;
338   }
339   if (frame)
340     *frame = gst_video_codec_frame_ref (picture->frame);
341   if (codedbuf)
342     *codedbuf = gst_vaapi_coded_buffer_proxy_ref (sync_pic->buf);
343
344 end:
345   if (sync_pic)
346     _free_sync_picture (encoder, sync_pic);
347   return ret;
348 }
349
350 GstVaapiEncoderStatus
351 gst_vaapi_encoder_flush (GstVaapiEncoder * encoder)
352 {
353   GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
354   GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
355
356   if (!klass->flush)
357     goto error;
358
359   ret = klass->flush (encoder);
360   return ret;
361
362 error:
363   GST_ERROR ("flush failed");
364   return GST_VAAPI_ENCODER_STATUS_FUNC_PTR_ERR;
365 }
366
367 GstVaapiEncoderStatus
368 gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder,
369     GstBuffer ** codec_data)
370 {
371   GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
372   GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
373
374   *codec_data = NULL;
375   if (!klass->get_codec_data)
376     return GST_VAAPI_ENCODER_STATUS_SUCCESS;
377
378   ret = klass->get_codec_data (encoder, codec_data);
379   return ret;
380 }
381
382 static gboolean
383 gst_vaapi_encoder_ensure_context (GstVaapiEncoder * encoder)
384 {
385   GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
386   GstVaapiContextInfo info;
387   GstVaapiContext *context;
388
389   if (GST_VAAPI_ENCODER_CONTEXT (encoder))
390     return TRUE;
391
392   memset (&info, 0, sizeof (info));
393   if (!klass->get_context_info || !klass->get_context_info (encoder, &info)) {
394     return FALSE;
395   }
396
397   context = gst_vaapi_context_new_full (GST_VAAPI_ENCODER_DISPLAY (encoder),
398       &info);
399   if (!context)
400     return FALSE;
401
402   GST_VAAPI_ENCODER_CONTEXT (encoder) = context;
403   GST_VAAPI_ENCODER_VA_CONTEXT (encoder) = gst_vaapi_context_get_id (context);
404   return TRUE;
405 }
406
407 GstCaps *
408 gst_vaapi_encoder_set_format (GstVaapiEncoder * encoder,
409     GstVideoCodecState * in_state, GstCaps * ref_caps)
410 {
411   GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
412   GstCaps *out_caps = NULL;
413
414   if (!GST_VIDEO_INFO_WIDTH (&in_state->info) ||
415       !GST_VIDEO_INFO_HEIGHT (&in_state->info)) {
416     GST_WARNING ("encoder set format failed, width or height equal to 0.");
417     return NULL;
418   }
419   GST_VAAPI_ENCODER_VIDEO_INFO (encoder) = in_state->info;
420
421   if (!klass->set_format)
422     goto error;
423
424   out_caps = klass->set_format (encoder, in_state, ref_caps);
425   if (!out_caps)
426     goto error;
427
428   if (GST_VAAPI_ENCODER_CAPS (encoder) &&
429       gst_caps_is_equal (out_caps, GST_VAAPI_ENCODER_CAPS (encoder))) {
430     gst_caps_unref (out_caps);
431     return GST_VAAPI_ENCODER_CAPS (encoder);
432   }
433   gst_caps_replace (&GST_VAAPI_ENCODER_CAPS (encoder), out_caps);
434   g_assert (GST_VAAPI_ENCODER_CONTEXT (encoder) == NULL);
435   gst_vaapi_object_replace (&GST_VAAPI_ENCODER_CONTEXT (encoder), NULL);
436
437   if (!gst_vaapi_encoder_ensure_context (encoder))
438     goto error;
439
440   encoder->codedbuf_size = (GST_VAAPI_ENCODER_WIDTH (encoder) *
441       GST_VAAPI_ENCODER_HEIGHT (encoder) * 400) / (16 * 16);
442
443   encoder->codedbuf_pool = gst_vaapi_coded_buffer_pool_new (encoder,
444       encoder->codedbuf_size);
445   if (!encoder->codedbuf_pool) {
446     GST_ERROR ("failed to initialized coded buffer pool");
447     goto error;
448   }
449   gst_vaapi_video_pool_set_capacity (encoder->codedbuf_pool, 5);
450
451   return out_caps;
452
453 error:
454   gst_caps_replace (&GST_VAAPI_ENCODER_CAPS (encoder), NULL);
455   gst_caps_replace (&out_caps, NULL);
456   GST_ERROR ("encoder set format failed");
457   return NULL;
458 }
459
460 static gboolean
461 gst_vaapi_encoder_init (GstVaapiEncoder * encoder, GstVaapiDisplay * display)
462 {
463   GstVaapiEncoderClass *kclass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
464
465   g_assert (kclass);
466   g_assert (display);
467
468   g_return_val_if_fail (display, FALSE);
469   g_return_val_if_fail (encoder->display == NULL, FALSE);
470
471   encoder->display = gst_vaapi_display_ref (display);
472   encoder->va_display = gst_vaapi_display_get_display (display);
473   encoder->context = NULL;
474   encoder->va_context = VA_INVALID_ID;
475   encoder->caps = NULL;
476
477   gst_video_info_init (&encoder->video_info);
478
479   g_mutex_init (&encoder->lock);
480   g_cond_init (&encoder->codedbuf_free);
481   g_cond_init (&encoder->surface_free);
482   g_queue_init (&encoder->sync_pictures);
483   g_cond_init (&encoder->sync_ready);
484
485   if (kclass->init)
486     return kclass->init (encoder);
487   return TRUE;
488 }
489
490 static void
491 gst_vaapi_encoder_destroy (GstVaapiEncoder * encoder)
492 {
493   GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
494
495   if (klass->destroy)
496     klass->destroy (encoder);
497
498   gst_vaapi_encoder_free_sync_pictures (encoder);
499   gst_vaapi_video_pool_replace (&encoder->codedbuf_pool, NULL);
500
501   gst_vaapi_object_replace (&encoder->context, NULL);
502   gst_vaapi_display_replace (&encoder->display, NULL);
503   encoder->va_display = NULL;
504   g_mutex_clear (&encoder->lock);
505   g_cond_clear (&encoder->codedbuf_free);
506   g_cond_clear (&encoder->surface_free);
507   g_queue_clear (&encoder->sync_pictures);
508   g_cond_clear (&encoder->sync_ready);
509 }
510
511 void
512 gst_vaapi_encoder_finalize (GstVaapiEncoder * encoder)
513 {
514   gst_vaapi_encoder_destroy (encoder);
515 }
516
517 void
518 gst_vaapi_encoder_class_init (GstVaapiEncoderClass * klass)
519 {
520   GstVaapiMiniObjectClass *const object_class =
521       GST_VAAPI_MINI_OBJECT_CLASS (klass);
522
523   object_class->size = sizeof (GstVaapiEncoder);
524   object_class->finalize = (GDestroyNotify) gst_vaapi_encoder_finalize;
525 }
526
527 GstVaapiEncoder *
528 gst_vaapi_encoder_new (const GstVaapiEncoderClass * klass,
529     GstVaapiDisplay * display)
530 {
531   GstVaapiEncoder *encoder;
532
533   encoder = (GstVaapiEncoder *)
534       gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS (klass));
535   if (!encoder)
536     return NULL;
537
538   if (!gst_vaapi_encoder_init (encoder, display))
539     goto error;
540   return encoder;
541
542 error:
543   gst_vaapi_encoder_unref (encoder);
544   return NULL;
545 }