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;
264 if (!klass->reordering || !klass->encode)
270 ret = klass->reordering (encoder, frame, FALSE, &picture);
272 if (ret == GST_VAAPI_ENCODER_STATUS_FRAME_NOT_READY)
273 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
276 if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
279 ret = GST_VAAPI_ENCODER_STATUS_PICTURE_ERR;
283 coded_buf = gst_vaapi_encoder_create_coded_buffer (encoder);
285 ret = GST_VAAPI_ENCODER_STATUS_OBJECT_ERR;
289 ret = klass->encode (encoder, picture, coded_buf);
290 if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
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);
298 if (!gst_vaapi_encoder_push_sync_picture (encoder, sync_pic)) {
299 ret = GST_VAAPI_ENCODER_STATUS_THREAD_ERR;
307 gst_vaapi_enc_picture_replace (&picture, NULL);
308 gst_vaapi_coded_buffer_proxy_replace (&coded_buf, NULL);
310 _free_sync_picture (encoder, sync_pic);
311 GST_ERROR ("encoding failed, error:%d", ret);
315 GstVaapiEncoderStatus
316 gst_vaapi_encoder_get_buffer (GstVaapiEncoder * encoder,
317 GstVideoCodecFrame ** frame,
318 GstVaapiCodedBufferProxy ** codedbuf, gint64 us_of_timeout)
320 GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
321 GstVaapiEncoderSyncPic *sync_pic = NULL;
322 GstVaapiSurfaceStatus surface_status;
323 GstVaapiEncPicture *picture;
325 ret = gst_vaapi_encoder_pop_sync_picture (encoder, &sync_pic, us_of_timeout);
326 if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
329 picture = sync_pic->picture;
331 if (!picture->surface || !gst_vaapi_surface_sync (picture->surface)) {
332 ret = GST_VAAPI_ENCODER_STATUS_PARAM_ERR;
335 if (!gst_vaapi_surface_query_status (picture->surface, &surface_status)) {
336 ret = GST_VAAPI_ENCODER_STATUS_PICTURE_ERR;
340 *frame = gst_video_codec_frame_ref (picture->frame);
342 *codedbuf = gst_vaapi_coded_buffer_proxy_ref (sync_pic->buf);
346 _free_sync_picture (encoder, sync_pic);
350 GstVaapiEncoderStatus
351 gst_vaapi_encoder_flush (GstVaapiEncoder * encoder)
353 GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
354 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
359 ret = klass->flush (encoder);
363 GST_ERROR ("flush failed");
364 return GST_VAAPI_ENCODER_STATUS_FUNC_PTR_ERR;
367 GstVaapiEncoderStatus
368 gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder,
369 GstBuffer ** codec_data)
371 GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
372 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
375 if (!klass->get_codec_data)
376 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
378 ret = klass->get_codec_data (encoder, codec_data);
383 gst_vaapi_encoder_ensure_context (GstVaapiEncoder * encoder)
385 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
386 GstVaapiContextInfo info;
387 GstVaapiContext *context;
389 if (GST_VAAPI_ENCODER_CONTEXT (encoder))
392 memset (&info, 0, sizeof (info));
393 if (!klass->get_context_info || !klass->get_context_info (encoder, &info)) {
397 context = gst_vaapi_context_new_full (GST_VAAPI_ENCODER_DISPLAY (encoder),
402 GST_VAAPI_ENCODER_CONTEXT (encoder) = context;
403 GST_VAAPI_ENCODER_VA_CONTEXT (encoder) = gst_vaapi_context_get_id (context);
408 gst_vaapi_encoder_set_format (GstVaapiEncoder * encoder,
409 GstVideoCodecState * in_state, GstCaps * ref_caps)
411 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
412 GstCaps *out_caps = NULL;
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.");
419 GST_VAAPI_ENCODER_VIDEO_INFO (encoder) = in_state->info;
421 if (!klass->set_format)
424 out_caps = klass->set_format (encoder, in_state, ref_caps);
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);
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);
437 if (!gst_vaapi_encoder_ensure_context (encoder))
440 encoder->codedbuf_size = (GST_VAAPI_ENCODER_WIDTH (encoder) *
441 GST_VAAPI_ENCODER_HEIGHT (encoder) * 400) / (16 * 16);
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");
449 gst_vaapi_video_pool_set_capacity (encoder->codedbuf_pool, 5);
454 gst_caps_replace (&GST_VAAPI_ENCODER_CAPS (encoder), NULL);
455 gst_caps_replace (&out_caps, NULL);
456 GST_ERROR ("encoder set format failed");
461 gst_vaapi_encoder_init (GstVaapiEncoder * encoder, GstVaapiDisplay * display)
463 GstVaapiEncoderClass *kclass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
468 g_return_val_if_fail (display, FALSE);
469 g_return_val_if_fail (encoder->display == NULL, FALSE);
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;
477 gst_video_info_init (&encoder->video_info);
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);
486 return kclass->init (encoder);
491 gst_vaapi_encoder_destroy (GstVaapiEncoder * encoder)
493 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
496 klass->destroy (encoder);
498 gst_vaapi_encoder_free_sync_pictures (encoder);
499 gst_vaapi_video_pool_replace (&encoder->codedbuf_pool, NULL);
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);
512 gst_vaapi_encoder_finalize (GstVaapiEncoder * encoder)
514 gst_vaapi_encoder_destroy (encoder);
518 gst_vaapi_encoder_class_init (GstVaapiEncoderClass * klass)
520 GstVaapiMiniObjectClass *const object_class =
521 GST_VAAPI_MINI_OBJECT_CLASS (klass);
523 object_class->size = sizeof (GstVaapiEncoder);
524 object_class->finalize = (GDestroyNotify) gst_vaapi_encoder_finalize;
528 gst_vaapi_encoder_new (const GstVaapiEncoderClass * klass,
529 GstVaapiDisplay * display)
531 GstVaapiEncoder *encoder;
533 encoder = (GstVaapiEncoder *)
534 gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS (klass));
538 if (!gst_vaapi_encoder_init (encoder, display))
543 gst_vaapi_encoder_unref (encoder);