1 /*
2 * gstvaapiencoder.c - VA encoder abstraction
3 *
4 * Copyright (C) 2013-2014 Intel Corporation
5 * Author: Wind Yuan <feng.yuan@intel.com>
6 * Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1
11 * of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA
22 */
23
24 #include "sysdeps.h"
25 #include "gstvaapicompat.h"
26 #include "gstvaapiencoder.h"
27 #include "gstvaapiencoder_priv.h"
28 #include "gstvaapicontext.h"
29 #include "gstvaapidisplay_priv.h"
30 #include "gstvaapiutils.h"
31 #include "gstvaapiutils_core.h"
32 #include "gstvaapivalue.h"
33
34 #define DEBUG 1
35 #include "gstvaapidebug.h"
36
37 /* Helper function to create a new encoder property object */
38 static GstVaapiEncoderPropData *
prop_new(gint id,GParamSpec * pspec)39 prop_new (gint id, GParamSpec * pspec)
40 {
41 GstVaapiEncoderPropData *prop;
42
43 if (!id || !pspec)
44 return NULL;
45
46 prop = g_slice_new (GstVaapiEncoderPropData);
47 if (!prop)
48 return NULL;
49
50 prop->prop = id;
51 prop->pspec = g_param_spec_ref_sink (pspec);
52 return prop;
53 }
54
55 /* Helper function to release a property object and any memory held herein */
56 static void
prop_free(GstVaapiEncoderPropData * prop)57 prop_free (GstVaapiEncoderPropData * prop)
58 {
59 if (!prop)
60 return;
61
62 if (prop->pspec) {
63 g_param_spec_unref (prop->pspec);
64 prop->pspec = NULL;
65 }
66 g_slice_free (GstVaapiEncoderPropData, prop);
67 }
68
69 /* Helper function to lookup the supplied property specification */
70 static GParamSpec *
prop_find_pspec(GstVaapiEncoder * encoder,gint prop_id)71 prop_find_pspec (GstVaapiEncoder * encoder, gint prop_id)
72 {
73 GPtrArray *const props = encoder->properties;
74 guint i;
75
76 if (props) {
77 for (i = 0; i < props->len; i++) {
78 GstVaapiEncoderPropInfo *const prop = g_ptr_array_index (props, i);
79 if (prop->prop == prop_id)
80 return prop->pspec;
81 }
82 }
83 return NULL;
84 }
85
86 /* Create a new array of properties, or NULL on error */
87 GPtrArray *
gst_vaapi_encoder_properties_append(GPtrArray * props,gint prop_id,GParamSpec * pspec)88 gst_vaapi_encoder_properties_append (GPtrArray * props, gint prop_id,
89 GParamSpec * pspec)
90 {
91 GstVaapiEncoderPropData *prop;
92
93 if (!props) {
94 props = g_ptr_array_new_with_free_func ((GDestroyNotify) prop_free);
95 if (!props)
96 return NULL;
97 }
98
99 prop = prop_new (prop_id, pspec);
100 if (!prop)
101 goto error_allocation_failed;
102 g_ptr_array_add (props, prop);
103 return props;
104
105 /* ERRORS */
106 error_allocation_failed:
107 {
108 GST_ERROR ("failed to allocate encoder property info structure");
109 g_ptr_array_unref (props);
110 return NULL;
111 }
112 }
113
114 /* Generate the common set of encoder properties */
115 GPtrArray *
gst_vaapi_encoder_properties_get_default(const GstVaapiEncoderClass * klass)116 gst_vaapi_encoder_properties_get_default (const GstVaapiEncoderClass * klass)
117 {
118 const GstVaapiEncoderClassData *const cdata = klass->class_data;
119 GPtrArray *props = NULL;
120
121 g_assert (cdata->rate_control_get_type != NULL);
122
123 /**
124 * GstVaapiEncoder:rate-control:
125 *
126 * The desired rate control mode, expressed as a #GstVaapiRateControl.
127 */
128 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
129 GST_VAAPI_ENCODER_PROP_RATECONTROL,
130 g_param_spec_enum ("rate-control",
131 "Rate Control", "Rate control mode",
132 cdata->rate_control_get_type (), cdata->default_rate_control,
133 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
134
135 /**
136 * GstVaapiEncoder:bitrate:
137 *
138 * The desired bitrate, expressed in kbps.
139 * This is available when rate-control is CBR or VBR.
140 *
141 * CBR: This applies equally to minimum, maximum and target bitrate in the driver.
142 * VBR: This applies to maximum bitrate in the driver.
143 * Minimum bitrate will be calculated like the following in the driver.
144 * if (target percentage < 50) minimum bitrate = 0
145 * else minimum bitrate = maximum bitrate * (2 * target percentage -100) / 100
146 * Target bitrate will be calculated like the following in the driver.
147 * target bitrate = maximum bitrate * target percentage / 100
148 *
149 * Note that target percentage is set as 70 currently in GStreamer VA-API.
150 */
151 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
152 GST_VAAPI_ENCODER_PROP_BITRATE,
153 g_param_spec_uint ("bitrate",
154 "Bitrate (kbps)",
155 "The desired bitrate expressed in kbps (0: auto-calculate)",
156 0, 100 * 1024, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
157
158 /**
159 * GstVaapiEncoder:keyframe-period:
160 *
161 * The maximal distance between two keyframes.
162 */
163 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
164 GST_VAAPI_ENCODER_PROP_KEYFRAME_PERIOD,
165 g_param_spec_uint ("keyframe-period",
166 "Keyframe Period",
167 "Maximal distance between two keyframes (0: auto-calculate)", 0,
168 G_MAXUINT32, 30, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
169
170 /**
171 * GstVaapiEncoder:tune:
172 *
173 * The desired encoder tuning option.
174 */
175 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
176 GST_VAAPI_ENCODER_PROP_TUNE,
177 g_param_spec_enum ("tune",
178 "Encoder Tuning",
179 "Encoder tuning option",
180 cdata->encoder_tune_get_type (), cdata->default_encoder_tune,
181 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
182
183 /**
184 * GstVaapiEncoder:quality-level:
185 *
186 * The Encoding quality level.
187 */
188 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
189 GST_VAAPI_ENCODER_PROP_QUALITY_LEVEL,
190 g_param_spec_uint ("quality-level",
191 "Quality Level", "Encoding Quality Level "
192 "(lower value means higher-quality/slow-encode, "
193 " higher value means lower-quality/fast-encode)",
194 1, 7, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
195
196 /**
197 * GstVapiEncoder:roi-default-delta-qp
198 *
199 * Default delta-qp to apply to each Region of Interest
200 */
201 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
202 GST_VAAPI_ENCODER_PROP_DEFAULT_ROI_VALUE,
203 g_param_spec_int ("default-roi-delta-qp", "Default ROI delta QP",
204 "The default delta-qp to apply to each Region of Interest"
205 "(lower value means higher-quality, "
206 "higher value means lower-quality)",
207 -10, 10, -10, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
208
209 return props;
210 }
211
212 gboolean
gst_vaapi_encoder_ensure_param_quality_level(GstVaapiEncoder * encoder,GstVaapiEncPicture * picture)213 gst_vaapi_encoder_ensure_param_quality_level (GstVaapiEncoder * encoder,
214 GstVaapiEncPicture * picture)
215 {
216 #if VA_CHECK_VERSION(0,36,0)
217 GstVaapiEncMiscParam *misc;
218
219 /* quality level param is not supported */
220 if (GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) == 0)
221 return TRUE;
222
223 misc = GST_VAAPI_ENC_QUALITY_LEVEL_MISC_PARAM_NEW (encoder);
224 if (!misc)
225 return FALSE;
226 memcpy (misc->data, &encoder->va_quality_level,
227 sizeof (encoder->va_quality_level));
228 gst_vaapi_enc_picture_add_misc_param (picture, misc);
229 gst_vaapi_codec_object_replace (&misc, NULL);
230 #endif
231 return TRUE;
232 }
233
234 gboolean
gst_vaapi_encoder_ensure_param_control_rate(GstVaapiEncoder * encoder,GstVaapiEncPicture * picture)235 gst_vaapi_encoder_ensure_param_control_rate (GstVaapiEncoder * encoder,
236 GstVaapiEncPicture * picture)
237 {
238 GstVaapiEncMiscParam *misc;
239
240 if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP)
241 return TRUE;
242
243 /* RateControl params */
244 misc = GST_VAAPI_ENC_MISC_PARAM_NEW (RateControl, encoder);
245 if (!misc)
246 return FALSE;
247 memcpy (misc->data, &GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder),
248 sizeof (VAEncMiscParameterRateControl));
249 gst_vaapi_enc_picture_add_misc_param (picture, misc);
250 gst_vaapi_codec_object_replace (&misc, NULL);
251
252 /* HRD params */
253 misc = GST_VAAPI_ENC_MISC_PARAM_NEW (HRD, encoder);
254 if (!misc)
255 return FALSE;
256 memcpy (misc->data, &GST_VAAPI_ENCODER_VA_HRD (encoder),
257 sizeof (VAEncMiscParameterHRD));
258 gst_vaapi_enc_picture_add_misc_param (picture, misc);
259 gst_vaapi_codec_object_replace (&misc, NULL);
260
261 /* FrameRate params */
262 if (GST_VAAPI_ENCODER_VA_FRAME_RATE (encoder).framerate == 0)
263 return TRUE;
264
265 misc = GST_VAAPI_ENC_MISC_PARAM_NEW (FrameRate, encoder);
266 if (!misc)
267 return FALSE;
268 memcpy (misc->data, &GST_VAAPI_ENCODER_VA_FRAME_RATE (encoder),
269 sizeof (VAEncMiscParameterFrameRate));
270 gst_vaapi_enc_picture_add_misc_param (picture, misc);
271 gst_vaapi_codec_object_replace (&misc, NULL);
272
273 return TRUE;
274 }
275
276 gboolean
gst_vaapi_encoder_ensure_param_roi_regions(GstVaapiEncoder * encoder,GstVaapiEncPicture * picture)277 gst_vaapi_encoder_ensure_param_roi_regions (GstVaapiEncoder * encoder,
278 GstVaapiEncPicture * picture)
279 {
280 #if VA_CHECK_VERSION(0,39,1)
281 GstVaapiContextInfo *const cip = &encoder->context_info;
282 const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
283 VAEncMiscParameterBufferROI *roi_param;
284 GstVaapiEncMiscParam *misc;
285 VAEncROI *region_roi;
286 GstBuffer *input;
287 guint num_roi, i;
288 gpointer state = NULL;
289
290 if (!config->roi_capability)
291 return TRUE;
292
293 if (!picture->frame)
294 return FALSE;
295
296 input = picture->frame->input_buffer;
297 if (!input)
298 return FALSE;
299
300 num_roi =
301 gst_buffer_get_n_meta (input, GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE);
302 if (num_roi == 0)
303 return TRUE;
304 num_roi = CLAMP (num_roi, 1, config->roi_num_supported);
305
306 misc =
307 gst_vaapi_enc_misc_param_new (encoder, VAEncMiscParameterTypeROI,
308 sizeof (VAEncMiscParameterBufferROI) + num_roi * sizeof (VAEncROI));
309 if (!misc)
310 return FALSE;
311
312 region_roi =
313 (VAEncROI *) ((guint8 *) misc->param + sizeof (VAEncMiscParameterBuffer) +
314 sizeof (VAEncMiscParameterBufferROI));
315
316 roi_param = misc->data;
317 roi_param->num_roi = num_roi;
318 roi_param->roi = region_roi;
319
320 /* roi_value in VAEncROI should be used as ROI delta QP */
321 roi_param->roi_flags.bits.roi_value_is_qp_delta = 1;
322 roi_param->max_delta_qp = 10;
323 roi_param->min_delta_qp = -10;
324
325 for (i = 0; i < num_roi; i++) {
326 GstVideoRegionOfInterestMeta *roi;
327 GstStructure *s;
328
329 roi = (GstVideoRegionOfInterestMeta *)
330 gst_buffer_iterate_meta_filtered (input, &state,
331 GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE);
332 if (!roi)
333 continue;
334
335 /* ignore roi if overflow */
336 if ((roi->x > G_MAXINT16) || (roi->y > G_MAXINT16)
337 || (roi->w > G_MAXUINT16) || (roi->h > G_MAXUINT16))
338 continue;
339
340 GST_LOG ("Input buffer ROI: type=%s id=%d (%d, %d) %dx%d",
341 g_quark_to_string (roi->roi_type), roi->id, roi->x, roi->y, roi->w,
342 roi->h);
343
344 region_roi[i].roi_rectangle.x = roi->x;
345 region_roi[i].roi_rectangle.y = roi->y;
346 region_roi[i].roi_rectangle.width = roi->w;
347 region_roi[i].roi_rectangle.height = roi->h;
348
349 s = gst_video_region_of_interest_meta_get_param (roi, "roi/vaapi");
350 if (s) {
351 int value = 0;
352
353 if (!gst_structure_get_int (s, "delta-qp", &value))
354 continue;
355 value = CLAMP (value, roi_param->min_delta_qp, roi_param->max_delta_qp);
356 region_roi[i].roi_value = value;
357 } else {
358 region_roi[i].roi_value = encoder->default_roi_value;
359
360 GST_LOG ("No ROI value specified upstream, use default (%d)",
361 encoder->default_roi_value);
362 }
363 }
364
365 gst_vaapi_enc_picture_add_misc_param (picture, misc);
366 gst_vaapi_codec_object_replace (&misc, NULL);
367 #endif
368 return TRUE;
369 }
370
371 /**
372 * gst_vaapi_encoder_ref:
373 * @encoder: a #GstVaapiEncoder
374 *
375 * Atomically increases the reference count of the given @encoder by one.
376 *
377 * Returns: The same @encoder argument
378 */
379 GstVaapiEncoder *
gst_vaapi_encoder_ref(GstVaapiEncoder * encoder)380 gst_vaapi_encoder_ref (GstVaapiEncoder * encoder)
381 {
382 return gst_vaapi_object_ref (encoder);
383 }
384
385 /**
386 * gst_vaapi_encoder_unref:
387 * @encoder: a #GstVaapiEncoder
388 *
389 * Atomically decreases the reference count of the @encoder by one. If
390 * the reference count reaches zero, the encoder will be free'd.
391 */
392 void
gst_vaapi_encoder_unref(GstVaapiEncoder * encoder)393 gst_vaapi_encoder_unref (GstVaapiEncoder * encoder)
394 {
395 gst_vaapi_object_unref (encoder);
396 }
397
398 /**
399 * gst_vaapi_encoder_replace:
400 * @old_encoder_ptr: a pointer to a #GstVaapiEncoder
401 * @new_encoder: a #GstVaapiEncoder
402 *
403 * Atomically replaces the encoder encoder held in @old_encoder_ptr
404 * with @new_encoder. This means that @old_encoder_ptr shall reference
405 * a valid encoder. However, @new_encoder can be NULL.
406 */
407 void
gst_vaapi_encoder_replace(GstVaapiEncoder ** old_encoder_ptr,GstVaapiEncoder * new_encoder)408 gst_vaapi_encoder_replace (GstVaapiEncoder ** old_encoder_ptr,
409 GstVaapiEncoder * new_encoder)
410 {
411 gst_vaapi_object_replace (old_encoder_ptr, new_encoder);
412 }
413
414 /* Notifies gst_vaapi_encoder_create_coded_buffer() that a new buffer is free */
415 static void
_coded_buffer_proxy_released_notify(GstVaapiEncoder * encoder)416 _coded_buffer_proxy_released_notify (GstVaapiEncoder * encoder)
417 {
418 g_mutex_lock (&encoder->mutex);
419 g_cond_signal (&encoder->codedbuf_free);
420 g_mutex_unlock (&encoder->mutex);
421 }
422
423 /* Creates a new VA coded buffer object proxy, backed from a pool */
424 static GstVaapiCodedBufferProxy *
gst_vaapi_encoder_create_coded_buffer(GstVaapiEncoder * encoder)425 gst_vaapi_encoder_create_coded_buffer (GstVaapiEncoder * encoder)
426 {
427 GstVaapiCodedBufferPool *const pool =
428 GST_VAAPI_CODED_BUFFER_POOL (encoder->codedbuf_pool);
429 GstVaapiCodedBufferProxy *codedbuf_proxy;
430
431 g_mutex_lock (&encoder->mutex);
432 do {
433 codedbuf_proxy = gst_vaapi_coded_buffer_proxy_new_from_pool (pool);
434 if (codedbuf_proxy)
435 break;
436
437 /* Wait for a free coded buffer to become available */
438 g_cond_wait (&encoder->codedbuf_free, &encoder->mutex);
439 codedbuf_proxy = gst_vaapi_coded_buffer_proxy_new_from_pool (pool);
440 } while (0);
441 g_mutex_unlock (&encoder->mutex);
442 if (!codedbuf_proxy)
443 return NULL;
444
445 gst_vaapi_coded_buffer_proxy_set_destroy_notify (codedbuf_proxy,
446 (GDestroyNotify) _coded_buffer_proxy_released_notify, encoder);
447 return codedbuf_proxy;
448 }
449
450 /* Notifies gst_vaapi_encoder_create_surface() that a new surface is free */
451 static void
_surface_proxy_released_notify(GstVaapiEncoder * encoder)452 _surface_proxy_released_notify (GstVaapiEncoder * encoder)
453 {
454 g_mutex_lock (&encoder->mutex);
455 g_cond_signal (&encoder->surface_free);
456 g_mutex_unlock (&encoder->mutex);
457 }
458
459 /* Creates a new VA surface object proxy, backed from a pool and
460 useful to allocate reconstructed surfaces */
461 GstVaapiSurfaceProxy *
gst_vaapi_encoder_create_surface(GstVaapiEncoder * encoder)462 gst_vaapi_encoder_create_surface (GstVaapiEncoder * encoder)
463 {
464 GstVaapiSurfaceProxy *proxy;
465
466 g_return_val_if_fail (encoder->context != NULL, NULL);
467
468 g_mutex_lock (&encoder->mutex);
469 for (;;) {
470 proxy = gst_vaapi_context_get_surface_proxy (encoder->context);
471 if (proxy)
472 break;
473
474 /* Wait for a free surface proxy to become available */
475 g_cond_wait (&encoder->surface_free, &encoder->mutex);
476 }
477 g_mutex_unlock (&encoder->mutex);
478
479 gst_vaapi_surface_proxy_set_destroy_notify (proxy,
480 (GDestroyNotify) _surface_proxy_released_notify, encoder);
481 return proxy;
482 }
483
484 /* Create a coded buffer proxy where the picture is going to be
485 * decoded, the subclass encode vmethod is called and, if it doesn't
486 * fail, the coded buffer is pushed into the async queue */
487 static GstVaapiEncoderStatus
gst_vaapi_encoder_encode_and_queue(GstVaapiEncoder * encoder,GstVaapiEncPicture * picture)488 gst_vaapi_encoder_encode_and_queue (GstVaapiEncoder * encoder,
489 GstVaapiEncPicture * picture)
490 {
491 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
492 GstVaapiCodedBufferProxy *codedbuf_proxy;
493 GstVaapiEncoderStatus status;
494
495 codedbuf_proxy = gst_vaapi_encoder_create_coded_buffer (encoder);
496 if (!codedbuf_proxy)
497 goto error_create_coded_buffer;
498
499 status = klass->encode (encoder, picture, codedbuf_proxy);
500 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
501 goto error_encode;
502
503 gst_vaapi_coded_buffer_proxy_set_user_data (codedbuf_proxy,
504 picture, (GDestroyNotify) gst_vaapi_mini_object_unref);
505 g_async_queue_push (encoder->codedbuf_queue, codedbuf_proxy);
506 encoder->num_codedbuf_queued++;
507
508 return status;
509
510 /* ERRORS */
511 error_create_coded_buffer:
512 {
513 GST_ERROR ("failed to allocate coded buffer");
514 return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
515 }
516 error_encode:
517 {
518 GST_ERROR ("failed to encode frame (status = %d)", status);
519 gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy);
520 return status;
521 }
522 }
523
524 /**
525 * gst_vaapi_encoder_put_frame:
526 * @encoder: a #GstVaapiEncoder
527 * @frame: a #GstVideoCodecFrame
528 *
529 * Queues a #GstVideoCodedFrame to the HW encoder. The encoder holds
530 * an extra reference to the @frame.
531 *
532 * Return value: a #GstVaapiEncoderStatus
533 */
534 GstVaapiEncoderStatus
gst_vaapi_encoder_put_frame(GstVaapiEncoder * encoder,GstVideoCodecFrame * frame)535 gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder,
536 GstVideoCodecFrame * frame)
537 {
538 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
539 GstVaapiEncoderStatus status;
540 GstVaapiEncPicture *picture;
541
542 for (;;) {
543 picture = NULL;
544 status = klass->reordering (encoder, frame, &picture);
545 if (status == GST_VAAPI_ENCODER_STATUS_NO_SURFACE)
546 break;
547 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
548 goto error_reorder_frame;
549
550 status = gst_vaapi_encoder_encode_and_queue (encoder, picture);
551 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
552 goto error_encode;
553
554 /* Try again with any pending reordered frame now available for encoding */
555 frame = NULL;
556 }
557 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
558
559 /* ERRORS */
560 error_reorder_frame:
561 {
562 GST_ERROR ("failed to process reordered frames");
563 return status;
564 }
565 error_encode:
566 {
567 gst_vaapi_enc_picture_unref (picture);
568 return status;
569 }
570 }
571
572 /**
573 * gst_vaapi_encoder_get_buffer_with_timeout:
574 * @encoder: a #GstVaapiEncoder
575 * @out_codedbuf_proxy_ptr: the next coded buffer as a #GstVaapiCodedBufferProxy
576 * @timeout: the number of microseconds to wait for the coded buffer, at most
577 *
578 * Upon successful return, *@out_codedbuf_proxy_ptr contains the next
579 * coded buffer as a #GstVaapiCodedBufferProxy. The caller owns this
580 * object, so gst_vaapi_coded_buffer_proxy_unref() shall be called
581 * after usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_BUFFER
582 * is returned if no coded buffer is available so far (timeout).
583 *
584 * The parent frame is available as a #GstVideoCodecFrame attached to
585 * the user-data anchor of the output coded buffer. Ownership of the
586 * frame is transferred to the coded buffer.
587 *
588 * Return value: a #GstVaapiEncoderStatus
589 */
590 GstVaapiEncoderStatus
gst_vaapi_encoder_get_buffer_with_timeout(GstVaapiEncoder * encoder,GstVaapiCodedBufferProxy ** out_codedbuf_proxy_ptr,guint64 timeout)591 gst_vaapi_encoder_get_buffer_with_timeout (GstVaapiEncoder * encoder,
592 GstVaapiCodedBufferProxy ** out_codedbuf_proxy_ptr, guint64 timeout)
593 {
594 GstVaapiEncPicture *picture;
595 GstVaapiCodedBufferProxy *codedbuf_proxy;
596
597 codedbuf_proxy = g_async_queue_timeout_pop (encoder->codedbuf_queue, timeout);
598 if (!codedbuf_proxy)
599 return GST_VAAPI_ENCODER_STATUS_NO_BUFFER;
600
601 /* Wait for completion of all operations and report any error that occurred */
602 picture = gst_vaapi_coded_buffer_proxy_get_user_data (codedbuf_proxy);
603 if (!gst_vaapi_surface_sync (picture->surface))
604 goto error_invalid_buffer;
605
606 gst_vaapi_coded_buffer_proxy_set_user_data (codedbuf_proxy,
607 gst_video_codec_frame_ref (picture->frame),
608 (GDestroyNotify) gst_video_codec_frame_unref);
609
610 if (out_codedbuf_proxy_ptr)
611 *out_codedbuf_proxy_ptr = gst_vaapi_coded_buffer_proxy_ref (codedbuf_proxy);
612 gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy);
613 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
614
615 /* ERRORS */
616 error_invalid_buffer:
617 {
618 GST_ERROR ("failed to encode the frame");
619 gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy);
620 return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_SURFACE;
621 }
622 }
623
624 static inline gboolean
_get_pending_reordered(GstVaapiEncoder * encoder,GstVaapiEncPicture ** picture,gpointer * state)625 _get_pending_reordered (GstVaapiEncoder * encoder,
626 GstVaapiEncPicture ** picture, gpointer * state)
627 {
628 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
629
630 if (!klass->get_pending_reordered)
631 return FALSE;
632 return klass->get_pending_reordered (encoder, picture, state);
633 }
634
635 /**
636 * gst_vaapi_encoder_flush:
637 * @encoder: a #GstVaapiEncoder
638 *
639 * Submits any pending (reordered) frame for encoding.
640 *
641 * Return value: a #GstVaapiEncoderStatus
642 */
643 GstVaapiEncoderStatus
gst_vaapi_encoder_flush(GstVaapiEncoder * encoder)644 gst_vaapi_encoder_flush (GstVaapiEncoder * encoder)
645 {
646 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
647 GstVaapiEncPicture *picture;
648 GstVaapiEncoderStatus status;
649 gpointer iter = NULL;
650
651 picture = NULL;
652 while (_get_pending_reordered (encoder, &picture, &iter)) {
653 if (!picture)
654 continue;
655 status = gst_vaapi_encoder_encode_and_queue (encoder, picture);
656 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
657 goto error_encode;
658 }
659 g_free (iter);
660
661 return klass->flush (encoder);
662
663 /* ERRORS */
664 error_encode:
665 {
666 gst_vaapi_enc_picture_unref (picture);
667 return status;
668 }
669 }
670
671 /**
672 * gst_vaapi_encoder_get_codec_data:
673 * @encoder: a #GstVaapiEncoder
674 * @out_codec_data_ptr: the pointer to the resulting codec-data (#GstBuffer)
675 *
676 * Returns a codec-data buffer that best represents the encoded
677 * bitstream. Upon successful return, and if the @out_codec_data_ptr
678 * contents is not NULL, then the caller function shall deallocates
679 * that buffer with gst_buffer_unref().
680 *
681 * Return value: a #GstVaapiEncoderStatus
682 */
683 GstVaapiEncoderStatus
gst_vaapi_encoder_get_codec_data(GstVaapiEncoder * encoder,GstBuffer ** out_codec_data_ptr)684 gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder,
685 GstBuffer ** out_codec_data_ptr)
686 {
687 GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
688 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
689
690 *out_codec_data_ptr = NULL;
691 if (!klass->get_codec_data)
692 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
693
694 ret = klass->get_codec_data (encoder, out_codec_data_ptr);
695 return ret;
696 }
697
698 /* Checks video info */
699 static GstVaapiEncoderStatus
check_video_info(GstVaapiEncoder * encoder,const GstVideoInfo * vip)700 check_video_info (GstVaapiEncoder * encoder, const GstVideoInfo * vip)
701 {
702 if (!vip->width || !vip->height)
703 goto error_invalid_resolution;
704 if (vip->fps_n < 0 || vip->fps_d <= 0)
705 goto error_invalid_framerate;
706 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
707
708 /* ERRORS */
709 error_invalid_resolution:
710 {
711 GST_ERROR ("invalid resolution (%dx%d)", vip->width, vip->height);
712 return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
713 }
714 error_invalid_framerate:
715 {
716 GST_ERROR ("invalid framerate (%d/%d)", vip->fps_n, vip->fps_d);
717 return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
718 }
719 }
720
721 /* Gets a compatible profile for the active codec */
722 static GstVaapiProfile
get_compatible_profile(GstVaapiEncoder * encoder)723 get_compatible_profile (GstVaapiEncoder * encoder)
724 {
725 const GstVaapiEncoderClassData *const cdata =
726 GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data;
727 GstVaapiProfile profile;
728 GArray *profiles;
729 guint i;
730
731 profiles = gst_vaapi_display_get_encode_profiles (encoder->display);
732 if (!profiles)
733 return GST_VAAPI_PROFILE_UNKNOWN;
734
735 // Pick a profile matching the class codec
736 for (i = 0; i < profiles->len; i++) {
737 profile = g_array_index (profiles, GstVaapiProfile, i);
738 if (gst_vaapi_profile_get_codec (profile) == cdata->codec)
739 break;
740 }
741 if (i == profiles->len)
742 profile = GST_VAAPI_PROFILE_UNKNOWN;
743
744 g_array_unref (profiles);
745 return profile;
746 }
747
748 /* Gets a supported profile for the active codec */
749 static GstVaapiProfile
get_profile(GstVaapiEncoder * encoder)750 get_profile (GstVaapiEncoder * encoder)
751 {
752 if (!encoder->profile)
753 encoder->profile = get_compatible_profile (encoder);
754 return encoder->profile;
755 }
756
757 /* Gets config attribute for the supplied profile */
758 static gboolean
get_config_attribute(GstVaapiEncoder * encoder,VAConfigAttribType type,guint * out_value_ptr)759 get_config_attribute (GstVaapiEncoder * encoder, VAConfigAttribType type,
760 guint * out_value_ptr)
761 {
762 GstVaapiProfile profile;
763 VAProfile va_profile;
764 VAEntrypoint va_entrypoint;
765
766 profile = get_profile (encoder);
767 if (!profile)
768 return FALSE;
769 va_profile = gst_vaapi_profile_get_va_profile (profile);
770
771 va_entrypoint =
772 gst_vaapi_entrypoint_get_va_entrypoint (encoder->context_info.entrypoint);
773
774 return gst_vaapi_get_config_attribute (encoder->display, va_profile,
775 va_entrypoint, type, out_value_ptr);
776 }
777
778 /* Determines the set of supported packed headers */
779 static guint
get_packed_headers(GstVaapiEncoder * encoder)780 get_packed_headers (GstVaapiEncoder * encoder)
781 {
782 const GstVaapiEncoderClassData *const cdata =
783 GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data;
784 guint value;
785
786 if (encoder->got_packed_headers)
787 return encoder->packed_headers;
788
789 if (!get_config_attribute (encoder, VAConfigAttribEncPackedHeaders, &value))
790 value = 0;
791 GST_INFO ("supported packed headers: 0x%08x", value);
792
793 encoder->got_packed_headers = TRUE;
794 encoder->packed_headers = cdata->packed_headers & value;
795
796 if (cdata->codec == GST_VAAPI_CODEC_JPEG) {
797 #if !VA_CHECK_VERSION(0,37,1)
798 encoder->packed_headers = VA_ENC_PACKED_HEADER_RAW_DATA;
799 GST_DEBUG ("Hard coding the packed header flag value to "
800 "VA_ENC_PACKED_HEADER_RAW_DATA. This is a work around for the driver "
801 "bug");
802 #endif
803 }
804
805 return encoder->packed_headers;
806 }
807
808 static gboolean
get_roi_capability(GstVaapiEncoder * encoder,guint * num_roi_supported)809 get_roi_capability (GstVaapiEncoder * encoder, guint * num_roi_supported)
810 {
811 #if VA_CHECK_VERSION(0,39,1)
812 VAConfigAttribValEncROI *roi_config;
813 guint value;
814
815 if (!get_config_attribute (encoder, VAConfigAttribEncROI, &value))
816 return FALSE;
817
818 roi_config = (VAConfigAttribValEncROI *) & value;
819
820 if (roi_config->bits.num_roi_regions == 0)
821 return FALSE;
822
823 /* Only support QP delta, and it only makes sense when rate control
824 * is not CQP */
825 if ((GST_VAAPI_ENCODER_RATE_CONTROL (encoder) != GST_VAAPI_RATECONTROL_CQP)
826 && (VA_ROI_RC_QP_DELTA_SUPPORT (roi_config) == 0))
827 return FALSE;
828
829 GST_INFO ("Support for ROI - number of regions supported: %d",
830 roi_config->bits.num_roi_regions);
831
832 *num_roi_supported = roi_config->bits.num_roi_regions;
833 return TRUE;
834 #else
835 return FALSE;
836 #endif
837 }
838
839 static inline gboolean
is_chroma_type_supported(GstVaapiEncoder * encoder)840 is_chroma_type_supported (GstVaapiEncoder * encoder)
841 {
842 GstVaapiContextInfo *const cip = &encoder->context_info;
843 const GstVideoFormat fmt =
844 GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder));
845 guint format = 0;
846
847 if (fmt == GST_VIDEO_FORMAT_ENCODED)
848 return TRUE;
849
850 if (cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV420 &&
851 cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV422 &&
852 cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV420_10BPP)
853 goto unsupported;
854
855 if (!get_config_attribute (encoder, VAConfigAttribRTFormat, &format))
856 return FALSE;
857
858 if (!(format & from_GstVaapiChromaType (cip->chroma_type)))
859 goto unsupported;
860
861 return TRUE;
862
863 /* ERRORS */
864 unsupported:
865 {
866 GST_ERROR ("We only support YUV 4:2:0 and YUV 4:2:2 for encoding. "
867 "Please try to use vaapipostproc to convert the input format.");
868 return FALSE;
869 }
870 }
871
872 static guint
get_default_chroma_type(GstVaapiEncoder * encoder,const GstVaapiContextInfo * cip)873 get_default_chroma_type (GstVaapiEncoder * encoder,
874 const GstVaapiContextInfo * cip)
875 {
876 guint value;
877
878 if (!gst_vaapi_get_config_attribute (encoder->display,
879 gst_vaapi_profile_get_va_profile (cip->profile),
880 gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint),
881 VAConfigAttribRTFormat, &value))
882 return 0;
883
884 return to_GstVaapiChromaType (value);
885 }
886
887 static void
init_context_info(GstVaapiEncoder * encoder,GstVaapiContextInfo * cip,GstVaapiProfile profile)888 init_context_info (GstVaapiEncoder * encoder, GstVaapiContextInfo * cip,
889 GstVaapiProfile profile)
890 {
891 const GstVaapiEncoderClassData *const cdata =
892 GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data;
893
894 cip->usage = GST_VAAPI_CONTEXT_USAGE_ENCODE;
895 cip->profile = profile;
896 if (cdata->codec == GST_VAAPI_CODEC_JPEG) {
897 cip->entrypoint = GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE;
898 } else {
899 if (cip->entrypoint != GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP &&
900 cip->entrypoint != GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_FEI)
901 cip->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
902 }
903 cip->chroma_type = get_default_chroma_type (encoder, cip);
904 cip->width = 0;
905 cip->height = 0;
906 cip->ref_frames = encoder->num_ref_frames;
907 }
908
909 /* Updates video context */
910 static gboolean
set_context_info(GstVaapiEncoder * encoder)911 set_context_info (GstVaapiEncoder * encoder)
912 {
913 GstVaapiContextInfo *const cip = &encoder->context_info;
914 GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
915 const GstVideoFormat format =
916 GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder));
917 guint fei_function = config->fei_function;
918
919 init_context_info (encoder, cip, get_profile (encoder));
920
921 cip->chroma_type = gst_vaapi_video_format_get_chroma_type (format);
922 cip->width = GST_VAAPI_ENCODER_WIDTH (encoder);
923 cip->height = GST_VAAPI_ENCODER_HEIGHT (encoder);
924
925 if (!is_chroma_type_supported (encoder))
926 goto error_unsupported_format;
927
928 memset (config, 0, sizeof (*config));
929 config->rc_mode = GST_VAAPI_ENCODER_RATE_CONTROL (encoder);
930 config->packed_headers = get_packed_headers (encoder);
931 config->roi_capability =
932 get_roi_capability (encoder, &config->roi_num_supported);
933 config->fei_function = fei_function;
934
935 return TRUE;
936
937 /* ERRORS */
938 error_unsupported_format:
939 {
940 GST_ERROR ("failed to determine chroma type for format %s",
941 gst_vaapi_video_format_to_string (format));
942 return FALSE;
943 }
944 }
945
946 /* Ensures the underlying VA context for encoding is created */
947 static gboolean
gst_vaapi_encoder_ensure_context(GstVaapiEncoder * encoder)948 gst_vaapi_encoder_ensure_context (GstVaapiEncoder * encoder)
949 {
950 GstVaapiContextInfo *const cip = &encoder->context_info;
951
952 if (!set_context_info (encoder))
953 return FALSE;
954
955 if (encoder->context) {
956 if (!gst_vaapi_context_reset (encoder->context, cip))
957 return FALSE;
958 } else {
959 encoder->context = gst_vaapi_context_new (encoder->display, cip);
960 if (!encoder->context)
961 return FALSE;
962 }
963 encoder->va_context = gst_vaapi_context_get_id (encoder->context);
964 return TRUE;
965 }
966
967 /* Reconfigures the encoder with the new properties */
968 static GstVaapiEncoderStatus
gst_vaapi_encoder_reconfigure_internal(GstVaapiEncoder * encoder)969 gst_vaapi_encoder_reconfigure_internal (GstVaapiEncoder * encoder)
970 {
971 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
972 GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
973 GstVaapiEncoderStatus status;
974 GstVaapiVideoPool *pool;
975 guint codedbuf_size, target_percentage;
976 guint fps_d, fps_n;
977 #if VA_CHECK_VERSION(0,36,0)
978 guint quality_level_max = 0;
979 #endif
980
981 fps_d = GST_VIDEO_INFO_FPS_D (vip);
982 fps_n = GST_VIDEO_INFO_FPS_N (vip);
983
984 /* Generate a keyframe every second */
985 if (!encoder->keyframe_period)
986 encoder->keyframe_period = (fps_n + fps_d - 1) / fps_d;
987
988 /* Default frame rate parameter */
989 if (fps_d > 0 && fps_n > 0)
990 GST_VAAPI_ENCODER_VA_FRAME_RATE (encoder).framerate = fps_d << 16 | fps_n;
991
992 target_percentage =
993 (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR) ?
994 100 : 70;
995
996 /* *INDENT-OFF* */
997 /* Default values for rate control parameter */
998 GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder) = (VAEncMiscParameterRateControl) {
999 .bits_per_second = encoder->bitrate * 1000,
1000 .target_percentage = target_percentage,
1001 .window_size = 500,
1002 };
1003 /* *INDENT-ON* */
1004
1005 status = klass->reconfigure (encoder);
1006 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
1007 return status;
1008
1009 if (!gst_vaapi_encoder_ensure_context (encoder))
1010 goto error_reset_context;
1011
1012 /* Currently only FEI entrypoint needed this.
1013 * FEI ENC+PAK requires two contexts where the first one is for ENC
1014 * and the second one is for PAK */
1015 if (klass->ensure_secondary_context
1016 && !klass->ensure_secondary_context (encoder))
1017 goto error_reset_secondary_context;
1018
1019 #if VA_CHECK_VERSION(0,36,0)
1020 if (get_config_attribute (encoder, VAConfigAttribEncQualityRange,
1021 &quality_level_max) && quality_level_max > 0) {
1022 GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) =
1023 CLAMP (GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder), 1, quality_level_max);
1024 } else {
1025 GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) = 0;
1026 }
1027 GST_INFO ("Quality level is fixed to %d",
1028 GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder));
1029 #endif
1030
1031 codedbuf_size = encoder->codedbuf_pool ?
1032 gst_vaapi_coded_buffer_pool_get_buffer_size (GST_VAAPI_CODED_BUFFER_POOL
1033 (encoder)) : 0;
1034 if (codedbuf_size != encoder->codedbuf_size) {
1035 pool = gst_vaapi_coded_buffer_pool_new (encoder, encoder->codedbuf_size);
1036 if (!pool)
1037 goto error_alloc_codedbuf_pool;
1038 gst_vaapi_video_pool_set_capacity (pool, 5);
1039 gst_vaapi_video_pool_replace (&encoder->codedbuf_pool, pool);
1040 gst_vaapi_video_pool_unref (pool);
1041 }
1042 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1043
1044 /* ERRORS */
1045 error_alloc_codedbuf_pool:
1046 {
1047 GST_ERROR ("failed to initialize coded buffer pool");
1048 return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
1049 }
1050 error_reset_context:
1051 {
1052 GST_ERROR ("failed to update VA context");
1053 return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
1054 }
1055 error_reset_secondary_context:
1056 {
1057 GST_ERROR ("failed to create/update secondary VA context");
1058 return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
1059 }
1060 }
1061
1062 /**
1063 * gst_vaapi_encoder_set_codec_state:
1064 * @encoder: a #GstVaapiEncoder
1065 * @state : a #GstVideoCodecState
1066 *
1067 * Notifies the encoder about the source surface properties. The
1068 * accepted set of properties is: video resolution, colorimetry,
1069 * pixel-aspect-ratio and framerate.
1070 *
1071 * This function is a synchronization point for codec configuration.
1072 * This means that, at this point, the encoder is reconfigured to
1073 * match the new properties and any other change beyond this point has
1074 * zero effect.
1075 *
1076 * Return value: a #GstVaapiEncoderStatus
1077 */
1078 GstVaapiEncoderStatus
gst_vaapi_encoder_set_codec_state(GstVaapiEncoder * encoder,GstVideoCodecState * state)1079 gst_vaapi_encoder_set_codec_state (GstVaapiEncoder * encoder,
1080 GstVideoCodecState * state)
1081 {
1082 GstVaapiEncoderStatus status;
1083
1084 g_return_val_if_fail (encoder != NULL,
1085 GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER);
1086 g_return_val_if_fail (state != NULL,
1087 GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER);
1088
1089 if (!gst_video_info_is_equal (&state->info, &encoder->video_info)) {
1090 status = check_video_info (encoder, &state->info);
1091 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
1092 return status;
1093 encoder->video_info = state->info;
1094 }
1095 return gst_vaapi_encoder_reconfigure_internal (encoder);
1096 }
1097
1098 /**
1099 * gst_vaapi_encoder_set_property:
1100 * @encoder: a #GstVaapiEncoder
1101 * @prop_id: the id of the property to change
1102 * @value: the new value to set
1103 *
1104 * Update the requested property, designed by @prop_id, with the
1105 * supplied @value. A @NULL value argument resets the property to its
1106 * default value.
1107 *
1108 * Return value: a #GstVaapiEncoderStatus
1109 */
1110 static GstVaapiEncoderStatus
set_property(GstVaapiEncoder * encoder,gint prop_id,const GValue * value)1111 set_property (GstVaapiEncoder * encoder, gint prop_id, const GValue * value)
1112 {
1113 GstVaapiEncoderStatus status =
1114 GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
1115
1116 g_assert (value != NULL);
1117
1118 /* Handle codec-specific properties */
1119 if (prop_id < 0) {
1120 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
1121
1122 if (klass->set_property) {
1123 if (encoder->num_codedbuf_queued > 0)
1124 goto error_operation_failed;
1125 status = klass->set_property (encoder, prop_id, value);
1126 }
1127 return status;
1128 }
1129
1130 /* Handle common properties */
1131 switch (prop_id) {
1132 case GST_VAAPI_ENCODER_PROP_RATECONTROL:
1133 status = gst_vaapi_encoder_set_rate_control (encoder,
1134 g_value_get_enum (value));
1135 break;
1136 case GST_VAAPI_ENCODER_PROP_BITRATE:
1137 status = gst_vaapi_encoder_set_bitrate (encoder,
1138 g_value_get_uint (value));
1139 break;
1140 case GST_VAAPI_ENCODER_PROP_KEYFRAME_PERIOD:
1141 status = gst_vaapi_encoder_set_keyframe_period (encoder,
1142 g_value_get_uint (value));
1143 break;
1144 case GST_VAAPI_ENCODER_PROP_TUNE:
1145 status = gst_vaapi_encoder_set_tuning (encoder, g_value_get_enum (value));
1146 break;
1147 case GST_VAAPI_ENCODER_PROP_QUALITY_LEVEL:
1148 status = gst_vaapi_encoder_set_quality_level (encoder,
1149 g_value_get_uint (value));
1150 break;
1151 case GST_VAAPI_ENCODER_PROP_DEFAULT_ROI_VALUE:
1152 encoder->default_roi_value = g_value_get_int (value);
1153 status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
1154 break;
1155 }
1156 return status;
1157
1158 /* ERRORS */
1159 error_operation_failed:
1160 {
1161 GST_ERROR ("could not change codec state after encoding started");
1162 return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
1163 }
1164 }
1165
1166 GstVaapiEncoderStatus
gst_vaapi_encoder_set_property(GstVaapiEncoder * encoder,gint prop_id,const GValue * value)1167 gst_vaapi_encoder_set_property (GstVaapiEncoder * encoder, gint prop_id,
1168 const GValue * value)
1169 {
1170 GstVaapiEncoderStatus status;
1171 GValue default_value = G_VALUE_INIT;
1172
1173 g_return_val_if_fail (encoder != NULL,
1174 GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER);
1175
1176 if (!value) {
1177 GParamSpec *const pspec = prop_find_pspec (encoder, prop_id);
1178 if (!pspec)
1179 goto error_invalid_property;
1180
1181 g_value_init (&default_value, pspec->value_type);
1182 g_param_value_set_default (pspec, &default_value);
1183 value = &default_value;
1184 }
1185
1186 status = set_property (encoder, prop_id, value);
1187
1188 if (default_value.g_type)
1189 g_value_unset (&default_value);
1190 return status;
1191
1192 /* ERRORS */
1193 error_invalid_property:
1194 {
1195 GST_ERROR ("unsupported property (%d)", prop_id);
1196 return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
1197 }
1198 }
1199
1200 /* Determine the supported rate control modes */
1201 static guint
get_rate_control_mask(GstVaapiEncoder * encoder)1202 get_rate_control_mask (GstVaapiEncoder * encoder)
1203 {
1204 const GstVaapiEncoderClassData *const cdata =
1205 GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data;
1206 guint i, value, rate_control_mask = 0;
1207
1208 if (encoder->got_rate_control_mask)
1209 return encoder->rate_control_mask;
1210
1211 if (get_config_attribute (encoder, VAConfigAttribRateControl, &value)) {
1212 for (i = 0; i < 32; i++) {
1213 if (!(value & (1U << i)))
1214 continue;
1215 rate_control_mask |= 1 << to_GstVaapiRateControl (1 << i);
1216 }
1217 GST_INFO ("supported rate controls: 0x%08x", rate_control_mask);
1218
1219 encoder->got_rate_control_mask = TRUE;
1220 encoder->rate_control_mask = cdata->rate_control_mask & rate_control_mask;
1221 }
1222
1223 return encoder->rate_control_mask;
1224 }
1225
1226 /**
1227 * gst_vaapi_encoder_set_rate_control:
1228 * @encoder: a #GstVaapiEncoder
1229 * @rate_control: the requested rate control
1230 *
1231 * Notifies the @encoder to use the supplied @rate_control mode.
1232 *
1233 * If the underlying encoder does not support that rate control mode,
1234 * then @GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_RATE_CONTROL is
1235 * returned.
1236 *
1237 * The rate control mode can only be specified before the first frame
1238 * is to be encoded. Afterwards, any change to this parameter is
1239 * invalid and @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED is
1240 * returned.
1241 *
1242 * Return value: a #GstVaapiEncoderStatus
1243 */
1244 GstVaapiEncoderStatus
gst_vaapi_encoder_set_rate_control(GstVaapiEncoder * encoder,GstVaapiRateControl rate_control)1245 gst_vaapi_encoder_set_rate_control (GstVaapiEncoder * encoder,
1246 GstVaapiRateControl rate_control)
1247 {
1248 guint32 rate_control_mask;
1249
1250 g_return_val_if_fail (encoder != NULL,
1251 GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER);
1252
1253 if (encoder->rate_control != rate_control && encoder->num_codedbuf_queued > 0)
1254 goto error_operation_failed;
1255
1256 rate_control_mask = get_rate_control_mask (encoder);
1257 if (rate_control_mask && !(rate_control_mask & (1U << rate_control)))
1258 goto error_unsupported_rate_control;
1259
1260 encoder->rate_control = rate_control;
1261 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1262
1263 /* ERRORS */
1264 error_operation_failed:
1265 {
1266 GST_ERROR ("could not change rate control mode after encoding started");
1267 return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
1268 }
1269 error_unsupported_rate_control:
1270 {
1271 GST_ERROR ("unsupported rate control mode (%d)", rate_control);
1272 return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_RATE_CONTROL;
1273 }
1274 }
1275
1276 /**
1277 * gst_vaapi_encoder_set_bitrate:
1278 * @encoder: a #GstVaapiEncoder
1279 * @bitrate: the requested bitrate (in kbps)
1280 *
1281 * Notifies the @encoder to use the supplied @bitrate value.
1282 *
1283 * Note: currently, the bitrate can only be specified before the first
1284 * frame is encoded. Afterwards, any change to this parameter is
1285 * invalid and @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED is
1286 * returned.
1287 *
1288 * Return value: a #GstVaapiEncoderStatus
1289 */
1290 GstVaapiEncoderStatus
gst_vaapi_encoder_set_bitrate(GstVaapiEncoder * encoder,guint bitrate)1291 gst_vaapi_encoder_set_bitrate (GstVaapiEncoder * encoder, guint bitrate)
1292 {
1293 g_return_val_if_fail (encoder != NULL, 0);
1294
1295 if (encoder->bitrate != bitrate && encoder->num_codedbuf_queued > 0) {
1296 GST_INFO ("Bitrate is changed to %d on runtime", bitrate);
1297 encoder->bitrate = bitrate;
1298 return gst_vaapi_encoder_reconfigure_internal (encoder);
1299 }
1300
1301 encoder->bitrate = bitrate;
1302 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1303 }
1304
1305 /**
1306 * gst_vaapi_encoder_set_keyframe_period:
1307 * @encoder: a #GstVaapiEncoder
1308 * @keyframe_period: the maximal distance between two keyframes
1309 *
1310 * Notifies the @encoder to use the supplied @keyframe_period value.
1311 *
1312 * Note: currently, the keyframe period can only be specified before
1313 * the last call to gst_vaapi_encoder_set_codec_state(), which shall
1314 * occur before the first frame is encoded. Afterwards, any change to
1315 * this parameter causes gst_vaapi_encoder_set_keyframe_period() to
1316 * return @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED.
1317 *
1318 * Return value: a #GstVaapiEncoderStatus
1319 */
1320 GstVaapiEncoderStatus
gst_vaapi_encoder_set_keyframe_period(GstVaapiEncoder * encoder,guint keyframe_period)1321 gst_vaapi_encoder_set_keyframe_period (GstVaapiEncoder * encoder,
1322 guint keyframe_period)
1323 {
1324 g_return_val_if_fail (encoder != NULL, 0);
1325
1326 if (encoder->keyframe_period != keyframe_period
1327 && encoder->num_codedbuf_queued > 0)
1328 goto error_operation_failed;
1329
1330 encoder->keyframe_period = keyframe_period;
1331 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1332
1333 /* ERRORS */
1334 error_operation_failed:
1335 {
1336 GST_ERROR ("could not change keyframe period after encoding started");
1337 return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
1338 }
1339 }
1340
1341 /**
1342 * gst_vaapi_encoder_set_tuning:
1343 * @encoder: a #GstVaapiEncoder
1344 * @tuning: the #GstVaapiEncoderTune option
1345 *
1346 * Notifies the @encoder to use the supplied @tuning option.
1347 *
1348 * Note: currently, the tuning option can only be specified before the
1349 * last call to gst_vaapi_encoder_set_codec_state(), which shall occur
1350 * before the first frame is encoded. Afterwards, any change to this
1351 * parameter causes gst_vaapi_encoder_set_tuning() to return
1352 * @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED.
1353 *
1354 * Return value: a #GstVaapiEncoderStatus
1355 */
1356 GstVaapiEncoderStatus
gst_vaapi_encoder_set_tuning(GstVaapiEncoder * encoder,GstVaapiEncoderTune tuning)1357 gst_vaapi_encoder_set_tuning (GstVaapiEncoder * encoder,
1358 GstVaapiEncoderTune tuning)
1359 {
1360 g_return_val_if_fail (encoder != NULL, 0);
1361
1362 if (encoder->tune != tuning && encoder->num_codedbuf_queued > 0)
1363 goto error_operation_failed;
1364
1365 encoder->tune = tuning;
1366 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1367
1368 /* ERRORS */
1369 error_operation_failed:
1370 {
1371 GST_ERROR ("could not change tuning options after encoding started");
1372 return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
1373 }
1374 }
1375
1376 /**
1377 * gst_vaapi_encoder_set_quality_level:
1378 * @encoder: a #GstVaapiEncoder
1379 * @quality_level: the encoder quality level
1380 *
1381 * Notifies the @encoder to use the supplied @quality_level value.
1382 *
1383 * Note: currently, the quality_level can only be specified before
1384 * the last call to gst_vaapi_encoder_set_codec_state(), which shall
1385 * occur before the first frame is encoded. Afterwards, any change to
1386 * this parameter causes gst_vaapi_encoder_set_quality_level() to
1387 * return @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED.
1388 *
1389 * Return value: a #GstVaapiEncoderStatus
1390 */
1391 GstVaapiEncoderStatus
gst_vaapi_encoder_set_quality_level(GstVaapiEncoder * encoder,guint quality_level)1392 gst_vaapi_encoder_set_quality_level (GstVaapiEncoder * encoder,
1393 guint quality_level)
1394 {
1395 g_return_val_if_fail (encoder != NULL, 0);
1396
1397 if (GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) != quality_level
1398 && encoder->num_codedbuf_queued > 0)
1399 goto error_operation_failed;
1400
1401 GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) = quality_level;
1402 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1403
1404 /* ERRORS */
1405 error_operation_failed:
1406 {
1407 GST_ERROR ("could not change quality level after encoding started");
1408 return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
1409 }
1410 }
1411
1412 /* Initialize default values for configurable properties */
1413 static gboolean
gst_vaapi_encoder_init_properties(GstVaapiEncoder * encoder)1414 gst_vaapi_encoder_init_properties (GstVaapiEncoder * encoder)
1415 {
1416 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
1417 GPtrArray *props;
1418 guint i;
1419
1420 props = klass->get_default_properties ();
1421 if (!props)
1422 return FALSE;
1423
1424 encoder->properties = props;
1425 for (i = 0; i < props->len; i++) {
1426 GstVaapiEncoderPropInfo *const prop = g_ptr_array_index (props, i);
1427
1428 if (gst_vaapi_encoder_set_property (encoder, prop->prop,
1429 NULL) != GST_VAAPI_ENCODER_STATUS_SUCCESS)
1430 return FALSE;
1431 }
1432
1433 return TRUE;
1434 }
1435
1436 /* Base encoder initialization (internal) */
1437 static gboolean
gst_vaapi_encoder_init(GstVaapiEncoder * encoder,GstVaapiDisplay * display)1438 gst_vaapi_encoder_init (GstVaapiEncoder * encoder, GstVaapiDisplay * display)
1439 {
1440 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
1441
1442 g_return_val_if_fail (display != NULL, FALSE);
1443
1444 #define CHECK_VTABLE_HOOK(FUNC) do { \
1445 if (!klass->FUNC) \
1446 goto error_invalid_vtable; \
1447 } while (0)
1448
1449 CHECK_VTABLE_HOOK (init);
1450 CHECK_VTABLE_HOOK (finalize);
1451 CHECK_VTABLE_HOOK (get_default_properties);
1452 CHECK_VTABLE_HOOK (reconfigure);
1453 CHECK_VTABLE_HOOK (encode);
1454 CHECK_VTABLE_HOOK (reordering);
1455 CHECK_VTABLE_HOOK (flush);
1456
1457 #undef CHECK_VTABLE_HOOK
1458
1459 encoder->display = gst_object_ref (display);
1460 encoder->va_display = gst_vaapi_display_get_display (display);
1461 encoder->va_context = VA_INVALID_ID;
1462
1463 gst_video_info_init (&encoder->video_info);
1464
1465 g_mutex_init (&encoder->mutex);
1466 g_cond_init (&encoder->surface_free);
1467 g_cond_init (&encoder->codedbuf_free);
1468
1469 encoder->codedbuf_queue = g_async_queue_new_full ((GDestroyNotify)
1470 gst_vaapi_coded_buffer_proxy_unref);
1471 if (!encoder->codedbuf_queue)
1472 return FALSE;
1473
1474 if (!klass->init (encoder))
1475 return FALSE;
1476 if (!gst_vaapi_encoder_init_properties (encoder))
1477 return FALSE;
1478 return TRUE;
1479
1480 /* ERRORS */
1481 error_invalid_vtable:
1482 {
1483 GST_ERROR ("invalid subclass hook (internal error)");
1484 return FALSE;
1485 }
1486 }
1487
1488 /* Base encoder cleanup (internal) */
1489 void
gst_vaapi_encoder_finalize(GstVaapiEncoder * encoder)1490 gst_vaapi_encoder_finalize (GstVaapiEncoder * encoder)
1491 {
1492 GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
1493
1494 klass->finalize (encoder);
1495
1496 gst_vaapi_object_replace (&encoder->context, NULL);
1497 gst_vaapi_display_replace (&encoder->display, NULL);
1498 encoder->va_display = NULL;
1499
1500 if (encoder->properties) {
1501 g_ptr_array_unref (encoder->properties);
1502 encoder->properties = NULL;
1503 }
1504
1505 gst_vaapi_video_pool_replace (&encoder->codedbuf_pool, NULL);
1506 if (encoder->codedbuf_queue) {
1507 g_async_queue_unref (encoder->codedbuf_queue);
1508 encoder->codedbuf_queue = NULL;
1509 }
1510 g_cond_clear (&encoder->surface_free);
1511 g_cond_clear (&encoder->codedbuf_free);
1512 g_mutex_clear (&encoder->mutex);
1513 }
1514
1515 /* Helper function to create new GstVaapiEncoder instances (internal) */
1516 GstVaapiEncoder *
gst_vaapi_encoder_new(const GstVaapiEncoderClass * klass,GstVaapiDisplay * display)1517 gst_vaapi_encoder_new (const GstVaapiEncoderClass * klass,
1518 GstVaapiDisplay * display)
1519 {
1520 GstVaapiEncoder *encoder;
1521
1522 encoder = (GstVaapiEncoder *)
1523 gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS (klass));
1524 if (!encoder)
1525 return NULL;
1526
1527 if (!gst_vaapi_encoder_init (encoder, display))
1528 goto error;
1529 return encoder;
1530
1531 /* ERRORS */
1532 error:
1533 {
1534 gst_vaapi_encoder_unref (encoder);
1535 return NULL;
1536 }
1537 }
1538
1539 static GstVaapiContext *
create_test_context_config(GstVaapiEncoder * encoder,GstVaapiProfile profile)1540 create_test_context_config (GstVaapiEncoder * encoder, GstVaapiProfile profile)
1541 {
1542 GstVaapiContextInfo cip = { 0, };
1543 GstVaapiContext *ctxt;
1544
1545 if (encoder->context)
1546 return gst_vaapi_object_ref (encoder->context);
1547
1548 /* if there is no profile, let's figure out one */
1549 if (profile == GST_VAAPI_PROFILE_UNKNOWN)
1550 profile = get_profile (encoder);
1551
1552 init_context_info (encoder, &cip, profile);
1553 ctxt = gst_vaapi_context_new (encoder->display, &cip);
1554 return ctxt;
1555 }
1556
1557 static GArray *
get_profile_surface_formats(GstVaapiEncoder * encoder,GstVaapiProfile profile)1558 get_profile_surface_formats (GstVaapiEncoder * encoder, GstVaapiProfile profile)
1559 {
1560 GstVaapiContext *ctxt;
1561 GArray *formats;
1562
1563 ctxt = create_test_context_config (encoder, profile);
1564 if (!ctxt)
1565 return NULL;
1566 formats = gst_vaapi_context_get_surface_formats (ctxt);
1567 gst_vaapi_object_unref (ctxt);
1568 return formats;
1569 }
1570
1571 static gboolean
merge_profile_surface_formats(GstVaapiEncoder * encoder,GstVaapiProfile profile,GArray * formats)1572 merge_profile_surface_formats (GstVaapiEncoder * encoder,
1573 GstVaapiProfile profile, GArray * formats)
1574 {
1575 GArray *surface_fmts;
1576 guint i, j;
1577 GstVideoFormat fmt, sfmt;
1578
1579 if (profile == GST_VAAPI_PROFILE_UNKNOWN)
1580 return FALSE;
1581
1582 surface_fmts = get_profile_surface_formats (encoder, profile);
1583 if (!surface_fmts)
1584 return FALSE;
1585
1586 for (i = 0; i < surface_fmts->len; i++) {
1587 sfmt = g_array_index (surface_fmts, GstVideoFormat, i);
1588 for (j = 0; j < formats->len; j++) {
1589 fmt = g_array_index (formats, GstVideoFormat, j);
1590 if (fmt == sfmt)
1591 break;
1592 }
1593 if (j >= formats->len)
1594 g_array_append_val (formats, sfmt);
1595 }
1596
1597 g_array_unref (surface_fmts);
1598 return TRUE;
1599 }
1600
1601 /**
1602 * gst_vaapi_encoder_get_surface_formats:
1603 * @encoder: a #GstVaapiEncoder instances
1604 *
1605 * Fetches the valid surface formats for the current VAConfig
1606 *
1607 * Returns: a #GArray of valid formats for the current VAConfig
1608 **/
1609 GArray *
gst_vaapi_encoder_get_surface_formats(GstVaapiEncoder * encoder,GstVaapiProfile profile)1610 gst_vaapi_encoder_get_surface_formats (GstVaapiEncoder * encoder,
1611 GstVaapiProfile profile)
1612 {
1613 const GstVaapiEncoderClassData *const cdata =
1614 GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data;
1615 GArray *profiles, *formats;
1616 guint i;
1617
1618 if (profile || encoder->context)
1619 return get_profile_surface_formats (encoder, profile);
1620
1621 /* no specific context neither specific profile, let's iterate among
1622 * the codec's profiles */
1623 profiles = gst_vaapi_display_get_encode_profiles (encoder->display);
1624 if (!profiles)
1625 return NULL;
1626
1627 formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
1628 for (i = 0; i < profiles->len; i++) {
1629 profile = g_array_index (profiles, GstVaapiProfile, i);
1630 if (gst_vaapi_profile_get_codec (profile) == cdata->codec) {
1631 if (!merge_profile_surface_formats (encoder, profile, formats)) {
1632 g_array_unref (formats);
1633 formats = NULL;
1634 break;
1635 }
1636 }
1637 }
1638
1639 g_array_unref (profiles);
1640
1641 return formats;
1642 }
1643
1644 /**
1645 * gst_vaapi_encoder_ensure_num_slices:
1646 * @encoder: a #GstVaapiEncoder
1647 * @profile: a #GstVaapiProfile
1648 * @entrypoint: a #GstVaapiEntrypoint
1649 * @media_max_slices: the number of the slices permitted by the stream
1650 * @num_slices: (out): the possible number of slices to process
1651 *
1652 * This function will clamp the @num_slices provided by the user,
1653 * according the limit of the number of slices permitted by the stream
1654 * and by the hardware.
1655 *
1656 * We need to pass the @profile and the @entrypoint, because at the
1657 * moment the encoder base class, still doesn't have them assigned,
1658 * and this function is meant to be called by the derived classes
1659 * while they are configured.
1660 *
1661 * Returns: %TRUE if the number of slices is different than zero.
1662 **/
1663 gboolean
gst_vaapi_encoder_ensure_num_slices(GstVaapiEncoder * encoder,GstVaapiProfile profile,GstVaapiEntrypoint entrypoint,guint media_max_slices,guint * num_slices)1664 gst_vaapi_encoder_ensure_num_slices (GstVaapiEncoder * encoder,
1665 GstVaapiProfile profile, GstVaapiEntrypoint entrypoint,
1666 guint media_max_slices, guint * num_slices)
1667 {
1668 VAProfile va_profile;
1669 VAEntrypoint va_entrypoint;
1670 guint max_slices, num;
1671
1672 va_profile = gst_vaapi_profile_get_va_profile (profile);
1673 va_entrypoint = gst_vaapi_entrypoint_get_va_entrypoint (entrypoint);
1674
1675 if (!gst_vaapi_get_config_attribute (encoder->display, va_profile,
1676 va_entrypoint, VAConfigAttribEncMaxSlices, &max_slices)) {
1677 *num_slices = 1;
1678 return TRUE;
1679 }
1680
1681 num = *num_slices;
1682 if (num > max_slices)
1683 num = max_slices;
1684 if (num > media_max_slices)
1685 num = media_max_slices;
1686
1687 if (num == 0)
1688 return FALSE;
1689 *num_slices = num;
1690 return TRUE;
1691 }
1692
1693 /**
1694 * gst_vaapi_encoder_ensure_max_num_ref_frames:
1695 * @encoder: a #GstVaapiEncoder
1696 * @profile: a #GstVaapiProfile
1697 * @entrypoint: a #GstVaapiEntrypoint
1698 *
1699 * This function will query VAConfigAttribEncMaxRefFrames to get the
1700 * maximum number of reference frames in the driver,
1701 * for both the reference picture list 0 (bottom 16 bits) and
1702 * the reference picture list 1 (top 16 bits).
1703 *
1704 * We need to pass the @profile and the @entrypoint, because at the
1705 * moment the encoder base class, still doesn't have them assigned,
1706 * and this function is meant to be called by the derived classes
1707 * while they are configured.
1708 *
1709 * Returns: %TRUE if the number of reference frames is different than zero.
1710 **/
1711 gboolean
gst_vaapi_encoder_ensure_max_num_ref_frames(GstVaapiEncoder * encoder,GstVaapiProfile profile,GstVaapiEntrypoint entrypoint)1712 gst_vaapi_encoder_ensure_max_num_ref_frames (GstVaapiEncoder * encoder,
1713 GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
1714 {
1715 VAProfile va_profile;
1716 VAEntrypoint va_entrypoint;
1717 guint max_ref_frames;
1718
1719 va_profile = gst_vaapi_profile_get_va_profile (profile);
1720 va_entrypoint = gst_vaapi_entrypoint_get_va_entrypoint (entrypoint);
1721
1722 if (!gst_vaapi_get_config_attribute (encoder->display, va_profile,
1723 va_entrypoint, VAConfigAttribEncMaxRefFrames, &max_ref_frames)) {
1724 /* Set the default the number of reference frames */
1725 encoder->max_num_ref_frames_0 = 1;
1726 encoder->max_num_ref_frames_1 = 0;
1727 return TRUE;
1728 }
1729
1730 encoder->max_num_ref_frames_0 = max_ref_frames & 0xffff;
1731 encoder->max_num_ref_frames_1 = (max_ref_frames >> 16) & 0xffff;
1732
1733 return TRUE;
1734 }
1735
1736 /** Returns a GType for the #GstVaapiEncoderTune set */
1737 GType
gst_vaapi_encoder_tune_get_type(void)1738 gst_vaapi_encoder_tune_get_type (void)
1739 {
1740 static volatile gsize g_type = 0;
1741
1742 static const GEnumValue encoder_tune_values[] = {
1743 /* *INDENT-OFF* */
1744 { GST_VAAPI_ENCODER_TUNE_NONE,
1745 "None", "none" },
1746 { GST_VAAPI_ENCODER_TUNE_HIGH_COMPRESSION,
1747 "High compression", "high-compression" },
1748 { GST_VAAPI_ENCODER_TUNE_LOW_LATENCY,
1749 "Low latency", "low-latency" },
1750 { GST_VAAPI_ENCODER_TUNE_LOW_POWER,
1751 "Low power mode", "low-power" },
1752 { 0, NULL, NULL },
1753 /* *INDENT-ON* */
1754 };
1755
1756 if (g_once_init_enter (&g_type)) {
1757 GType type =
1758 g_enum_register_static ("GstVaapiEncoderTune", encoder_tune_values);
1759 g_once_init_leave (&g_type, type);
1760 }
1761 return g_type;
1762 }
1763
1764 /** Returns a GType for the #GstVaapiEncoderMbbrc set */
1765 GType
gst_vaapi_encoder_mbbrc_get_type(void)1766 gst_vaapi_encoder_mbbrc_get_type (void)
1767 {
1768 static volatile gsize g_type = 0;
1769
1770 if (g_once_init_enter (&g_type)) {
1771 static const GEnumValue encoder_mbbrc_values[] = {
1772 {GST_VAAPI_ENCODER_MBBRC_AUTO, "Auto", "auto"},
1773 {GST_VAAPI_ENCODER_MBBRC_ON, "On", "on"},
1774 {GST_VAAPI_ENCODER_MBBRC_OFF, "Off", "off"},
1775 {0, NULL, NULL},
1776 };
1777
1778 GType type =
1779 g_enum_register_static (g_intern_static_string ("GstVaapiEncoderMbbrc"),
1780 encoder_mbbrc_values);
1781 g_once_init_leave (&g_type, type);
1782 }
1783 return g_type;
1784 }
1785