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