1 /*
2  *  gstvaapiencoder_vp9.c - VP9 encoder
3  *
4  *  Copyright (C) 2016 Intel Corporation
5  *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public License
9  *  as published by the Free Software Foundation; either version 2.1
10  *  of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free
19  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301 USA
21  */
22 
23 #include "sysdeps.h"
24 #include <gst/base/gstbitwriter.h>
25 #include <gst/codecparsers/gstvp9parser.h>
26 #include "gstvaapicompat.h"
27 #include "gstvaapiencoder_priv.h"
28 #include "gstvaapiencoder_vp9.h"
29 #include "gstvaapicodedbufferproxy_priv.h"
30 #include "gstvaapisurface.h"
31 
32 #define DEBUG 1
33 #include "gstvaapidebug.h"
34 
35 /* Define default rate control mode ("constant-qp") */
36 #define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP
37 
38 /* Supported set of VA rate controls, within this implementation */
39 #define SUPPORTED_RATECONTROLS                  \
40   (GST_VAAPI_RATECONTROL_MASK (CQP) |           \
41    GST_VAAPI_RATECONTROL_MASK (CBR) |           \
42    GST_VAAPI_RATECONTROL_MASK (VBR))
43 
44 /* Supported set of tuning options, within this implementation */
45 #define SUPPORTED_TUNE_OPTIONS \
46   (GST_VAAPI_ENCODER_TUNE_MASK (NONE))
47 
48 /* Supported set of VA packed headers, within this implementation */
49 #define SUPPORTED_PACKED_HEADERS                \
50   (VA_ENC_PACKED_HEADER_NONE)
51 
52 #define DEFAULT_LOOP_FILTER_LEVEL 10
53 #define DEFAULT_SHARPNESS_LEVEL 0
54 #define DEFAULT_YAC_QINDEX 60
55 
56 #define MAX_FRAME_WIDTH 4096
57 #define MAX_FRAME_HEIGHT 4096
58 
59 /* Default CPB length (in milliseconds) */
60 #define DEFAULT_CPB_LENGTH 1500
61 
62 typedef enum
63 {
64   GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0 = 0,
65   GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1 = 1
66 } GstVaapiEnoderVP9RefPicMode;
67 
68 static GType
gst_vaapi_encoder_vp9_ref_pic_mode_type(void)69 gst_vaapi_encoder_vp9_ref_pic_mode_type (void)
70 {
71   static GType gtype = 0;
72 
73   if (gtype == 0) {
74     static const GEnumValue values[] = {
75       {GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0,
76             "Use Keyframe(Alt & Gold) and Previousframe(Last) for prediction ",
77           "mode-0"},
78       {GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1,
79             "Use last three frames for prediction (n:Last n-1:Gold n-2:Alt)",
80           "mode-1"},
81       {0, NULL, NULL},
82     };
83 
84     gtype = g_enum_register_static ("GstVaapiEncoderVP9RefPicMode", values);
85   }
86   return gtype;
87 }
88 
89 
90 /* ------------------------------------------------------------------------- */
91 /* --- VP9 Encoder                                                      --- */
92 /* ------------------------------------------------------------------------- */
93 
94 struct _GstVaapiEncoderVP9
95 {
96   GstVaapiEncoder parent_instance;
97   GstVaapiProfile profile;
98   guint loop_filter_level;
99   guint sharpness_level;
100   guint yac_qi;
101   guint ref_pic_mode;
102   guint frame_num;
103   GstVaapiSurfaceProxy *ref_list[GST_VP9_REF_FRAMES];   /* reference list */
104   guint ref_list_idx;           /* next free slot in ref_list */
105 
106   /* Bitrate contral parameters, CPB = Coded Picture Buffer */
107   guint bitrate_bits;           /* bitrate (bits) */
108   guint cpb_length;             /* length of CPB buffer (ms) */
109 };
110 
111 /* Estimates a good enough bitrate if none was supplied */
112 static void
ensure_bitrate(GstVaapiEncoderVP9 * encoder)113 ensure_bitrate (GstVaapiEncoderVP9 * encoder)
114 {
115   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
116   guint bitrate;
117 
118   switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
119     case GST_VAAPI_RATECONTROL_CBR:
120     case GST_VAAPI_RATECONTROL_VBR:
121       if (!base_encoder->bitrate) {
122         /* FIXME: Provide better estimation */
123         /* Using a 1/6 compression ratio */
124         /* 12 bits per pixel fro yuv420 */
125         base_encoder->bitrate =
126             (GST_VAAPI_ENCODER_WIDTH (encoder) *
127             GST_VAAPI_ENCODER_HEIGHT (encoder) * 12 / 6) *
128             GST_VAAPI_ENCODER_FPS_N (encoder) /
129             GST_VAAPI_ENCODER_FPS_D (encoder) / 1000;
130         GST_INFO ("target bitrate computed to %u kbps", base_encoder->bitrate);
131       }
132 
133       bitrate = (base_encoder->bitrate * 1000);
134       if (bitrate != encoder->bitrate_bits) {
135         GST_DEBUG ("HRD bitrate: %u bits/sec", bitrate);
136         encoder->bitrate_bits = bitrate;
137       }
138 
139       break;
140     default:
141       base_encoder->bitrate = 0;
142       break;
143   }
144 }
145 
146 /* Derives the profile that suits best to the configuration */
147 static GstVaapiEncoderStatus
ensure_profile(GstVaapiEncoderVP9 * encoder)148 ensure_profile (GstVaapiEncoderVP9 * encoder)
149 {
150   /* Always start from "simple" profile for maximum compatibility */
151   encoder->profile = GST_VAAPI_PROFILE_VP9_0;
152 
153   /* Ensure bitrate if not set already */
154   ensure_bitrate (encoder);
155 
156   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
157 }
158 
159 /* Derives the profile supported by the underlying hardware */
160 static gboolean
ensure_hw_profile(GstVaapiEncoderVP9 * encoder)161 ensure_hw_profile (GstVaapiEncoderVP9 * encoder)
162 {
163   GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
164   GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
165   GstVaapiProfile profile, profiles[2];
166   guint i, num_profiles = 0;
167 
168   profiles[num_profiles++] = encoder->profile;
169 
170   profile = GST_VAAPI_PROFILE_UNKNOWN;
171   for (i = 0; i < num_profiles; i++) {
172     if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) {
173       profile = profiles[i];
174       break;
175     }
176   }
177   if (profile == GST_VAAPI_PROFILE_UNKNOWN)
178     goto error_unsupported_profile;
179 
180   GST_VAAPI_ENCODER_CAST (encoder)->profile = profile;
181   return TRUE;
182 
183   /* ERRORS */
184 error_unsupported_profile:
185   {
186     GST_ERROR ("unsupported HW profile %s",
187         gst_vaapi_profile_get_name (encoder->profile));
188     return FALSE;
189   }
190 }
191 
192 static GstVaapiEncoderStatus
set_context_info(GstVaapiEncoder * base_encoder)193 set_context_info (GstVaapiEncoder * base_encoder)
194 {
195   GstVaapiEncoderVP9 *encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
196   GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
197   const guint DEFAULT_SURFACES_COUNT = 2;
198 
199   /* FIXME: Maximum sizes for common headers (in bytes) */
200 
201   if (!ensure_hw_profile (encoder))
202     return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
203 
204   base_encoder->num_ref_frames = 3 + DEFAULT_SURFACES_COUNT;
205 
206   /* Only YUV 4:2:0 formats are supported for now. */
207   base_encoder->codedbuf_size = GST_ROUND_UP_16 (vip->width) *
208       GST_ROUND_UP_16 (vip->height) * 3 / 2;
209 
210   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
211 }
212 
213 static gboolean
fill_sequence(GstVaapiEncoderVP9 * encoder,GstVaapiEncSequence * sequence)214 fill_sequence (GstVaapiEncoderVP9 * encoder, GstVaapiEncSequence * sequence)
215 {
216   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
217   VAEncSequenceParameterBufferVP9 *const seq_param = sequence->param;
218 
219   memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferVP9));
220 
221   seq_param->max_frame_width = MAX_FRAME_WIDTH;
222   seq_param->max_frame_height = MAX_FRAME_HEIGHT;
223 
224   /* keyframe minimum interval */
225   seq_param->kf_min_dist = 1;
226   /* keyframe maximum interval */
227   seq_param->kf_max_dist = base_encoder->keyframe_period;
228   seq_param->intra_period = base_encoder->keyframe_period;
229   seq_param->bits_per_second = encoder->bitrate_bits;
230 
231   return TRUE;
232 }
233 
234 static gboolean
ensure_sequence(GstVaapiEncoderVP9 * encoder,GstVaapiEncPicture * picture)235 ensure_sequence (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture)
236 {
237   GstVaapiEncSequence *sequence;
238 
239   g_assert (picture);
240 
241   if (picture->type != GST_VAAPI_PICTURE_TYPE_I)
242     return TRUE;
243 
244   sequence = GST_VAAPI_ENC_SEQUENCE_NEW (VP9, encoder);
245   if (!sequence)
246     goto error;
247 
248   if (!fill_sequence (encoder, sequence))
249     goto error;
250 
251   gst_vaapi_enc_picture_set_sequence (picture, sequence);
252   gst_vaapi_codec_object_replace (&sequence, NULL);
253   return TRUE;
254 
255   /* ERRORS */
256 error:
257   {
258     gst_vaapi_codec_object_replace (&sequence, NULL);
259     return FALSE;
260   }
261 }
262 
263 static gboolean
ensure_control_rate_params(GstVaapiEncoderVP9 * encoder)264 ensure_control_rate_params (GstVaapiEncoderVP9 * encoder)
265 {
266   if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP)
267     return TRUE;
268 
269   /* RateControl params */
270   GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).bits_per_second =
271       encoder->bitrate_bits;
272   GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).window_size = encoder->cpb_length;
273 
274   /* *INDENT-OFF* */
275   /* HRD params */
276   GST_VAAPI_ENCODER_VA_HRD (encoder) = (VAEncMiscParameterHRD) {
277     .buffer_size = encoder->bitrate_bits * 2,
278     .initial_buffer_fullness = encoder->bitrate_bits,
279   };
280   /* *INDENT-ON* */
281 
282   return TRUE;
283 }
284 
285 static gboolean
ensure_misc_params(GstVaapiEncoderVP9 * encoder,GstVaapiEncPicture * picture)286 ensure_misc_params (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture)
287 {
288   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
289 
290   if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture))
291     return FALSE;
292   if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture))
293     return FALSE;
294   return TRUE;
295 }
296 
297 static void
get_ref_indices(guint ref_pic_mode,guint ref_list_idx,guint * last_idx,guint * gf_idx,guint * arf_idx,guint8 * refresh_frame_flags)298 get_ref_indices (guint ref_pic_mode, guint ref_list_idx, guint * last_idx,
299     guint * gf_idx, guint * arf_idx, guint8 * refresh_frame_flags)
300 {
301   if (ref_pic_mode == GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0) {
302     *last_idx = ref_list_idx - 1;
303     *gf_idx = 1;
304     *arf_idx = 2;
305     *refresh_frame_flags = 0x01;
306   } else if (ref_pic_mode == GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1) {
307     gint last_filled_idx = (ref_list_idx - 1) & (GST_VP9_REF_FRAMES - 1);
308 
309     *last_idx = last_filled_idx;
310     *gf_idx = (last_filled_idx - 1) & (GST_VP9_REF_FRAMES - 1);
311     *arf_idx = (last_filled_idx - 2) & (GST_VP9_REF_FRAMES - 1);
312 
313     *refresh_frame_flags = 1 << ((*last_idx + 1) % GST_VP9_REF_FRAMES);
314   }
315 
316   GST_LOG
317       ("last_ref_idx:%d gold_ref_idx:%d alt_reff_idx:%d refesh_frame_flag:%x",
318       *last_idx, *gf_idx, *arf_idx, *refresh_frame_flags);
319 }
320 
321 static gboolean
fill_picture(GstVaapiEncoderVP9 * encoder,GstVaapiEncPicture * picture,GstVaapiCodedBuffer * codedbuf,GstVaapiSurfaceProxy * surface)322 fill_picture (GstVaapiEncoderVP9 * encoder,
323     GstVaapiEncPicture * picture,
324     GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
325 {
326   VAEncPictureParameterBufferVP9 *const pic_param = picture->param;
327   guint i, last_idx = 0, gf_idx = 0, arf_idx = 0;
328   guint8 refresh_frame_flags = 0;
329 
330   memset (pic_param, 0, sizeof (VAEncPictureParameterBufferVP9));
331 
332   pic_param->reconstructed_frame = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
333   pic_param->coded_buf = GST_VAAPI_OBJECT_ID (codedbuf);
334 
335   /* Update Reference Frame list */
336   if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
337     memset (pic_param->reference_frames, 0xFF,
338         sizeof (pic_param->reference_frames));
339   else {
340     for (i = 0; i < G_N_ELEMENTS (pic_param->reference_frames); i++) {
341       pic_param->reference_frames[i] =
342           GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->ref_list[i]);
343     }
344   }
345 
346   /* It is possible to have dynamic scaling with gpu by providing
347    * src and destination resoltuion. For now we are just using
348    * default encoder width and height */
349   pic_param->frame_width_src = GST_VAAPI_ENCODER_WIDTH (encoder);
350   pic_param->frame_height_src = GST_VAAPI_ENCODER_HEIGHT (encoder);
351   pic_param->frame_width_dst = GST_VAAPI_ENCODER_WIDTH (encoder);
352   pic_param->frame_height_dst = GST_VAAPI_ENCODER_HEIGHT (encoder);
353 
354   pic_param->pic_flags.bits.show_frame = 1;
355 
356   if (picture->type == GST_VAAPI_PICTURE_TYPE_P) {
357     pic_param->pic_flags.bits.frame_type = GST_VP9_INTER_FRAME;
358 
359     /* use three of the reference frames (last, golden and altref)
360      * for prediction */
361     pic_param->ref_flags.bits.ref_frame_ctrl_l0 = 0x7;
362 
363     get_ref_indices (encoder->ref_pic_mode, encoder->ref_list_idx, &last_idx,
364         &gf_idx, &arf_idx, &refresh_frame_flags);
365 
366     pic_param->ref_flags.bits.ref_last_idx = last_idx;
367     pic_param->ref_flags.bits.ref_gf_idx = gf_idx;
368     pic_param->ref_flags.bits.ref_arf_idx = arf_idx;
369     pic_param->refresh_frame_flags = refresh_frame_flags;
370   }
371 
372   pic_param->luma_ac_qindex = encoder->yac_qi;
373   pic_param->luma_dc_qindex_delta = 1;
374   pic_param->chroma_ac_qindex_delta = 1;
375   pic_param->chroma_dc_qindex_delta = 1;
376   pic_param->filter_level = encoder->loop_filter_level;
377   pic_param->sharpness_level = encoder->sharpness_level;
378 
379   return TRUE;
380 }
381 
382 static gboolean
ensure_picture(GstVaapiEncoderVP9 * encoder,GstVaapiEncPicture * picture,GstVaapiCodedBufferProxy * codedbuf_proxy,GstVaapiSurfaceProxy * surface)383 ensure_picture (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture,
384     GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
385 {
386   GstVaapiCodedBuffer *const codedbuf =
387       GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
388 
389   if (!fill_picture (encoder, picture, codedbuf, surface))
390     return FALSE;
391 
392   return TRUE;
393 }
394 
395 static void
update_ref_list(GstVaapiEncoderVP9 * encoder,GstVaapiEncPicture * picture,GstVaapiSurfaceProxy * ref)396 update_ref_list (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture,
397     GstVaapiSurfaceProxy * ref)
398 {
399   guint i;
400 
401   if (picture->type == GST_VAAPI_PICTURE_TYPE_I) {
402     for (i = 0; i < G_N_ELEMENTS (encoder->ref_list); i++)
403       gst_vaapi_surface_proxy_replace (&encoder->ref_list[i], ref);
404     gst_vaapi_surface_proxy_unref (ref);
405     /* set next free slot index */
406     encoder->ref_list_idx = 1;
407     return;
408   }
409 
410   switch (encoder->ref_pic_mode) {
411     case GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0:
412       gst_vaapi_surface_proxy_replace (&encoder->ref_list[0], ref);
413       gst_vaapi_surface_proxy_unref (ref);
414       break;
415     case GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1:
416       gst_vaapi_surface_proxy_replace (&encoder->
417           ref_list[encoder->ref_list_idx], ref);
418       gst_vaapi_surface_proxy_unref (ref);
419       encoder->ref_list_idx = (encoder->ref_list_idx + 1) % GST_VP9_REF_FRAMES;
420       break;
421     default:
422       g_assert ("Code shouldn't reach here");
423       break;
424   }
425 }
426 
427 static GstVaapiEncoderStatus
gst_vaapi_encoder_vp9_encode(GstVaapiEncoder * base_encoder,GstVaapiEncPicture * picture,GstVaapiCodedBufferProxy * codedbuf)428 gst_vaapi_encoder_vp9_encode (GstVaapiEncoder * base_encoder,
429     GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
430 {
431   GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
432   GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
433   GstVaapiSurfaceProxy *reconstruct = NULL;
434 
435   reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
436 
437   g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
438 
439   if (!ensure_sequence (encoder, picture))
440     goto error;
441   if (!ensure_misc_params (encoder, picture))
442     goto error;
443   if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
444     goto error;
445   if (!gst_vaapi_enc_picture_encode (picture))
446     goto error;
447 
448   update_ref_list (encoder, picture, reconstruct);
449 
450   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
451 
452   /* ERRORS */
453 error:
454   {
455     if (reconstruct)
456       gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
457           reconstruct);
458     return ret;
459   }
460 }
461 
462 static GstVaapiEncoderStatus
gst_vaapi_encoder_vp9_flush(GstVaapiEncoder * base_encoder)463 gst_vaapi_encoder_vp9_flush (GstVaapiEncoder * base_encoder)
464 {
465   GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
466 
467   encoder->frame_num = 0;
468 
469   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
470 }
471 
472 static GstVaapiEncoderStatus
gst_vaapi_encoder_vp9_reordering(GstVaapiEncoder * base_encoder,GstVideoCodecFrame * frame,GstVaapiEncPicture ** output)473 gst_vaapi_encoder_vp9_reordering (GstVaapiEncoder * base_encoder,
474     GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
475 {
476   GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
477   GstVaapiEncPicture *picture = NULL;
478   GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
479 
480   if (!frame)
481     return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
482 
483   picture = GST_VAAPI_ENC_PICTURE_NEW (VP9, encoder, frame);
484   if (!picture) {
485     GST_WARNING ("create VP9 picture failed, frame timestamp:%"
486         GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
487     return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
488   }
489 
490   if (encoder->frame_num >= base_encoder->keyframe_period) {
491     encoder->frame_num = 0;
492   }
493   if (encoder->frame_num == 0) {
494     picture->type = GST_VAAPI_PICTURE_TYPE_I;
495     GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
496   } else {
497     picture->type = GST_VAAPI_PICTURE_TYPE_P;
498   }
499 
500   encoder->frame_num++;
501   *output = picture;
502   return status;
503 }
504 
505 static GstVaapiEncoderStatus
gst_vaapi_encoder_vp9_reconfigure(GstVaapiEncoder * base_encoder)506 gst_vaapi_encoder_vp9_reconfigure (GstVaapiEncoder * base_encoder)
507 {
508   GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
509   GstVaapiEncoderStatus status;
510 
511   status = ensure_profile (encoder);
512   if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
513     return status;
514 
515   ensure_control_rate_params (encoder);
516   return set_context_info (base_encoder);
517 }
518 
519 static gboolean
gst_vaapi_encoder_vp9_init(GstVaapiEncoder * base_encoder)520 gst_vaapi_encoder_vp9_init (GstVaapiEncoder * base_encoder)
521 {
522   GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
523 
524   encoder->frame_num = 0;
525   encoder->loop_filter_level = DEFAULT_LOOP_FILTER_LEVEL;
526   encoder->sharpness_level = DEFAULT_SHARPNESS_LEVEL;
527   encoder->yac_qi = DEFAULT_YAC_QINDEX;
528   encoder->cpb_length = DEFAULT_CPB_LENGTH;
529 
530   memset (encoder->ref_list, 0,
531       G_N_ELEMENTS (encoder->ref_list) * sizeof (encoder->ref_list[0]));
532   encoder->ref_list_idx = 0;
533 
534   return TRUE;
535 }
536 
537 static void
gst_vaapi_encoder_vp9_finalize(GstVaapiEncoder * base_encoder)538 gst_vaapi_encoder_vp9_finalize (GstVaapiEncoder * base_encoder)
539 {
540 }
541 
542 static GstVaapiEncoderStatus
gst_vaapi_encoder_vp9_set_property(GstVaapiEncoder * base_encoder,gint prop_id,const GValue * value)543 gst_vaapi_encoder_vp9_set_property (GstVaapiEncoder * base_encoder,
544     gint prop_id, const GValue * value)
545 {
546   GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
547 
548   switch (prop_id) {
549     case GST_VAAPI_ENCODER_VP9_PROP_LOOP_FILTER_LEVEL:
550       encoder->loop_filter_level = g_value_get_uint (value);
551       break;
552     case GST_VAAPI_ENCODER_VP9_PROP_SHARPNESS_LEVEL:
553       encoder->sharpness_level = g_value_get_uint (value);
554       break;
555     case GST_VAAPI_ENCODER_VP9_PROP_YAC_Q_INDEX:
556       encoder->yac_qi = g_value_get_uint (value);
557       break;
558     case GST_VAAPI_ENCODER_VP9_PROP_REF_PIC_MODE:
559       encoder->ref_pic_mode = g_value_get_enum (value);
560       break;
561     case GST_VAAPI_ENCODER_VP9_PROP_CPB_LENGTH:
562       encoder->cpb_length = g_value_get_uint (value);
563       break;
564     default:
565       return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
566   }
567   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
568 }
569 
570 GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (VP9);
571 
572 static inline const GstVaapiEncoderClass *
gst_vaapi_encoder_vp9_class(void)573 gst_vaapi_encoder_vp9_class (void)
574 {
575   static const GstVaapiEncoderClass GstVaapiEncoderVP9Class = {
576     GST_VAAPI_ENCODER_CLASS_INIT (VP9, vp9),
577     .set_property = gst_vaapi_encoder_vp9_set_property,
578   };
579   return &GstVaapiEncoderVP9Class;
580 }
581 
582 /**
583  * gst_vaapi_encoder_vp9_new:
584  * @display: a #GstVaapiDisplay
585  *
586  * Creates a new #GstVaapiEncoder for VP9 encoding.
587  *
588  * Return value: the newly allocated #GstVaapiEncoder object
589  */
590 GstVaapiEncoder *
gst_vaapi_encoder_vp9_new(GstVaapiDisplay * display)591 gst_vaapi_encoder_vp9_new (GstVaapiDisplay * display)
592 {
593   return gst_vaapi_encoder_new (gst_vaapi_encoder_vp9_class (), display);
594 }
595 
596 /**
597  * gst_vaapi_encoder_vp9_get_default_properties:
598  *
599  * Determines the set of common and vp9 specific encoder properties.
600  * The caller owns an extra reference to the resulting array of
601  * #GstVaapiEncoderPropInfo elements, so it shall be released with
602  * g_ptr_array_unref() after usage.
603  *
604  * Return value: the set of encoder properties for #GstVaapiEncoderVP9,
605  *   or %NULL if an error occurred.
606  */
607 GPtrArray *
gst_vaapi_encoder_vp9_get_default_properties(void)608 gst_vaapi_encoder_vp9_get_default_properties (void)
609 {
610   const GstVaapiEncoderClass *const klass = gst_vaapi_encoder_vp9_class ();
611   GPtrArray *props;
612 
613   props = gst_vaapi_encoder_properties_get_default (klass);
614   if (!props)
615     return NULL;
616 
617   GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
618       GST_VAAPI_ENCODER_VP9_PROP_LOOP_FILTER_LEVEL,
619       g_param_spec_uint ("loop-filter-level",
620           "Loop Filter Level",
621           "Controls the deblocking filter strength",
622           0, 63, DEFAULT_LOOP_FILTER_LEVEL,
623           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
624 
625   GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
626       GST_VAAPI_ENCODER_VP9_PROP_SHARPNESS_LEVEL,
627       g_param_spec_uint ("sharpness-level",
628           "Sharpness Level",
629           "Controls the deblocking filter sensitivity",
630           0, 7, DEFAULT_SHARPNESS_LEVEL,
631           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
632 
633   GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
634       GST_VAAPI_ENCODER_VP9_PROP_YAC_Q_INDEX,
635       g_param_spec_uint ("yac-qi",
636           "Luma AC Quant Table index",
637           "Quantization Table index for Luma AC Coefficients",
638           0, 255, DEFAULT_YAC_QINDEX,
639           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
640 
641   GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
642       GST_VAAPI_ENCODER_VP9_PROP_REF_PIC_MODE,
643       g_param_spec_enum ("ref-pic-mode",
644           "RefPic Selection",
645           "Reference Picture Selection Modes",
646           gst_vaapi_encoder_vp9_ref_pic_mode_type (),
647           GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0,
648           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
649 
650   /**
651    * GstVaapiEncoderVP9:cpb-length:
652    *
653    * The size of the Coded Picture Buffer , which means
654    * the window size in milliseconds.
655    *
656    */
657   GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
658       GST_VAAPI_ENCODER_VP9_PROP_CPB_LENGTH,
659       g_param_spec_uint ("cpb-length",
660           "CPB Length", "Length of the CPB_buffer/window_size in milliseconds",
661           1, 10000, DEFAULT_CPB_LENGTH,
662           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
663 
664   return props;
665 }
666