1 /*
2 * gstvaapifeienc_h264.c - H264 FEI ENC
3 *
4 * Copyright (C) 2016-2018 Intel Corporation
5 * Author: Leilei Shang <leilei.shang@intel.com>
6 * Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1
11 * of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA
22 */
23
24 /* GValueArray has deprecated without providing an alternative in glib >= 2.32
25 * See https://bugzilla.gnome.org/show_bug.cgi?id=667228
26 */
27
28 #define GLIB_DISABLE_DEPRECATION_WARNINGS
29
30 #include "sysdeps.h"
31 #include <va/va.h>
32 #include <gst/base/gstbitwriter.h>
33 #include <gst/codecparsers/gsth264parser.h>
34 #include "gstvaapicompat.h"
35 #include "gstvaapiencoder_priv.h"
36 #include "gstvaapifeienc_h264.h"
37 #include "gstvaapiutils_h264_priv.h"
38 #include "gstvaapicodedbufferproxy_priv.h"
39 #include "gstvaapisurfaceproxy_priv.h"
40 #include "gstvaapisurface.h"
41 #include "gstvaapiutils.h"
42 #include <unistd.h>
43 #define DEBUG 1
44 #include "gstvaapidebug.h"
45
46 /* Define the maximum number of views supported */
47 #define MAX_NUM_VIEWS 10
48
49 /* Define the maximum value for view-id */
50 #define MAX_VIEW_ID 1023
51
52 /* Default CPB length (in milliseconds) */
53 #define DEFAULT_CPB_LENGTH 1500
54
55 /* Scale factor for CPB size (HRD cpb_size_scale: min = 4) */
56 #define SX_CPB_SIZE 4
57
58 /* Scale factor for bitrate (HRD bit_rate_scale: min = 6) */
59 #define SX_BITRATE 6
60
61 /* Define default rate control mode ("constant-qp") */
62 #define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP
63
64 /* Supported set of VA rate controls, within this implementation */
65 #define SUPPORTED_RATECONTROLS \
66 (GST_VAAPI_RATECONTROL_MASK (CQP) | \
67 GST_VAAPI_RATECONTROL_MASK (CBR) | \
68 GST_VAAPI_RATECONTROL_MASK (VBR) | \
69 GST_VAAPI_RATECONTROL_MASK (VBR_CONSTRAINED))
70
71 /* Supported set of tuning options, within this implementation */
72 #define SUPPORTED_TUNE_OPTIONS \
73 (GST_VAAPI_ENCODER_TUNE_MASK (NONE) | \
74 GST_VAAPI_ENCODER_TUNE_MASK (HIGH_COMPRESSION) | \
75 GST_VAAPI_ENCODER_TUNE_MASK (LOW_POWER))
76
77 /* Supported set of VA packed headers, within this implementation */
78 #define SUPPORTED_PACKED_HEADERS \
79 VA_ENC_PACKED_HEADER_NONE
80
81 typedef struct
82 {
83 GstVaapiSurfaceProxy *pic;
84 guint poc;
85 guint frame_num;
86 } GstVaapiFeiEncH264Ref;
87
88 typedef enum
89 {
90 GST_VAAPI_ENC_H264_REORD_NONE = 0,
91 GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES = 1,
92 GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES = 2
93 } GstVaapiEncH264ReorderState;
94
95 typedef struct _GstVaapiH264ViewRefPool
96 {
97 GQueue ref_list;
98 guint max_ref_frames;
99 guint max_reflist0_count;
100 guint max_reflist1_count;
101 } GstVaapiH264ViewRefPool;
102
103 typedef struct _GstVaapiH264ViewReorderPool
104 {
105 GQueue reorder_frame_list;
106 guint reorder_state;
107 guint frame_index;
108 guint frame_count; /* monotonically increasing with in every idr period */
109 guint cur_frame_num;
110 guint cur_present_index;
111 } GstVaapiH264ViewReorderPool;
112
113 static inline gboolean
_poc_greater_than(guint poc1,guint poc2,guint max_poc)114 _poc_greater_than (guint poc1, guint poc2, guint max_poc)
115 {
116 return (((poc1 - poc2) & (max_poc - 1)) < max_poc / 2);
117 }
118
119 /* Get slice_type value for H.264 specification */
120 static guint8
h264_get_slice_type(GstVaapiPictureType type)121 h264_get_slice_type (GstVaapiPictureType type)
122 {
123 switch (type) {
124 case GST_VAAPI_PICTURE_TYPE_I:
125 return GST_H264_I_SLICE;
126 case GST_VAAPI_PICTURE_TYPE_P:
127 return GST_H264_P_SLICE;
128 case GST_VAAPI_PICTURE_TYPE_B:
129 return GST_H264_B_SLICE;
130 default:
131 break;
132 }
133 return -1;
134 }
135
136 /* Get log2_max_frame_num value for H.264 specification */
137 static guint
h264_get_log2_max_frame_num(guint num)138 h264_get_log2_max_frame_num (guint num)
139 {
140 guint ret = 0;
141
142 while (num) {
143 ++ret;
144 num >>= 1;
145 }
146 if (ret <= 4)
147 ret = 4;
148 else if (ret > 10)
149 ret = 10;
150 /* must be greater than 4 */
151 return ret;
152 }
153
154 /* Determines the cpbBrNalFactor based on the supplied profile */
155 static guint
h264_get_cpb_nal_factor(GstVaapiProfile profile)156 h264_get_cpb_nal_factor (GstVaapiProfile profile)
157 {
158 guint f;
159
160 /* Table A-2 */
161 switch (profile) {
162 case GST_VAAPI_PROFILE_H264_HIGH:
163 f = 1500;
164 break;
165 case GST_VAAPI_PROFILE_H264_HIGH10:
166 f = 3600;
167 break;
168 case GST_VAAPI_PROFILE_H264_HIGH_422:
169 case GST_VAAPI_PROFILE_H264_HIGH_444:
170 f = 4800;
171 break;
172 case GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH:
173 case GST_VAAPI_PROFILE_H264_STEREO_HIGH:
174 f = 1500; /* H.10.2.1 (r) */
175 break;
176 default:
177 f = 1200;
178 break;
179 }
180 return f;
181 }
182
183 /* ------------------------------------------------------------------------- */
184 /* --- FEI Enc --- */
185 /* ------------------------------------------------------------------------- */
186
187 #define GST_VAAPI_FEI_H264_ENC_CAST(feienc) \
188 ((GstVaapiFeiEncH264 *)(feienc))
189
190 struct _GstVaapiFeiEncH264
191 {
192 GstVaapiEncoder parent_instance;
193
194 GstVaapiProfile profile;
195 GstVaapiLevelH264 level;
196 GstVaapiEntrypoint entrypoint;
197 guint8 profile_idc;
198 guint8 max_profile_idc;
199 guint8 hw_max_profile_idc;
200 guint8 level_idc;
201 guint32 idr_period;
202 guint32 init_qp;
203 guint32 min_qp;
204 guint32 num_slices;
205 guint32 num_bframes;
206 guint32 mb_width;
207 guint32 mb_height;
208 gboolean use_cabac;
209 gboolean use_dct8x8;
210 GstClockTime cts_offset;
211 gboolean config_changed;
212
213 /* frame, poc */
214 guint32 max_frame_num;
215 guint32 log2_max_frame_num;
216 guint32 max_pic_order_cnt;
217 guint32 log2_max_pic_order_cnt;
218 guint32 idr_num;
219 guint8 pic_order_cnt_type;
220 guint8 delta_pic_order_always_zero_flag;
221
222 GstBuffer *sps_data;
223 GstBuffer *subset_sps_data;
224 GstBuffer *pps_data;
225
226 guint bitrate_bits; // bitrate (bits)
227 guint cpb_length; // length of CPB buffer (ms)
228 guint cpb_length_bits; // length of CPB buffer (bits)
229 guint32 num_ref_frames; // set reference frame num
230
231 /* MVC */
232 gboolean is_mvc;
233 guint32 view_idx; /* View Order Index (VOIdx) */
234 guint32 num_views;
235 guint16 view_ids[MAX_NUM_VIEWS];
236 GstVaapiH264ViewRefPool ref_pools[MAX_NUM_VIEWS];
237 GstVaapiH264ViewReorderPool reorder_pools[MAX_NUM_VIEWS];
238
239 /*Fei frame level control */
240 guint search_window;
241 guint len_sp;
242 guint search_path;
243 guint ref_width;
244 guint ref_height;
245 guint submb_part_mask;
246 guint subpel_mode;
247 guint intra_part_mask;
248 guint intra_sad;
249 guint inter_sad;
250 guint num_mv_predictors_l0;
251 guint num_mv_predictors_l1;
252 guint adaptive_search;
253 guint multi_predL0;
254 guint multi_predL1;
255 };
256
257 /* Determines the largest supported profile by the underlying hardware */
258 static gboolean
ensure_hw_profile_limits(GstVaapiFeiEncH264 * feienc)259 ensure_hw_profile_limits (GstVaapiFeiEncH264 * feienc)
260 {
261 GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (feienc);
262 GArray *profiles;
263 guint i, profile_idc, max_profile_idc;
264
265 if (feienc->hw_max_profile_idc)
266 return TRUE;
267
268 profiles = gst_vaapi_display_get_encode_profiles (display);
269 if (!profiles)
270 return FALSE;
271
272 max_profile_idc = 0;
273 for (i = 0; i < profiles->len; i++) {
274 const GstVaapiProfile profile =
275 g_array_index (profiles, GstVaapiProfile, i);
276 profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
277 if (!profile_idc)
278 continue;
279 if (max_profile_idc < profile_idc)
280 max_profile_idc = profile_idc;
281 }
282 g_array_unref (profiles);
283
284 feienc->hw_max_profile_idc = max_profile_idc;
285 return TRUE;
286 }
287
288 /* Derives the profile supported by the underlying hardware */
289 static gboolean
ensure_hw_profile(GstVaapiFeiEncH264 * feienc)290 ensure_hw_profile (GstVaapiFeiEncH264 * feienc)
291 {
292 GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (feienc);
293 GstVaapiEntrypoint entrypoint = feienc->entrypoint;
294 GstVaapiProfile profile, profiles[4];
295 guint i, num_profiles = 0;
296
297 profiles[num_profiles++] = feienc->profile;
298 switch (feienc->profile) {
299 case GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE:
300 profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_BASELINE;
301 profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_MAIN;
302 // fall-through
303 case GST_VAAPI_PROFILE_H264_MAIN:
304 profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_HIGH;
305 break;
306 default:
307 break;
308 }
309
310 profile = GST_VAAPI_PROFILE_UNKNOWN;
311 for (i = 0; i < num_profiles; i++) {
312 if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) {
313 profile = profiles[i];
314 break;
315 }
316 }
317 if (profile == GST_VAAPI_PROFILE_UNKNOWN)
318 goto error_unsupported_profile;
319
320 GST_VAAPI_ENCODER_CAST (feienc)->profile = profile;
321 return TRUE;
322
323 /* ERRORS */
324 error_unsupported_profile:
325 {
326 GST_ERROR ("unsupported HW profile (0x%08x)", feienc->profile);
327 return FALSE;
328 }
329 }
330
331 /* Check target decoder constraints */
332 static gboolean
ensure_profile_limits(GstVaapiFeiEncH264 * feienc)333 ensure_profile_limits (GstVaapiFeiEncH264 * feienc)
334 {
335 GstVaapiProfile profile;
336
337 if (!feienc->max_profile_idc
338 || feienc->profile_idc <= feienc->max_profile_idc)
339 return TRUE;
340
341 GST_WARNING ("lowering coding tools to meet target decoder constraints");
342
343 profile = GST_VAAPI_PROFILE_UNKNOWN;
344
345 /* Try Main profile coding tools */
346 if (feienc->max_profile_idc < 100) {
347 feienc->use_dct8x8 = FALSE;
348 profile = GST_VAAPI_PROFILE_H264_MAIN;
349 }
350
351 /* Try Constrained Baseline profile coding tools */
352 if (feienc->max_profile_idc < 77) {
353 feienc->num_bframes = 0;
354 feienc->use_cabac = FALSE;
355 profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
356 }
357
358 if (profile) {
359 feienc->profile = profile;
360 feienc->profile_idc = feienc->max_profile_idc;
361 }
362 return TRUE;
363 }
364
365 /* Derives the minimum profile from the active coding tools */
366 static gboolean
ensure_profile(GstVaapiFeiEncH264 * feienc)367 ensure_profile (GstVaapiFeiEncH264 * feienc)
368 {
369 GstVaapiProfile profile;
370
371 /* Always start from "constrained-baseline" profile for maximum
372 compatibility */
373 profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
374
375 /* Main profile coding tools */
376 if (feienc->num_bframes > 0 || feienc->use_cabac)
377 profile = GST_VAAPI_PROFILE_H264_MAIN;
378
379 /* High profile coding tools */
380 if (feienc->use_dct8x8)
381 profile = GST_VAAPI_PROFILE_H264_HIGH;
382
383 /* MVC profiles coding tools */
384 if (feienc->num_views == 2)
385 profile = GST_VAAPI_PROFILE_H264_STEREO_HIGH;
386 else if (feienc->num_views > 2)
387 profile = GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH;
388
389 feienc->profile = profile;
390 feienc->profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
391 return TRUE;
392 }
393
394 /* Derives the level from the currently set limits */
395 static gboolean
ensure_level(GstVaapiFeiEncH264 * feienc)396 ensure_level (GstVaapiFeiEncH264 * feienc)
397 {
398 const guint cpb_factor = h264_get_cpb_nal_factor (feienc->profile);
399 const GstVaapiH264LevelLimits *limits_table;
400 guint i, num_limits, PicSizeMbs, MaxDpbMbs, MaxMBPS;
401
402 PicSizeMbs = feienc->mb_width * feienc->mb_height;
403 MaxDpbMbs = PicSizeMbs * ((feienc->num_bframes) ? 2 : 1);
404 MaxMBPS = gst_util_uint64_scale_int_ceil (PicSizeMbs,
405 GST_VAAPI_ENCODER_FPS_N (feienc), GST_VAAPI_ENCODER_FPS_D (feienc));
406
407 limits_table = gst_vaapi_utils_h264_get_level_limits_table (&num_limits);
408 for (i = 0; i < num_limits; i++) {
409 const GstVaapiH264LevelLimits *const limits = &limits_table[i];
410 if (PicSizeMbs <= limits->MaxFS &&
411 MaxDpbMbs <= limits->MaxDpbMbs &&
412 MaxMBPS <= limits->MaxMBPS && (!feienc->bitrate_bits
413 || feienc->bitrate_bits <= (limits->MaxBR * cpb_factor)) &&
414 (!feienc->cpb_length_bits ||
415 feienc->cpb_length_bits <= (limits->MaxCPB * cpb_factor)))
416 break;
417 }
418 if (i == num_limits)
419 goto error_unsupported_level;
420
421 feienc->level = limits_table[i].level;
422 feienc->level_idc = limits_table[i].level_idc;
423 return TRUE;
424
425 /* ERRORS */
426 error_unsupported_level:
427 {
428 GST_ERROR ("failed to find a suitable level matching codec config");
429 return FALSE;
430 }
431 }
432
433 /* Enable "high-compression" tuning options */
434 static gboolean
ensure_tuning_high_compression(GstVaapiFeiEncH264 * feienc)435 ensure_tuning_high_compression (GstVaapiFeiEncH264 * feienc)
436 {
437 guint8 profile_idc;
438
439 if (!ensure_hw_profile_limits (feienc))
440 return FALSE;
441
442 profile_idc = feienc->hw_max_profile_idc;
443 if (feienc->max_profile_idc && feienc->max_profile_idc < profile_idc)
444 profile_idc = feienc->max_profile_idc;
445
446 /* Tuning options to enable Main profile */
447 if (profile_idc >= 77 && profile_idc != 88) {
448 feienc->use_cabac = TRUE;
449 if (!feienc->num_bframes)
450 feienc->num_bframes = 1;
451 }
452
453 /* Tuning options to enable High profile */
454 if (profile_idc >= 100) {
455 feienc->use_dct8x8 = TRUE;
456 }
457 return TRUE;
458 }
459
460 /* Ensure tuning options */
461 static gboolean
ensure_tuning(GstVaapiFeiEncH264 * feienc)462 ensure_tuning (GstVaapiFeiEncH264 * feienc)
463 {
464 gboolean success;
465
466 switch (GST_VAAPI_ENCODER_TUNE (feienc)) {
467 case GST_VAAPI_ENCODER_TUNE_HIGH_COMPRESSION:
468 success = ensure_tuning_high_compression (feienc);
469 break;
470 case GST_VAAPI_ENCODER_TUNE_LOW_POWER:
471 /* Set low-power encode entry point. If hardware doesn't have
472 * support, it will fail in ensure_hw_profile() in later stage.
473 * So not duplicating the profile/entrypont query mechanism
474 * here as a part of optimization */
475 feienc->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP;
476 success = TRUE;
477 break;
478 default:
479 success = TRUE;
480 break;
481 }
482 return success;
483 }
484
485 /* Handle new GOP starts */
486 static void
reset_gop_start(GstVaapiFeiEncH264 * feienc)487 reset_gop_start (GstVaapiFeiEncH264 * feienc)
488 {
489 GstVaapiH264ViewReorderPool *const reorder_pool =
490 &feienc->reorder_pools[feienc->view_idx];
491
492 reorder_pool->frame_index = 1;
493 reorder_pool->cur_frame_num = 0;
494 reorder_pool->cur_present_index = 0;
495 ++feienc->idr_num;
496 }
497
498 /* Marks the supplied picture as a B-frame */
499 static void
set_b_frame(GstVaapiEncPicture * pic,GstVaapiFeiEncH264 * feienc)500 set_b_frame (GstVaapiEncPicture * pic, GstVaapiFeiEncH264 * feienc)
501 {
502 GstVaapiH264ViewReorderPool *const reorder_pool =
503 &feienc->reorder_pools[feienc->view_idx];
504
505 g_assert (pic && feienc);
506 g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
507 pic->type = GST_VAAPI_PICTURE_TYPE_B;
508 pic->frame_num = (reorder_pool->cur_frame_num % feienc->max_frame_num);
509 }
510
511 /* Marks the supplied picture as a P-frame */
512 static void
set_p_frame(GstVaapiEncPicture * pic,GstVaapiFeiEncH264 * feienc)513 set_p_frame (GstVaapiEncPicture * pic, GstVaapiFeiEncH264 * feienc)
514 {
515 GstVaapiH264ViewReorderPool *const reorder_pool =
516 &feienc->reorder_pools[feienc->view_idx];
517
518 g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
519 pic->type = GST_VAAPI_PICTURE_TYPE_P;
520 pic->frame_num = (reorder_pool->cur_frame_num % feienc->max_frame_num);
521 }
522
523 /* Marks the supplied picture as an I-frame */
524 static void
set_i_frame(GstVaapiEncPicture * pic,GstVaapiFeiEncH264 * feienc)525 set_i_frame (GstVaapiEncPicture * pic, GstVaapiFeiEncH264 * feienc)
526 {
527 GstVaapiH264ViewReorderPool *const reorder_pool =
528 &feienc->reorder_pools[feienc->view_idx];
529
530 g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
531 pic->type = GST_VAAPI_PICTURE_TYPE_I;
532 pic->frame_num = (reorder_pool->cur_frame_num % feienc->max_frame_num);
533
534 g_assert (pic->frame);
535 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame);
536 }
537
538 /* Marks the supplied picture as an IDR frame */
539 static void
set_idr_frame(GstVaapiEncPicture * pic,GstVaapiFeiEncH264 * feienc)540 set_idr_frame (GstVaapiEncPicture * pic, GstVaapiFeiEncH264 * feienc)
541 {
542 g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
543 pic->type = GST_VAAPI_PICTURE_TYPE_I;
544 pic->frame_num = 0;
545 pic->poc = 0;
546 GST_VAAPI_ENC_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_IDR);
547
548 g_assert (pic->frame);
549 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame);
550 }
551
552 /* Marks the supplied picture a a key-frame */
553 static void
set_key_frame(GstVaapiEncPicture * picture,GstVaapiFeiEncH264 * feienc,gboolean is_idr)554 set_key_frame (GstVaapiEncPicture * picture,
555 GstVaapiFeiEncH264 * feienc, gboolean is_idr)
556 {
557 if (is_idr) {
558 reset_gop_start (feienc);
559 set_idr_frame (picture, feienc);
560 } else
561 set_i_frame (picture, feienc);
562 }
563
564 /* Fills in VA HRD parameters */
565 static void
fill_hrd_params(GstVaapiFeiEncH264 * feienc,VAEncMiscParameterHRD * hrd)566 fill_hrd_params (GstVaapiFeiEncH264 * feienc, VAEncMiscParameterHRD * hrd)
567 {
568 if (feienc->bitrate_bits > 0) {
569 hrd->buffer_size = feienc->cpb_length_bits;
570 hrd->initial_buffer_fullness = hrd->buffer_size / 2;
571 } else {
572 hrd->buffer_size = 0;
573 hrd->initial_buffer_fullness = 0;
574 }
575 }
576
577 /* Reference list */
578 static gboolean
reference_list_init(GstVaapiFeiEncH264 * feienc,GstVaapiEncPicture * picture,GstVaapiFeiEncH264Ref ** reflist_0,guint * reflist_0_count,GstVaapiFeiEncH264Ref ** reflist_1,guint * reflist_1_count)579 reference_list_init (GstVaapiFeiEncH264 * feienc,
580 GstVaapiEncPicture * picture,
581 GstVaapiFeiEncH264Ref ** reflist_0,
582 guint * reflist_0_count,
583 GstVaapiFeiEncH264Ref ** reflist_1, guint * reflist_1_count)
584 {
585 GstVaapiFeiEncH264Ref *tmp;
586 GstVaapiH264ViewRefPool *const ref_pool =
587 &feienc->ref_pools[feienc->view_idx];
588 GList *iter, *list_0_start = NULL, *list_1_start = NULL;
589 guint count;
590
591 *reflist_0_count = 0;
592 *reflist_1_count = 0;
593 if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
594 return TRUE;
595
596 iter = g_queue_peek_tail_link (&ref_pool->ref_list);
597 for (; iter; iter = g_list_previous (iter)) {
598 tmp = (GstVaapiFeiEncH264Ref *) iter->data;
599 g_assert (tmp && tmp->poc != picture->poc);
600 if (_poc_greater_than (picture->poc, tmp->poc, feienc->max_pic_order_cnt)) {
601 list_0_start = iter;
602 list_1_start = g_list_next (iter);
603 break;
604 }
605 }
606
607 /* order reflist_0 */
608 g_assert (list_0_start);
609 iter = list_0_start;
610 count = 0;
611 for (; iter; iter = g_list_previous (iter)) {
612 reflist_0[count] = (GstVaapiFeiEncH264Ref *) iter->data;
613 ++count;
614 }
615 *reflist_0_count = count;
616
617 if (picture->type != GST_VAAPI_PICTURE_TYPE_B)
618 return TRUE;
619
620 /* order reflist_1 */
621 count = 0;
622 iter = list_1_start;
623 for (; iter; iter = g_list_next (iter)) {
624 reflist_1[count] = (GstVaapiFeiEncH264Ref *) iter->data;
625 ++count;
626 }
627 *reflist_1_count = count;
628 return TRUE;
629 }
630
631 /* Fills in VA sequence parameter buffer */
632 static gboolean
fill_sequence(GstVaapiFeiEncH264 * feienc,GstVaapiEncSequence * sequence)633 fill_sequence (GstVaapiFeiEncH264 * feienc, GstVaapiEncSequence * sequence)
634 {
635 VAEncSequenceParameterBufferH264 *const seq_param = sequence->param;
636 GstVaapiH264ViewRefPool *const ref_pool =
637 &feienc->ref_pools[feienc->view_idx];
638
639 memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferH264));
640 seq_param->seq_parameter_set_id = feienc->view_idx;
641 seq_param->level_idc = feienc->level_idc;
642 seq_param->intra_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (feienc);
643 seq_param->intra_idr_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (feienc);
644 seq_param->ip_period = seq_param->intra_period > 1 ?
645 (1 + feienc->num_bframes) : 0;
646 seq_param->bits_per_second = feienc->bitrate_bits;
647
648 seq_param->max_num_ref_frames = ref_pool->max_ref_frames;
649 seq_param->picture_width_in_mbs = feienc->mb_width;
650 seq_param->picture_height_in_mbs = feienc->mb_height;
651
652 /*sequence field values */
653 seq_param->seq_fields.value = 0;
654 seq_param->seq_fields.bits.chroma_format_idc = 1;
655 seq_param->seq_fields.bits.frame_mbs_only_flag = 1;
656 seq_param->seq_fields.bits.mb_adaptive_frame_field_flag = FALSE;
657 seq_param->seq_fields.bits.seq_scaling_matrix_present_flag = FALSE;
658 /* direct_8x8_inference_flag default false */
659 seq_param->seq_fields.bits.direct_8x8_inference_flag = FALSE;
660 g_assert (feienc->log2_max_frame_num >= 4);
661 seq_param->seq_fields.bits.log2_max_frame_num_minus4 =
662 feienc->log2_max_frame_num - 4;
663 /* picture order count */
664 feienc->pic_order_cnt_type = seq_param->seq_fields.bits.pic_order_cnt_type =
665 0;
666 g_assert (feienc->log2_max_pic_order_cnt >= 4);
667 seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 =
668 feienc->log2_max_pic_order_cnt - 4;
669
670 seq_param->bit_depth_luma_minus8 = 0;
671 seq_param->bit_depth_chroma_minus8 = 0;
672
673 /* not used if pic_order_cnt_type == 0 */
674 if (seq_param->seq_fields.bits.pic_order_cnt_type == 1) {
675 feienc->delta_pic_order_always_zero_flag =
676 seq_param->seq_fields.bits.delta_pic_order_always_zero_flag = TRUE;
677 seq_param->num_ref_frames_in_pic_order_cnt_cycle = 0;
678 seq_param->offset_for_non_ref_pic = 0;
679 seq_param->offset_for_top_to_bottom_field = 0;
680 memset (seq_param->offset_for_ref_frame, 0,
681 sizeof (seq_param->offset_for_ref_frame));
682 }
683
684 /* frame_cropping_flag */
685 if ((GST_VAAPI_ENCODER_WIDTH (feienc) & 15) ||
686 (GST_VAAPI_ENCODER_HEIGHT (feienc) & 15)) {
687 static const guint SubWidthC[] = { 1, 2, 2, 1 };
688 static const guint SubHeightC[] = { 1, 2, 1, 1 };
689 const guint CropUnitX =
690 SubWidthC[seq_param->seq_fields.bits.chroma_format_idc];
691 const guint CropUnitY =
692 SubHeightC[seq_param->seq_fields.bits.chroma_format_idc] *
693 (2 - seq_param->seq_fields.bits.frame_mbs_only_flag);
694
695 seq_param->frame_cropping_flag = 1;
696 seq_param->frame_crop_left_offset = 0;
697 seq_param->frame_crop_right_offset =
698 (16 * feienc->mb_width - GST_VAAPI_ENCODER_WIDTH (feienc)) / CropUnitX;
699 seq_param->frame_crop_top_offset = 0;
700 seq_param->frame_crop_bottom_offset =
701 (16 * feienc->mb_height -
702 GST_VAAPI_ENCODER_HEIGHT (feienc)) / CropUnitY;
703 }
704
705 /* VUI parameters are always set, at least for timing_info (framerate) */
706 seq_param->vui_parameters_present_flag = TRUE;
707 if (seq_param->vui_parameters_present_flag) {
708 seq_param->vui_fields.bits.aspect_ratio_info_present_flag = TRUE;
709 if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) {
710 const GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (feienc);
711 seq_param->aspect_ratio_idc = 0xff;
712 seq_param->sar_width = GST_VIDEO_INFO_PAR_N (vip);
713 seq_param->sar_height = GST_VIDEO_INFO_PAR_D (vip);
714 }
715 seq_param->vui_fields.bits.bitstream_restriction_flag = FALSE;
716 /* if vui_parameters_present_flag is TRUE and sps data belongs to
717 * subset sps, timing_info_preset_flag should be zero (H.7.4.2.1.1) */
718 seq_param->vui_fields.bits.timing_info_present_flag = !feienc->view_idx;
719 if (seq_param->vui_fields.bits.timing_info_present_flag) {
720 seq_param->num_units_in_tick = GST_VAAPI_ENCODER_FPS_D (feienc);
721 seq_param->time_scale = GST_VAAPI_ENCODER_FPS_N (feienc) * 2;
722 }
723 }
724
725 return TRUE;
726 }
727
728 /* Fills in VA picture parameter buffer */
729 static gboolean
fill_picture(GstVaapiFeiEncH264 * feienc,GstVaapiEncPicture * picture,GstVaapiSurfaceProxy * surface,GstVaapiCodedBuffer * const codedbuf)730 fill_picture (GstVaapiFeiEncH264 * feienc, GstVaapiEncPicture * picture,
731 GstVaapiSurfaceProxy * surface, GstVaapiCodedBuffer * const codedbuf)
732 {
733 VAEncPictureParameterBufferH264 *const pic_param = picture->param;
734 GstVaapiH264ViewRefPool *const ref_pool =
735 &feienc->ref_pools[feienc->view_idx];
736 GstVaapiFeiEncH264Ref *ref_pic;
737 GList *reflist;
738 guint i;
739
740 memset (pic_param, 0, sizeof (VAEncPictureParameterBufferH264));
741
742 /* reference list, */
743 pic_param->CurrPic.picture_id = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
744 pic_param->CurrPic.TopFieldOrderCnt = picture->poc;
745 pic_param->CurrPic.frame_idx = picture->frame_num;
746 i = 0;
747 if (picture->type != GST_VAAPI_PICTURE_TYPE_I) {
748 for (reflist = g_queue_peek_head_link (&ref_pool->ref_list);
749 reflist; reflist = g_list_next (reflist)) {
750 ref_pic = reflist->data;
751 g_assert (ref_pic && ref_pic->pic &&
752 GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic) != VA_INVALID_ID);
753
754 pic_param->ReferenceFrames[i].picture_id =
755 GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic);
756 pic_param->ReferenceFrames[i].TopFieldOrderCnt = ref_pic->poc;
757 pic_param->ReferenceFrames[i].flags |=
758 VA_PICTURE_H264_SHORT_TERM_REFERENCE;
759 pic_param->ReferenceFrames[i].frame_idx = ref_pic->frame_num;
760 ++i;
761 }
762 g_assert (i <= 16 && i <= ref_pool->max_ref_frames);
763 }
764 for (; i < 16; ++i) {
765 pic_param->ReferenceFrames[i].picture_id = VA_INVALID_ID;
766 pic_param->ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID;
767 }
768
769 pic_param->coded_buf = GST_VAAPI_OBJECT_ID (codedbuf);
770
771 pic_param->pic_parameter_set_id = feienc->view_idx;
772 pic_param->seq_parameter_set_id = feienc->view_idx ? 1 : 0;
773 pic_param->last_picture = 0; /* means last encoding picture */
774 pic_param->frame_num = picture->frame_num;
775 pic_param->pic_init_qp = feienc->init_qp;
776 pic_param->num_ref_idx_l0_active_minus1 =
777 (ref_pool->max_reflist0_count ? (ref_pool->max_reflist0_count - 1) : 0);
778 pic_param->num_ref_idx_l1_active_minus1 =
779 (ref_pool->max_reflist1_count ? (ref_pool->max_reflist1_count - 1) : 0);
780 pic_param->chroma_qp_index_offset = 0;
781 pic_param->second_chroma_qp_index_offset = 0;
782
783 /* set picture fields */
784 pic_param->pic_fields.value = 0;
785 pic_param->pic_fields.bits.idr_pic_flag =
786 GST_VAAPI_ENC_PICTURE_IS_IDR (picture);
787 pic_param->pic_fields.bits.reference_pic_flag =
788 (picture->type != GST_VAAPI_PICTURE_TYPE_B);
789 pic_param->pic_fields.bits.entropy_coding_mode_flag = feienc->use_cabac;
790 pic_param->pic_fields.bits.weighted_pred_flag = FALSE;
791 pic_param->pic_fields.bits.weighted_bipred_idc = 0;
792 pic_param->pic_fields.bits.constrained_intra_pred_flag = 0;
793 pic_param->pic_fields.bits.transform_8x8_mode_flag = feienc->use_dct8x8;
794 /* enable debloking */
795 pic_param->pic_fields.bits.deblocking_filter_control_present_flag = TRUE;
796 pic_param->pic_fields.bits.redundant_pic_cnt_present_flag = FALSE;
797 /* bottom_field_pic_order_in_frame_present_flag */
798 pic_param->pic_fields.bits.pic_order_present_flag = FALSE;
799 pic_param->pic_fields.bits.pic_scaling_matrix_present_flag = FALSE;
800
801 return TRUE;
802 }
803
804 /* Adds slice headers to picture */
805 static gboolean
add_slice_headers(GstVaapiFeiEncH264 * feienc,GstVaapiEncPicture * picture,GstVaapiFeiEncH264Ref ** reflist_0,guint reflist_0_count,GstVaapiFeiEncH264Ref ** reflist_1,guint reflist_1_count,GstVaapiFeiInfoToPakH264 * info_to_pak)806 add_slice_headers (GstVaapiFeiEncH264 * feienc, GstVaapiEncPicture * picture,
807 GstVaapiFeiEncH264Ref ** reflist_0, guint reflist_0_count,
808 GstVaapiFeiEncH264Ref ** reflist_1, guint reflist_1_count,
809 GstVaapiFeiInfoToPakH264 * info_to_pak)
810 {
811 VAEncSliceParameterBufferH264 *slice_param;
812 GstVaapiEncSlice *slice;
813 GArray *h264_slice_params;
814 guint slice_of_mbs, slice_mod_mbs, cur_slice_mbs;
815 guint mb_size;
816 guint last_mb_index;
817 guint i_slice, i_ref;
818
819 g_assert (picture);
820
821 mb_size = feienc->mb_width * feienc->mb_height;
822
823 g_assert (feienc->num_slices && feienc->num_slices < mb_size);
824 slice_of_mbs = mb_size / feienc->num_slices;
825 slice_mod_mbs = mb_size % feienc->num_slices;
826 last_mb_index = 0;
827 h264_slice_params =
828 g_array_new (FALSE, TRUE, sizeof (VAEncSliceParameterBufferH264));
829 for (i_slice = 0; i_slice < feienc->num_slices; ++i_slice) {
830 cur_slice_mbs = slice_of_mbs;
831 if (slice_mod_mbs) {
832 ++cur_slice_mbs;
833 --slice_mod_mbs;
834 }
835 slice = GST_VAAPI_ENC_SLICE_NEW (H264, feienc);
836 g_assert (slice && slice->param_id != VA_INVALID_ID);
837 slice_param = slice->param;
838
839 memset (slice_param, 0, sizeof (VAEncSliceParameterBufferH264));
840 slice_param->macroblock_address = last_mb_index;
841 slice_param->num_macroblocks = cur_slice_mbs;
842 slice_param->macroblock_info = VA_INVALID_ID;
843 slice_param->slice_type = h264_get_slice_type (picture->type);
844 g_assert ((gint8) slice_param->slice_type != -1);
845 slice_param->pic_parameter_set_id = feienc->view_idx;
846 slice_param->idr_pic_id = feienc->idr_num;
847 slice_param->pic_order_cnt_lsb = picture->poc;
848
849 /* not used if pic_order_cnt_type = 0 */
850 slice_param->delta_pic_order_cnt_bottom = 0;
851 memset (slice_param->delta_pic_order_cnt, 0,
852 sizeof (slice_param->delta_pic_order_cnt));
853
854 /* only works for B frames */
855 if (slice_param->slice_type == GST_H264_B_SLICE)
856 slice_param->direct_spatial_mv_pred_flag = TRUE;
857 /* default equal to picture parameters */
858 slice_param->num_ref_idx_active_override_flag = TRUE;
859 if (picture->type != GST_VAAPI_PICTURE_TYPE_I && reflist_0_count > 0)
860 slice_param->num_ref_idx_l0_active_minus1 = reflist_0_count - 1;
861 else
862 slice_param->num_ref_idx_l0_active_minus1 = 0;
863 if (picture->type == GST_VAAPI_PICTURE_TYPE_B && reflist_1_count > 0)
864 slice_param->num_ref_idx_l1_active_minus1 = reflist_1_count - 1;
865 else
866 slice_param->num_ref_idx_l1_active_minus1 = 0;
867 g_assert (slice_param->num_ref_idx_l0_active_minus1 >= 0);
868 g_assert (slice_param->num_ref_idx_l1_active_minus1 == 0);
869
870 i_ref = 0;
871 if (picture->type != GST_VAAPI_PICTURE_TYPE_I) {
872 for (; i_ref < reflist_0_count; ++i_ref) {
873 slice_param->RefPicList0[i_ref].picture_id =
874 GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_0[i_ref]->pic);
875 slice_param->RefPicList0[i_ref].TopFieldOrderCnt =
876 reflist_0[i_ref]->poc;
877 slice_param->RefPicList0[i_ref].flags |=
878 VA_PICTURE_H264_SHORT_TERM_REFERENCE;
879 slice_param->RefPicList0[i_ref].frame_idx = reflist_0[i_ref]->frame_num;
880 }
881 g_assert (i_ref >= 1);
882 }
883 for (; i_ref < G_N_ELEMENTS (slice_param->RefPicList0); ++i_ref) {
884 slice_param->RefPicList0[i_ref].picture_id = VA_INVALID_SURFACE;
885 slice_param->RefPicList0[i_ref].flags = VA_PICTURE_H264_INVALID;
886 }
887
888 i_ref = 0;
889 if (picture->type == GST_VAAPI_PICTURE_TYPE_B) {
890 for (; i_ref < reflist_1_count; ++i_ref) {
891 slice_param->RefPicList1[i_ref].picture_id =
892 GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_1[i_ref]->pic);
893 slice_param->RefPicList1[i_ref].TopFieldOrderCnt =
894 reflist_1[i_ref]->poc;
895 slice_param->RefPicList1[i_ref].flags |=
896 VA_PICTURE_H264_SHORT_TERM_REFERENCE;
897 slice_param->RefPicList1[i_ref].frame_idx = reflist_1[i_ref]->frame_num;
898 }
899 g_assert (i_ref == 1);
900 }
901 for (; i_ref < G_N_ELEMENTS (slice_param->RefPicList1); ++i_ref) {
902 slice_param->RefPicList1[i_ref].picture_id = VA_INVALID_SURFACE;
903 slice_param->RefPicList1[i_ref].flags = VA_PICTURE_H264_INVALID;
904 }
905
906 /* not used if pic_param.pic_fields.bits.weighted_pred_flag == FALSE */
907 slice_param->luma_log2_weight_denom = 0;
908 slice_param->chroma_log2_weight_denom = 0;
909 slice_param->luma_weight_l0_flag = FALSE;
910 memset (slice_param->luma_weight_l0, 0,
911 sizeof (slice_param->luma_weight_l0));
912 memset (slice_param->luma_offset_l0, 0,
913 sizeof (slice_param->luma_offset_l0));
914 slice_param->chroma_weight_l0_flag = FALSE;
915 memset (slice_param->chroma_weight_l0, 0,
916 sizeof (slice_param->chroma_weight_l0));
917 memset (slice_param->chroma_offset_l0, 0,
918 sizeof (slice_param->chroma_offset_l0));
919 slice_param->luma_weight_l1_flag = FALSE;
920 memset (slice_param->luma_weight_l1, 0,
921 sizeof (slice_param->luma_weight_l1));
922 memset (slice_param->luma_offset_l1, 0,
923 sizeof (slice_param->luma_offset_l1));
924 slice_param->chroma_weight_l1_flag = FALSE;
925 memset (slice_param->chroma_weight_l1, 0,
926 sizeof (slice_param->chroma_weight_l1));
927 memset (slice_param->chroma_offset_l1, 0,
928 sizeof (slice_param->chroma_offset_l1));
929
930 slice_param->cabac_init_idc = 0;
931 slice_param->slice_qp_delta = feienc->init_qp - feienc->min_qp;
932 if (slice_param->slice_qp_delta > 4)
933 slice_param->slice_qp_delta = 4;
934 slice_param->disable_deblocking_filter_idc = 0;
935 slice_param->slice_alpha_c0_offset_div2 = 2;
936 slice_param->slice_beta_offset_div2 = 2;
937
938 /* set calculation for next slice */
939 last_mb_index += cur_slice_mbs;
940
941 g_array_append_val (h264_slice_params, *slice_param);
942
943 gst_vaapi_enc_picture_add_slice (picture, slice);
944 gst_vaapi_codec_object_replace (&slice, NULL);
945 }
946 g_assert (last_mb_index == mb_size);
947
948 info_to_pak->h264_slice_headers = h264_slice_params;
949
950 return TRUE;
951
952 }
953
954 /* Generates and submits SPS header accordingly into the bitstream */
955 static gboolean
ensure_sequence(GstVaapiFeiEncH264 * feienc,GstVaapiEncPicture * picture,GstVaapiFeiInfoToPakH264 * info_to_pak)956 ensure_sequence (GstVaapiFeiEncH264 * feienc, GstVaapiEncPicture * picture,
957 GstVaapiFeiInfoToPakH264 * info_to_pak)
958 {
959 GstVaapiEncSequence *sequence = NULL;
960 VAEncSequenceParameterBufferH264 *seq_param;
961
962 sequence = GST_VAAPI_ENC_SEQUENCE_NEW (H264, feienc);
963 if (!sequence || !fill_sequence (feienc, sequence))
964 goto error_create_seq_param;
965
966 seq_param = sequence->param;
967 info_to_pak->h264_enc_sps = *seq_param;
968
969 if (sequence) {
970 gst_vaapi_enc_picture_set_sequence (picture, sequence);
971 gst_vaapi_codec_object_replace (&sequence, NULL);
972 }
973
974 if (!feienc->is_mvc || feienc->view_idx > 0)
975 feienc->config_changed = FALSE;
976 return TRUE;
977
978 /* ERRORS */
979 error_create_seq_param:
980 {
981 GST_ERROR ("failed to create sequence parameter buffer (SPS)");
982 gst_vaapi_codec_object_replace (&sequence, NULL);
983 return FALSE;
984 }
985 }
986
987 /* Generates additional fei control parameters */
988 static gboolean
ensure_fei_misc_params(GstVaapiFeiEncH264 * feienc,GstVaapiEncPicture * picture,GstVaapiCodedBufferProxy * codedbuf_proxy)989 ensure_fei_misc_params (GstVaapiFeiEncH264 * feienc,
990 GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf_proxy)
991 {
992 GstVaapiEncMiscParam *misc = NULL;
993 GstVaapiSurfaceProxy *surface_proxy = picture->proxy;
994 VAEncMiscParameterFEIFrameControlH264 *misc_fei_pic_control_param;
995 guint mbcode_size = 0;
996 guint mv_size = 0;
997 guint dist_size = 0;
998
999 /*fei pic control params */
1000 misc = GST_VAAPI_ENC_FEI_MISC_PARAM_NEW (H264, feienc);
1001 g_assert (misc);
1002 if (!misc)
1003 return FALSE;
1004 misc_fei_pic_control_param = misc->data;
1005 surface_proxy = picture->proxy;
1006
1007 misc_fei_pic_control_param->function = VA_FEI_FUNCTION_ENC;
1008 misc_fei_pic_control_param->search_path = feienc->search_path;
1009 misc_fei_pic_control_param->num_mv_predictors_l0 =
1010 feienc->num_mv_predictors_l0;
1011 misc_fei_pic_control_param->num_mv_predictors_l1 =
1012 feienc->num_mv_predictors_l1;
1013 misc_fei_pic_control_param->len_sp = feienc->len_sp;
1014 misc_fei_pic_control_param->sub_mb_part_mask = feienc->submb_part_mask;
1015 if (!feienc->use_dct8x8)
1016 misc_fei_pic_control_param->intra_part_mask = feienc->intra_part_mask | 2;
1017 misc_fei_pic_control_param->multi_pred_l0 = feienc->multi_predL0;
1018 misc_fei_pic_control_param->multi_pred_l1 = feienc->multi_predL1;
1019 misc_fei_pic_control_param->sub_pel_mode = feienc->subpel_mode;
1020 misc_fei_pic_control_param->inter_sad = feienc->inter_sad;
1021 misc_fei_pic_control_param->intra_sad = feienc->intra_sad;
1022 misc_fei_pic_control_param->distortion_type = 0;
1023 misc_fei_pic_control_param->repartition_check_enable = 0;
1024 misc_fei_pic_control_param->adaptive_search = feienc->adaptive_search;
1025 misc_fei_pic_control_param->mb_size_ctrl = 0;
1026 misc_fei_pic_control_param->ref_width = feienc->ref_width;
1027 misc_fei_pic_control_param->ref_height = feienc->ref_height;
1028 misc_fei_pic_control_param->search_window = feienc->search_window;
1029
1030 /***** ENC input: mv_predictor *****/
1031 if (surface_proxy->mvpred) {
1032 misc_fei_pic_control_param->mv_predictor =
1033 GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->mvpred)->param_id;
1034 misc_fei_pic_control_param->mv_predictor_enable = TRUE;
1035 gst_vaapi_codec_object_replace (&picture->mvpred, surface_proxy->mvpred);
1036 } else {
1037 misc_fei_pic_control_param->mv_predictor = VA_INVALID_ID;
1038 misc_fei_pic_control_param->mv_predictor_enable = FALSE;
1039 picture->mvpred = NULL;
1040 }
1041
1042 /***** ENC input: qp ******/
1043 if (surface_proxy->qp) {
1044 misc_fei_pic_control_param->qp =
1045 GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->qp)->param_id;
1046 misc_fei_pic_control_param->mb_qp = TRUE;
1047 gst_vaapi_codec_object_replace (&picture->qp, surface_proxy->qp);
1048 } else {
1049 misc_fei_pic_control_param->qp = VA_INVALID_ID;
1050 misc_fei_pic_control_param->mb_qp = FALSE;
1051 picture->qp = NULL;
1052 }
1053 /***** ENC input: mb_control ******/
1054 if (surface_proxy->mbcntrl) {
1055 misc_fei_pic_control_param->mb_ctrl =
1056 GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->mbcntrl)->param_id;
1057 misc_fei_pic_control_param->mb_input = TRUE;
1058 gst_vaapi_codec_object_replace (&picture->mbcntrl, surface_proxy->mbcntrl);
1059 } else {
1060 misc_fei_pic_control_param->mb_ctrl = VA_INVALID_ID;
1061 misc_fei_pic_control_param->mb_input = FALSE;
1062 picture->mbcntrl = NULL;
1063 }
1064
1065 mbcode_size = sizeof (VAEncFEIMBCodeH264) *
1066 feienc->mb_width * feienc->mb_height;
1067 mv_size = sizeof (VAMotionVector) * 16 * feienc->mb_width * feienc->mb_height;
1068 dist_size = sizeof (VAEncFEIDistortionH264) *
1069 feienc->mb_width * feienc->mb_height;
1070 /***** ENC_PAK/ENC output: macroblock code buffer *****/
1071 codedbuf_proxy->mbcode =
1072 gst_vaapi_enc_fei_mb_code_new (GST_VAAPI_ENCODER_CAST (feienc),
1073 NULL, mbcode_size);
1074 misc_fei_pic_control_param->mb_code_data =
1075 GST_VAAPI_FEI_CODEC_OBJECT (codedbuf_proxy->mbcode)->param_id;
1076 picture->mbcode = gst_vaapi_codec_object_ref (codedbuf_proxy->mbcode);
1077
1078 /***** ENC_PAK/ENC output: motion vector buffer *****/
1079 codedbuf_proxy->mv =
1080 gst_vaapi_enc_fei_mv_new (GST_VAAPI_ENCODER_CAST (feienc), NULL, mv_size);
1081 misc_fei_pic_control_param->mv_data =
1082 GST_VAAPI_FEI_CODEC_OBJECT (codedbuf_proxy->mv)->param_id;
1083 picture->mv = gst_vaapi_codec_object_ref (codedbuf_proxy->mv);
1084
1085 /* Fixme: a copy needed in coded_buf proxy */
1086 /***** ENC_PAK/ENC output: distortion buffer *****/
1087 picture->dist =
1088 gst_vaapi_enc_fei_distortion_new (GST_VAAPI_ENCODER_CAST (feienc),
1089 NULL, dist_size);
1090 misc_fei_pic_control_param->distortion =
1091 GST_VAAPI_FEI_CODEC_OBJECT (picture->dist)->param_id;
1092 codedbuf_proxy->dist = gst_vaapi_codec_object_ref (picture->dist);
1093
1094 gst_vaapi_enc_picture_add_misc_param (picture, misc);
1095 gst_vaapi_codec_object_replace (&misc, NULL);
1096 return TRUE;
1097 }
1098
1099 /* Generates additional control parameters */
1100 static gboolean
ensure_misc_params(GstVaapiFeiEncH264 * feienc,GstVaapiEncPicture * picture)1101 ensure_misc_params (GstVaapiFeiEncH264 * feienc, GstVaapiEncPicture * picture)
1102 {
1103 GstVaapiEncMiscParam *misc = NULL;
1104 VAEncMiscParameterRateControl *rate_control;
1105
1106 /* HRD params */
1107 misc = GST_VAAPI_ENC_MISC_PARAM_NEW (HRD, feienc);
1108 g_assert (misc);
1109 if (!misc)
1110 return FALSE;
1111 fill_hrd_params (feienc, misc->data);
1112 gst_vaapi_enc_picture_add_misc_param (picture, misc);
1113 gst_vaapi_codec_object_replace (&misc, NULL);
1114
1115 /* RateControl params */
1116 if (GST_VAAPI_ENCODER_RATE_CONTROL (feienc) == GST_VAAPI_RATECONTROL_CBR ||
1117 GST_VAAPI_ENCODER_RATE_CONTROL (feienc) == GST_VAAPI_RATECONTROL_VBR) {
1118 misc = GST_VAAPI_ENC_MISC_PARAM_NEW (RateControl, feienc);
1119 g_assert (misc);
1120 if (!misc)
1121 return FALSE;
1122 rate_control = misc->data;
1123 memset (rate_control, 0, sizeof (VAEncMiscParameterRateControl));
1124 rate_control->bits_per_second = feienc->bitrate_bits;
1125 rate_control->target_percentage = 70;
1126 rate_control->window_size = feienc->cpb_length;
1127 rate_control->initial_qp = feienc->init_qp;
1128 rate_control->min_qp = feienc->min_qp;
1129 rate_control->basic_unit_size = 0;
1130 gst_vaapi_enc_picture_add_misc_param (picture, misc);
1131 gst_vaapi_codec_object_replace (&misc, NULL);
1132
1133 }
1134 return TRUE;
1135
1136 }
1137
1138 /* Generates and submits PPS header accordingly into the bitstream */
1139 static gboolean
ensure_picture(GstVaapiFeiEncH264 * feienc,GstVaapiEncPicture * picture,GstVaapiSurfaceProxy * surface,GstVaapiCodedBufferProxy * codedbuf_proxy,GstVaapiFeiInfoToPakH264 * info_to_pak)1140 ensure_picture (GstVaapiFeiEncH264 * feienc, GstVaapiEncPicture * picture,
1141 GstVaapiSurfaceProxy * surface, GstVaapiCodedBufferProxy * codedbuf_proxy,
1142 GstVaapiFeiInfoToPakH264 * info_to_pak)
1143 {
1144 gboolean res = FALSE;
1145 GstVaapiCodedBuffer *const codedbuf =
1146 GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
1147 VAEncPictureParameterBufferH264 *const pic_param = picture->param;
1148
1149 res = fill_picture (feienc, picture, surface, codedbuf);
1150
1151 if (!res)
1152 return FALSE;
1153
1154 info_to_pak->h264_enc_pps = *pic_param;
1155
1156 return TRUE;
1157 }
1158
1159 /* Generates slice headers */
1160 static gboolean
ensure_slices(GstVaapiFeiEncH264 * feienc,GstVaapiEncPicture * picture,GstVaapiFeiInfoToPakH264 * info_to_pak)1161 ensure_slices (GstVaapiFeiEncH264 * feienc, GstVaapiEncPicture * picture,
1162 GstVaapiFeiInfoToPakH264 * info_to_pak)
1163 {
1164 GstVaapiFeiEncH264Ref *reflist_0[16];
1165 GstVaapiFeiEncH264Ref *reflist_1[16];
1166 GstVaapiH264ViewRefPool *const ref_pool =
1167 &feienc->ref_pools[feienc->view_idx];
1168 guint reflist_0_count = 0, reflist_1_count = 0;
1169
1170 g_assert (picture);
1171
1172 if (picture->type != GST_VAAPI_PICTURE_TYPE_I &&
1173 !reference_list_init (feienc, picture,
1174 reflist_0, &reflist_0_count, reflist_1, &reflist_1_count)) {
1175 GST_ERROR ("reference list reorder failed");
1176 return FALSE;
1177 }
1178
1179 g_assert (reflist_0_count + reflist_1_count <= ref_pool->max_ref_frames);
1180 if (reflist_0_count > ref_pool->max_reflist0_count)
1181 reflist_0_count = ref_pool->max_reflist0_count;
1182 if (reflist_1_count > ref_pool->max_reflist1_count)
1183 reflist_1_count = ref_pool->max_reflist1_count;
1184
1185 if (!add_slice_headers (feienc, picture,
1186 reflist_0, reflist_0_count, reflist_1, reflist_1_count, info_to_pak))
1187 return FALSE;
1188
1189 return TRUE;
1190 }
1191
1192 /* Normalizes bitrate (and CPB size) for HRD conformance */
1193 static void
ensure_bitrate_hrd(GstVaapiFeiEncH264 * feienc)1194 ensure_bitrate_hrd (GstVaapiFeiEncH264 * feienc)
1195 {
1196 GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (feienc);
1197 guint bitrate, cpb_size;
1198
1199 if (!base_encoder->bitrate) {
1200 feienc->bitrate_bits = 0;
1201 return;
1202 }
1203
1204 /* Round down bitrate. This is a hard limit mandated by the user */
1205 g_assert (SX_BITRATE >= 6);
1206 bitrate = (base_encoder->bitrate * 1000) & ~((1U << SX_BITRATE) - 1);
1207 if (bitrate != feienc->bitrate_bits) {
1208 GST_DEBUG ("HRD bitrate: %u bits/sec", bitrate);
1209 feienc->bitrate_bits = bitrate;
1210 feienc->config_changed = TRUE;
1211 }
1212
1213 /* Round up CPB size. This is an HRD compliance detail */
1214 g_assert (SX_CPB_SIZE >= 4);
1215 cpb_size = gst_util_uint64_scale (bitrate, feienc->cpb_length, 1000) &
1216 ~((1U << SX_CPB_SIZE) - 1);
1217 if (cpb_size != feienc->cpb_length_bits) {
1218 GST_DEBUG ("HRD CPB size: %u bits", cpb_size);
1219 feienc->cpb_length_bits = cpb_size;
1220 feienc->config_changed = TRUE;
1221 }
1222 }
1223
1224 /* Estimates a good enough bitrate if none was supplied */
1225 static void
ensure_bitrate(GstVaapiFeiEncH264 * feienc)1226 ensure_bitrate (GstVaapiFeiEncH264 * feienc)
1227 {
1228 GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (feienc);
1229
1230 /* Default compression: 48 bits per macroblock in "high-compression" mode */
1231 switch (GST_VAAPI_ENCODER_RATE_CONTROL (feienc)) {
1232 case GST_VAAPI_RATECONTROL_CBR:
1233 case GST_VAAPI_RATECONTROL_VBR:
1234 case GST_VAAPI_RATECONTROL_VBR_CONSTRAINED:
1235 if (!base_encoder->bitrate) {
1236 /* According to the literature and testing, CABAC entropy coding
1237 mode could provide for +10% to +18% improvement in general,
1238 thus estimating +15% here ; and using adaptive 8x8 transforms
1239 in I-frames could bring up to +10% improvement. */
1240 guint bits_per_mb = 48;
1241 if (!feienc->use_cabac)
1242 bits_per_mb += (bits_per_mb * 15) / 100;
1243 if (!feienc->use_dct8x8)
1244 bits_per_mb += (bits_per_mb * 10) / 100;
1245
1246 base_encoder->bitrate =
1247 feienc->mb_width * feienc->mb_height * bits_per_mb *
1248 GST_VAAPI_ENCODER_FPS_N (feienc) /
1249 GST_VAAPI_ENCODER_FPS_D (feienc) / 1000;
1250 GST_INFO ("target bitrate computed to %u kbps", base_encoder->bitrate);
1251 }
1252 break;
1253 default:
1254 base_encoder->bitrate = 0;
1255 break;
1256 }
1257 ensure_bitrate_hrd (feienc);
1258 }
1259
1260 /* Constructs profile and level information based on user-defined limits */
1261 static GstVaapiEncoderStatus
ensure_profile_and_level(GstVaapiFeiEncH264 * feienc)1262 ensure_profile_and_level (GstVaapiFeiEncH264 * feienc)
1263 {
1264 const GstVaapiProfile profile = feienc->profile;
1265 const GstVaapiLevelH264 level = feienc->level;
1266
1267 if (!ensure_tuning (feienc))
1268 GST_WARNING ("Failed to set some of the tuning option as expected! ");
1269
1270 if (!ensure_profile (feienc) || !ensure_profile_limits (feienc))
1271 return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
1272
1273 /* Check HW constraints */
1274 if (!ensure_hw_profile_limits (feienc))
1275 return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
1276 if (feienc->profile_idc > feienc->hw_max_profile_idc)
1277 return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
1278
1279 /* Ensure bitrate if not set already and derive the right level to use */
1280 ensure_bitrate (feienc);
1281 if (!ensure_level (feienc))
1282 return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
1283
1284 if (feienc->profile != profile || feienc->level != level) {
1285 GST_DEBUG ("selected %s profile at level %s",
1286 gst_vaapi_utils_h264_get_profile_string (feienc->profile),
1287 gst_vaapi_utils_h264_get_level_string (feienc->level));
1288 feienc->config_changed = TRUE;
1289 }
1290 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1291 }
1292
1293 static void
reset_properties(GstVaapiFeiEncH264 * feienc)1294 reset_properties (GstVaapiFeiEncH264 * feienc)
1295 {
1296 GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (feienc);
1297 guint mb_size, i;
1298 guint max_reflist0_count;
1299
1300 if (feienc->idr_period < base_encoder->keyframe_period)
1301 feienc->idr_period = base_encoder->keyframe_period;
1302
1303 if (feienc->min_qp > feienc->init_qp ||
1304 (GST_VAAPI_ENCODER_RATE_CONTROL (feienc) == GST_VAAPI_RATECONTROL_CQP &&
1305 feienc->min_qp < feienc->init_qp))
1306 feienc->min_qp = feienc->init_qp;
1307
1308 mb_size = feienc->mb_width * feienc->mb_height;
1309 if (feienc->num_slices > (mb_size + 1) / 2)
1310 feienc->num_slices = (mb_size + 1) / 2;
1311 g_assert (feienc->num_slices);
1312
1313 if (feienc->num_bframes > (base_encoder->keyframe_period + 1) / 2)
1314 feienc->num_bframes = (base_encoder->keyframe_period + 1) / 2;
1315
1316 /* Workaround : vaapi-intel-driver doesn't have support for
1317 * B-frame encode when utilizing low-power encode hardware block.
1318 * So Disabling b-frame encoding in low-pwer encode.
1319 *
1320 * Fixme :We should query the VAConfigAttribEncMaxRefFrames
1321 * instead of blindly disabling b-frame support and set b/p frame count,
1322 * buffer pool size etc based on that.*/
1323 if ((feienc->num_bframes > 0)
1324 && (feienc->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP)) {
1325 GST_WARNING
1326 ("Disabling b-frame since the driver doesn't supporting it in low-power encode");
1327 feienc->num_bframes = 0;
1328 }
1329
1330 if (feienc->num_bframes > 0 && GST_VAAPI_ENCODER_FPS_N (feienc) > 0)
1331 feienc->cts_offset = gst_util_uint64_scale (GST_SECOND,
1332 GST_VAAPI_ENCODER_FPS_D (feienc), GST_VAAPI_ENCODER_FPS_N (feienc));
1333 else
1334 feienc->cts_offset = 0;
1335
1336 /* init max_frame_num, max_poc */
1337 feienc->log2_max_frame_num = h264_get_log2_max_frame_num (feienc->idr_period);
1338 g_assert (feienc->log2_max_frame_num >= 4);
1339 feienc->max_frame_num = (1 << feienc->log2_max_frame_num);
1340 feienc->log2_max_pic_order_cnt = feienc->log2_max_frame_num + 1;
1341 feienc->max_pic_order_cnt = (1 << feienc->log2_max_pic_order_cnt);
1342 feienc->idr_num = 0;
1343
1344 if (feienc->num_bframes > 0) {
1345 if (feienc->num_ref_frames == 1) {
1346 GST_INFO ("num ref frames is modified as 2 as b frame is set");
1347 feienc->num_ref_frames = 2;
1348 }
1349 max_reflist0_count = feienc->num_ref_frames - 1;
1350 } else {
1351 max_reflist0_count = feienc->num_ref_frames;
1352 }
1353 max_reflist0_count = max_reflist0_count > 5 ? 5 : max_reflist0_count;
1354
1355 for (i = 0; i < feienc->num_views; i++) {
1356 GstVaapiH264ViewRefPool *const ref_pool = &feienc->ref_pools[i];
1357 GstVaapiH264ViewReorderPool *const reorder_pool = &feienc->reorder_pools[i];
1358
1359 ref_pool->max_reflist0_count = max_reflist0_count;
1360 ref_pool->max_reflist1_count = feienc->num_bframes > 0;
1361 ref_pool->max_ref_frames = ref_pool->max_reflist0_count
1362 + ref_pool->max_reflist1_count;
1363
1364 reorder_pool->frame_index = 0;
1365 }
1366
1367 }
1368
1369 /* only for vaapi encoder framework checking */
1370 static GstVaapiEncoderStatus
gst_vaapi_feienc_h264_fake_encode(GstVaapiEncoder * base_encoder,GstVaapiEncPicture * picture,GstVaapiCodedBufferProxy * codedbuf)1371 gst_vaapi_feienc_h264_fake_encode (GstVaapiEncoder * base_encoder,
1372 GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
1373 {
1374 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1375 }
1376
1377 GstVaapiEncoderStatus
gst_vaapi_feienc_h264_encode(GstVaapiEncoder * base_encoder,GstVaapiEncPicture * picture,GstVaapiSurfaceProxy * reconstruct,GstVaapiCodedBufferProxy * codedbuf_proxy,GstVaapiFeiInfoToPakH264 * info_to_pak)1378 gst_vaapi_feienc_h264_encode (GstVaapiEncoder * base_encoder,
1379 GstVaapiEncPicture * picture, GstVaapiSurfaceProxy * reconstruct,
1380 GstVaapiCodedBufferProxy * codedbuf_proxy,
1381 GstVaapiFeiInfoToPakH264 * info_to_pak)
1382 {
1383 GstVaapiFeiEncH264 *const feienc = GST_VAAPI_FEI_H264_ENC_CAST (base_encoder);
1384 GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
1385
1386 if (!reconstruct || !codedbuf_proxy)
1387 return ret;
1388
1389 if (!ensure_sequence (feienc, picture, info_to_pak))
1390 goto error;
1391 if (!ensure_misc_params (feienc, picture))
1392 goto error;
1393 if (!ensure_fei_misc_params (feienc, picture, codedbuf_proxy))
1394 goto error;
1395 if (!ensure_picture (feienc, picture, reconstruct, codedbuf_proxy,
1396 info_to_pak))
1397 goto error;
1398 if (!ensure_slices (feienc, picture, info_to_pak))
1399 goto error;
1400 if (!gst_vaapi_enc_picture_encode (picture))
1401 goto error;
1402
1403 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1404
1405 error:
1406 g_slice_free (GstVaapiFeiInfoToPakH264, info_to_pak);
1407 return ret;
1408 }
1409
1410 GstVaapiEncoderStatus
gst_vaapi_feienc_h264_flush(GstVaapiEncoder * base_encoder)1411 gst_vaapi_feienc_h264_flush (GstVaapiEncoder * base_encoder)
1412 {
1413 GstVaapiFeiEncH264 *const feienc = GST_VAAPI_FEI_H264_ENC_CAST (base_encoder);
1414 GstVaapiH264ViewReorderPool *reorder_pool;
1415 GstVaapiEncPicture *pic;
1416 guint i;
1417
1418 for (i = 0; i < feienc->num_views; i++) {
1419 reorder_pool = &feienc->reorder_pools[i];
1420 reorder_pool->frame_index = 0;
1421 reorder_pool->cur_frame_num = 0;
1422 reorder_pool->cur_present_index = 0;
1423
1424 while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
1425 pic = (GstVaapiEncPicture *)
1426 g_queue_pop_head (&reorder_pool->reorder_frame_list);
1427 gst_vaapi_enc_picture_unref (pic);
1428 }
1429 g_queue_clear (&reorder_pool->reorder_frame_list);
1430 }
1431
1432 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1433 }
1434
1435 /* Generate "codec-data" buffer */
1436 static GstVaapiEncoderStatus
gst_vaapi_feienc_h264_get_codec_data(GstVaapiEncoder * base_encoder,GstBuffer ** out_buffer_ptr)1437 gst_vaapi_feienc_h264_get_codec_data (GstVaapiEncoder * base_encoder,
1438 GstBuffer ** out_buffer_ptr)
1439 {
1440 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1441 }
1442
1443 GstVaapiEncoderStatus
gst_vaapi_feienc_h264_reordering(GstVaapiEncoder * base_encoder,GstVideoCodecFrame * frame,GstVaapiEncPicture ** output)1444 gst_vaapi_feienc_h264_reordering (GstVaapiEncoder * base_encoder,
1445 GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
1446 {
1447 GstVaapiFeiEncH264 *const feienc = GST_VAAPI_FEI_H264_ENC_CAST (base_encoder);
1448 GstVaapiH264ViewReorderPool *reorder_pool = NULL;
1449 GstVaapiEncPicture *picture;
1450 gboolean is_idr = FALSE;
1451
1452 *output = NULL;
1453
1454 /* encoding views alternatively for MVC */
1455 if (feienc->is_mvc) {
1456 /* FIXME: Use first-in-bundle flag on buffers to reset view idx? */
1457 if (frame)
1458 feienc->view_idx = frame->system_frame_number % feienc->num_views;
1459 else
1460 feienc->view_idx = (feienc->view_idx + 1) % feienc->num_views;
1461 }
1462 reorder_pool = &feienc->reorder_pools[feienc->view_idx];
1463
1464 if (!frame) {
1465 if (reorder_pool->reorder_state != GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES)
1466 return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
1467
1468 /* reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES
1469 dump B frames from queue, sometime, there may also have P frame or I frame */
1470 g_assert (feienc->num_bframes > 0);
1471 g_return_val_if_fail (!g_queue_is_empty (&reorder_pool->reorder_frame_list),
1472 GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN);
1473 picture = g_queue_pop_head (&reorder_pool->reorder_frame_list);
1474 g_assert (picture);
1475 if (g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
1476 reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES;
1477 }
1478 goto end;
1479 }
1480
1481 /* new frame coming */
1482 picture = GST_VAAPI_ENC_PICTURE_NEW (H264, feienc, frame);
1483 if (!picture) {
1484 GST_WARNING ("create H264 picture failed, frame timestamp:%"
1485 GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
1486 return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
1487 }
1488 ++reorder_pool->cur_present_index;
1489 picture->poc = ((reorder_pool->cur_present_index * 2) %
1490 feienc->max_pic_order_cnt);
1491
1492 is_idr = (reorder_pool->frame_index == 0 ||
1493 reorder_pool->frame_index >= feienc->idr_period);
1494
1495 /* check key frames */
1496 if (is_idr || GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame) ||
1497 (reorder_pool->frame_index %
1498 GST_VAAPI_ENCODER_KEYFRAME_PERIOD (feienc)) == 0) {
1499 ++reorder_pool->cur_frame_num;
1500 ++reorder_pool->frame_index;
1501
1502 /* b frame enabled, check queue of reorder_frame_list */
1503 if (feienc->num_bframes
1504 && !g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
1505 GstVaapiEncPicture *p_pic;
1506
1507 p_pic = g_queue_pop_tail (&reorder_pool->reorder_frame_list);
1508 set_p_frame (p_pic, feienc);
1509 g_queue_foreach (&reorder_pool->reorder_frame_list,
1510 (GFunc) set_b_frame, feienc);
1511 ++reorder_pool->cur_frame_num;
1512 set_key_frame (picture, feienc, is_idr);
1513 g_queue_push_tail (&reorder_pool->reorder_frame_list, picture);
1514 picture = p_pic;
1515 reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES;
1516 } else { /* no b frames in queue */
1517 set_key_frame (picture, feienc, is_idr);
1518 g_assert (g_queue_is_empty (&reorder_pool->reorder_frame_list));
1519 if (feienc->num_bframes)
1520 reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES;
1521 }
1522 goto end;
1523 }
1524
1525 /* new p/b frames coming */
1526 ++reorder_pool->frame_index;
1527 if (reorder_pool->reorder_state == GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES &&
1528 g_queue_get_length (&reorder_pool->reorder_frame_list) <
1529 feienc->num_bframes) {
1530 g_queue_push_tail (&reorder_pool->reorder_frame_list, picture);
1531 return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
1532 }
1533
1534 ++reorder_pool->cur_frame_num;
1535 set_p_frame (picture, feienc);
1536
1537 if (reorder_pool->reorder_state == GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES) {
1538 g_queue_foreach (&reorder_pool->reorder_frame_list, (GFunc) set_b_frame,
1539 feienc);
1540 reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES;
1541 g_assert (!g_queue_is_empty (&reorder_pool->reorder_frame_list));
1542 }
1543
1544 end:
1545 g_assert (picture);
1546 frame = picture->frame;
1547 if (GST_CLOCK_TIME_IS_VALID (frame->pts))
1548 frame->pts += feienc->cts_offset;
1549 *output = picture;
1550
1551 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1552 }
1553
1554 static GstVaapiEncoderStatus
set_context_info(GstVaapiEncoder * base_encoder)1555 set_context_info (GstVaapiEncoder * base_encoder)
1556 {
1557 GstVaapiFeiEncH264 *const feienc = GST_VAAPI_FEI_H264_ENC_CAST (base_encoder);
1558 GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (feienc);
1559 const guint DEFAULT_SURFACES_COUNT = 3;
1560
1561 /* Maximum sizes for common headers (in bits) */
1562 enum
1563 {
1564 MAX_SPS_HDR_SIZE = 16473,
1565 MAX_VUI_PARAMS_SIZE = 210,
1566 MAX_HRD_PARAMS_SIZE = 4103,
1567 MAX_PPS_HDR_SIZE = 101,
1568 MAX_SLICE_HDR_SIZE = 397 + 2572 + 6670 + 2402,
1569 };
1570
1571 if (!ensure_hw_profile (feienc))
1572 return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
1573
1574 base_encoder->num_ref_frames =
1575 (feienc->num_ref_frames + DEFAULT_SURFACES_COUNT) * feienc->num_views;
1576
1577 /* Only YUV 4:2:0 formats are supported for now. This means that we
1578 have a limit of 3200 bits per macroblock. */
1579 /* XXX: check profile and compute RawMbBits */
1580 base_encoder->codedbuf_size = (GST_ROUND_UP_16 (vip->width) *
1581 GST_ROUND_UP_16 (vip->height) / 256) * 400;
1582
1583 /* Account for SPS header */
1584 /* XXX: exclude scaling lists, MVC/SVC extensions */
1585 base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE +
1586 MAX_VUI_PARAMS_SIZE + 2 * MAX_HRD_PARAMS_SIZE) / 8;
1587
1588 /* Account for PPS header */
1589 /* XXX: exclude slice groups, scaling lists, MVC/SVC extensions */
1590 base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8;
1591
1592 /* Account for slice header */
1593 base_encoder->codedbuf_size += feienc->num_slices * (4 +
1594 GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE) / 8);
1595
1596 base_encoder->context_info.entrypoint = feienc->entrypoint;
1597
1598 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1599 }
1600
1601 GstVaapiEncoderStatus
gst_vaapi_feienc_h264_reconfigure(GstVaapiEncoder * base_encoder)1602 gst_vaapi_feienc_h264_reconfigure (GstVaapiEncoder * base_encoder)
1603 {
1604 GstVaapiFeiEncH264 *const feienc = GST_VAAPI_FEI_H264_ENC_CAST (base_encoder);
1605 GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (feienc);
1606 GstVaapiEncoderStatus status;
1607 guint mb_width, mb_height;
1608
1609 mb_width = (GST_VAAPI_ENCODER_WIDTH (feienc) + 15) / 16;
1610 mb_height = (GST_VAAPI_ENCODER_HEIGHT (feienc) + 15) / 16;
1611 if (mb_width != feienc->mb_width || mb_height != feienc->mb_height) {
1612 GST_DEBUG ("resolution: %dx%d", GST_VAAPI_ENCODER_WIDTH (feienc),
1613 GST_VAAPI_ENCODER_HEIGHT (feienc));
1614 feienc->mb_width = mb_width;
1615 feienc->mb_height = mb_height;
1616 feienc->config_changed = TRUE;
1617 }
1618
1619 /* Take number of MVC views from input caps if provided */
1620 if (GST_VIDEO_INFO_MULTIVIEW_MODE (vip) ==
1621 GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME
1622 || GST_VIDEO_INFO_MULTIVIEW_MODE (vip) ==
1623 GST_VIDEO_MULTIVIEW_MODE_MULTIVIEW_FRAME_BY_FRAME)
1624 feienc->num_views = GST_VIDEO_INFO_VIEWS (vip);
1625
1626 feienc->is_mvc = feienc->num_views > 1;
1627
1628 status = ensure_profile_and_level (feienc);
1629 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
1630 return status;
1631
1632 reset_properties (feienc);
1633 status = set_context_info (base_encoder);
1634 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
1635 return status;
1636
1637 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1638 }
1639
1640 static gboolean
gst_vaapi_feienc_h264_init(GstVaapiEncoder * base_encoder)1641 gst_vaapi_feienc_h264_init (GstVaapiEncoder * base_encoder)
1642 {
1643 GstVaapiFeiEncH264 *const feienc = GST_VAAPI_FEI_H264_ENC_CAST (base_encoder);
1644 guint32 i;
1645
1646 /* Default encoding entrypoint */
1647 feienc->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
1648 feienc->search_path = GST_VAAPI_FEI_H264_SEARCH_PATH_DEFAULT;
1649 feienc->len_sp = GST_VAAPI_FEI_H264_SEARCH_PATH_LENGTH_DEFAULT;
1650 feienc->ref_width = GST_VAAPI_FEI_H264_REF_WIDTH_DEFAULT;
1651 feienc->ref_height = GST_VAAPI_FEI_H264_REF_HEIGHT_DEFAULT;
1652 feienc->intra_part_mask = GST_VAAPI_FEI_H264_INTRA_PART_MASK_DEFAULT;
1653 feienc->submb_part_mask = GST_VAAPI_FEI_H264_SUB_MB_PART_MASK_DEFAULT;
1654
1655 /* Multi-view coding information */
1656 feienc->is_mvc = FALSE;
1657 feienc->num_views = 1;
1658 feienc->view_idx = 0;
1659
1660 /* default num ref frames */
1661 feienc->num_ref_frames = 1;
1662 memset (feienc->view_ids, 0, sizeof (feienc->view_ids));
1663
1664 feienc->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_FEI;
1665
1666 /* re-ordering list initialize */
1667 for (i = 0; i < MAX_NUM_VIEWS; i++) {
1668 GstVaapiH264ViewReorderPool *const reorder_pool = &feienc->reorder_pools[i];
1669 g_queue_init (&reorder_pool->reorder_frame_list);
1670 reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_NONE;
1671 reorder_pool->frame_index = 0;
1672 reorder_pool->cur_frame_num = 0;
1673 reorder_pool->cur_present_index = 0;
1674 }
1675
1676 return TRUE;
1677 }
1678
1679 static void
gst_vaapi_feienc_h264_finalize(GstVaapiEncoder * base_encoder)1680 gst_vaapi_feienc_h264_finalize (GstVaapiEncoder * base_encoder)
1681 {
1682 /*free private buffers */
1683 GstVaapiFeiEncH264 *const feienc = GST_VAAPI_FEI_H264_ENC_CAST (base_encoder);
1684 GstVaapiEncPicture *pic;
1685 guint32 i;
1686
1687 gst_buffer_replace (&feienc->sps_data, NULL);
1688 gst_buffer_replace (&feienc->subset_sps_data, NULL);
1689 gst_buffer_replace (&feienc->pps_data, NULL);
1690
1691 /* re-ordering list initialize */
1692 for (i = 0; i < MAX_NUM_VIEWS; i++) {
1693 GstVaapiH264ViewReorderPool *const reorder_pool = &feienc->reorder_pools[i];
1694 while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
1695 pic = (GstVaapiEncPicture *)
1696 g_queue_pop_head (&reorder_pool->reorder_frame_list);
1697 gst_vaapi_enc_picture_unref (pic);
1698 }
1699 g_queue_clear (&reorder_pool->reorder_frame_list);
1700 }
1701 }
1702
1703 static void
set_view_ids(GstVaapiFeiEncH264 * const encoder,const GValue * value)1704 set_view_ids (GstVaapiFeiEncH264 * const encoder, const GValue * value)
1705 {
1706 guint i, j;
1707 guint len = gst_value_array_get_size (value);
1708
1709 if (len == 0)
1710 goto set_default_ids;
1711
1712 if (len != encoder->num_views) {
1713 GST_WARNING ("The view number is %d, but %d view IDs are provided. Just "
1714 "fallback to use default view IDs.", encoder->num_views, len);
1715 goto set_default_ids;
1716 }
1717
1718 for (i = 0; i < len; i++) {
1719 const GValue *val = gst_value_array_get_value (value, i);
1720 encoder->view_ids[i] = g_value_get_uint (val);
1721 }
1722
1723 /* check whether duplicated ID */
1724 for (i = 0; i < len; i++) {
1725 for (j = i + 1; j < len; j++) {
1726 if (encoder->view_ids[i] == encoder->view_ids[j]) {
1727 GST_WARNING ("The view %d and view %d have same view ID %d. Just "
1728 "fallback to use default view IDs.", i, j, encoder->view_ids[i]);
1729 goto set_default_ids;
1730 }
1731 }
1732 }
1733
1734 return;
1735
1736 set_default_ids:
1737 {
1738 for (i = 0; i < encoder->num_views; i++)
1739 encoder->view_ids[i] = i;
1740 }
1741 }
1742
1743 GstVaapiEncoderStatus
gst_vaapi_feienc_h264_set_property(GstVaapiEncoder * base_encoder,gint prop_id,const GValue * value)1744 gst_vaapi_feienc_h264_set_property (GstVaapiEncoder * base_encoder,
1745 gint prop_id, const GValue * value)
1746 {
1747 GstVaapiFeiEncH264 *const feienc = GST_VAAPI_FEI_H264_ENC_CAST (base_encoder);
1748
1749 switch (prop_id) {
1750 case GST_VAAPI_FEI_H264_ENC_PROP_MAX_BFRAMES:
1751 feienc->num_bframes = g_value_get_uint (value);
1752 break;
1753 case GST_VAAPI_FEI_H264_ENC_PROP_INIT_QP:
1754 feienc->init_qp = g_value_get_uint (value);
1755 break;
1756 case GST_VAAPI_FEI_H264_ENC_PROP_MIN_QP:
1757 feienc->min_qp = g_value_get_uint (value);
1758 break;
1759 case GST_VAAPI_FEI_H264_ENC_PROP_NUM_SLICES:
1760 feienc->num_slices = g_value_get_uint (value);
1761 break;
1762 case GST_VAAPI_FEI_H264_ENC_PROP_CABAC:
1763 feienc->use_cabac = g_value_get_boolean (value);
1764 break;
1765 case GST_VAAPI_FEI_H264_ENC_PROP_DCT8X8:
1766 feienc->use_dct8x8 = g_value_get_boolean (value);
1767 break;
1768 case GST_VAAPI_FEI_H264_ENC_PROP_CPB_LENGTH:
1769 feienc->cpb_length = g_value_get_uint (value);
1770 break;
1771 case GST_VAAPI_FEI_H264_ENC_PROP_NUM_VIEWS:
1772 feienc->num_views = g_value_get_uint (value);
1773 break;
1774 case GST_VAAPI_FEI_H264_ENC_PROP_VIEW_IDS:
1775 set_view_ids (feienc, value);
1776 break;
1777 case GST_VAAPI_FEI_H264_ENC_PROP_NUM_REF:
1778 feienc->num_ref_frames = g_value_get_uint (value);
1779 break;
1780 case GST_VAAPI_FEI_H264_ENC_PROP_NUM_MV_PREDICT_L0:
1781 feienc->num_mv_predictors_l0 = g_value_get_uint (value);
1782 break;
1783 case GST_VAAPI_FEI_H264_ENC_PROP_NUM_MV_PREDICT_L1:
1784 feienc->num_mv_predictors_l1 = g_value_get_uint (value);
1785 break;
1786 case GST_VAAPI_FEI_H264_ENC_PROP_SEARCH_WINDOW:
1787 feienc->search_window = g_value_get_enum (value);
1788 break;
1789 case GST_VAAPI_FEI_H264_ENC_PROP_LEN_SP:
1790 feienc->len_sp = g_value_get_uint (value);
1791 break;
1792 case GST_VAAPI_FEI_H264_ENC_PROP_SEARCH_PATH:
1793 feienc->search_path = g_value_get_enum (value);
1794 break;
1795 case GST_VAAPI_FEI_H264_ENC_PROP_REF_WIDTH:
1796 feienc->ref_width = g_value_get_uint (value);
1797 break;
1798 case GST_VAAPI_FEI_H264_ENC_PROP_REF_HEIGHT:
1799 feienc->ref_height = g_value_get_uint (value);
1800 break;
1801 case GST_VAAPI_FEI_H264_ENC_PROP_SUBMB_MASK:
1802 feienc->submb_part_mask = g_value_get_flags (value);
1803 break;
1804 case GST_VAAPI_FEI_H264_ENC_PROP_SUBPEL_MODE:
1805 feienc->subpel_mode = g_value_get_enum (value);
1806 break;
1807 case GST_VAAPI_FEI_H264_ENC_PROP_INTRA_PART_MASK:
1808 feienc->intra_part_mask = g_value_get_flags (value);
1809 break;
1810 case GST_VAAPI_FEI_H264_ENC_PROP_INTRA_SAD:
1811 feienc->intra_sad = g_value_get_enum (value);
1812 break;
1813 case GST_VAAPI_FEI_H264_ENC_PROP_INTER_SAD:
1814 feienc->inter_sad = g_value_get_enum (value);
1815 break;
1816 case GST_VAAPI_FEI_H264_ENC_PROP_ADAPT_SEARCH:
1817 feienc->adaptive_search = g_value_get_boolean (value) ? 1 : 0;
1818 break;
1819 case GST_VAAPI_FEI_H264_ENC_PROP_MULTI_PRED_L0:
1820 feienc->multi_predL0 = g_value_get_boolean (value) ? 1 : 0;
1821 break;
1822 case GST_VAAPI_FEI_H264_ENC_PROP_MULTI_PRED_L1:
1823 feienc->multi_predL1 = g_value_get_boolean (value) ? 1 : 0;
1824 break;
1825 default:
1826 return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
1827 }
1828 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
1829 }
1830
1831 static const GstVaapiEncoderClassData fei_enc_class_data = {
1832 .codec = GST_VAAPI_CODEC_H264,
1833 .packed_headers = SUPPORTED_PACKED_HEADERS,
1834 .rate_control_get_type = gst_vaapi_rate_control_get_type,
1835 .default_rate_control = DEFAULT_RATECONTROL,
1836 .rate_control_mask = SUPPORTED_RATECONTROLS,
1837 .encoder_tune_get_type = gst_vaapi_encoder_tune_get_type,
1838 .default_encoder_tune = GST_VAAPI_ENCODER_TUNE_NONE,
1839 .encoder_tune_mask = SUPPORTED_TUNE_OPTIONS,
1840 };
1841
1842 static inline const GstVaapiEncoderClass *
gst_vaapi_feienc_h264_class(void)1843 gst_vaapi_feienc_h264_class (void)
1844 {
1845 static const GstVaapiEncoderClass GstVaapiFeiEncH264Class = {
1846 .parent_class = {
1847 .size = sizeof (GstVaapiFeiEncH264),
1848 .finalize = (GDestroyNotify) gst_vaapi_encoder_finalize,
1849 }
1850 ,
1851 .class_data = &fei_enc_class_data,
1852 .init = gst_vaapi_feienc_h264_init,
1853 .finalize = gst_vaapi_feienc_h264_finalize,
1854 .reconfigure = gst_vaapi_feienc_h264_reconfigure,
1855 .get_default_properties = gst_vaapi_feienc_h264_get_default_properties,
1856 .reordering = gst_vaapi_feienc_h264_reordering,
1857 .encode = gst_vaapi_feienc_h264_fake_encode,
1858 .flush = gst_vaapi_feienc_h264_flush,
1859 .set_property = gst_vaapi_feienc_h264_set_property,
1860 .get_codec_data = gst_vaapi_feienc_h264_get_codec_data,
1861 };
1862 return &GstVaapiFeiEncH264Class;
1863 }
1864
1865 /**
1866 * gst_vaapi_feienc_h264_new:
1867 * @display: a #GstVaapiDisplay
1868 *
1869 * Creates a new #GstVaapiEncoder for H.264 encoding. Note that the
1870 * only supported output stream format is "byte-stream" format.
1871 *
1872 * Return value: the newly allocated #GstVaapiEncoder object
1873 */
1874 GstVaapiEncoder *
gst_vaapi_feienc_h264_new(GstVaapiDisplay * display)1875 gst_vaapi_feienc_h264_new (GstVaapiDisplay * display)
1876 {
1877 return gst_vaapi_encoder_new (gst_vaapi_feienc_h264_class (), display);
1878 }
1879
1880 /**
1881 * gst_vaapi_feienc_h264_get_fei_properties:
1882 *
1883 * Determines the set of common and H.264 Fei specific feienc properties.
1884 * The caller owns an extra reference to the resulting array of
1885 * #GstVaapiEncoderPropInfo elements, so it shall be released with
1886 * g_ptr_array_unref() after usage.
1887 *
1888 * Return value: the set of feienc properties for #GstVaapiFeiEncH264,
1889 * or %NULL if an error occurred.
1890 */
1891 static GPtrArray *
gst_vaapi_feienc_h264_get_fei_properties(GPtrArray * props)1892 gst_vaapi_feienc_h264_get_fei_properties (GPtrArray * props)
1893 {
1894 /**
1895 * GstVaapiFeiEncH264:num_mv_predictors_l0:
1896 *
1897 * The number of mv predict
1898 */
1899 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
1900 GST_VAAPI_FEI_H264_ENC_PROP_NUM_MV_PREDICT_L0,
1901 g_param_spec_uint ("num-mvpredict-l0",
1902 "Num mv predict l0",
1903 "Indicate how many predictors should be used for l0",
1904 0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1905 /**
1906 * GstVaapiFeiEncH264:num_mv_predictors_l1:
1907 *
1908 * The number of mv predict
1909 */
1910 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
1911 GST_VAAPI_FEI_H264_ENC_PROP_NUM_MV_PREDICT_L1,
1912 g_param_spec_uint ("num-mvpredict-l1",
1913 "Num mv predict l1",
1914 "Indicate how many predictors should be used for l1",
1915 0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1916 /**
1917 * GstVaapiFeiEncH264:search-window:
1918 */
1919 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
1920 GST_VAAPI_FEI_H264_ENC_PROP_SEARCH_WINDOW,
1921 g_param_spec_enum ("search-window",
1922 "search window",
1923 "Specify one of the predefined search path",
1924 GST_VAAPI_TYPE_FEI_H264_SEARCH_WINDOW,
1925 GST_VAAPI_FEI_H264_SEARCH_WINDOW_DEFAULT,
1926 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1927 /**
1928 * GstVaapiFeiEncH264:len-sp:
1929 */
1930 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
1931 GST_VAAPI_FEI_H264_ENC_PROP_LEN_SP,
1932 g_param_spec_uint ("len-sp",
1933 "len sp",
1934 "This value defines number of search units in search path",
1935 1, 63, 32, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1936
1937 /**
1938 * GstVaapiFeiEncH264:search-path:
1939 */
1940 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
1941 GST_VAAPI_FEI_H264_ENC_PROP_SEARCH_PATH,
1942 g_param_spec_enum ("search-path",
1943 "search path",
1944 "Specify search path",
1945 GST_VAAPI_TYPE_FEI_H264_SEARCH_PATH,
1946 GST_VAAPI_FEI_H264_SEARCH_PATH_DEFAULT,
1947 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1948
1949 /**
1950 * GstVaapiFeiEncH264:ref-width:
1951 */
1952 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
1953 GST_VAAPI_FEI_H264_ENC_PROP_REF_WIDTH,
1954 g_param_spec_uint ("ref-width",
1955 "ref width",
1956 "Width of search region in pixel, must be multiple of 4",
1957 4, 64, 32, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1958
1959 /**
1960 * GstVaapiFeiEncH264:ref-height:
1961 */
1962 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
1963 GST_VAAPI_FEI_H264_ENC_PROP_REF_HEIGHT,
1964 g_param_spec_uint ("ref-height",
1965 "ref height",
1966 "Height of search region in pixel, must be multiple of 4",
1967 4, 32, 32, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1968 /**
1969 * GstVaapiFeiEncH264:submb-mask:
1970 * Defines the bit-mask for disabling sub-partition
1971 *
1972 */
1973 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
1974 GST_VAAPI_FEI_H264_ENC_PROP_SUBMB_MASK,
1975 g_param_spec_flags ("submbpart-mask",
1976 "submb part mask",
1977 "defines the bit-mask for disabling sub mb partition",
1978 GST_VAAPI_TYPE_FEI_H264_SUB_MB_PART_MASK,
1979 GST_VAAPI_FEI_H264_SUB_MB_PART_MASK_DEFAULT,
1980 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1981
1982 /**
1983 * GstVaapiFeiEncH264:subpel-mode:
1984 */
1985 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
1986 GST_VAAPI_FEI_H264_ENC_PROP_SUBPEL_MODE,
1987 g_param_spec_enum ("subpel-mode",
1988 "subpel mode",
1989 "Sub pixel precision for motion estimation",
1990 GST_VAAPI_TYPE_FEI_H264_SUB_PEL_MODE,
1991 GST_VAAPI_FEI_H264_SUB_PEL_MODE_DEFAULT,
1992 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1993 /**
1994 * GstVaapiFeiEncH264:intrapart-mask:
1995 */
1996 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
1997 GST_VAAPI_FEI_H264_ENC_PROP_INTRA_PART_MASK,
1998 g_param_spec_flags ("intrapart-mask",
1999 "intra part mask",
2000 "What block and sub-block partitions are disabled for intra MBs",
2001 GST_VAAPI_TYPE_FEI_H264_INTRA_PART_MASK,
2002 GST_VAAPI_FEI_H264_INTRA_PART_MASK_DEFAULT,
2003 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2004 /**
2005 * GstVaapiFeiEncH264:intra-sad:
2006 */
2007 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2008 GST_VAAPI_FEI_H264_ENC_PROP_INTRA_SAD,
2009 g_param_spec_enum ("intra-sad",
2010 "intra sad",
2011 "Specifies distortion measure adjustments used in the motion search SAD comparison for intra MB",
2012 GST_VAAPI_TYPE_FEI_H264_SAD_MODE, GST_VAAPI_FEI_H264_SAD_MODE_DEFAULT,
2013 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2014
2015 /**
2016 * GstVaapiFeiEncH264:inter-sad:
2017 */
2018 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2019 GST_VAAPI_FEI_H264_ENC_PROP_INTER_SAD,
2020 g_param_spec_enum ("inter-sad",
2021 "inter sad",
2022 "Specifies distortion measure adjustments used in the motion search SAD comparison for inter MB",
2023 GST_VAAPI_TYPE_FEI_H264_SAD_MODE, GST_VAAPI_FEI_H264_SAD_MODE_DEFAULT,
2024 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2025
2026 /**
2027 * GstVaapiFeiEncH264:adaptive-search:
2028 */
2029 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2030 GST_VAAPI_FEI_H264_ENC_PROP_ADAPT_SEARCH,
2031 g_param_spec_boolean ("adaptive-search",
2032 "adaptive-search",
2033 "Enable adaptive search",
2034 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2035
2036 /**
2037 * GstVaapiFeiEncH264:multi-predL0:
2038 */
2039 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2040 GST_VAAPI_FEI_H264_ENC_PROP_MULTI_PRED_L0,
2041 g_param_spec_boolean ("multi-predL0",
2042 "multi predL0",
2043 "Enable multi prediction for ref L0 list",
2044 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2045
2046 /**
2047 * GstVaapiFeiEncH264:multi-predL0:
2048 */
2049 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2050 GST_VAAPI_FEI_H264_ENC_PROP_MULTI_PRED_L1,
2051 g_param_spec_boolean ("multi-predL1",
2052 "multi predL1",
2053 "Enable multi prediction for ref L1 list",
2054 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2055
2056 return props;
2057
2058 }
2059
2060 /**
2061 * gst_vaapi_feienc_h264_get_default_properties:
2062 *
2063 * Determines the set of common and H.264 specific feienc properties.
2064 * The caller owns an extra reference to the resulting array of
2065 * #GstVaapiEncoderPropInfo elements, so it shall be released with
2066 * g_ptr_array_unref() after usage.
2067 *
2068 * Return value: the set of feienc properties for #GstVaapiFeiEncH264,
2069 * or %NULL if an error occurred.
2070 */
2071 GPtrArray *
gst_vaapi_feienc_h264_get_default_properties(void)2072 gst_vaapi_feienc_h264_get_default_properties (void)
2073 {
2074 const GstVaapiEncoderClass *const klass = gst_vaapi_feienc_h264_class ();
2075 GPtrArray *props;
2076
2077 props = gst_vaapi_encoder_properties_get_default (klass);
2078
2079 if (!props)
2080 return NULL;
2081
2082 /**
2083 * GstVaapiFeiEncH264:max-bframes:
2084 *
2085 * The number of B-frames between I and P.
2086 */
2087 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2088 GST_VAAPI_FEI_H264_ENC_PROP_MAX_BFRAMES,
2089 g_param_spec_uint ("max-bframes",
2090 "Max B-Frames", "Number of B-frames between I and P", 0, 10, 0,
2091 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2092
2093 /**
2094 * GstVaapiFeiEncH264:init-qp:
2095 *
2096 * The initial quantizer value.
2097 */
2098 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2099 GST_VAAPI_FEI_H264_ENC_PROP_INIT_QP,
2100 g_param_spec_uint ("init-qp",
2101 "Initial QP", "Initial quantizer value", 1, 51, 26,
2102 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2103
2104 /**
2105 * GstVaapiFeiEncH264:min-qp:
2106 *
2107 * The minimum quantizer value.
2108 */
2109 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2110 GST_VAAPI_FEI_H264_ENC_PROP_MIN_QP,
2111 g_param_spec_uint ("min-qp",
2112 "Minimum QP", "Minimum quantizer value", 1, 51, 1,
2113 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2114
2115 /**
2116 * GstVaapiFeiEncH264:num-slices:
2117 *
2118 * The number of slices per frame.
2119 */
2120 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2121 GST_VAAPI_FEI_H264_ENC_PROP_NUM_SLICES,
2122 g_param_spec_uint ("num-slices",
2123 "Number of Slices",
2124 "Number of slices per frame",
2125 1, 200, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2126
2127 /**
2128 * GstVaapiFeiEncH264:cabac:
2129 *
2130 * Enable CABAC entropy coding mode for improved compression ratio,
2131 * at the expense that the minimum target profile is Main. Default
2132 * is CAVLC entropy coding mode.
2133 */
2134 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2135 GST_VAAPI_FEI_H264_ENC_PROP_CABAC,
2136 g_param_spec_boolean ("cabac",
2137 "Enable CABAC",
2138 "Enable CABAC entropy coding mode",
2139 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2140
2141 /**
2142 * GstVaapiFeiEncH264:dct8x8:
2143 *
2144 * Enable adaptive use of 8x8 transforms in I-frames. This improves
2145 * the compression ratio by the minimum target profile is High.
2146 * Default is to use 4x4 DCT only.
2147 */
2148 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2149 GST_VAAPI_FEI_H264_ENC_PROP_DCT8X8,
2150 g_param_spec_boolean ("dct8x8",
2151 "Enable 8x8 DCT",
2152 "Enable adaptive use of 8x8 transforms in I-frames",
2153 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2154
2155 /**
2156 * GstVaapiFeiEncH264:cpb-length:
2157 *
2158 * The size of the CPB buffer in milliseconds.
2159 */
2160 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2161 GST_VAAPI_FEI_H264_ENC_PROP_CPB_LENGTH,
2162 g_param_spec_uint ("cpb-length",
2163 "CPB Length", "Length of the CPB buffer in milliseconds",
2164 1, 10000, DEFAULT_CPB_LENGTH,
2165 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2166
2167 /**
2168 * GstVaapiFeiEncH264:num-views:
2169 *
2170 * The number of views for MVC encoding .
2171 */
2172 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2173 GST_VAAPI_FEI_H264_ENC_PROP_NUM_VIEWS,
2174 g_param_spec_uint ("num-views",
2175 "Number of Views",
2176 "Number of Views for MVC encoding",
2177 1, MAX_NUM_VIEWS, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2178 /**
2179 * GstVaapiFeiEncH264:view-ids:
2180 *
2181 * The view ids for MVC encoding .
2182 */
2183 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2184 GST_VAAPI_FEI_H264_ENC_PROP_VIEW_IDS,
2185 gst_param_spec_array ("view-ids",
2186 "View IDs", "Set of View Ids used for MVC encoding",
2187 g_param_spec_uint ("view-id-value", "View id value",
2188 "view id values used for mvc encoding", 0, MAX_VIEW_ID, 0,
2189 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
2190 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2191 /**
2192 * GstVaapiFeiEncH264:num-ref:
2193 *
2194 * The number of reference frames.
2195 */
2196 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
2197 GST_VAAPI_FEI_H264_ENC_PROP_NUM_REF,
2198 g_param_spec_uint ("num-ref",
2199 "Num Ref",
2200 "reference frame number",
2201 1, 6, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2202
2203 props = gst_vaapi_feienc_h264_get_fei_properties (props);
2204
2205 return props;
2206 }
2207
2208 /**
2209 * gst_vaapi_feienc_h264_set_max_profile:
2210 * @feienc: a #GstVaapiFeiEncH264
2211 * @profile: an H.264 #GstVaapiProfile
2212 *
2213 * Notifies the @feienc to use coding tools from the supplied
2214 * @profile at most.
2215 *
2216 * This means that if the minimal profile derived to
2217 * support the specified coding tools is greater than this @profile,
2218 * then an error is returned when the @feienc is configured.
2219 *
2220 * Return value: %TRUE on success
2221 */
2222 gboolean
gst_vaapi_feienc_h264_set_max_profile(GstVaapiFeiEncH264 * feienc,GstVaapiProfile profile)2223 gst_vaapi_feienc_h264_set_max_profile (GstVaapiFeiEncH264 * feienc,
2224 GstVaapiProfile profile)
2225 {
2226 guint8 profile_idc;
2227
2228 g_return_val_if_fail (feienc != NULL, FALSE);
2229 g_return_val_if_fail (profile != GST_VAAPI_PROFILE_UNKNOWN, FALSE);
2230
2231 if (gst_vaapi_profile_get_codec (profile) != GST_VAAPI_CODEC_H264)
2232 return FALSE;
2233
2234 profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
2235 if (!profile_idc)
2236 return FALSE;
2237
2238 feienc->max_profile_idc = profile_idc;
2239 return TRUE;
2240 }
2241
2242 gboolean
gst_vaapi_feienc_h264_set_ref_pool(GstVaapiFeiEncH264 * feienc,gpointer ref_pool_ptr)2243 gst_vaapi_feienc_h264_set_ref_pool (GstVaapiFeiEncH264 * feienc,
2244 gpointer ref_pool_ptr)
2245 {
2246 g_return_val_if_fail (feienc != NULL, FALSE);
2247
2248 if (!ref_pool_ptr)
2249 return FALSE;
2250
2251 memcpy (&feienc->ref_pools[0], ref_pool_ptr,
2252 sizeof (GstVaapiH264ViewRefPool) * MAX_NUM_VIEWS);
2253
2254 return TRUE;
2255 }
2256
2257 /**
2258 * gst_vaapi_feienc_h264_get_profile_and_level
2259 * @feienc: a #GstVaapiFeiEncH264
2260 * @out_profile_ptr: return location for the #GstVaapiProfile
2261 * @out_profile_idc_ptr: return location for the #GstVaapiLevelH264
2262 *
2263 * Queries the H.264 @feienc for the active profile and level. That
2264 * information is only constructed and valid after the feienc is
2265 * configured, i.e. after the gst_vaapi_feienc_set_codec_state()
2266 * function is called.
2267 *
2268 * Return value: %TRUE on success
2269 */
2270 gboolean
gst_vaapi_feienc_h264_get_profile_and_idc(GstVaapiFeiEncH264 * feienc,GstVaapiProfile * out_profile_ptr,guint8 * out_profile_idc_ptr)2271 gst_vaapi_feienc_h264_get_profile_and_idc (GstVaapiFeiEncH264 * feienc,
2272 GstVaapiProfile * out_profile_ptr, guint8 * out_profile_idc_ptr)
2273 {
2274 g_return_val_if_fail (feienc != NULL, FALSE);
2275
2276 if (!feienc->profile || !feienc->profile_idc)
2277 return FALSE;
2278
2279 if (out_profile_ptr)
2280 *out_profile_ptr = feienc->profile;
2281 if (out_profile_idc_ptr)
2282 *out_profile_idc_ptr = feienc->profile_idc;
2283 return TRUE;
2284 }
2285