Merge remote-tracking branch 'gst-rtsp-server/tizen_gst_1.19.2' into tizen_gst_1...
[platform/upstream/gstreamer.git] / subprojects / gstreamer-vaapi / gst-libs / gst / vaapi / gstvaapiencoder_vp8.c
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
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
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_va_name (encoder->profile));
113     return FALSE;
114   }
115 }
116
117 static gboolean
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
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   base_encoder->context_info.profile = base_encoder->profile;
177   base_encoder->context_info.entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
178
179   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
180 }
181
182 static void
183 clear_ref (GstVaapiEncoderVP8 * encoder, GstVaapiSurfaceProxy ** ref)
184 {
185   if (*ref) {
186     gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), *ref);
187     *ref = NULL;
188   }
189 }
190
191 static void
192 clear_references (GstVaapiEncoderVP8 * encoder)
193 {
194   clear_ref (encoder, &encoder->last_ref);
195   clear_ref (encoder, &encoder->golden_ref);
196   clear_ref (encoder, &encoder->alt_ref);
197 }
198
199 static void
200 push_reference (GstVaapiEncoderVP8 * encoder, GstVaapiSurfaceProxy * ref)
201 {
202   if (encoder->last_ref == NULL) {
203     encoder->golden_ref = gst_vaapi_surface_proxy_ref (ref);
204     encoder->alt_ref = gst_vaapi_surface_proxy_ref (ref);
205   } else {
206     clear_ref (encoder, &encoder->alt_ref);
207     encoder->alt_ref = encoder->golden_ref;
208     encoder->golden_ref = encoder->last_ref;
209   }
210   encoder->last_ref = ref;
211 }
212
213 static gboolean
214 fill_sequence (GstVaapiEncoderVP8 * encoder, GstVaapiEncSequence * sequence)
215 {
216   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
217   VAEncSequenceParameterBufferVP8 *const seq_param = sequence->param;
218
219   memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferVP8));
220
221   seq_param->frame_width = GST_VAAPI_ENCODER_WIDTH (encoder);
222   seq_param->frame_height = GST_VAAPI_ENCODER_HEIGHT (encoder);
223
224   if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR ||
225       GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_VBR)
226     seq_param->bits_per_second = base_encoder->bitrate * 1000;
227
228   seq_param->intra_period = base_encoder->keyframe_period;
229
230   return TRUE;
231 }
232
233 static gboolean
234 ensure_sequence (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture)
235 {
236   GstVaapiEncSequence *sequence;
237
238   g_assert (picture);
239
240   if (picture->type != GST_VAAPI_PICTURE_TYPE_I)
241     return TRUE;
242
243   sequence = GST_VAAPI_ENC_SEQUENCE_NEW (VP8, encoder);
244   if (!sequence)
245     goto error;
246
247   if (!fill_sequence (encoder, sequence))
248     goto error;
249
250   gst_vaapi_enc_picture_set_sequence (picture, sequence);
251   gst_vaapi_codec_object_replace (&sequence, NULL);
252   return TRUE;
253
254   /* ERRORS */
255 error:
256   {
257     gst_vaapi_codec_object_replace (&sequence, NULL);
258     return FALSE;
259   }
260 }
261
262 static gboolean
263 ensure_control_rate_params (GstVaapiEncoderVP8 * encoder)
264 {
265   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
266
267   if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP)
268     return TRUE;
269
270   /* RateControl params */
271   GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).initial_qp = encoder->yac_qi;
272   GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).min_qp = 1;
273
274   /* *INDENT-OFF* */
275   /* HRD params */
276   GST_VAAPI_ENCODER_VA_HRD (encoder) = (VAEncMiscParameterHRD) {
277     .buffer_size = base_encoder->bitrate * 1000 * 2,
278     .initial_buffer_fullness = base_encoder->bitrate * 1000,
279   };
280   /* *INDENT-ON* */
281
282   return TRUE;
283 }
284
285 static gboolean
286 ensure_misc_params (GstVaapiEncoderVP8 * 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
293   if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture))
294     return FALSE;
295
296   return TRUE;
297 }
298
299 static gboolean
300 fill_picture (GstVaapiEncoderVP8 * encoder,
301     GstVaapiEncPicture * picture,
302     GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
303 {
304   VAEncPictureParameterBufferVP8 *const pic_param = picture->param;
305   int i;
306
307   memset (pic_param, 0, sizeof (VAEncPictureParameterBufferVP8));
308
309   pic_param->reconstructed_frame = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
310   pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf);
311
312   if (picture->type == GST_VAAPI_PICTURE_TYPE_P) {
313     pic_param->pic_flags.bits.frame_type = 1;
314     pic_param->ref_arf_frame =
315         GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->alt_ref);
316     pic_param->ref_gf_frame =
317         GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->golden_ref);
318     pic_param->ref_last_frame =
319         GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->last_ref);
320     pic_param->pic_flags.bits.refresh_last = 1;
321     pic_param->pic_flags.bits.refresh_golden_frame = 0;
322     pic_param->pic_flags.bits.copy_buffer_to_golden = 1;
323     pic_param->pic_flags.bits.refresh_alternate_frame = 0;
324     pic_param->pic_flags.bits.copy_buffer_to_alternate = 2;
325   } else {
326     pic_param->ref_last_frame = VA_INVALID_SURFACE;
327     pic_param->ref_gf_frame = VA_INVALID_SURFACE;
328     pic_param->ref_arf_frame = VA_INVALID_SURFACE;
329     pic_param->pic_flags.bits.refresh_last = 1;
330     pic_param->pic_flags.bits.refresh_golden_frame = 1;
331     pic_param->pic_flags.bits.refresh_alternate_frame = 1;
332   }
333
334   pic_param->pic_flags.bits.show_frame = 1;
335
336   if (encoder->loop_filter_level) {
337     pic_param->pic_flags.bits.version = 1;
338     pic_param->pic_flags.bits.loop_filter_type = 1;     /* Enable simple loop filter */
339     /* Disabled segmentation, so what matters is only loop_filter_level[0] */
340     for (i = 0; i < 4; i++)
341       pic_param->loop_filter_level[i] = encoder->loop_filter_level;
342   }
343
344   pic_param->sharpness_level = encoder->sharpness_level;
345
346   /* Used for CBR */
347   pic_param->clamp_qindex_low = 0;
348   pic_param->clamp_qindex_high = 127;
349
350   return TRUE;
351 }
352
353 static gboolean
354 ensure_picture (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture,
355     GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
356 {
357   GstVaapiCodedBuffer *const codedbuf =
358       GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
359
360   if (!fill_picture (encoder, picture, codedbuf, surface))
361     return FALSE;
362
363   return TRUE;
364 }
365
366 static gboolean
367 fill_quantization_table (GstVaapiEncoderVP8 * encoder,
368     GstVaapiEncPicture * picture, GstVaapiEncQMatrix * q_matrix)
369 {
370   VAQMatrixBufferVP8 *const qmatrix_param = q_matrix->param;
371   int i;
372
373   memset (qmatrix_param, 0, sizeof (VAQMatrixBufferVP8));
374
375   /* DefaultYacQantVal = 8 for I frame, which is ac_qlookup[4] and
376    * DefaultYacQantVAl = 44 for P frame, which is ac_qllookup[40] */
377   for (i = 0; i < 4; i++) {
378     if (encoder->yac_qi == DEFAULT_YAC_QI) {
379       if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
380         qmatrix_param->quantization_index[i] = 4;
381       else
382         qmatrix_param->quantization_index[i] = 40;
383     } else
384       qmatrix_param->quantization_index[i] = encoder->yac_qi;
385   }
386
387   return TRUE;
388 }
389
390 static gboolean
391 ensure_quantization_table (GstVaapiEncoderVP8 * encoder,
392     GstVaapiEncPicture * picture)
393 {
394   g_assert (picture);
395
396   picture->q_matrix = GST_VAAPI_ENC_Q_MATRIX_NEW (VP8, encoder);
397   if (!picture->q_matrix) {
398     GST_ERROR ("failed to allocate quantiser table");
399     return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
400   }
401
402   if (!fill_quantization_table (encoder, picture, picture->q_matrix))
403     return FALSE;
404
405   return TRUE;
406 }
407
408 static GstVaapiEncoderStatus
409 gst_vaapi_encoder_vp8_encode (GstVaapiEncoder * base_encoder,
410     GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
411 {
412   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
413   GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
414   GstVaapiSurfaceProxy *reconstruct = NULL;
415
416   reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
417
418   g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
419
420   if (!ensure_sequence (encoder, picture))
421     goto error;
422   if (!ensure_misc_params (encoder, picture))
423     goto error;
424   if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
425     goto error;
426   if (!ensure_quantization_table (encoder, picture))
427     goto error;
428   if (!gst_vaapi_enc_picture_encode (picture))
429     goto error;
430   if (reconstruct) {
431     if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
432       clear_references (encoder);
433     push_reference (encoder, reconstruct);
434   }
435
436   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
437
438   /* ERRORS */
439 error:
440   {
441     if (reconstruct)
442       gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
443           reconstruct);
444     return ret;
445   }
446 }
447
448 static GstVaapiEncoderStatus
449 gst_vaapi_encoder_vp8_flush (GstVaapiEncoder * base_encoder)
450 {
451   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
452
453   encoder->frame_num = 0;
454   clear_references (encoder);
455
456   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
457 }
458
459 static GstVaapiEncoderStatus
460 gst_vaapi_encoder_vp8_reordering (GstVaapiEncoder * base_encoder,
461     GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
462 {
463   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
464   GstVaapiEncPicture *picture = NULL;
465   GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
466
467   if (!frame)
468     return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
469
470   picture = GST_VAAPI_ENC_PICTURE_NEW (VP8, encoder, frame);
471   if (!picture) {
472     GST_WARNING ("create VP8 picture failed, frame timestamp:%"
473         GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
474     return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
475   }
476
477   if (encoder->frame_num >= base_encoder->keyframe_period) {
478     encoder->frame_num = 0;
479     clear_references (encoder);
480   }
481   if (encoder->frame_num == 0) {
482     picture->type = GST_VAAPI_PICTURE_TYPE_I;
483     GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
484   } else {
485     picture->type = GST_VAAPI_PICTURE_TYPE_P;
486   }
487
488   encoder->frame_num++;
489   *output = picture;
490   return status;
491 }
492
493 static GstVaapiEncoderStatus
494 gst_vaapi_encoder_vp8_reconfigure (GstVaapiEncoder * base_encoder)
495 {
496   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
497   GstVaapiEncoderStatus status;
498
499   status = ensure_profile (encoder);
500   if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
501     return status;
502
503   if (!ensure_bitrate (encoder))
504     goto error;
505
506   ensure_control_rate_params (encoder);
507   return set_context_info (base_encoder);
508
509   /* ERRORS */
510 error:
511   {
512     return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
513   }
514 }
515
516 struct _GstVaapiEncoderVP8Class
517 {
518   GstVaapiEncoderClass parent_class;
519 };
520
521 G_DEFINE_TYPE (GstVaapiEncoderVP8, gst_vaapi_encoder_vp8,
522     GST_TYPE_VAAPI_ENCODER);
523
524 static void
525 gst_vaapi_encoder_vp8_init (GstVaapiEncoderVP8 * encoder)
526 {
527   encoder->frame_num = 0;
528   encoder->last_ref = NULL;
529   encoder->golden_ref = NULL;
530   encoder->alt_ref = NULL;
531 }
532
533 static void
534 gst_vaapi_encoder_vp8_finalize (GObject * object)
535 {
536   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (object);
537   clear_references (encoder);
538   G_OBJECT_CLASS (gst_vaapi_encoder_vp8_parent_class)->finalize (object);
539 }
540
541 /**
542  * @ENCODER_VP8_PROP_RATECONTROL: Rate control (#GstVaapiRateControl).
543  * @ENCODER_VP8_PROP_TUNE: The tuning options (#GstVaapiEncoderTune).
544  * @ENCODER_VP8_PROP_LOOP_FILTER_LEVEL: Loop Filter Level(uint).
545  * @ENCODER_VP8_PROP_LOOP_SHARPNESS_LEVEL: Sharpness Level(uint).
546  * @ENCODER_VP8_PROP_YAC_Q_INDEX: Quantization table index for luma AC(uint).
547  *
548  * The set of VP8 encoder specific configurable properties.
549  */
550 enum
551 {
552   ENCODER_VP8_PROP_RATECONTROL = 1,
553   ENCODER_VP8_PROP_TUNE,
554   ENCODER_VP8_PROP_LOOP_FILTER_LEVEL,
555   ENCODER_VP8_PROP_SHARPNESS_LEVEL,
556   ENCODER_VP8_PROP_YAC_Q_INDEX,
557   ENCODER_VP8_N_PROPERTIES
558 };
559
560 static GParamSpec *properties[ENCODER_VP8_N_PROPERTIES];
561
562 static void
563 gst_vaapi_encoder_vp8_set_property (GObject * object, guint prop_id,
564     const GValue * value, GParamSpec * pspec)
565 {
566   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
567   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (object);
568
569   if (base_encoder->num_codedbuf_queued > 0) {
570     GST_ERROR_OBJECT (object,
571         "failed to set any property after encoding started");
572     return;
573   }
574
575   switch (prop_id) {
576     case ENCODER_VP8_PROP_RATECONTROL:
577       gst_vaapi_encoder_set_rate_control (base_encoder,
578           g_value_get_enum (value));
579       break;
580     case ENCODER_VP8_PROP_TUNE:
581       gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value));
582       break;
583     case ENCODER_VP8_PROP_LOOP_FILTER_LEVEL:
584       encoder->loop_filter_level = g_value_get_uint (value);
585       break;
586     case ENCODER_VP8_PROP_SHARPNESS_LEVEL:
587       encoder->sharpness_level = g_value_get_uint (value);
588       break;
589     case ENCODER_VP8_PROP_YAC_Q_INDEX:
590       encoder->yac_qi = g_value_get_uint (value);
591       break;
592     default:
593       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
594   }
595 }
596
597 static void
598 gst_vaapi_encoder_vp8_get_property (GObject * object, guint prop_id,
599     GValue * value, GParamSpec * pspec)
600 {
601   GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (object);
602   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
603
604   switch (prop_id) {
605     case ENCODER_VP8_PROP_RATECONTROL:
606       g_value_set_enum (value, base_encoder->rate_control);
607       break;
608     case ENCODER_VP8_PROP_TUNE:
609       g_value_set_enum (value, base_encoder->tune);
610       break;
611     case ENCODER_VP8_PROP_LOOP_FILTER_LEVEL:
612       g_value_set_uint (value, encoder->loop_filter_level);
613       break;
614     case ENCODER_VP8_PROP_SHARPNESS_LEVEL:
615       g_value_set_uint (value, encoder->sharpness_level);
616       break;
617     case ENCODER_VP8_PROP_YAC_Q_INDEX:
618       g_value_set_uint (value, encoder->yac_qi);
619       break;
620     default:
621       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
622   }
623 }
624
625 GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (VP8);
626
627 static void
628 gst_vaapi_encoder_vp8_class_init (GstVaapiEncoderVP8Class * klass)
629 {
630   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
631   GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass);
632
633   encoder_class->class_data = &g_class_data;
634   encoder_class->reconfigure = gst_vaapi_encoder_vp8_reconfigure;
635   encoder_class->reordering = gst_vaapi_encoder_vp8_reordering;
636   encoder_class->encode = gst_vaapi_encoder_vp8_encode;
637   encoder_class->flush = gst_vaapi_encoder_vp8_flush;
638
639   object_class->set_property = gst_vaapi_encoder_vp8_set_property;
640   object_class->get_property = gst_vaapi_encoder_vp8_get_property;
641   object_class->finalize = gst_vaapi_encoder_vp8_finalize;
642
643   properties[ENCODER_VP8_PROP_RATECONTROL] =
644       g_param_spec_enum ("rate-control",
645       "Rate Control", "Rate control mode",
646       g_class_data.rate_control_get_type (),
647       g_class_data.default_rate_control,
648       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
649       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
650
651   properties[ENCODER_VP8_PROP_TUNE] =
652       g_param_spec_enum ("tune", "Encoder Tuning", "Encoder tuning option",
653       g_class_data.encoder_tune_get_type (),
654       g_class_data.default_encoder_tune,
655       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
656       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
657
658   properties[ENCODER_VP8_PROP_LOOP_FILTER_LEVEL] =
659       g_param_spec_uint ("loop-filter-level", "Loop Filter Level",
660       "Controls the deblocking filter strength", 0, 63,
661       DEFAULT_LOOP_FILTER_LEVEL,
662       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
663       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
664
665   properties[ENCODER_VP8_PROP_SHARPNESS_LEVEL] =
666       g_param_spec_uint ("sharpness-level", "Sharpness Level",
667       "Controls the deblocking filter sensitivity", 0, 7,
668       DEFAULT_SHARPNESS_LEVEL,
669       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
670       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
671
672   properties[ENCODER_VP8_PROP_YAC_Q_INDEX] =
673       g_param_spec_uint ("yac-qi",
674       "Luma AC Quant Table index",
675       "Quantization Table index for Luma AC Coefficients,"
676       " (in default case, yac_qi=4 for key frames and yac_qi=40"
677       " for P frames)",
678       0, 127, DEFAULT_YAC_QI,
679       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
680       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
681
682   g_object_class_install_properties (object_class, ENCODER_VP8_N_PROPERTIES,
683       properties);
684
685   gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0);
686   gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0);
687 }
688
689 /**
690  * gst_vaapi_encoder_vp8_new:
691  * @display: a #GstVaapiDisplay
692  *
693  * Creates a new #GstVaapiEncoder for VP8 encoding.
694  *
695  * Return value: the newly allocated #GstVaapiEncoder object
696  */
697 GstVaapiEncoder *
698 gst_vaapi_encoder_vp8_new (GstVaapiDisplay * display)
699 {
700   return g_object_new (GST_TYPE_VAAPI_ENCODER_VP8, "display", display, NULL);
701 }