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