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