2 * gstvaapiencoder.c - VA encoder abstraction
4 * Copyright (C) 2013 Intel Corporation
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.
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.
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
22 #include "gstvaapicompat.h"
23 #include "gstvaapiencoder.h"
24 #include "gstvaapiencoder_priv.h"
25 #include "gstvaapicontext.h"
26 #include "gstvaapidisplay_priv.h"
29 #include "gstvaapidebug.h"
31 #define GST_VAAPI_ENCODER_LOCK(encoder) \
33 g_mutex_lock (&(GST_VAAPI_ENCODER_CAST(encoder))->lock); \
36 #define GST_VAAPI_ENCODER_UNLOCK(encoder) \
38 g_mutex_unlock (&(GST_VAAPI_ENCODER_CAST(encoder))->lock); \
41 #define GST_VAAPI_ENCODER_BUF_FREE_WAIT(encoder) \
43 g_cond_wait (&(GST_VAAPI_ENCODER_CAST(encoder))->codedbuf_free, \
44 &(GST_VAAPI_ENCODER_CAST(encoder))->lock); \
47 #define GST_VAAPI_ENCODER_BUF_FREE_SIGNAL(encoder) \
49 g_cond_signal (&(GST_VAAPI_ENCODER_CAST(encoder))->codedbuf_free); \
52 #define GST_VAAPI_ENCODER_FREE_SURFACE_WAIT(encoder) \
54 g_cond_wait (&(GST_VAAPI_ENCODER_CAST(encoder))->surface_free, \
55 &(GST_VAAPI_ENCODER_CAST(encoder))->lock); \
58 #define GST_VAAPI_ENCODER_FREE_SURFACE_SIGNAL(encoder) \
60 g_cond_signal (&(GST_VAAPI_ENCODER_CAST(encoder))->surface_free); \
63 #define GST_VAAPI_ENCODER_SYNC_SIGNAL(encoder) \
65 g_cond_signal (&(GST_VAAPI_ENCODER_CAST(encoder))->sync_ready); \
68 static inline gboolean
69 GST_VAAPI_ENCODER_SYNC_WAIT_TIMEOUT (GstVaapiEncoder * encoder, gint64 timeout)
71 gint64 end_time = g_get_monotonic_time () + timeout;
72 return g_cond_wait_until (&encoder->sync_ready, &encoder->lock, end_time);
77 GstVaapiEncPicture *picture;
78 GstVaapiCodedBufferProxy *buf;
79 } GstVaapiEncoderSyncPic;
82 gst_vaapi_encoder_ref (GstVaapiEncoder * encoder)
84 return gst_vaapi_object_ref (encoder);
88 gst_vaapi_encoder_unref (GstVaapiEncoder * encoder)
90 gst_vaapi_object_unref (encoder);
94 gst_vaapi_encoder_replace (GstVaapiEncoder ** old_encoder_ptr,
95 GstVaapiEncoder * new_encoder)
97 gst_vaapi_object_replace (old_encoder_ptr, new_encoder);
101 _coded_buffer_proxy_released_notify (GstVaapiEncoder * encoder)
103 GST_VAAPI_ENCODER_LOCK (encoder);
104 GST_VAAPI_ENCODER_BUF_FREE_SIGNAL (encoder);
105 GST_VAAPI_ENCODER_UNLOCK (encoder);
108 static GstVaapiCodedBufferProxy *
109 gst_vaapi_encoder_create_coded_buffer (GstVaapiEncoder * encoder)
111 GstVaapiCodedBufferPool *const pool =
112 GST_VAAPI_CODED_BUFFER_POOL (encoder->codedbuf_pool);
113 GstVaapiCodedBufferProxy *codedbuf_proxy;
115 GST_VAAPI_ENCODER_LOCK (encoder);
117 codedbuf_proxy = gst_vaapi_coded_buffer_proxy_new_from_pool (pool);
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);
125 GST_VAAPI_ENCODER_UNLOCK (encoder);
129 gst_vaapi_coded_buffer_proxy_set_destroy_notify (codedbuf_proxy,
130 (GDestroyNotify)_coded_buffer_proxy_released_notify, encoder);
131 return codedbuf_proxy;
135 _surface_proxy_released_notify (GstVaapiEncoder * encoder)
137 GST_VAAPI_ENCODER_FREE_SURFACE_SIGNAL (encoder);
140 GstVaapiSurfaceProxy *
141 gst_vaapi_encoder_create_surface (GstVaapiEncoder * encoder)
143 GstVaapiSurfaceProxy *proxy;
145 g_assert (encoder && encoder->context);
146 g_return_val_if_fail (encoder->context, NULL);
148 GST_VAAPI_ENCODER_LOCK (encoder);
149 while (!gst_vaapi_context_get_surface_count (encoder->context)) {
150 GST_VAAPI_ENCODER_FREE_SURFACE_WAIT (encoder);
152 proxy = gst_vaapi_context_get_surface_proxy (encoder->context);
153 GST_VAAPI_ENCODER_UNLOCK (encoder);
155 gst_vaapi_surface_proxy_set_destroy_notify (proxy,
156 (GDestroyNotify) _surface_proxy_released_notify, encoder);
162 gst_vaapi_encoder_release_surface (GstVaapiEncoder * encoder,
163 GstVaapiSurfaceProxy * surface)
165 GST_VAAPI_ENCODER_LOCK (encoder);
166 gst_vaapi_surface_proxy_unref (surface);
167 GST_VAAPI_ENCODER_UNLOCK (encoder);
170 static GstVaapiEncoderSyncPic *
171 _create_sync_picture (GstVaapiEncPicture * picture,
172 GstVaapiCodedBufferProxy * coded_buf)
174 GstVaapiEncoderSyncPic *sync = g_slice_new0 (GstVaapiEncoderSyncPic);
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);
183 _free_sync_picture (GstVaapiEncoder * encoder,
184 GstVaapiEncoderSyncPic * sync_pic)
188 if (sync_pic->picture)
189 gst_vaapi_enc_picture_unref (sync_pic->picture);
191 gst_vaapi_coded_buffer_proxy_unref (sync_pic->buf);
192 g_slice_free (GstVaapiEncoderSyncPic, sync_pic);
196 gst_vaapi_encoder_free_sync_pictures (GstVaapiEncoder * encoder)
198 GstVaapiEncoderSyncPic *sync;
200 GST_VAAPI_ENCODER_LOCK (encoder);
201 while (!g_queue_is_empty (&encoder->sync_pictures)) {
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);
208 GST_VAAPI_ENCODER_UNLOCK (encoder);
212 gst_vaapi_encoder_push_sync_picture (GstVaapiEncoder * encoder,
213 GstVaapiEncoderSyncPic * sync_pic)
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);
222 static GstVaapiEncoderStatus
223 gst_vaapi_encoder_pop_sync_picture (GstVaapiEncoder * encoder,
224 GstVaapiEncoderSyncPic ** sync_pic, guint64 timeout)
226 GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
230 GST_VAAPI_ENCODER_LOCK (encoder);
231 if (g_queue_is_empty (&encoder->sync_pictures) &&
232 !GST_VAAPI_ENCODER_SYNC_WAIT_TIMEOUT (encoder, timeout))
235 if (g_queue_is_empty (&encoder->sync_pictures)) {
236 ret = GST_VAAPI_ENCODER_STATUS_UNKNOWN_ERR;
241 (GstVaapiEncoderSyncPic *) g_queue_pop_head (&encoder->sync_pictures);
242 g_assert (*sync_pic);
243 ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
247 ret = GST_VAAPI_ENCODER_STATUS_TIMEOUT;
250 GST_VAAPI_ENCODER_UNLOCK (encoder);
254 GstVaapiEncoderStatus
255 gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder,
256 GstVideoCodecFrame * frame)
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;
267 ret = klass->reordering (encoder, frame, FALSE, &picture);
269 if (ret == GST_VAAPI_ENCODER_STATUS_FRAME_NOT_READY)
270 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
273 if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
276 ret = GST_VAAPI_ENCODER_STATUS_PICTURE_ERR;
280 coded_buf = gst_vaapi_encoder_create_coded_buffer (encoder);
282 ret = GST_VAAPI_ENCODER_STATUS_OBJECT_ERR;
286 ret = klass->encode (encoder, picture, coded_buf);
287 if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
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);
295 if (!gst_vaapi_encoder_push_sync_picture (encoder, sync_pic)) {
296 ret = GST_VAAPI_ENCODER_STATUS_THREAD_ERR;
304 gst_vaapi_enc_picture_replace (&picture, NULL);
305 gst_vaapi_coded_buffer_proxy_replace (&coded_buf, NULL);
307 _free_sync_picture (encoder, sync_pic);
308 GST_ERROR ("encoding failed, error:%d", ret);
312 GstVaapiEncoderStatus
313 gst_vaapi_encoder_get_buffer (GstVaapiEncoder * encoder,
314 GstVideoCodecFrame ** frame,
315 GstVaapiCodedBufferProxy ** codedbuf, gint64 us_of_timeout)
317 GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
318 GstVaapiEncoderSyncPic *sync_pic = NULL;
319 GstVaapiSurfaceStatus surface_status;
320 GstVaapiEncPicture *picture;
322 ret = gst_vaapi_encoder_pop_sync_picture (encoder, &sync_pic, us_of_timeout);
323 if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
326 picture = sync_pic->picture;
328 if (!picture->surface || !gst_vaapi_surface_sync (picture->surface)) {
329 ret = GST_VAAPI_ENCODER_STATUS_PARAM_ERR;
332 if (!gst_vaapi_surface_query_status (picture->surface, &surface_status)) {
333 ret = GST_VAAPI_ENCODER_STATUS_PICTURE_ERR;
337 *frame = gst_video_codec_frame_ref (picture->frame);
339 *codedbuf = gst_vaapi_coded_buffer_proxy_ref (sync_pic->buf);
343 _free_sync_picture (encoder, sync_pic);
347 GstVaapiEncoderStatus
348 gst_vaapi_encoder_flush (GstVaapiEncoder * encoder)
350 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
352 return klass->flush (encoder);
355 GstVaapiEncoderStatus
356 gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder,
357 GstBuffer ** codec_data)
359 GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
360 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
363 if (!klass->get_codec_data)
364 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
366 ret = klass->get_codec_data (encoder, codec_data);
371 gst_vaapi_encoder_ensure_context (GstVaapiEncoder * encoder)
373 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
374 GstVaapiContextInfo info;
375 GstVaapiContext *context;
377 if (GST_VAAPI_ENCODER_CONTEXT (encoder))
380 memset (&info, 0, sizeof (info));
381 if (!klass->get_context_info (encoder, &info))
384 context = gst_vaapi_context_new_full (GST_VAAPI_ENCODER_DISPLAY (encoder),
389 GST_VAAPI_ENCODER_CONTEXT (encoder) = context;
390 GST_VAAPI_ENCODER_VA_CONTEXT (encoder) = gst_vaapi_context_get_id (context);
395 gst_vaapi_encoder_set_format (GstVaapiEncoder * encoder,
396 GstVideoCodecState * in_state, GstCaps * ref_caps)
398 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
399 GstCaps *out_caps = NULL;
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.");
406 GST_VAAPI_ENCODER_VIDEO_INFO (encoder) = in_state->info;
408 out_caps = klass->set_format (encoder, in_state, ref_caps);
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);
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);
421 if (!gst_vaapi_encoder_ensure_context (encoder))
424 encoder->codedbuf_size = (GST_VAAPI_ENCODER_WIDTH (encoder) *
425 GST_VAAPI_ENCODER_HEIGHT (encoder) * 400) / (16 * 16);
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");
433 gst_vaapi_video_pool_set_capacity (encoder->codedbuf_pool, 5);
438 gst_caps_replace (&GST_VAAPI_ENCODER_CAPS (encoder), NULL);
439 gst_caps_replace (&out_caps, NULL);
440 GST_ERROR ("encoder set format failed");
445 gst_vaapi_encoder_init (GstVaapiEncoder * encoder, GstVaapiDisplay * display)
447 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
449 g_return_val_if_fail (display != NULL, FALSE);
451 #define CHECK_VTABLE_HOOK(FUNC) do { \
453 goto error_invalid_vtable; \
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);
464 #undef CHECK_VTABLE_HOOK
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;
470 gst_video_info_init (&encoder->video_info);
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);
478 return klass->init (encoder);
481 error_invalid_vtable:
483 GST_ERROR ("invalid subclass hook (internal error)");
489 gst_vaapi_encoder_finalize (GstVaapiEncoder * encoder)
491 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
493 klass->finalize (encoder);
495 gst_vaapi_encoder_free_sync_pictures (encoder);
496 gst_vaapi_video_pool_replace (&encoder->codedbuf_pool, NULL);
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);
509 gst_vaapi_encoder_new (const GstVaapiEncoderClass * klass,
510 GstVaapiDisplay * display)
512 GstVaapiEncoder *encoder;
514 encoder = (GstVaapiEncoder *)
515 gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS (klass));
519 if (!gst_vaapi_encoder_init (encoder, display))
524 gst_vaapi_encoder_unref (encoder);