1 /*
2  *  gstvaapiencoder_vp8.c - VP8 encoder
3  *
4  *  Copyright (C) 2015 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/gstvp8parser.h>
26 #include "gstvaapicompat.h"
27 #include "gstvaapiencoder_priv.h"
28 #include "gstvaapiencoder_vp8.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 0
53 #define DEFAULT_SHARPNESS_LEVEL 0
54 #define DEFAULT_YAC_QI 40
55 
56 /* ------------------------------------------------------------------------- */
57 /* --- VP8 Encoder                                                      --- */
58 /* ------------------------------------------------------------------------- */
59 
60 struct _GstVaapiEncoderVP8
61 {
62   GstVaapiEncoder parent_instance;
63   GstVaapiProfile profile;
64   guint loop_filter_level;
65   guint sharpness_level;
66   guint yac_qi;
67   guint frame_num;
68   /* reference list */
69   GstVaapiSurfaceProxy *last_ref;
70   GstVaapiSurfaceProxy *golden_ref;
71   GstVaapiSurfaceProxy *alt_ref;
72 };
73 
74 /* Derives the profile that suits best to the configuration */
75 static GstVaapiEncoderStatus
ensure_profile(GstVaapiEncoderVP8 * encoder)76 ensure_profile (GstVaapiEncoderVP8 * encoder)
77 {
78   /* Always start from "simple" profile for maximum compatibility */
79   encoder->profile = GST_VAAPI_PROFILE_VP8;
80 
81   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
82 }
83 
84 /* Derives the profile supported by the underlying hardware */
85 static gboolean
ensure_hw_profile(GstVaapiEncoderVP8 * encoder)86 ensure_hw_profile (GstVaapiEncoderVP8 * encoder)
87 {
88   GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
89   GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
90   GstVaapiProfile profile, profiles[2];
91   guint i, num_profiles = 0;
92 
93   profiles[num_profiles++] = encoder->profile;
94 
95   profile = GST_VAAPI_PROFILE_UNKNOWN;
96   for (i = 0; i < num_profiles; i++) {
97     if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) {
98       profile = profiles[i];
99       break;
100     }
101   }
102   if (profile == GST_VAAPI_PROFILE_UNKNOWN)
103     goto error_unsupported_profile;
104 
105   GST_VAAPI_ENCODER_CAST (encoder)->profile = profile;
106   return TRUE;
107 
108   /* ERRORS */
109 error_unsupported_profile:
110   {
111     GST_ERROR ("unsupported HW profile %s",
112         gst_vaapi_profile_get_name (encoder->profile));
113     return FALSE;
114   }
115 }
116 
117 static gboolean
ensure_bitrate(GstVaapiEncoderVP8 * encoder)118 ensure_bitrate (GstVaapiEncoderVP8 * encoder)
119 {
120   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
121 
122   /* Default compression: 64 bits per macroblock  */
123   switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
124     case GST_VAAPI_RATECONTROL_CBR:
125     case GST_VAAPI_RATECONTROL_VBR:
126       if (!base_encoder->bitrate) {
127         base_encoder->bitrate =
128             gst_util_uint64_scale (GST_VAAPI_ENCODER_WIDTH (encoder) *
129             GST_VAAPI_ENCODER_HEIGHT (encoder),
130             GST_VAAPI_ENCODER_FPS_N (encoder),
131             GST_VAAPI_ENCODER_FPS_D (encoder)) / (4 * 1000);
132       }
133       break;
134     default:
135       base_encoder->bitrate = 0;
136       break;
137   }
138 
139   return TRUE;
140 }
141 
142 static GstVaapiEncoderStatus
set_context_info(GstVaapiEncoder * base_encoder)143 set_context_info (GstVaapiEncoder * base_encoder)
144 {
145   GstVaapiEncoderVP8 *encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
146   GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
147 
148   /* Maximum sizes for common headers (in bytes) */
149   enum
150   {
151     MAX_FRAME_TAG_SIZE = 10,
152     MAX_UPDATE_SEGMENTATION_SIZE = 13,
153     MAX_MB_LF_ADJUSTMENTS_SIZE = 9,
154     MAX_QUANT_INDICES_SIZE = 5,
155     MAX_TOKEN_PROB_UPDATE_SIZE = 1188,
156     MAX_MV_PROBE_UPDATE_SIZE = 38,
157     MAX_REST_OF_FRAME_HDR_SIZE = 15
158   };
159 
160   if (!ensure_hw_profile (encoder))
161     return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
162 
163   base_encoder->num_ref_frames = 3;
164 
165   /* Only YUV 4:2:0 formats are supported for now. */
166   /* Assumig 4 times compression ratio */
167   base_encoder->codedbuf_size = GST_ROUND_UP_16 (vip->width) *
168       GST_ROUND_UP_16 (vip->height) * 12 / 4;
169 
170   base_encoder->codedbuf_size +=
171       MAX_FRAME_TAG_SIZE + MAX_UPDATE_SEGMENTATION_SIZE +
172       MAX_MB_LF_ADJUSTMENTS_SIZE + MAX_QUANT_INDICES_SIZE +
173       MAX_TOKEN_PROB_UPDATE_SIZE + MAX_MV_PROBE_UPDATE_SIZE +
174       MAX_REST_OF_FRAME_HDR_SIZE;
175 
176   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
177 }
178 
179 static void
clear_ref(GstVaapiEncoderVP8 * encoder,GstVaapiSurfaceProxy ** ref)180 clear_ref (GstVaapiEncoderVP8 * encoder, GstVaapiSurfaceProxy ** ref)
181 {
182   if (*ref) {
183     gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), *ref);
184     *ref = NULL;
185   }
186 }
187 
188 static void
clear_references(GstVaapiEncoderVP8 * encoder)189 clear_references (GstVaapiEncoderVP8 * encoder)
190 {
191   clear_ref (encoder, &encoder->last_ref);
192   clear_ref (encoder, &encoder->golden_ref);
193   clear_ref (encoder, &encoder->alt_ref);
194 }
195 
196 static void
push_reference(GstVaapiEncoderVP8 * encoder,GstVaapiSurfaceProxy * ref)197 push_reference (GstVaapiEncoderVP8 * encoder, GstVaapiSurfaceProxy * ref)
198 {
199   if (encoder->last_ref == NULL) {
200     encoder->golden_ref = gst_vaapi_surface_proxy_ref (ref);
201     encoder->alt_ref = gst_vaapi_surface_proxy_ref (ref);
202   } else {
203     clear_ref (encoder, &encoder->alt_ref);
204     encoder->alt_ref = encoder->golden_ref;
205     encoder->golden_ref = encoder->last_ref;
206   }
207   encoder->last_ref = ref;
208 }
209 
210 static gboolean
fill_sequence(GstVaapiEncoderVP8 * encoder,GstVaapiEncSequence * sequence)211 fill_sequence (GstVaapiEncoderVP8 * encoder, GstVaapiEncSequence * sequence)
212 {
213   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
214   VAEncSequenceParameterBufferVP8 *const seq_param = sequence->param;
215 
216   memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferVP8));
217 
218   seq_param->frame_width = GST_VAAPI_ENCODER_WIDTH (encoder);
219   seq_param->frame_height = GST_VAAPI_ENCODER_HEIGHT (encoder);
220 
221   if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR ||
222       GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_VBR)
223     seq_param->bits_per_second = base_encoder->bitrate * 1000;
224 
225   seq_param->intra_period = base_encoder->keyframe_period;
226 
227   return TRUE;
228 }
229 
230 static gboolean
ensure_sequence(GstVaapiEncoderVP8 * encoder,GstVaapiEncPicture * picture)231 ensure_sequence (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture)
232 {
233   GstVaapiEncSequence *sequence;
234 
235   g_assert (picture);
236 
237   if (picture->type != GST_VAAPI_PICTURE_TYPE_I)
238     return TRUE;
239 
240   sequence = GST_VAAPI_ENC_SEQUENCE_NEW (VP8, encoder);
241   if (!sequence)
242     goto error;
243 
244   if (!fill_sequence (encoder, sequence))
245     goto error;
246 
247   gst_vaapi_enc_picture_set_sequence (picture, sequence);
248   gst_vaapi_codec_object_replace (&sequence, NULL);
249   return TRUE;
250 
251   /* ERRORS */
252 error:
253   {
254     gst_vaapi_codec_object_replace (&sequence, NULL);
255     return FALSE;
256   }
257 }
258 
259 static gboolean
ensure_control_rate_params(GstVaapiEncoderVP8 * encoder)260 ensure_control_rate_params (GstVaapiEncoderVP8 * encoder)
261 {
262   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
263 
264   if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP)
265     return TRUE;
266 
267   /* RateControl params */
268   GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).initial_qp = encoder->yac_qi;
269   GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).min_qp = 1;
270 
271   /* *INDENT-OFF* */
272   /* HRD params */
273   GST_VAAPI_ENCODER_VA_HRD (encoder) = (VAEncMiscParameterHRD) {
274     .buffer_size = base_encoder->bitrate * 1000 * 2,
275     .initial_buffer_fullness = base_encoder->bitrate * 1000,
276   };
277   /* *INDENT-ON* */
278 
279   return TRUE;
280 }
281 
282 static gboolean
ensure_misc_params(GstVaapiEncoderVP8 * encoder,GstVaapiEncPicture * picture)283 ensure_misc_params (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture)
284 {
285   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
286 
287   if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture))
288     return FALSE;
289 
290   if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture))
291     return FALSE;
292 
293   return TRUE;
294 }
295 
296 static gboolean
fill_picture(GstVaapiEncoderVP8 * encoder,GstVaapiEncPicture * picture,GstVaapiCodedBuffer * codedbuf,GstVaapiSurfaceProxy * surface)297 fill_picture (GstVaapiEncoderVP8 * encoder,
298     GstVaapiEncPicture * picture,
299     GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
300 {
301   VAEncPictureParameterBufferVP8 *const pic_param = picture->param;
302   int i;
303 
304   memset (pic_param, 0, sizeof (VAEncPictureParameterBufferVP8));
305 
306   pic_param->reconstructed_frame = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
307   pic_param->coded_buf = GST_VAAPI_OBJECT_ID (codedbuf);
308 
309   if (picture->type == GST_VAAPI_PICTURE_TYPE_P) {
310     pic_param->pic_flags.bits.frame_type = 1;
311     pic_param->ref_arf_frame =
312         GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->alt_ref);
313     pic_param->ref_gf_frame =
314         GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->golden_ref);
315     pic_param->ref_last_frame =
316         GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->last_ref);
317     pic_param->pic_flags.bits.refresh_last = 1;
318     pic_param->pic_flags.bits.refresh_golden_frame = 0;
319     pic_param->pic_flags.bits.copy_buffer_to_golden = 1;
320     pic_param->pic_flags.bits.refresh_alternate_frame = 0;
321     pic_param->pic_flags.bits.copy_buffer_to_alternate = 2;
322   } else {
323     pic_param->ref_last_frame = VA_INVALID_SURFACE;
324     pic_param->ref_gf_frame = VA_INVALID_SURFACE;
325     pic_param->ref_arf_frame = VA_INVALID_SURFACE;
326     pic_param->pic_flags.bits.refresh_last = 1;
327     pic_param->pic_flags.bits.refresh_golden_frame = 1;
328     pic_param->pic_flags.bits.refresh_alternate_frame = 1;
329   }
330 
331   pic_param->pic_flags.bits.show_frame = 1;
332 
333   if (encoder->loop_filter_level) {
334     pic_param->pic_flags.bits.version = 1;
335     pic_param->pic_flags.bits.loop_filter_type = 1;     /* Enable simple loop filter */
336     /* Disabled segmentation, so what matters is only loop_filter_level[0] */
337     for (i = 0; i < 4; i++)
338       pic_param->loop_filter_level[i] = encoder->loop_filter_level;
339   }
340 
341   pic_param->sharpness_level = encoder->sharpness_level;
342 
343   /* Used for CBR */
344   pic_param->clamp_qindex_low = 0;
345   pic_param->clamp_qindex_high = 127;
346 
347   return TRUE;
348 }
349 
350 static gboolean
ensure_picture(GstVaapiEncoderVP8 * encoder,GstVaapiEncPicture * picture,GstVaapiCodedBufferProxy * codedbuf_proxy,GstVaapiSurfaceProxy * surface)351 ensure_picture (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture,
352     GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
353 {
354   GstVaapiCodedBuffer *const codedbuf =
355       GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
356 
357   if (!fill_picture (encoder, picture, codedbuf, surface))
358     return FALSE;
359 
360   return TRUE;
361 }
362 
363 static gboolean
fill_quantization_table(GstVaapiEncoderVP8 * encoder,GstVaapiEncPicture * picture,GstVaapiEncQMatrix * q_matrix)364 fill_quantization_table (GstVaapiEncoderVP8 * encoder,
365     GstVaapiEncPicture * picture, GstVaapiEncQMatrix * q_matrix)
366 {
367   VAQMatrixBufferVP8 *const qmatrix_param = q_matrix->param;
368   int i;
369 
370   memset (qmatrix_param, 0, sizeof (VAQMatrixBufferVP8));
371 
372   /* DefaultYacQantVal = 8 for I frame, which is ac_qlookup[4] and
373    * DefaultYacQantVAl = 44 for P frame, which is ac_qllookup[40] */
374   for (i = 0; i < 4; i++) {
375     if (encoder->yac_qi == DEFAULT_YAC_QI) {
376       if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
377         qmatrix_param->quantization_index[i] = 4;
378       else
379         qmatrix_param->quantization_index[i] = 40;
380     } else
381       qmatrix_param->quantization_index[i] = encoder->yac_qi;
382   }
383 
384   return TRUE;
385 }
386 
387 static gboolean
ensure_quantization_table(GstVaapiEncoderVP8 * encoder,GstVaapiEncPicture * picture)388 ensure_quantization_table (GstVaapiEncoderVP8 * encoder,
389     GstVaapiEncPicture * picture)
390 {
391   g_assert (picture);
392 
393   picture->q_matrix = GST_VAAPI_ENC_Q_MATRIX_NEW (VP8, encoder);
394   if (!picture->q_matrix) {
395     GST_ERROR ("failed to allocate quantiser table");
396     return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
397   }
398 
399   if (!fill_quantization_table (encoder, picture, picture->q_matrix))
400     return FALSE;
401 
402   return TRUE;
403 }
404 
405 static GstVaapiEncoderStatus
gst_vaapi_encoder_vp8_encode(GstVaapiEncoder * base_encoder,GstVaapiEncPicture * picture,GstVaapiCodedBufferProxy * codedbuf)406 gst_vaapi_encoder_vp8_encode (GstVaapiEncoder * base_encoder,
407     GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
408 {
409   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
410   GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
411   GstVaapiSurfaceProxy *reconstruct = NULL;
412 
413   reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
414 
415   g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
416 
417   if (!ensure_sequence (encoder, picture))
418     goto error;
419   if (!ensure_misc_params (encoder, picture))
420     goto error;
421   if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
422     goto error;
423   if (!ensure_quantization_table (encoder, picture))
424     goto error;
425   if (!gst_vaapi_enc_picture_encode (picture))
426     goto error;
427   if (reconstruct) {
428     if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
429       clear_references (encoder);
430     push_reference (encoder, reconstruct);
431   }
432 
433   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
434 
435   /* ERRORS */
436 error:
437   {
438     if (reconstruct)
439       gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
440           reconstruct);
441     return ret;
442   }
443 }
444 
445 static GstVaapiEncoderStatus
gst_vaapi_encoder_vp8_flush(GstVaapiEncoder * base_encoder)446 gst_vaapi_encoder_vp8_flush (GstVaapiEncoder * base_encoder)
447 {
448   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
449 
450   encoder->frame_num = 0;
451   clear_references (encoder);
452 
453   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
454 }
455 
456 static GstVaapiEncoderStatus
gst_vaapi_encoder_vp8_reordering(GstVaapiEncoder * base_encoder,GstVideoCodecFrame * frame,GstVaapiEncPicture ** output)457 gst_vaapi_encoder_vp8_reordering (GstVaapiEncoder * base_encoder,
458     GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
459 {
460   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
461   GstVaapiEncPicture *picture = NULL;
462   GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
463 
464   if (!frame)
465     return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
466 
467   picture = GST_VAAPI_ENC_PICTURE_NEW (VP8, encoder, frame);
468   if (!picture) {
469     GST_WARNING ("create VP8 picture failed, frame timestamp:%"
470         GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
471     return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
472   }
473 
474   if (encoder->frame_num >= base_encoder->keyframe_period) {
475     encoder->frame_num = 0;
476     clear_references (encoder);
477   }
478   if (encoder->frame_num == 0) {
479     picture->type = GST_VAAPI_PICTURE_TYPE_I;
480     GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
481   } else {
482     picture->type = GST_VAAPI_PICTURE_TYPE_P;
483   }
484 
485   encoder->frame_num++;
486   *output = picture;
487   return status;
488 }
489 
490 static GstVaapiEncoderStatus
gst_vaapi_encoder_vp8_reconfigure(GstVaapiEncoder * base_encoder)491 gst_vaapi_encoder_vp8_reconfigure (GstVaapiEncoder * base_encoder)
492 {
493   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
494   GstVaapiEncoderStatus status;
495 
496   status = ensure_profile (encoder);
497   if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
498     return status;
499 
500   if (!ensure_bitrate (encoder))
501     goto error;
502 
503   ensure_control_rate_params (encoder);
504   return set_context_info (base_encoder);
505 
506   /* ERRORS */
507 error:
508   {
509     return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
510   }
511 }
512 
513 static gboolean
gst_vaapi_encoder_vp8_init(GstVaapiEncoder * base_encoder)514 gst_vaapi_encoder_vp8_init (GstVaapiEncoder * base_encoder)
515 {
516   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
517 
518   encoder->frame_num = 0;
519   encoder->last_ref = NULL;
520   encoder->golden_ref = NULL;
521   encoder->alt_ref = NULL;
522 
523   return TRUE;
524 }
525 
526 static void
gst_vaapi_encoder_vp8_finalize(GstVaapiEncoder * base_encoder)527 gst_vaapi_encoder_vp8_finalize (GstVaapiEncoder * base_encoder)
528 {
529   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
530   clear_references (encoder);
531 }
532 
533 static GstVaapiEncoderStatus
gst_vaapi_encoder_vp8_set_property(GstVaapiEncoder * base_encoder,gint prop_id,const GValue * value)534 gst_vaapi_encoder_vp8_set_property (GstVaapiEncoder * base_encoder,
535     gint prop_id, const GValue * value)
536 {
537   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
538 
539   switch (prop_id) {
540     case GST_VAAPI_ENCODER_VP8_PROP_LOOP_FILTER_LEVEL:
541       encoder->loop_filter_level = g_value_get_uint (value);
542       break;
543     case GST_VAAPI_ENCODER_VP8_PROP_SHARPNESS_LEVEL:
544       encoder->sharpness_level = g_value_get_uint (value);
545       break;
546     case GST_VAAPI_ENCODER_VP8_PROP_YAC_Q_INDEX:
547       encoder->yac_qi = g_value_get_uint (value);
548       break;
549     default:
550       return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
551   }
552   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
553 }
554 
555 GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (VP8);
556 
557 static inline const GstVaapiEncoderClass *
gst_vaapi_encoder_vp8_class(void)558 gst_vaapi_encoder_vp8_class (void)
559 {
560   static const GstVaapiEncoderClass GstVaapiEncoderVP8Class = {
561     GST_VAAPI_ENCODER_CLASS_INIT (VP8, vp8),
562     .set_property = gst_vaapi_encoder_vp8_set_property,
563   };
564   return &GstVaapiEncoderVP8Class;
565 }
566 
567 /**
568  * gst_vaapi_encoder_vp8_new:
569  * @display: a #GstVaapiDisplay
570  *
571  * Creates a new #GstVaapiEncoder for VP8 encoding.
572  *
573  * Return value: the newly allocated #GstVaapiEncoder object
574  */
575 GstVaapiEncoder *
gst_vaapi_encoder_vp8_new(GstVaapiDisplay * display)576 gst_vaapi_encoder_vp8_new (GstVaapiDisplay * display)
577 {
578   return gst_vaapi_encoder_new (gst_vaapi_encoder_vp8_class (), display);
579 }
580 
581 /**
582  * gst_vaapi_encoder_vp8_get_default_properties:
583  *
584  * Determines the set of common and vp8 specific encoder properties.
585  * The caller owns an extra reference to the resulting array of
586  * #GstVaapiEncoderPropInfo elements, so it shall be released with
587  * g_ptr_array_unref() after usage.
588  *
589  * Return value: the set of encoder properties for #GstVaapiEncoderVP8,
590  *   or %NULL if an error occurred.
591  */
592 GPtrArray *
gst_vaapi_encoder_vp8_get_default_properties(void)593 gst_vaapi_encoder_vp8_get_default_properties (void)
594 {
595   const GstVaapiEncoderClass *const klass = gst_vaapi_encoder_vp8_class ();
596   GPtrArray *props;
597 
598   props = gst_vaapi_encoder_properties_get_default (klass);
599   if (!props)
600     return NULL;
601 
602   GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
603       GST_VAAPI_ENCODER_VP8_PROP_LOOP_FILTER_LEVEL,
604       g_param_spec_uint ("loop-filter-level",
605           "Loop Filter Level",
606           "Controls the deblocking filter strength",
607           0, 63, DEFAULT_LOOP_FILTER_LEVEL,
608           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
609 
610   GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
611       GST_VAAPI_ENCODER_VP8_PROP_SHARPNESS_LEVEL,
612       g_param_spec_uint ("sharpness-level",
613           "Sharpness Level",
614           "Controls the deblocking filter sensitivity",
615           0, 7, DEFAULT_SHARPNESS_LEVEL,
616           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
617 
618   GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
619       GST_VAAPI_ENCODER_VP8_PROP_YAC_Q_INDEX,
620       g_param_spec_uint ("yac-qi",
621           "Luma AC Quant Table index",
622           "Quantization Table index for Luma AC Coefficients, (in default case, yac_qi=4 for key frames and yac_qi=40 for P frames)",
623           0, 127, DEFAULT_YAC_QI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
624 
625   return props;
626 }
627