1 /*
2 * gstvaapiencoder_h264_fei.c - H.264 FEI encoder
3 *
4 * Copyright (C) 2016-2017 Intel Corporation
5 * Author: Yi A Wang <yi.a.wang@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 #define GLIB_DISABLE_DEPRECATION_WARNINGS
28
29 #include "sysdeps.h"
30 #include <va/va.h>
31 #include <va/va_enc_h264.h>
32 #include <gst/base/gstbitwriter.h>
33 #include <gst/codecparsers/gsth264parser.h>
34 #include "gstvaapicompat.h"
35 #include "gstvaapiencoder_priv.h"
36 #include "gstvaapiutils_h264_priv.h"
37 #include "gstvaapicodedbufferproxy_priv.h"
38 #include "gstvaapisurfaceproxy_priv.h"
39 #include "gstvaapisurface.h"
40 #include "gstvaapifeiutils_h264.h"
41 #include "gstvaapiencoder_h264_fei.h"
42 #include "gstvaapifeienc_h264.h"
43 #include "gstvaapifeipak_h264.h"
44 #include "gstvaapiutils.h"
45 #include "gstvaapiutils_core.h"
46 #include "gstvaapifei_objects_priv.h"
47 #define DEBUG 1
48 #include "gstvaapidebug.h"
49
50 GPtrArray *gst_vaapi_encoder_h264_fei_get_default_properties (void);
51 static gboolean
52 gst_vaapi_encoder_h264_fei_ensure_secondary_context (GstVaapiEncoder *
53 base_encoder);
54
55 /* Define the maximum number of views supported */
56 #define MAX_NUM_VIEWS 10
57
58 /* Define the maximum value for view-id */
59 #define MAX_VIEW_ID 1023
60
61 /* Default CPB length (in milliseconds) */
62 #define DEFAULT_CPB_LENGTH 1500
63
64 /* Scale factor for CPB size (HRD cpb_size_scale: min = 4) */
65 #define SX_CPB_SIZE 4
66
67 /* Scale factor for bitrate (HRD bit_rate_scale: min = 6) */
68 #define SX_BITRATE 6
69
70 /* Define default rate control mode ("constant-qp") */
71 #define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP
72
73 /* Supported set of VA rate controls, within this implementation */
74 #define SUPPORTED_RATECONTROLS \
75 (GST_VAAPI_RATECONTROL_MASK (CQP) | \
76 GST_VAAPI_RATECONTROL_MASK (CBR) | \
77 GST_VAAPI_RATECONTROL_MASK (VBR) | \
78 GST_VAAPI_RATECONTROL_MASK (VBR_CONSTRAINED))
79
80 /* Supported set of tuning options, within this implementation */
81 #define SUPPORTED_TUNE_OPTIONS \
82 (GST_VAAPI_ENCODER_TUNE_MASK (NONE) | \
83 GST_VAAPI_ENCODER_TUNE_MASK (HIGH_COMPRESSION) | \
84 GST_VAAPI_ENCODER_TUNE_MASK (LOW_POWER))
85
86 /* Supported set of VA packed headers, within this implementation */
87 #define SUPPORTED_PACKED_HEADERS \
88 (VA_ENC_PACKED_HEADER_SEQUENCE | \
89 VA_ENC_PACKED_HEADER_PICTURE | \
90 VA_ENC_PACKED_HEADER_SLICE | \
91 VA_ENC_PACKED_HEADER_RAW_DATA | \
92 VA_ENC_PACKED_HEADER_MISC)
93
94 #define GST_H264_NAL_REF_IDC_NONE 0
95 #define GST_H264_NAL_REF_IDC_LOW 1
96 #define GST_H264_NAL_REF_IDC_MEDIUM 2
97 #define GST_H264_NAL_REF_IDC_HIGH 3
98
99 /* only for internal usage, values won't be equal to actual payload type */
100 typedef enum
101 {
102 GST_VAAPI_H264_SEI_UNKNOWN = 0,
103 GST_VAAPI_H264_SEI_BUF_PERIOD = (1 << 0),
104 GST_VAAPI_H264_SEI_PIC_TIMING = (1 << 1)
105 } GstVaapiH264SeiPayloadType;
106
107 typedef struct
108 {
109 GstVaapiSurfaceProxy *pic;
110 guint poc;
111 guint frame_num;
112 } GstVaapiEncoderH264FeiRef;
113
114 typedef enum
115 {
116 GST_VAAPI_ENC_H264_REORD_NONE = 0,
117 GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES = 1,
118 GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES = 2
119 } GstVaapiEncH264ReorderState;
120
121 typedef struct _GstVaapiH264ViewRefPool
122 {
123 GQueue ref_list;
124 guint max_ref_frames;
125 guint max_reflist0_count;
126 guint max_reflist1_count;
127 } GstVaapiH264ViewRefPool;
128
129 typedef struct _GstVaapiH264ViewReorderPool
130 {
131 GQueue reorder_frame_list;
132 guint reorder_state;
133 guint frame_index;
134 guint frame_count; /* monotonically increasing with in every idr period */
135 guint cur_frame_num;
136 guint cur_present_index;
137 } GstVaapiH264ViewReorderPool;
138
139 static inline gboolean
_poc_greater_than(guint poc1,guint poc2,guint max_poc)140 _poc_greater_than (guint poc1, guint poc2, guint max_poc)
141 {
142 return (((poc1 - poc2) & (max_poc - 1)) < max_poc / 2);
143 }
144
145 /* Get slice_type value for H.264 specification */
146 static guint8
h264_get_slice_type(GstVaapiPictureType type)147 h264_get_slice_type (GstVaapiPictureType type)
148 {
149 switch (type) {
150 case GST_VAAPI_PICTURE_TYPE_I:
151 return GST_H264_I_SLICE;
152 case GST_VAAPI_PICTURE_TYPE_P:
153 return GST_H264_P_SLICE;
154 case GST_VAAPI_PICTURE_TYPE_B:
155 return GST_H264_B_SLICE;
156 default:
157 break;
158 }
159 return -1;
160 }
161
162 /* Get log2_max_frame_num value for H.264 specification */
163 static guint
h264_get_log2_max_frame_num(guint num)164 h264_get_log2_max_frame_num (guint num)
165 {
166 guint ret = 0;
167
168 while (num) {
169 ++ret;
170 num >>= 1;
171 }
172 if (ret <= 4)
173 ret = 4;
174 else if (ret > 10)
175 ret = 10;
176 /* must be greater than 4 */
177 return ret;
178 }
179
180 /* Determines the cpbBrNalFactor based on the supplied profile */
181 static guint
h264_get_cpb_nal_factor(GstVaapiProfile profile)182 h264_get_cpb_nal_factor (GstVaapiProfile profile)
183 {
184 guint f;
185
186 /* Table A-2 */
187 switch (profile) {
188 case GST_VAAPI_PROFILE_H264_HIGH:
189 f = 1500;
190 break;
191 case GST_VAAPI_PROFILE_H264_HIGH10:
192 f = 3600;
193 break;
194 case GST_VAAPI_PROFILE_H264_HIGH_422:
195 case GST_VAAPI_PROFILE_H264_HIGH_444:
196 f = 4800;
197 break;
198 case GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH:
199 case GST_VAAPI_PROFILE_H264_STEREO_HIGH:
200 f = 1500; /* H.10.2.1 (r) */
201 break;
202 default:
203 f = 1200;
204 break;
205 }
206 return f;
207 }
208
209 /* ------------------------------------------------------------------------- */
210 /* --- H.264 Bitstream Writer --- */
211 /* ------------------------------------------------------------------------- */
212
213 #define WRITE_UINT32(bs, val, nbits) do { \
214 if (!gst_bit_writer_put_bits_uint32 (bs, val, nbits)) { \
215 GST_WARNING ("failed to write uint32, nbits: %d", nbits); \
216 goto bs_error; \
217 } \
218 } while (0)
219
220 #define WRITE_UE(bs, val) do { \
221 if (!bs_write_ue (bs, val)) { \
222 GST_WARNING ("failed to write ue(v)"); \
223 goto bs_error; \
224 } \
225 } while (0)
226
227 #define WRITE_SE(bs, val) do { \
228 if (!bs_write_se (bs, val)) { \
229 GST_WARNING ("failed to write se(v)"); \
230 goto bs_error; \
231 } \
232 } while (0)
233
234 /* Write an unsigned integer Exp-Golomb-coded syntax element. i.e. ue(v) */
235 static gboolean
bs_write_ue(GstBitWriter * bs,guint32 value)236 bs_write_ue (GstBitWriter * bs, guint32 value)
237 {
238 guint32 size_in_bits = 0;
239 guint32 tmp_value = ++value;
240
241 while (tmp_value) {
242 ++size_in_bits;
243 tmp_value >>= 1;
244 }
245 if (size_in_bits > 1
246 && !gst_bit_writer_put_bits_uint32 (bs, 0, size_in_bits - 1))
247 return FALSE;
248 if (!gst_bit_writer_put_bits_uint32 (bs, value, size_in_bits))
249 return FALSE;
250 return TRUE;
251 }
252
253 /* Write a signed integer Exp-Golomb-coded syntax element. i.e. se(v) */
254 static gboolean
bs_write_se(GstBitWriter * bs,gint32 value)255 bs_write_se (GstBitWriter * bs, gint32 value)
256 {
257 guint32 new_val;
258
259 if (value <= 0)
260 new_val = -(value << 1);
261 else
262 new_val = (value << 1) - 1;
263
264 if (!bs_write_ue (bs, new_val))
265 return FALSE;
266 return TRUE;
267 }
268
269 /* Write the NAL unit header */
270 static gboolean
bs_write_nal_header(GstBitWriter * bs,guint32 nal_ref_idc,guint32 nal_unit_type)271 bs_write_nal_header (GstBitWriter * bs, guint32 nal_ref_idc,
272 guint32 nal_unit_type)
273 {
274 WRITE_UINT32 (bs, 0, 1);
275 WRITE_UINT32 (bs, nal_ref_idc, 2);
276 WRITE_UINT32 (bs, nal_unit_type, 5);
277 return TRUE;
278
279 /* ERRORS */
280 bs_error:
281 {
282 GST_WARNING ("failed to write NAL unit header");
283 return FALSE;
284 }
285 }
286
287 /* Write the MVC NAL unit header extension */
288 static gboolean
bs_write_nal_header_mvc_extension(GstBitWriter * bs,GstVaapiEncPicture * picture,guint32 view_id)289 bs_write_nal_header_mvc_extension (GstBitWriter * bs,
290 GstVaapiEncPicture * picture, guint32 view_id)
291 {
292 guint32 svc_extension_flag = 0;
293 guint32 non_idr_flag = 1;
294 guint32 priority_id = 0;
295 guint32 temporal_id = 0;
296 guint32 anchor_pic_flag = 0;
297 guint32 inter_view_flag = 0;
298
299 if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
300 non_idr_flag = 0;
301
302 if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
303 anchor_pic_flag = 1;
304 /* svc_extension_flag == 0 for mvc stream */
305 WRITE_UINT32 (bs, svc_extension_flag, 1);
306
307 WRITE_UINT32 (bs, non_idr_flag, 1);
308 WRITE_UINT32 (bs, priority_id, 6);
309 WRITE_UINT32 (bs, view_id, 10);
310 WRITE_UINT32 (bs, temporal_id, 3);
311 WRITE_UINT32 (bs, anchor_pic_flag, 1);
312 WRITE_UINT32 (bs, inter_view_flag, 1);
313 WRITE_UINT32 (bs, 1, 1);
314
315 return TRUE;
316
317 /* ERRORS */
318 bs_error:
319 {
320 GST_WARNING ("failed to write NAL unit header");
321 return FALSE;
322 }
323 }
324
325 /* Write the NAL unit trailing bits */
326 static gboolean
bs_write_trailing_bits(GstBitWriter * bs)327 bs_write_trailing_bits (GstBitWriter * bs)
328 {
329 if (!gst_bit_writer_put_bits_uint32 (bs, 1, 1))
330 goto bs_error;
331 gst_bit_writer_align_bytes_unchecked (bs, 0);
332 return TRUE;
333
334 /* ERRORS */
335 bs_error:
336 {
337 GST_WARNING ("failed to write NAL unit trailing bits");
338 return FALSE;
339 }
340 }
341
342 /* Write an SPS NAL unit */
343 static gboolean
bs_write_sps_data(GstBitWriter * bs,const VAEncSequenceParameterBufferH264 * seq_param,GstVaapiProfile profile,const VAEncMiscParameterHRD * hrd_params)344 bs_write_sps_data (GstBitWriter * bs,
345 const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile,
346 const VAEncMiscParameterHRD * hrd_params)
347 {
348 guint8 profile_idc;
349 guint32 constraint_set0_flag, constraint_set1_flag;
350 guint32 constraint_set2_flag, constraint_set3_flag;
351 guint32 gaps_in_frame_num_value_allowed_flag = 0; // ??
352 gboolean nal_hrd_parameters_present_flag;
353
354 guint32 b_qpprime_y_zero_transform_bypass = 0;
355 guint32 residual_color_transform_flag = 0;
356 guint32 pic_height_in_map_units =
357 (seq_param->seq_fields.bits.frame_mbs_only_flag ?
358 seq_param->picture_height_in_mbs : seq_param->picture_height_in_mbs / 2);
359 guint32 mb_adaptive_frame_field =
360 !seq_param->seq_fields.bits.frame_mbs_only_flag;
361 guint32 i = 0;
362
363 profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
364 constraint_set0_flag = /* A.2.1 (baseline profile constraints) */
365 profile == GST_VAAPI_PROFILE_H264_BASELINE ||
366 profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
367 constraint_set1_flag = /* A.2.2 (main profile constraints) */
368 profile == GST_VAAPI_PROFILE_H264_MAIN ||
369 profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
370 constraint_set2_flag = 0;
371 constraint_set3_flag = 0;
372
373 /* profile_idc */
374 WRITE_UINT32 (bs, profile_idc, 8);
375 /* constraint_set0_flag */
376 WRITE_UINT32 (bs, constraint_set0_flag, 1);
377 /* constraint_set1_flag */
378 WRITE_UINT32 (bs, constraint_set1_flag, 1);
379 /* constraint_set2_flag */
380 WRITE_UINT32 (bs, constraint_set2_flag, 1);
381 /* constraint_set3_flag */
382 WRITE_UINT32 (bs, constraint_set3_flag, 1);
383 /* reserved_zero_4bits */
384 WRITE_UINT32 (bs, 0, 4);
385 /* level_idc */
386 WRITE_UINT32 (bs, seq_param->level_idc, 8);
387 /* seq_parameter_set_id */
388 WRITE_UE (bs, seq_param->seq_parameter_set_id);
389
390 if (profile == GST_VAAPI_PROFILE_H264_HIGH ||
391 profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH ||
392 profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH) {
393 /* for high profile */
394 /* chroma_format_idc = 1, 4:2:0 */
395 WRITE_UE (bs, seq_param->seq_fields.bits.chroma_format_idc);
396 if (3 == seq_param->seq_fields.bits.chroma_format_idc) {
397 WRITE_UINT32 (bs, residual_color_transform_flag, 1);
398 }
399 /* bit_depth_luma_minus8 */
400 WRITE_UE (bs, seq_param->bit_depth_luma_minus8);
401 /* bit_depth_chroma_minus8 */
402 WRITE_UE (bs, seq_param->bit_depth_chroma_minus8);
403 /* b_qpprime_y_zero_transform_bypass */
404 WRITE_UINT32 (bs, b_qpprime_y_zero_transform_bypass, 1);
405
406 /* seq_scaling_matrix_present_flag */
407 g_assert (seq_param->seq_fields.bits.seq_scaling_matrix_present_flag == 0);
408 WRITE_UINT32 (bs,
409 seq_param->seq_fields.bits.seq_scaling_matrix_present_flag, 1);
410
411 #if 0
412 if (seq_param->seq_fields.bits.seq_scaling_matrix_present_flag) {
413 for (i = 0;
414 i < (seq_param->seq_fields.bits.chroma_format_idc != 3 ? 8 : 12);
415 i++) {
416 gst_bit_writer_put_bits_uint8 (bs,
417 seq_param->seq_fields.bits.seq_scaling_list_present_flag, 1);
418 if (seq_param->seq_fields.bits.seq_scaling_list_present_flag) {
419 g_assert (0);
420 /* FIXME, need write scaling list if seq_scaling_matrix_present_flag ==1 */
421 }
422 }
423 }
424 #endif
425 }
426
427 /* log2_max_frame_num_minus4 */
428 WRITE_UE (bs, seq_param->seq_fields.bits.log2_max_frame_num_minus4);
429 /* pic_order_cnt_type */
430 WRITE_UE (bs, seq_param->seq_fields.bits.pic_order_cnt_type);
431
432 if (seq_param->seq_fields.bits.pic_order_cnt_type == 0) {
433 /* log2_max_pic_order_cnt_lsb_minus4 */
434 WRITE_UE (bs, seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4);
435 } else if (seq_param->seq_fields.bits.pic_order_cnt_type == 1) {
436 g_assert (0 && "only POC type 0 is supported");
437 WRITE_UINT32 (bs,
438 seq_param->seq_fields.bits.delta_pic_order_always_zero_flag, 1);
439 WRITE_SE (bs, seq_param->offset_for_non_ref_pic);
440 WRITE_SE (bs, seq_param->offset_for_top_to_bottom_field);
441 WRITE_UE (bs, seq_param->num_ref_frames_in_pic_order_cnt_cycle);
442 for (i = 0; i < seq_param->num_ref_frames_in_pic_order_cnt_cycle; i++) {
443 WRITE_SE (bs, seq_param->offset_for_ref_frame[i]);
444 }
445 }
446
447 /* num_ref_frames */
448 WRITE_UE (bs, seq_param->max_num_ref_frames);
449 /* gaps_in_frame_num_value_allowed_flag */
450 WRITE_UINT32 (bs, gaps_in_frame_num_value_allowed_flag, 1);
451
452 /* pic_width_in_mbs_minus1 */
453 WRITE_UE (bs, seq_param->picture_width_in_mbs - 1);
454 /* pic_height_in_map_units_minus1 */
455 WRITE_UE (bs, pic_height_in_map_units - 1);
456 /* frame_mbs_only_flag */
457 WRITE_UINT32 (bs, seq_param->seq_fields.bits.frame_mbs_only_flag, 1);
458
459 if (!seq_param->seq_fields.bits.frame_mbs_only_flag) { //ONLY mbs
460 g_assert (0 && "only progressive frames encoding is supported");
461 WRITE_UINT32 (bs, mb_adaptive_frame_field, 1);
462 }
463
464 /* direct_8x8_inference_flag */
465 WRITE_UINT32 (bs, 0, 1);
466 /* frame_cropping_flag */
467 WRITE_UINT32 (bs, seq_param->frame_cropping_flag, 1);
468
469 if (seq_param->frame_cropping_flag) {
470 /* frame_crop_left_offset */
471 WRITE_UE (bs, seq_param->frame_crop_left_offset);
472 /* frame_crop_right_offset */
473 WRITE_UE (bs, seq_param->frame_crop_right_offset);
474 /* frame_crop_top_offset */
475 WRITE_UE (bs, seq_param->frame_crop_top_offset);
476 /* frame_crop_bottom_offset */
477 WRITE_UE (bs, seq_param->frame_crop_bottom_offset);
478 }
479
480 /* vui_parameters_present_flag */
481 WRITE_UINT32 (bs, seq_param->vui_parameters_present_flag, 1);
482 if (seq_param->vui_parameters_present_flag) {
483 /* aspect_ratio_info_present_flag */
484 WRITE_UINT32 (bs,
485 seq_param->vui_fields.bits.aspect_ratio_info_present_flag, 1);
486 if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) {
487 WRITE_UINT32 (bs, seq_param->aspect_ratio_idc, 8);
488 if (seq_param->aspect_ratio_idc == 0xFF) {
489 WRITE_UINT32 (bs, seq_param->sar_width, 16);
490 WRITE_UINT32 (bs, seq_param->sar_height, 16);
491 }
492 }
493
494 /* overscan_info_present_flag */
495 WRITE_UINT32 (bs, 0, 1);
496 /* video_signal_type_present_flag */
497 WRITE_UINT32 (bs, 0, 1);
498 /* chroma_loc_info_present_flag */
499 WRITE_UINT32 (bs, 0, 1);
500
501 /* timing_info_present_flag */
502 WRITE_UINT32 (bs, seq_param->vui_fields.bits.timing_info_present_flag, 1);
503 if (seq_param->vui_fields.bits.timing_info_present_flag) {
504 WRITE_UINT32 (bs, seq_param->num_units_in_tick, 32);
505 WRITE_UINT32 (bs, seq_param->time_scale, 32);
506 WRITE_UINT32 (bs, 1, 1); /* fixed_frame_rate_flag */
507 }
508
509 /* nal_hrd_parameters_present_flag */
510 nal_hrd_parameters_present_flag = seq_param->bits_per_second > 0;
511 WRITE_UINT32 (bs, nal_hrd_parameters_present_flag, 1);
512 if (nal_hrd_parameters_present_flag) {
513 /* hrd_parameters */
514 /* cpb_cnt_minus1 */
515 WRITE_UE (bs, 0);
516 WRITE_UINT32 (bs, SX_BITRATE - 6, 4); /* bit_rate_scale */
517 WRITE_UINT32 (bs, SX_CPB_SIZE - 4, 4); /* cpb_size_scale */
518
519 for (i = 0; i < 1; ++i) {
520 /* bit_rate_value_minus1[0] */
521 WRITE_UE (bs, (seq_param->bits_per_second >> SX_BITRATE) - 1);
522 /* cpb_size_value_minus1[0] */
523 WRITE_UE (bs, (hrd_params->buffer_size >> SX_CPB_SIZE) - 1);
524 /* cbr_flag[0] */
525 WRITE_UINT32 (bs, 1, 1);
526 }
527 /* initial_cpb_removal_delay_length_minus1 */
528 WRITE_UINT32 (bs, 23, 5);
529 /* cpb_removal_delay_length_minus1 */
530 WRITE_UINT32 (bs, 23, 5);
531 /* dpb_output_delay_length_minus1 */
532 WRITE_UINT32 (bs, 23, 5);
533 /* time_offset_length */
534 WRITE_UINT32 (bs, 23, 5);
535 }
536
537 /* vcl_hrd_parameters_present_flag */
538 WRITE_UINT32 (bs, 0, 1);
539
540 if (nal_hrd_parameters_present_flag
541 || 0 /*vcl_hrd_parameters_present_flag */ ) {
542 /* low_delay_hrd_flag */
543 WRITE_UINT32 (bs, 0, 1);
544 }
545 /* pic_struct_present_flag */
546 WRITE_UINT32 (bs, 1, 1);
547 /* bs_restriction_flag */
548 WRITE_UINT32 (bs, 0, 1);
549 }
550 return TRUE;
551
552 /* ERRORS */
553 bs_error:
554 {
555 GST_WARNING ("failed to write SPS NAL unit");
556 return FALSE;
557 }
558 }
559
560 static gboolean
bs_write_sps(GstBitWriter * bs,const VAEncSequenceParameterBufferH264 * seq_param,GstVaapiProfile profile,const VAEncMiscParameterHRD * hrd_params)561 bs_write_sps (GstBitWriter * bs,
562 const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile,
563 const VAEncMiscParameterHRD * hrd_params)
564 {
565 if (!bs_write_sps_data (bs, seq_param, profile, hrd_params))
566 return FALSE;
567
568 /* rbsp_trailing_bits */
569 bs_write_trailing_bits (bs);
570
571 return FALSE;
572 }
573
574 static gboolean
bs_write_subset_sps(GstBitWriter * bs,const VAEncSequenceParameterBufferH264 * seq_param,GstVaapiProfile profile,guint num_views,guint16 * view_ids,const VAEncMiscParameterHRD * hrd_params)575 bs_write_subset_sps (GstBitWriter * bs,
576 const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile,
577 guint num_views, guint16 * view_ids,
578 const VAEncMiscParameterHRD * hrd_params)
579 {
580 guint32 i, j, k;
581
582 if (!bs_write_sps_data (bs, seq_param, profile, hrd_params))
583 return FALSE;
584
585 if (profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH ||
586 profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH) {
587 guint32 num_views_minus1, num_level_values_signalled_minus1;
588
589 num_views_minus1 = num_views - 1;
590 g_assert (num_views_minus1 < 1024);
591
592 /* bit equal to one */
593 WRITE_UINT32 (bs, 1, 1);
594
595 WRITE_UE (bs, num_views_minus1);
596
597 for (i = 0; i <= num_views_minus1; i++)
598 WRITE_UE (bs, view_ids[i]);
599
600 for (i = 1; i <= num_views_minus1; i++) {
601 guint32 num_anchor_refs_l0 = 0;
602 guint32 num_anchor_refs_l1 = 0;
603
604 WRITE_UE (bs, num_anchor_refs_l0);
605 for (j = 0; j < num_anchor_refs_l0; j++)
606 WRITE_UE (bs, 0);
607
608 WRITE_UE (bs, num_anchor_refs_l1);
609 for (j = 0; j < num_anchor_refs_l1; j++)
610 WRITE_UE (bs, 0);
611 }
612
613 for (i = 1; i <= num_views_minus1; i++) {
614 guint32 num_non_anchor_refs_l0 = 0;
615 guint32 num_non_anchor_refs_l1 = 0;
616
617 WRITE_UE (bs, num_non_anchor_refs_l0);
618 for (j = 0; j < num_non_anchor_refs_l0; j++)
619 WRITE_UE (bs, 0);
620
621 WRITE_UE (bs, num_non_anchor_refs_l1);
622 for (j = 0; j < num_non_anchor_refs_l1; j++)
623 WRITE_UE (bs, 0);
624 }
625
626 /* num level values signalled minus1 */
627 num_level_values_signalled_minus1 = 0;
628 g_assert (num_level_values_signalled_minus1 < 64);
629 WRITE_UE (bs, num_level_values_signalled_minus1);
630
631 for (i = 0; i <= num_level_values_signalled_minus1; i++) {
632 guint16 num_applicable_ops_minus1 = 0;
633 g_assert (num_applicable_ops_minus1 < 1024);
634
635 WRITE_UINT32 (bs, seq_param->level_idc, 8);
636 WRITE_UE (bs, num_applicable_ops_minus1);
637
638 for (j = 0; j <= num_applicable_ops_minus1; j++) {
639 guint8 temporal_id = 0;
640 guint16 num_target_views_minus1 = 1;
641
642 WRITE_UINT32 (bs, temporal_id, 3);
643 WRITE_UE (bs, num_target_views_minus1);
644
645 for (k = 0; k <= num_target_views_minus1; k++)
646 WRITE_UE (bs, k);
647
648 WRITE_UE (bs, num_views_minus1);
649 }
650 }
651
652 /* mvc_vui_parameters_present_flag */
653 WRITE_UINT32 (bs, 0, 1);
654 }
655
656 /* additional_extension2_flag */
657 WRITE_UINT32 (bs, 0, 1);
658
659 /* rbsp_trailing_bits */
660 bs_write_trailing_bits (bs);
661 return TRUE;
662
663 /* ERRORS */
664 bs_error:
665 {
666 GST_WARNING ("failed to write subset SPS NAL unit");
667 return FALSE;
668 }
669 return FALSE;
670 }
671
672 /* Write a PPS NAL unit */
673 static gboolean
bs_write_pps(GstBitWriter * bs,const VAEncPictureParameterBufferH264 * pic_param,GstVaapiProfile profile)674 bs_write_pps (GstBitWriter * bs,
675 const VAEncPictureParameterBufferH264 * pic_param, GstVaapiProfile profile)
676 {
677 guint32 num_slice_groups_minus1 = 0;
678 guint32 pic_init_qs_minus26 = 0;
679 guint32 redundant_pic_cnt_present_flag = 0;
680
681 /* pic_parameter_set_id */
682 WRITE_UE (bs, pic_param->pic_parameter_set_id);
683 /* seq_parameter_set_id */
684 WRITE_UE (bs, pic_param->seq_parameter_set_id);
685 /* entropy_coding_mode_flag */
686 WRITE_UINT32 (bs, pic_param->pic_fields.bits.entropy_coding_mode_flag, 1);
687 /* pic_order_present_flag */
688 WRITE_UINT32 (bs, pic_param->pic_fields.bits.pic_order_present_flag, 1);
689 /* slice_groups-1 */
690 WRITE_UE (bs, num_slice_groups_minus1);
691
692 if (num_slice_groups_minus1 > 0) {
693 /*FIXME*/ g_assert (0 && "unsupported arbitrary slice ordering (ASO)");
694 }
695 WRITE_UE (bs, pic_param->num_ref_idx_l0_active_minus1);
696 WRITE_UE (bs, pic_param->num_ref_idx_l1_active_minus1);
697 WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_pred_flag, 1);
698 WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_bipred_idc, 2);
699 /* pic_init_qp_minus26 */
700 WRITE_SE (bs, pic_param->pic_init_qp - 26);
701 /* pic_init_qs_minus26 */
702 WRITE_SE (bs, pic_init_qs_minus26);
703 /* chroma_qp_index_offset */
704 WRITE_SE (bs, pic_param->chroma_qp_index_offset);
705
706 WRITE_UINT32 (bs,
707 pic_param->pic_fields.bits.deblocking_filter_control_present_flag, 1);
708 WRITE_UINT32 (bs, pic_param->pic_fields.bits.constrained_intra_pred_flag, 1);
709 WRITE_UINT32 (bs, redundant_pic_cnt_present_flag, 1);
710
711 /* more_rbsp_data */
712 if (profile == GST_VAAPI_PROFILE_H264_HIGH
713 || profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH
714 || profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH) {
715 WRITE_UINT32 (bs, pic_param->pic_fields.bits.transform_8x8_mode_flag, 1);
716 WRITE_UINT32 (bs,
717 pic_param->pic_fields.bits.pic_scaling_matrix_present_flag, 1);
718 if (pic_param->pic_fields.bits.pic_scaling_matrix_present_flag) {
719 g_assert (0 && "unsupported scaling lists");
720 /* FIXME */
721 /*
722 for (i = 0; i <
723 (6+(-( (chroma_format_idc ! = 3) ? 2 : 6) * -pic_param->pic_fields.bits.transform_8x8_mode_flag));
724 i++) {
725 gst_bit_writer_put_bits_uint8(bs, pic_param->pic_fields.bits.pic_scaling_list_present_flag, 1);
726 }
727 */
728 }
729 WRITE_SE (bs, pic_param->second_chroma_qp_index_offset);
730 }
731
732 /* rbsp_trailing_bits */
733 bs_write_trailing_bits (bs);
734 return TRUE;
735
736 /* ERRORS */
737 bs_error:
738 {
739 GST_WARNING ("failed to write PPS NAL unit");
740 return FALSE;
741 }
742 }
743
744 /* ------------------------------------------------------------------------- */
745 /* --- H.264 Encoder --- */
746 /* ------------------------------------------------------------------------- */
747
748 #define GST_VAAPI_ENCODER_H264_FEI_CAST(encoder) \
749 ((GstVaapiEncoderH264Fei *)(encoder))
750
751 struct _GstVaapiEncoderH264Fei
752 {
753 GstVaapiEncoder parent_instance;
754 GstVaapiFeiEncH264 *feienc;
755 GstVaapiFEIPakH264 *feipak;
756
757 GstVaapiProfile profile;
758 GstVaapiLevelH264 level;
759 GstVaapiEntrypoint entrypoint;
760 VAConfigID va_config;
761 guint8 profile_idc;
762 VABufferID coded_buf;
763 guint8 max_profile_idc;
764 guint8 hw_max_profile_idc;
765 guint8 level_idc;
766 guint32 idr_period;
767 guint32 init_qp;
768 guint32 min_qp;
769 guint32 num_slices;
770 guint32 num_bframes;
771 guint32 mb_width;
772 guint32 mb_height;
773 gboolean use_cabac;
774 gboolean use_dct8x8;
775 GstClockTime cts_offset;
776 gboolean config_changed;
777
778 /* frame, poc */
779 guint32 max_frame_num;
780 guint32 log2_max_frame_num;
781 guint32 max_pic_order_cnt;
782 guint32 log2_max_pic_order_cnt;
783 guint32 idr_num;
784 guint8 pic_order_cnt_type;
785 guint8 delta_pic_order_always_zero_flag;
786
787 GstBuffer *sps_data;
788 GstBuffer *subset_sps_data;
789 GstBuffer *pps_data;
790
791 guint bitrate_bits; // bitrate (bits)
792 guint cpb_length; // length of CPB buffer (ms)
793 guint cpb_length_bits; // length of CPB buffer (bits)
794 guint num_ref_frames;
795
796 /* MVC */
797 gboolean is_mvc;
798 guint32 view_idx; /* View Order Index (VOIdx) */
799 guint32 num_views;
800 guint16 view_ids[MAX_NUM_VIEWS];
801 GstVaapiH264ViewRefPool ref_pools[MAX_NUM_VIEWS];
802 GstVaapiH264ViewReorderPool reorder_pools[MAX_NUM_VIEWS];
803 gpointer ref_pool_ptr;
804 /*Fei frame level control */
805 gboolean is_fei_disabled;
806 gboolean is_stats_out_enabled;
807 guint search_window;
808 guint len_sp;
809 guint search_path;
810 guint ref_width;
811 guint ref_height;
812 guint submb_part_mask;
813 guint subpel_mode;
814 guint intra_part_mask;
815 guint intra_sad;
816 guint inter_sad;
817 guint num_mv_predictors_l0;
818 guint num_mv_predictors_l1;
819 guint adaptive_search;
820 guint multi_predL0;
821 guint multi_predL1;
822 guint fei_mode;
823
824 };
825
826 /* Write a SEI buffering period payload */
827 static gboolean
bs_write_sei_buf_period(GstBitWriter * bs,GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture)828 bs_write_sei_buf_period (GstBitWriter * bs,
829 GstVaapiEncoderH264Fei * encoder, GstVaapiEncPicture * picture)
830 {
831 guint initial_cpb_removal_delay = 0;
832 guint initial_cpb_removal_delay_offset = 0;
833 guint8 initial_cpb_removal_delay_length = 24;
834
835 /* sequence_parameter_set_id */
836 WRITE_UE (bs, encoder->view_idx);
837 /* NalHrdBpPresentFlag == TRUE */
838 /* cpb_cnt_minus1 == 0 */
839
840 /* decoding should start when the CPB fullness reaches half of cpb size
841 * initial_cpb_remvoal_delay = (((cpb_length / 2) * 90000) / 1000) */
842 initial_cpb_removal_delay = encoder->cpb_length * 45;
843
844 /* initial_cpb_remvoal_dealy */
845 WRITE_UINT32 (bs, initial_cpb_removal_delay,
846 initial_cpb_removal_delay_length);
847
848 /* initial_cpb_removal_delay_offset */
849 WRITE_UINT32 (bs, initial_cpb_removal_delay_offset,
850 initial_cpb_removal_delay_length);
851
852 /* VclHrdBpPresentFlag == FALSE */
853 return TRUE;
854
855 /* ERRORS */
856 bs_error:
857 {
858 GST_WARNING ("failed to write Buffering Period SEI message");
859 return FALSE;
860 }
861 }
862
863 /* Write a SEI picture timing payload */
864 static gboolean
bs_write_sei_pic_timing(GstBitWriter * bs,GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture)865 bs_write_sei_pic_timing (GstBitWriter * bs,
866 GstVaapiEncoderH264Fei * encoder, GstVaapiEncPicture * picture)
867 {
868 GstVaapiH264ViewReorderPool *reorder_pool = NULL;
869 guint cpb_removal_delay;
870 guint dpb_output_delay;
871 guint8 cpb_removal_delay_length = 24;
872 guint8 dpb_output_delay_length = 24;
873 guint pic_struct = 0;
874 guint clock_timestamp_flag = 0;
875
876 reorder_pool = &encoder->reorder_pools[encoder->view_idx];
877 if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
878 reorder_pool->frame_count = 0;
879 else
880 reorder_pool->frame_count++;
881
882 /* clock-tick = no_units_in_tick/time_scale (C-1)
883 * time_scale = FPS_N * 2 (E.2.1)
884 * num_units_in_tick = FPS_D (E.2.1)
885 * frame_duration = clock-tick * 2
886 * so removal time for one frame is 2 clock-ticks.
887 * but adding a tolerance of one frame duration,
888 * which is 2 more clock-ticks */
889 cpb_removal_delay = (reorder_pool->frame_count * 2 + 2);
890
891 if (picture->type == GST_VAAPI_PICTURE_TYPE_B)
892 dpb_output_delay = 0;
893 else
894 dpb_output_delay = picture->poc - reorder_pool->frame_count * 2;
895
896 /* CpbDpbDelaysPresentFlag == 1 */
897 WRITE_UINT32 (bs, cpb_removal_delay, cpb_removal_delay_length);
898 WRITE_UINT32 (bs, dpb_output_delay, dpb_output_delay_length);
899
900 /* pic_struct_present_flag == 1 */
901 /* pic_struct */
902 WRITE_UINT32 (bs, pic_struct, 4);
903 /* clock_timestamp_flag */
904 WRITE_UINT32 (bs, clock_timestamp_flag, 1);
905
906 return TRUE;
907
908 /* ERRORS */
909 bs_error:
910 {
911 GST_WARNING ("failed to write Picture Timing SEI message");
912 return FALSE;
913 }
914 }
915
916 /* Write a Slice NAL unit */
917 static gboolean
bs_write_slice(GstBitWriter * bs,const VAEncSliceParameterBufferH264 * slice_param,GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture)918 bs_write_slice (GstBitWriter * bs,
919 const VAEncSliceParameterBufferH264 * slice_param,
920 GstVaapiEncoderH264Fei * encoder, GstVaapiEncPicture * picture)
921 {
922 const VAEncPictureParameterBufferH264 *const pic_param = picture->param;
923 guint32 field_pic_flag = 0;
924 guint32 ref_pic_list_modification_flag_l0 = 0;
925 guint32 ref_pic_list_modification_flag_l1 = 0;
926 guint32 no_output_of_prior_pics_flag = 0;
927 guint32 long_term_reference_flag = 0;
928 guint32 adaptive_ref_pic_marking_mode_flag = 0;
929
930 /* first_mb_in_slice */
931 WRITE_UE (bs, slice_param->macroblock_address);
932 /* slice_type */
933 WRITE_UE (bs, slice_param->slice_type);
934 /* pic_parameter_set_id */
935 WRITE_UE (bs, slice_param->pic_parameter_set_id);
936 /* frame_num */
937 WRITE_UINT32 (bs, picture->frame_num, encoder->log2_max_frame_num);
938
939 /* XXX: only frames (i.e. non-interlaced) are supported for now */
940 /* frame_mbs_only_flag == 0 */
941
942 /* idr_pic_id */
943 if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
944 WRITE_UE (bs, slice_param->idr_pic_id);
945
946 /* XXX: only POC type 0 is supported */
947 if (!encoder->pic_order_cnt_type) {
948 WRITE_UINT32 (bs, slice_param->pic_order_cnt_lsb,
949 encoder->log2_max_pic_order_cnt);
950 /* bottom_field_pic_order_in_frame_present_flag is FALSE */
951 if (pic_param->pic_fields.bits.pic_order_present_flag && !field_pic_flag)
952 WRITE_SE (bs, slice_param->delta_pic_order_cnt_bottom);
953 } else if (encoder->pic_order_cnt_type == 1 &&
954 !encoder->delta_pic_order_always_zero_flag) {
955 WRITE_SE (bs, slice_param->delta_pic_order_cnt[0]);
956 if (pic_param->pic_fields.bits.pic_order_present_flag && !field_pic_flag)
957 WRITE_SE (bs, slice_param->delta_pic_order_cnt[1]);
958 }
959 /* redundant_pic_cnt_present_flag is FALSE, no redundant coded pictures */
960
961 /* only works for B-frames */
962 if (slice_param->slice_type == GST_H264_B_SLICE)
963 WRITE_UINT32 (bs, slice_param->direct_spatial_mv_pred_flag, 1);
964
965 /* not supporting SP slices */
966 if (slice_param->slice_type == 0 || slice_param->slice_type == 1) {
967 WRITE_UINT32 (bs, slice_param->num_ref_idx_active_override_flag, 1);
968 if (slice_param->num_ref_idx_active_override_flag) {
969 WRITE_UE (bs, slice_param->num_ref_idx_l0_active_minus1);
970 if (slice_param->slice_type == 1)
971 WRITE_UE (bs, slice_param->num_ref_idx_l1_active_minus1);
972 }
973 }
974 /* XXX: not supporting custom reference picture list modifications */
975 if ((slice_param->slice_type != 2) && (slice_param->slice_type != 4))
976 WRITE_UINT32 (bs, ref_pic_list_modification_flag_l0, 1);
977 if (slice_param->slice_type == 1)
978 WRITE_UINT32 (bs, ref_pic_list_modification_flag_l1, 1);
979
980 /* we have: weighted_pred_flag == FALSE and */
981 /* : weighted_bipred_idc == FALSE */
982 if ((pic_param->pic_fields.bits.weighted_pred_flag &&
983 (slice_param->slice_type == 0)) ||
984 ((pic_param->pic_fields.bits.weighted_bipred_idc == 1) &&
985 (slice_param->slice_type == 1))) {
986 /* XXXX: add pred_weight_table() */
987 }
988
989 /* dec_ref_pic_marking() */
990 if (slice_param->slice_type == 0 || slice_param->slice_type == 2) {
991 if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) {
992 /* no_output_of_prior_pics_flag = 0 */
993 WRITE_UINT32 (bs, no_output_of_prior_pics_flag, 1);
994 /* long_term_reference_flag = 0 */
995 WRITE_UINT32 (bs, long_term_reference_flag, 1);
996 } else {
997 /* only sliding_window reference picture marking mode is supported */
998 /* adpative_ref_pic_marking_mode_flag = 0 */
999 WRITE_UINT32 (bs, adaptive_ref_pic_marking_mode_flag, 1);
1000 }
1001 }
1002
1003 /* cabac_init_idc */
1004 if (pic_param->pic_fields.bits.entropy_coding_mode_flag &&
1005 slice_param->slice_type != 2)
1006 WRITE_UE (bs, slice_param->cabac_init_idc);
1007 /*slice_qp_delta */
1008 WRITE_SE (bs, slice_param->slice_qp_delta);
1009
1010 /* XXX: only supporting I, P and B type slices */
1011 /* no sp_for_switch_flag and no slice_qs_delta */
1012
1013 if (pic_param->pic_fields.bits.deblocking_filter_control_present_flag) {
1014 /* disable_deblocking_filter_idc */
1015 WRITE_UE (bs, slice_param->disable_deblocking_filter_idc);
1016 if (slice_param->disable_deblocking_filter_idc != 1) {
1017 WRITE_SE (bs, slice_param->slice_alpha_c0_offset_div2);
1018 WRITE_SE (bs, slice_param->slice_beta_offset_div2);
1019 }
1020 }
1021
1022 /* XXX: unsupported arbitrary slice ordering (ASO) */
1023 /* num_slic_groups_minus1 should be zero */
1024 return TRUE;
1025
1026 /* ERRORS */
1027 bs_error:
1028 {
1029 GST_WARNING ("failed to write Slice NAL unit");
1030 return FALSE;
1031 }
1032 }
1033
1034 static inline void
_check_sps_pps_status(GstVaapiEncoderH264Fei * encoder,const guint8 * nal,guint32 size)1035 _check_sps_pps_status (GstVaapiEncoderH264Fei * encoder,
1036 const guint8 * nal, guint32 size)
1037 {
1038 guint8 nal_type;
1039 G_GNUC_UNUSED gsize ret; /* FIXME */
1040 gboolean has_subset_sps;
1041
1042 g_assert (size);
1043
1044 has_subset_sps = !encoder->is_mvc || (encoder->subset_sps_data != NULL);
1045 if (encoder->sps_data && encoder->pps_data && has_subset_sps)
1046 return;
1047
1048 nal_type = nal[0] & 0x1F;
1049 switch (nal_type) {
1050 case GST_H264_NAL_SPS:
1051 encoder->sps_data = gst_buffer_new_allocate (NULL, size, NULL);
1052 ret = gst_buffer_fill (encoder->sps_data, 0, nal, size);
1053 g_assert (ret == size);
1054 break;
1055 case GST_H264_NAL_SUBSET_SPS:
1056 encoder->subset_sps_data = gst_buffer_new_allocate (NULL, size, NULL);
1057 ret = gst_buffer_fill (encoder->subset_sps_data, 0, nal, size);
1058 g_assert (ret == size);
1059 break;
1060 case GST_H264_NAL_PPS:
1061 encoder->pps_data = gst_buffer_new_allocate (NULL, size, NULL);
1062 ret = gst_buffer_fill (encoder->pps_data, 0, nal, size);
1063 g_assert (ret == size);
1064 break;
1065 default:
1066 break;
1067 }
1068 }
1069
1070 /* Determines the largest supported profile by the underlying hardware */
1071 static gboolean
ensure_hw_profile_limits(GstVaapiEncoderH264Fei * encoder)1072 ensure_hw_profile_limits (GstVaapiEncoderH264Fei * encoder)
1073 {
1074 GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
1075 GArray *profiles;
1076 guint i, profile_idc, max_profile_idc;
1077
1078 if (encoder->hw_max_profile_idc)
1079 return TRUE;
1080
1081 profiles = gst_vaapi_display_get_encode_profiles (display);
1082 if (!profiles)
1083 return FALSE;
1084
1085 max_profile_idc = 0;
1086 for (i = 0; i < profiles->len; i++) {
1087 const GstVaapiProfile profile =
1088 g_array_index (profiles, GstVaapiProfile, i);
1089 profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
1090 if (!profile_idc)
1091 continue;
1092 if (max_profile_idc < profile_idc)
1093 max_profile_idc = profile_idc;
1094 }
1095 g_array_unref (profiles);
1096
1097 encoder->hw_max_profile_idc = max_profile_idc;
1098 return TRUE;
1099 }
1100
1101 /* Derives the profile supported by the underlying hardware */
1102 static gboolean
ensure_hw_profile(GstVaapiEncoderH264Fei * encoder)1103 ensure_hw_profile (GstVaapiEncoderH264Fei * encoder)
1104 {
1105 GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
1106 GstVaapiEntrypoint entrypoint = encoder->entrypoint;
1107 GstVaapiProfile profile, profiles[4];
1108 guint i, num_profiles = 0;
1109
1110 profiles[num_profiles++] = encoder->profile;
1111 switch (encoder->profile) {
1112 case GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE:
1113 profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_BASELINE;
1114 profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_MAIN;
1115 // fall-through
1116 case GST_VAAPI_PROFILE_H264_MAIN:
1117 profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_HIGH;
1118 break;
1119 default:
1120 break;
1121 }
1122
1123 profile = GST_VAAPI_PROFILE_UNKNOWN;
1124 for (i = 0; i < num_profiles; i++) {
1125 if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) {
1126 profile = profiles[i];
1127 break;
1128 }
1129 }
1130 if (profile == GST_VAAPI_PROFILE_UNKNOWN)
1131 goto error_unsupported_profile;
1132
1133 GST_VAAPI_ENCODER_CAST (encoder)->profile = profile;
1134 return TRUE;
1135
1136 /* ERRORS */
1137 error_unsupported_profile:
1138 {
1139 GST_ERROR ("unsupported HW profile (0x%08x)", encoder->profile);
1140 return FALSE;
1141 }
1142 }
1143
1144 /* Check target decoder constraints */
1145 static gboolean
ensure_profile_limits(GstVaapiEncoderH264Fei * encoder)1146 ensure_profile_limits (GstVaapiEncoderH264Fei * encoder)
1147 {
1148 GstVaapiProfile profile;
1149
1150 if (!encoder->max_profile_idc
1151 || encoder->profile_idc <= encoder->max_profile_idc)
1152 return TRUE;
1153
1154 GST_WARNING ("lowering coding tools to meet target decoder constraints");
1155
1156 profile = GST_VAAPI_PROFILE_UNKNOWN;
1157
1158 /* Try Main profile coding tools */
1159 if (encoder->max_profile_idc < 100) {
1160 encoder->use_dct8x8 = FALSE;
1161 profile = GST_VAAPI_PROFILE_H264_MAIN;
1162 }
1163
1164 /* Try Constrained Baseline profile coding tools */
1165 if (encoder->max_profile_idc < 77) {
1166 encoder->num_bframes = 0;
1167 encoder->use_cabac = FALSE;
1168 profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
1169 }
1170
1171 if (profile) {
1172 encoder->profile = profile;
1173 encoder->profile_idc = encoder->max_profile_idc;
1174 }
1175 return TRUE;
1176 }
1177
1178 /* Derives the minimum profile from the active coding tools */
1179 static gboolean
ensure_profile(GstVaapiEncoderH264Fei * encoder)1180 ensure_profile (GstVaapiEncoderH264Fei * encoder)
1181 {
1182 GstVaapiProfile profile;
1183
1184 /* Always start from "constrained-baseline" profile for maximum
1185 compatibility */
1186 profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
1187
1188 /* Main profile coding tools */
1189 if (encoder->num_bframes > 0 || encoder->use_cabac)
1190 profile = GST_VAAPI_PROFILE_H264_MAIN;
1191
1192 /* High profile coding tools */
1193 if (encoder->use_dct8x8)
1194 profile = GST_VAAPI_PROFILE_H264_HIGH;
1195
1196 /* MVC profiles coding tools */
1197 if (encoder->num_views == 2)
1198 profile = GST_VAAPI_PROFILE_H264_STEREO_HIGH;
1199 else if (encoder->num_views > 2)
1200 profile = GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH;
1201
1202 encoder->profile = profile;
1203 encoder->profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
1204 return TRUE;
1205 }
1206
1207 /* Derives the level from the currently set limits */
1208 static gboolean
ensure_level(GstVaapiEncoderH264Fei * encoder)1209 ensure_level (GstVaapiEncoderH264Fei * encoder)
1210 {
1211 const guint cpb_factor = h264_get_cpb_nal_factor (encoder->profile);
1212 const GstVaapiH264LevelLimits *limits_table;
1213 guint i, num_limits, PicSizeMbs, MaxDpbMbs, MaxMBPS;
1214
1215 PicSizeMbs = encoder->mb_width * encoder->mb_height;
1216 MaxDpbMbs = PicSizeMbs * ((encoder->num_bframes) ? 2 : 1);
1217 MaxMBPS = gst_util_uint64_scale_int_ceil (PicSizeMbs,
1218 GST_VAAPI_ENCODER_FPS_N (encoder), GST_VAAPI_ENCODER_FPS_D (encoder));
1219
1220 limits_table = gst_vaapi_utils_h264_get_level_limits_table (&num_limits);
1221 for (i = 0; i < num_limits; i++) {
1222 const GstVaapiH264LevelLimits *const limits = &limits_table[i];
1223 if (PicSizeMbs <= limits->MaxFS &&
1224 MaxDpbMbs <= limits->MaxDpbMbs &&
1225 MaxMBPS <= limits->MaxMBPS && (!encoder->bitrate_bits
1226 || encoder->bitrate_bits <= (limits->MaxBR * cpb_factor)) &&
1227 (!encoder->cpb_length_bits ||
1228 encoder->cpb_length_bits <= (limits->MaxCPB * cpb_factor)))
1229 break;
1230 }
1231 if (i == num_limits)
1232 goto error_unsupported_level;
1233
1234 encoder->level = limits_table[i].level;
1235 encoder->level_idc = limits_table[i].level_idc;
1236 return TRUE;
1237
1238 /* ERRORS */
1239 error_unsupported_level:
1240 {
1241 GST_ERROR ("failed to find a suitable level matching codec config");
1242 return FALSE;
1243 }
1244 }
1245
1246 /* Enable "high-compression" tuning options */
1247 static gboolean
ensure_tuning_high_compression(GstVaapiEncoderH264Fei * encoder)1248 ensure_tuning_high_compression (GstVaapiEncoderH264Fei * encoder)
1249 {
1250 guint8 profile_idc;
1251
1252 if (!ensure_hw_profile_limits (encoder))
1253 return FALSE;
1254
1255 profile_idc = encoder->hw_max_profile_idc;
1256 if (encoder->max_profile_idc && encoder->max_profile_idc < profile_idc)
1257 profile_idc = encoder->max_profile_idc;
1258
1259 /* Tuning options to enable Main profile */
1260 if (profile_idc >= 77 && profile_idc != 88) {
1261 encoder->use_cabac = TRUE;
1262 if (!encoder->num_bframes)
1263 encoder->num_bframes = 1;
1264 }
1265
1266 /* Tuning options to enable High profile */
1267 if (profile_idc >= 100) {
1268 encoder->use_dct8x8 = TRUE;
1269 }
1270 return TRUE;
1271 }
1272
1273 /* Ensure tuning options */
1274 static gboolean
ensure_tuning(GstVaapiEncoderH264Fei * encoder)1275 ensure_tuning (GstVaapiEncoderH264Fei * encoder)
1276 {
1277 gboolean success;
1278
1279 switch (GST_VAAPI_ENCODER_TUNE (encoder)) {
1280 case GST_VAAPI_ENCODER_TUNE_HIGH_COMPRESSION:
1281 success = ensure_tuning_high_compression (encoder);
1282 break;
1283 case GST_VAAPI_ENCODER_TUNE_LOW_POWER:
1284 /* Set low-power encode entry point. If hardware doesn't have
1285 * support, it will fail in ensure_hw_profile() in later stage.
1286 * So not duplicating the profile/entrypont query mechanism
1287 * here as a part of optimization */
1288 encoder->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP;
1289 success = TRUE;
1290 break;
1291 default:
1292 success = TRUE;
1293 break;
1294 }
1295 return success;
1296 }
1297
1298 /* Handle new GOP starts */
1299 static void
reset_gop_start(GstVaapiEncoderH264Fei * encoder)1300 reset_gop_start (GstVaapiEncoderH264Fei * encoder)
1301 {
1302 GstVaapiH264ViewReorderPool *const reorder_pool =
1303 &encoder->reorder_pools[encoder->view_idx];
1304
1305 reorder_pool->frame_index = 1;
1306 reorder_pool->cur_frame_num = 0;
1307 reorder_pool->cur_present_index = 0;
1308 ++encoder->idr_num;
1309 }
1310
1311 /* Marks the supplied picture as a B-frame */
1312 static void
set_b_frame(GstVaapiEncPicture * pic,GstVaapiEncoderH264Fei * encoder)1313 set_b_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264Fei * encoder)
1314 {
1315 GstVaapiH264ViewReorderPool *const reorder_pool =
1316 &encoder->reorder_pools[encoder->view_idx];
1317
1318 g_assert (pic && encoder);
1319 g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
1320 pic->type = GST_VAAPI_PICTURE_TYPE_B;
1321 pic->frame_num = (reorder_pool->cur_frame_num % encoder->max_frame_num);
1322 }
1323
1324 /* Marks the supplied picture as a P-frame */
1325 static void
set_p_frame(GstVaapiEncPicture * pic,GstVaapiEncoderH264Fei * encoder)1326 set_p_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264Fei * encoder)
1327 {
1328 GstVaapiH264ViewReorderPool *const reorder_pool =
1329 &encoder->reorder_pools[encoder->view_idx];
1330
1331 g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
1332 pic->type = GST_VAAPI_PICTURE_TYPE_P;
1333 pic->frame_num = (reorder_pool->cur_frame_num % encoder->max_frame_num);
1334 }
1335
1336 /* Marks the supplied picture as an I-frame */
1337 static void
set_i_frame(GstVaapiEncPicture * pic,GstVaapiEncoderH264Fei * encoder)1338 set_i_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264Fei * encoder)
1339 {
1340 GstVaapiH264ViewReorderPool *const reorder_pool =
1341 &encoder->reorder_pools[encoder->view_idx];
1342
1343 g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
1344 pic->type = GST_VAAPI_PICTURE_TYPE_I;
1345 pic->frame_num = (reorder_pool->cur_frame_num % encoder->max_frame_num);
1346
1347 g_assert (pic->frame);
1348 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame);
1349 }
1350
1351 /* Marks the supplied picture as an IDR frame */
1352 static void
set_idr_frame(GstVaapiEncPicture * pic,GstVaapiEncoderH264Fei * encoder)1353 set_idr_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264Fei * encoder)
1354 {
1355 g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
1356 pic->type = GST_VAAPI_PICTURE_TYPE_I;
1357 pic->frame_num = 0;
1358 pic->poc = 0;
1359 GST_VAAPI_ENC_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_IDR);
1360
1361 g_assert (pic->frame);
1362 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame);
1363 }
1364
1365 /* Marks the supplied picture a a key-frame */
1366 static void
set_key_frame(GstVaapiEncPicture * picture,GstVaapiEncoderH264Fei * encoder,gboolean is_idr)1367 set_key_frame (GstVaapiEncPicture * picture,
1368 GstVaapiEncoderH264Fei * encoder, gboolean is_idr)
1369 {
1370 if (is_idr) {
1371 reset_gop_start (encoder);
1372 set_idr_frame (picture, encoder);
1373 } else
1374 set_i_frame (picture, encoder);
1375 }
1376
1377 /* Fills in VA HRD parameters */
1378 static void
fill_hrd_params(GstVaapiEncoderH264Fei * encoder,VAEncMiscParameterHRD * hrd)1379 fill_hrd_params (GstVaapiEncoderH264Fei * encoder, VAEncMiscParameterHRD * hrd)
1380 {
1381 if (encoder->bitrate_bits > 0) {
1382 hrd->buffer_size = encoder->cpb_length_bits;
1383 hrd->initial_buffer_fullness = hrd->buffer_size / 2;
1384 } else {
1385 hrd->buffer_size = 0;
1386 hrd->initial_buffer_fullness = 0;
1387 }
1388 }
1389
1390 /* Adds the supplied sequence header (SPS) to the list of packed
1391 headers to pass down as-is to the encoder */
1392 static gboolean
add_packed_sequence_header(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiEncSequence * sequence)1393 add_packed_sequence_header (GstVaapiEncoderH264Fei * encoder,
1394 GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence)
1395 {
1396 GstVaapiEncPackedHeader *packed_seq;
1397 GstBitWriter bs;
1398 VAEncPackedHeaderParameterBuffer packed_seq_param = { 0 };
1399 const VAEncSequenceParameterBufferH264 *const seq_param = sequence->param;
1400 GstVaapiProfile profile = encoder->profile;
1401
1402 VAEncMiscParameterHRD hrd_params;
1403 guint32 data_bit_size;
1404 guint8 *data;
1405
1406 fill_hrd_params (encoder, &hrd_params);
1407
1408 gst_bit_writer_init_with_size (&bs, 128, FALSE);
1409 WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */
1410 bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_HIGH, GST_H264_NAL_SPS);
1411
1412 /* Set High profile for encoding the MVC base view. Otherwise, some
1413 traditional decoder cannot recognize MVC profile streams with
1414 only the base view in there */
1415 if (profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH ||
1416 profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH)
1417 profile = GST_VAAPI_PROFILE_H264_HIGH;
1418
1419 bs_write_sps (&bs, seq_param, profile, &hrd_params);
1420
1421 g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
1422 data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
1423 data = GST_BIT_WRITER_DATA (&bs);
1424
1425 packed_seq_param.type = VAEncPackedHeaderSequence;
1426 packed_seq_param.bit_length = data_bit_size;
1427 packed_seq_param.has_emulation_bytes = 0;
1428
1429 packed_seq = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
1430 &packed_seq_param, sizeof (packed_seq_param),
1431 data, (data_bit_size + 7) / 8);
1432 g_assert (packed_seq);
1433
1434 gst_vaapi_enc_picture_add_packed_header (picture, packed_seq);
1435 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & packed_seq, NULL);
1436
1437 /* store sps data */
1438 _check_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4);
1439 gst_bit_writer_reset (&bs);
1440 return TRUE;
1441
1442 /* ERRORS */
1443 bs_error:
1444 {
1445 GST_WARNING ("failed to write SPS NAL unit");
1446 gst_bit_writer_reset (&bs);
1447 return FALSE;
1448 }
1449 }
1450
1451 static gboolean
add_packed_sequence_header_mvc(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiEncSequence * sequence)1452 add_packed_sequence_header_mvc (GstVaapiEncoderH264Fei * encoder,
1453 GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence)
1454 {
1455 GstVaapiEncPackedHeader *packed_seq;
1456 GstBitWriter bs;
1457 VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
1458 const VAEncSequenceParameterBufferH264 *const seq_param = sequence->param;
1459 VAEncMiscParameterHRD hrd_params;
1460 guint32 data_bit_size;
1461 guint8 *data;
1462
1463 fill_hrd_params (encoder, &hrd_params);
1464
1465 /* non-base layer, pack one subset sps */
1466 gst_bit_writer_init_with_size (&bs, 128, FALSE);
1467 WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */
1468 bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_HIGH, GST_H264_NAL_SUBSET_SPS);
1469
1470 bs_write_subset_sps (&bs, seq_param, encoder->profile, encoder->num_views,
1471 encoder->view_ids, &hrd_params);
1472
1473 g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
1474 data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
1475 data = GST_BIT_WRITER_DATA (&bs);
1476
1477 packed_header_param_buffer.type = VAEncPackedHeaderSequence;
1478 packed_header_param_buffer.bit_length = data_bit_size;
1479 packed_header_param_buffer.has_emulation_bytes = 0;
1480
1481 packed_seq = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
1482 &packed_header_param_buffer, sizeof (packed_header_param_buffer),
1483 data, (data_bit_size + 7) / 8);
1484 g_assert (packed_seq);
1485
1486 gst_vaapi_enc_picture_add_packed_header (picture, packed_seq);
1487 gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) & packed_seq, NULL);
1488
1489 /* store subset sps data */
1490 _check_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4);
1491 gst_bit_writer_reset (&bs);
1492 return TRUE;
1493
1494 /* ERRORS */
1495 bs_error:
1496 {
1497 GST_WARNING ("failed to write SPS NAL unit");
1498 gst_bit_writer_reset (&bs);
1499 return FALSE;
1500 }
1501 }
1502
1503 /* Adds the supplied picture header (PPS) to the list of packed
1504 headers to pass down as-is to the encoder */
1505 static gboolean
add_packed_picture_header(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture)1506 add_packed_picture_header (GstVaapiEncoderH264Fei * encoder,
1507 GstVaapiEncPicture * picture)
1508 {
1509 GstVaapiEncPackedHeader *packed_pic;
1510 GstBitWriter bs;
1511 VAEncPackedHeaderParameterBuffer packed_pic_param = { 0 };
1512 const VAEncPictureParameterBufferH264 *const pic_param = picture->param;
1513 guint32 data_bit_size;
1514 guint8 *data;
1515
1516 gst_bit_writer_init_with_size (&bs, 128, FALSE);
1517 WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */
1518 bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_HIGH, GST_H264_NAL_PPS);
1519 bs_write_pps (&bs, pic_param, encoder->profile);
1520 g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
1521 data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
1522 data = GST_BIT_WRITER_DATA (&bs);
1523
1524 packed_pic_param.type = VAEncPackedHeaderPicture;
1525 packed_pic_param.bit_length = data_bit_size;
1526 packed_pic_param.has_emulation_bytes = 0;
1527
1528 packed_pic = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
1529 &packed_pic_param, sizeof (packed_pic_param),
1530 data, (data_bit_size + 7) / 8);
1531 g_assert (packed_pic);
1532
1533 gst_vaapi_enc_picture_add_packed_header (picture, packed_pic);
1534 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & packed_pic, NULL);
1535
1536 /* store pps data */
1537 _check_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4);
1538 gst_bit_writer_reset (&bs);
1539 return TRUE;
1540
1541 /* ERRORS */
1542 bs_error:
1543 {
1544 GST_WARNING ("failed to write PPS NAL unit");
1545 gst_bit_writer_reset (&bs);
1546 return FALSE;
1547 }
1548 }
1549
1550 static gboolean
add_packed_sei_header(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiH264SeiPayloadType payloadtype)1551 add_packed_sei_header (GstVaapiEncoderH264Fei * encoder,
1552 GstVaapiEncPicture * picture, GstVaapiH264SeiPayloadType payloadtype)
1553 {
1554 GstVaapiEncPackedHeader *packed_sei;
1555 GstBitWriter bs, bs_buf_period, bs_pic_timing;
1556 VAEncPackedHeaderParameterBuffer packed_sei_param = { 0 };
1557 guint32 data_bit_size;
1558 guint8 buf_period_payload_size = 0, pic_timing_payload_size = 0;
1559 guint8 *data, *buf_period_payload = NULL, *pic_timing_payload = NULL;
1560 gboolean need_buf_period, need_pic_timing;
1561
1562 gst_bit_writer_init_with_size (&bs_buf_period, 128, FALSE);
1563 gst_bit_writer_init_with_size (&bs_pic_timing, 128, FALSE);
1564 gst_bit_writer_init_with_size (&bs, 128, FALSE);
1565
1566 need_buf_period = GST_VAAPI_H264_SEI_BUF_PERIOD & payloadtype;
1567 need_pic_timing = GST_VAAPI_H264_SEI_PIC_TIMING & payloadtype;
1568
1569 if (need_buf_period) {
1570 /* Write a Buffering Period SEI message */
1571 bs_write_sei_buf_period (&bs_buf_period, encoder, picture);
1572 /* Write byte alignment bits */
1573 if (GST_BIT_WRITER_BIT_SIZE (&bs_buf_period) % 8 != 0)
1574 bs_write_trailing_bits (&bs_buf_period);
1575 buf_period_payload_size = (GST_BIT_WRITER_BIT_SIZE (&bs_buf_period)) / 8;
1576 buf_period_payload = GST_BIT_WRITER_DATA (&bs_buf_period);
1577 }
1578
1579 if (need_pic_timing) {
1580 /* Write a Picture Timing SEI message */
1581 if (GST_VAAPI_H264_SEI_PIC_TIMING & payloadtype)
1582 bs_write_sei_pic_timing (&bs_pic_timing, encoder, picture);
1583 /* Write byte alignment bits */
1584 if (GST_BIT_WRITER_BIT_SIZE (&bs_pic_timing) % 8 != 0)
1585 bs_write_trailing_bits (&bs_pic_timing);
1586 pic_timing_payload_size = (GST_BIT_WRITER_BIT_SIZE (&bs_pic_timing)) / 8;
1587 pic_timing_payload = GST_BIT_WRITER_DATA (&bs_pic_timing);
1588 }
1589
1590 /* Write the SEI message */
1591 WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */
1592 bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_NONE, GST_H264_NAL_SEI);
1593
1594 if (need_buf_period) {
1595 WRITE_UINT32 (&bs, GST_H264_SEI_BUF_PERIOD, 8);
1596 WRITE_UINT32 (&bs, buf_period_payload_size, 8);
1597 /* Add buffering period sei message */
1598 gst_bit_writer_put_bytes (&bs, buf_period_payload, buf_period_payload_size);
1599 }
1600
1601 if (need_pic_timing) {
1602 WRITE_UINT32 (&bs, GST_H264_SEI_PIC_TIMING, 8);
1603 WRITE_UINT32 (&bs, pic_timing_payload_size, 8);
1604 /* Add picture timing sei message */
1605 gst_bit_writer_put_bytes (&bs, pic_timing_payload, pic_timing_payload_size);
1606 }
1607
1608 /* rbsp_trailing_bits */
1609 bs_write_trailing_bits (&bs);
1610
1611 g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
1612 data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
1613 data = GST_BIT_WRITER_DATA (&bs);
1614
1615 packed_sei_param.type = VA_ENC_PACKED_HEADER_H264_SEI;
1616 packed_sei_param.bit_length = data_bit_size;
1617 packed_sei_param.has_emulation_bytes = 0;
1618
1619 packed_sei = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
1620 &packed_sei_param, sizeof (packed_sei_param),
1621 data, (data_bit_size + 7) / 8);
1622 g_assert (packed_sei);
1623
1624 gst_vaapi_enc_picture_add_packed_header (picture, packed_sei);
1625 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & packed_sei, NULL);
1626
1627 gst_bit_writer_reset (&bs_buf_period);
1628 gst_bit_writer_reset (&bs_pic_timing);
1629 gst_bit_writer_reset (&bs);
1630 return TRUE;
1631
1632 /* ERRORS */
1633 bs_error:
1634 {
1635 GST_WARNING ("failed to write SEI NAL unit");
1636 gst_bit_writer_reset (&bs_buf_period);
1637 gst_bit_writer_reset (&bs_pic_timing);
1638 gst_bit_writer_reset (&bs);
1639 return FALSE;
1640 }
1641 }
1642
1643 static gboolean
get_nal_hdr_attributes(GstVaapiEncPicture * picture,guint8 * nal_ref_idc,guint8 * nal_unit_type)1644 get_nal_hdr_attributes (GstVaapiEncPicture * picture,
1645 guint8 * nal_ref_idc, guint8 * nal_unit_type)
1646 {
1647 switch (picture->type) {
1648 case GST_VAAPI_PICTURE_TYPE_I:
1649 *nal_ref_idc = GST_H264_NAL_REF_IDC_HIGH;
1650 if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
1651 *nal_unit_type = GST_H264_NAL_SLICE_IDR;
1652 else
1653 *nal_unit_type = GST_H264_NAL_SLICE;
1654 break;
1655 case GST_VAAPI_PICTURE_TYPE_P:
1656 *nal_ref_idc = GST_H264_NAL_REF_IDC_MEDIUM;
1657 *nal_unit_type = GST_H264_NAL_SLICE;
1658 break;
1659 case GST_VAAPI_PICTURE_TYPE_B:
1660 *nal_ref_idc = GST_H264_NAL_REF_IDC_NONE;
1661 *nal_unit_type = GST_H264_NAL_SLICE;
1662 break;
1663 default:
1664 return FALSE;
1665 }
1666 return TRUE;
1667 }
1668
1669 /* Adds the supplied prefix nal header to the list of packed
1670 headers to pass down as-is to the encoder */
1671 static gboolean
add_packed_prefix_nal_header(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiEncSlice * slice)1672 add_packed_prefix_nal_header (GstVaapiEncoderH264Fei * encoder,
1673 GstVaapiEncPicture * picture, GstVaapiEncSlice * slice)
1674 {
1675 GstVaapiEncPackedHeader *packed_prefix_nal;
1676 GstBitWriter bs;
1677 VAEncPackedHeaderParameterBuffer packed_prefix_nal_param = { 0 };
1678 guint32 data_bit_size;
1679 guint8 *data;
1680 guint8 nal_ref_idc, nal_unit_type;
1681
1682 gst_bit_writer_init_with_size (&bs, 128, FALSE);
1683 WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */
1684
1685 if (!get_nal_hdr_attributes (picture, &nal_ref_idc, &nal_unit_type))
1686 goto bs_error;
1687 nal_unit_type = GST_H264_NAL_PREFIX_UNIT;
1688
1689 bs_write_nal_header (&bs, nal_ref_idc, nal_unit_type);
1690 bs_write_nal_header_mvc_extension (&bs, picture, encoder->view_idx);
1691 g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
1692 data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
1693 data = GST_BIT_WRITER_DATA (&bs);
1694
1695 packed_prefix_nal_param.type = VAEncPackedHeaderRawData;
1696 packed_prefix_nal_param.bit_length = data_bit_size;
1697 packed_prefix_nal_param.has_emulation_bytes = 0;
1698
1699 packed_prefix_nal =
1700 gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
1701 &packed_prefix_nal_param, sizeof (packed_prefix_nal_param), data,
1702 (data_bit_size + 7) / 8);
1703 g_assert (packed_prefix_nal);
1704
1705 gst_vaapi_enc_slice_add_packed_header (slice, packed_prefix_nal);
1706 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & packed_prefix_nal,
1707 NULL);
1708
1709 gst_bit_writer_reset (&bs);
1710
1711 return TRUE;
1712
1713 /* ERRORS */
1714 bs_error:
1715 {
1716 GST_WARNING ("failed to write Prefix NAL unit header");
1717 gst_bit_writer_reset (&bs);
1718 return FALSE;
1719 }
1720 }
1721
1722 /* Adds the supplied slice header to the list of packed
1723 headers to pass down as-is to the encoder */
1724 static gboolean
add_packed_slice_header(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiEncSlice * slice)1725 add_packed_slice_header (GstVaapiEncoderH264Fei * encoder,
1726 GstVaapiEncPicture * picture, GstVaapiEncSlice * slice)
1727 {
1728 GstVaapiEncPackedHeader *packed_slice;
1729 GstBitWriter bs;
1730 VAEncPackedHeaderParameterBuffer packed_slice_param = { 0 };
1731 const VAEncSliceParameterBufferH264 *const slice_param = slice->param;
1732 guint32 data_bit_size;
1733 guint8 *data;
1734 guint8 nal_ref_idc, nal_unit_type;
1735
1736 gst_bit_writer_init_with_size (&bs, 128, FALSE);
1737 WRITE_UINT32 (&bs, 0x00000001, 32); /* start code */
1738
1739 if (!get_nal_hdr_attributes (picture, &nal_ref_idc, &nal_unit_type))
1740 goto bs_error;
1741 /* pack nal_unit_header_mvc_extension() for the non base view */
1742 if (encoder->is_mvc && encoder->view_idx) {
1743 bs_write_nal_header (&bs, nal_ref_idc, GST_H264_NAL_SLICE_EXT);
1744 bs_write_nal_header_mvc_extension (&bs, picture,
1745 encoder->view_ids[encoder->view_idx]);
1746 } else
1747 bs_write_nal_header (&bs, nal_ref_idc, nal_unit_type);
1748
1749 bs_write_slice (&bs, slice_param, encoder, picture);
1750 data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
1751 data = GST_BIT_WRITER_DATA (&bs);
1752
1753 packed_slice_param.type = VAEncPackedHeaderSlice;
1754 packed_slice_param.bit_length = data_bit_size;
1755 packed_slice_param.has_emulation_bytes = 0;
1756
1757 packed_slice = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
1758 &packed_slice_param, sizeof (packed_slice_param),
1759 data, (data_bit_size + 7) / 8);
1760 g_assert (packed_slice);
1761
1762 gst_vaapi_enc_slice_add_packed_header (slice, packed_slice);
1763 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & packed_slice,
1764 NULL);
1765
1766 gst_bit_writer_reset (&bs);
1767 return TRUE;
1768
1769 /* ERRORS */
1770 bs_error:
1771 {
1772 GST_WARNING ("failed to write Slice NAL unit header");
1773 gst_bit_writer_reset (&bs);
1774 return FALSE;
1775 }
1776 }
1777
1778 /* Reference picture management */
1779 static void
reference_pic_free(GstVaapiEncoderH264Fei * encoder,GstVaapiEncoderH264FeiRef * ref)1780 reference_pic_free (GstVaapiEncoderH264Fei * encoder,
1781 GstVaapiEncoderH264FeiRef * ref)
1782 {
1783 if (!ref)
1784 return;
1785 if (ref->pic)
1786 gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), ref->pic);
1787 g_slice_free (GstVaapiEncoderH264FeiRef, ref);
1788 }
1789
1790 static inline GstVaapiEncoderH264FeiRef *
reference_pic_create(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiSurfaceProxy * surface)1791 reference_pic_create (GstVaapiEncoderH264Fei * encoder,
1792 GstVaapiEncPicture * picture, GstVaapiSurfaceProxy * surface)
1793 {
1794 GstVaapiEncoderH264FeiRef *const ref =
1795 g_slice_new0 (GstVaapiEncoderH264FeiRef);
1796
1797 ref->pic = surface;
1798 ref->frame_num = picture->frame_num;
1799 ref->poc = picture->poc;
1800 return ref;
1801 }
1802
1803 static gboolean
reference_list_update(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiSurfaceProxy * surface)1804 reference_list_update (GstVaapiEncoderH264Fei * encoder,
1805 GstVaapiEncPicture * picture, GstVaapiSurfaceProxy * surface)
1806 {
1807 GstVaapiEncoderH264FeiRef *ref;
1808 GstVaapiH264ViewRefPool *const ref_pool =
1809 &encoder->ref_pools[encoder->view_idx];
1810
1811 if (GST_VAAPI_PICTURE_TYPE_B == picture->type) {
1812 gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), surface);
1813 return TRUE;
1814 }
1815 if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) {
1816 while (!g_queue_is_empty (&ref_pool->ref_list))
1817 reference_pic_free (encoder, g_queue_pop_head (&ref_pool->ref_list));
1818 } else if (g_queue_get_length (&ref_pool->ref_list) >=
1819 ref_pool->max_ref_frames) {
1820 reference_pic_free (encoder, g_queue_pop_head (&ref_pool->ref_list));
1821 }
1822 ref = reference_pic_create (encoder, picture, surface);
1823 g_queue_push_tail (&ref_pool->ref_list, ref);
1824 g_assert (g_queue_get_length (&ref_pool->ref_list) <=
1825 ref_pool->max_ref_frames);
1826 return TRUE;
1827 }
1828
1829 static gboolean
reference_list_init(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiEncoderH264FeiRef ** reflist_0,guint * reflist_0_count,GstVaapiEncoderH264FeiRef ** reflist_1,guint * reflist_1_count)1830 reference_list_init (GstVaapiEncoderH264Fei * encoder,
1831 GstVaapiEncPicture * picture,
1832 GstVaapiEncoderH264FeiRef ** reflist_0,
1833 guint * reflist_0_count,
1834 GstVaapiEncoderH264FeiRef ** reflist_1, guint * reflist_1_count)
1835 {
1836 GstVaapiEncoderH264FeiRef *tmp;
1837 GstVaapiH264ViewRefPool *const ref_pool =
1838 &encoder->ref_pools[encoder->view_idx];
1839 GList *iter, *list_0_start = NULL, *list_1_start = NULL;
1840 guint count;
1841
1842 *reflist_0_count = 0;
1843 *reflist_1_count = 0;
1844 if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
1845 return TRUE;
1846
1847 iter = g_queue_peek_tail_link (&ref_pool->ref_list);
1848 for (; iter; iter = g_list_previous (iter)) {
1849 tmp = (GstVaapiEncoderH264FeiRef *) iter->data;
1850 g_assert (tmp && tmp->poc != picture->poc);
1851 if (_poc_greater_than (picture->poc, tmp->poc, encoder->max_pic_order_cnt)) {
1852 list_0_start = iter;
1853 list_1_start = g_list_next (iter);
1854 break;
1855 }
1856 }
1857
1858 /* order reflist_0 */
1859 g_assert (list_0_start);
1860 iter = list_0_start;
1861 count = 0;
1862 for (; iter; iter = g_list_previous (iter)) {
1863 reflist_0[count] = (GstVaapiEncoderH264FeiRef *) iter->data;
1864 ++count;
1865 }
1866 *reflist_0_count = count;
1867
1868 if (picture->type != GST_VAAPI_PICTURE_TYPE_B)
1869 return TRUE;
1870
1871 /* order reflist_1 */
1872 count = 0;
1873 iter = list_1_start;
1874 for (; iter; iter = g_list_next (iter)) {
1875 reflist_1[count] = (GstVaapiEncoderH264FeiRef *) iter->data;
1876 ++count;
1877 }
1878 *reflist_1_count = count;
1879 return TRUE;
1880 }
1881
1882 /* Fills in VA sequence parameter buffer */
1883 static gboolean
fill_sequence(GstVaapiEncoderH264Fei * encoder,GstVaapiEncSequence * sequence)1884 fill_sequence (GstVaapiEncoderH264Fei * encoder, GstVaapiEncSequence * sequence)
1885 {
1886 VAEncSequenceParameterBufferH264 *const seq_param = sequence->param;
1887 GstVaapiH264ViewRefPool *const ref_pool =
1888 &encoder->ref_pools[encoder->view_idx];
1889
1890 memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferH264));
1891 seq_param->seq_parameter_set_id = encoder->view_idx;
1892 seq_param->level_idc = encoder->level_idc;
1893 seq_param->intra_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder);
1894 seq_param->intra_idr_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder);
1895 seq_param->ip_period = seq_param->intra_period > 1 ?
1896 (1 + encoder->num_bframes) : 0;
1897 seq_param->bits_per_second = encoder->bitrate_bits;
1898
1899 seq_param->max_num_ref_frames = ref_pool->max_ref_frames;
1900 seq_param->picture_width_in_mbs = encoder->mb_width;
1901 seq_param->picture_height_in_mbs = encoder->mb_height;
1902
1903 /*sequence field values */
1904 seq_param->seq_fields.value = 0;
1905 seq_param->seq_fields.bits.chroma_format_idc = 1;
1906 seq_param->seq_fields.bits.frame_mbs_only_flag = 1;
1907 seq_param->seq_fields.bits.mb_adaptive_frame_field_flag = FALSE;
1908 seq_param->seq_fields.bits.seq_scaling_matrix_present_flag = FALSE;
1909 /* direct_8x8_inference_flag default false */
1910 seq_param->seq_fields.bits.direct_8x8_inference_flag = FALSE;
1911 g_assert (encoder->log2_max_frame_num >= 4);
1912 seq_param->seq_fields.bits.log2_max_frame_num_minus4 =
1913 encoder->log2_max_frame_num - 4;
1914 /* picture order count */
1915 encoder->pic_order_cnt_type = seq_param->seq_fields.bits.pic_order_cnt_type =
1916 0;
1917 g_assert (encoder->log2_max_pic_order_cnt >= 4);
1918 seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 =
1919 encoder->log2_max_pic_order_cnt - 4;
1920
1921 seq_param->bit_depth_luma_minus8 = 0;
1922 seq_param->bit_depth_chroma_minus8 = 0;
1923
1924 /* not used if pic_order_cnt_type == 0 */
1925 if (seq_param->seq_fields.bits.pic_order_cnt_type == 1) {
1926 encoder->delta_pic_order_always_zero_flag =
1927 seq_param->seq_fields.bits.delta_pic_order_always_zero_flag = TRUE;
1928 seq_param->num_ref_frames_in_pic_order_cnt_cycle = 0;
1929 seq_param->offset_for_non_ref_pic = 0;
1930 seq_param->offset_for_top_to_bottom_field = 0;
1931 memset (seq_param->offset_for_ref_frame, 0,
1932 sizeof (seq_param->offset_for_ref_frame));
1933 }
1934
1935 /* frame_cropping_flag */
1936 if ((GST_VAAPI_ENCODER_WIDTH (encoder) & 15) ||
1937 (GST_VAAPI_ENCODER_HEIGHT (encoder) & 15)) {
1938 static const guint SubWidthC[] = { 1, 2, 2, 1 };
1939 static const guint SubHeightC[] = { 1, 2, 1, 1 };
1940 const guint CropUnitX =
1941 SubWidthC[seq_param->seq_fields.bits.chroma_format_idc];
1942 const guint CropUnitY =
1943 SubHeightC[seq_param->seq_fields.bits.chroma_format_idc] *
1944 (2 - seq_param->seq_fields.bits.frame_mbs_only_flag);
1945
1946 seq_param->frame_cropping_flag = 1;
1947 seq_param->frame_crop_left_offset = 0;
1948 seq_param->frame_crop_right_offset =
1949 (16 * encoder->mb_width -
1950 GST_VAAPI_ENCODER_WIDTH (encoder)) / CropUnitX;
1951 seq_param->frame_crop_top_offset = 0;
1952 seq_param->frame_crop_bottom_offset =
1953 (16 * encoder->mb_height -
1954 GST_VAAPI_ENCODER_HEIGHT (encoder)) / CropUnitY;
1955 }
1956
1957 /* VUI parameters are always set, at least for timing_info (framerate) */
1958 seq_param->vui_parameters_present_flag = TRUE;
1959 if (seq_param->vui_parameters_present_flag) {
1960 seq_param->vui_fields.bits.aspect_ratio_info_present_flag = TRUE;
1961 if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) {
1962 const GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
1963 seq_param->aspect_ratio_idc = 0xff;
1964 seq_param->sar_width = GST_VIDEO_INFO_PAR_N (vip);
1965 seq_param->sar_height = GST_VIDEO_INFO_PAR_D (vip);
1966 }
1967 seq_param->vui_fields.bits.bitstream_restriction_flag = FALSE;
1968 /* if vui_parameters_present_flag is TRUE and sps data belongs to
1969 * subset sps, timing_info_preset_flag should be zero (H.7.4.2.1.1) */
1970 seq_param->vui_fields.bits.timing_info_present_flag = !encoder->view_idx;
1971 if (seq_param->vui_fields.bits.timing_info_present_flag) {
1972 seq_param->num_units_in_tick = GST_VAAPI_ENCODER_FPS_D (encoder);
1973 seq_param->time_scale = GST_VAAPI_ENCODER_FPS_N (encoder) * 2;
1974 }
1975 }
1976 return TRUE;
1977 }
1978
1979 /* Fills in VA picture parameter buffer */
1980 static gboolean
fill_picture(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiCodedBuffer * codedbuf,GstVaapiSurfaceProxy * surface)1981 fill_picture (GstVaapiEncoderH264Fei * encoder, GstVaapiEncPicture * picture,
1982 GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
1983 {
1984 VAEncPictureParameterBufferH264 *const pic_param = picture->param;
1985 GstVaapiH264ViewRefPool *const ref_pool =
1986 &encoder->ref_pools[encoder->view_idx];
1987 GstVaapiEncoderH264FeiRef *ref_pic;
1988 GList *reflist;
1989 guint i;
1990
1991 memset (pic_param, 0, sizeof (VAEncPictureParameterBufferH264));
1992
1993 /* reference list, */
1994 pic_param->CurrPic.picture_id = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
1995 pic_param->CurrPic.TopFieldOrderCnt = picture->poc;
1996 i = 0;
1997 if (picture->type != GST_VAAPI_PICTURE_TYPE_I) {
1998 for (reflist = g_queue_peek_head_link (&ref_pool->ref_list);
1999 reflist; reflist = g_list_next (reflist)) {
2000 ref_pic = reflist->data;
2001 g_assert (ref_pic && ref_pic->pic &&
2002 GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic) != VA_INVALID_ID);
2003
2004 pic_param->ReferenceFrames[i].picture_id =
2005 GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic);
2006 pic_param->ReferenceFrames[i].TopFieldOrderCnt = ref_pic->poc;
2007 pic_param->ReferenceFrames[i].flags |=
2008 VA_PICTURE_H264_SHORT_TERM_REFERENCE;
2009 pic_param->ReferenceFrames[i].frame_idx = ref_pic->frame_num;
2010
2011 ++i;
2012 }
2013 g_assert (i <= 16 && i <= ref_pool->max_ref_frames);
2014 }
2015 for (; i < 16; ++i) {
2016 pic_param->ReferenceFrames[i].picture_id = VA_INVALID_ID;
2017 }
2018 pic_param->coded_buf = GST_VAAPI_OBJECT_ID (codedbuf);
2019
2020 pic_param->pic_parameter_set_id = encoder->view_idx;
2021 pic_param->seq_parameter_set_id = encoder->view_idx ? 1 : 0;
2022 pic_param->last_picture = 0; /* means last encoding picture */
2023 pic_param->frame_num = picture->frame_num;
2024 pic_param->pic_init_qp = encoder->init_qp;
2025 pic_param->num_ref_idx_l0_active_minus1 =
2026 (ref_pool->max_reflist0_count ? (ref_pool->max_reflist0_count - 1) : 0);
2027 pic_param->num_ref_idx_l1_active_minus1 =
2028 (ref_pool->max_reflist1_count ? (ref_pool->max_reflist1_count - 1) : 0);
2029 pic_param->chroma_qp_index_offset = 0;
2030 pic_param->second_chroma_qp_index_offset = 0;
2031
2032 /* set picture fields */
2033 pic_param->pic_fields.value = 0;
2034 pic_param->pic_fields.bits.idr_pic_flag =
2035 GST_VAAPI_ENC_PICTURE_IS_IDR (picture);
2036 pic_param->pic_fields.bits.reference_pic_flag =
2037 (picture->type != GST_VAAPI_PICTURE_TYPE_B);
2038 pic_param->pic_fields.bits.entropy_coding_mode_flag = encoder->use_cabac;
2039 pic_param->pic_fields.bits.weighted_pred_flag = FALSE;
2040 pic_param->pic_fields.bits.weighted_bipred_idc = 0;
2041 pic_param->pic_fields.bits.constrained_intra_pred_flag = 0;
2042 pic_param->pic_fields.bits.transform_8x8_mode_flag = encoder->use_dct8x8;
2043 /* enable debloking */
2044 pic_param->pic_fields.bits.deblocking_filter_control_present_flag = TRUE;
2045 pic_param->pic_fields.bits.redundant_pic_cnt_present_flag = FALSE;
2046 /* bottom_field_pic_order_in_frame_present_flag */
2047 pic_param->pic_fields.bits.pic_order_present_flag = FALSE;
2048 pic_param->pic_fields.bits.pic_scaling_matrix_present_flag = FALSE;
2049
2050 return TRUE;
2051 }
2052
2053 /* Adds slice headers to picture */
2054 static gboolean
add_slice_headers(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiEncoderH264FeiRef ** reflist_0,guint reflist_0_count,GstVaapiEncoderH264FeiRef ** reflist_1,guint reflist_1_count)2055 add_slice_headers (GstVaapiEncoderH264Fei * encoder,
2056 GstVaapiEncPicture * picture, GstVaapiEncoderH264FeiRef ** reflist_0,
2057 guint reflist_0_count, GstVaapiEncoderH264FeiRef ** reflist_1,
2058 guint reflist_1_count)
2059 {
2060 VAEncSliceParameterBufferH264 *slice_param;
2061 GstVaapiEncSlice *slice;
2062 guint slice_of_mbs, slice_mod_mbs, cur_slice_mbs;
2063 guint mb_size;
2064 guint last_mb_index;
2065 guint i_slice, i_ref;
2066
2067 g_assert (picture);
2068
2069 mb_size = encoder->mb_width * encoder->mb_height;
2070
2071 g_assert (encoder->num_slices && encoder->num_slices < mb_size);
2072 slice_of_mbs = mb_size / encoder->num_slices;
2073 slice_mod_mbs = mb_size % encoder->num_slices;
2074 last_mb_index = 0;
2075 for (i_slice = 0; i_slice < encoder->num_slices; ++i_slice) {
2076 cur_slice_mbs = slice_of_mbs;
2077 if (slice_mod_mbs) {
2078 ++cur_slice_mbs;
2079 --slice_mod_mbs;
2080 }
2081 slice = GST_VAAPI_ENC_SLICE_NEW (H264, encoder);
2082 g_assert (slice && slice->param_id != VA_INVALID_ID);
2083 slice_param = slice->param;
2084
2085 memset (slice_param, 0, sizeof (VAEncSliceParameterBufferH264));
2086 slice_param->macroblock_address = last_mb_index;
2087 slice_param->num_macroblocks = cur_slice_mbs;
2088 slice_param->macroblock_info = VA_INVALID_ID;
2089 slice_param->slice_type = h264_get_slice_type (picture->type);
2090 g_assert ((gint8) slice_param->slice_type != -1);
2091 slice_param->pic_parameter_set_id = encoder->view_idx;
2092 slice_param->idr_pic_id = encoder->idr_num;
2093 slice_param->pic_order_cnt_lsb = picture->poc;
2094
2095 /* not used if pic_order_cnt_type = 0 */
2096 slice_param->delta_pic_order_cnt_bottom = 0;
2097 memset (slice_param->delta_pic_order_cnt, 0,
2098 sizeof (slice_param->delta_pic_order_cnt));
2099
2100 /* only works for B frames */
2101 if (slice_param->slice_type == GST_H264_B_SLICE)
2102 slice_param->direct_spatial_mv_pred_flag = TRUE;
2103 /* default equal to picture parameters */
2104 slice_param->num_ref_idx_active_override_flag = FALSE;
2105 if (picture->type != GST_VAAPI_PICTURE_TYPE_I && reflist_0_count > 0)
2106 slice_param->num_ref_idx_l0_active_minus1 = reflist_0_count - 1;
2107 else
2108 slice_param->num_ref_idx_l0_active_minus1 = 0;
2109 if (picture->type == GST_VAAPI_PICTURE_TYPE_B && reflist_1_count > 0)
2110 slice_param->num_ref_idx_l1_active_minus1 = reflist_1_count - 1;
2111 else
2112 slice_param->num_ref_idx_l1_active_minus1 = 0;
2113 g_assert (slice_param->num_ref_idx_l0_active_minus1 == 0);
2114 g_assert (slice_param->num_ref_idx_l1_active_minus1 == 0);
2115
2116 i_ref = 0;
2117 if (picture->type != GST_VAAPI_PICTURE_TYPE_I) {
2118 for (; i_ref < reflist_0_count; ++i_ref) {
2119 slice_param->RefPicList0[i_ref].picture_id =
2120 GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_0[i_ref]->pic);
2121 slice_param->RefPicList0[i_ref].TopFieldOrderCnt =
2122 reflist_0[i_ref]->poc;
2123 slice_param->RefPicList0[i_ref].flags |=
2124 VA_PICTURE_H264_SHORT_TERM_REFERENCE;
2125 slice_param->RefPicList0[i_ref].frame_idx = reflist_0[i_ref]->frame_num;
2126 }
2127 g_assert (i_ref == 1);
2128 }
2129 for (; i_ref < G_N_ELEMENTS (slice_param->RefPicList0); ++i_ref) {
2130 slice_param->RefPicList0[i_ref].picture_id = VA_INVALID_SURFACE;
2131 }
2132
2133 i_ref = 0;
2134 if (picture->type == GST_VAAPI_PICTURE_TYPE_B) {
2135 for (; i_ref < reflist_1_count; ++i_ref) {
2136 slice_param->RefPicList1[i_ref].picture_id =
2137 GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_1[i_ref]->pic);
2138 slice_param->RefPicList1[i_ref].TopFieldOrderCnt =
2139 reflist_1[i_ref]->poc;
2140 slice_param->RefPicList1[i_ref].flags |=
2141 VA_PICTURE_H264_SHORT_TERM_REFERENCE;
2142 slice_param->RefPicList1[i_ref].frame_idx = reflist_1[i_ref]->frame_num;
2143 }
2144 g_assert (i_ref == 1);
2145 }
2146 for (; i_ref < G_N_ELEMENTS (slice_param->RefPicList1); ++i_ref) {
2147 slice_param->RefPicList1[i_ref].picture_id = VA_INVALID_SURFACE;
2148 }
2149
2150 /* not used if pic_param.pic_fields.bits.weighted_pred_flag == FALSE */
2151 slice_param->luma_log2_weight_denom = 0;
2152 slice_param->chroma_log2_weight_denom = 0;
2153 slice_param->luma_weight_l0_flag = FALSE;
2154 memset (slice_param->luma_weight_l0, 0,
2155 sizeof (slice_param->luma_weight_l0));
2156 memset (slice_param->luma_offset_l0, 0,
2157 sizeof (slice_param->luma_offset_l0));
2158 slice_param->chroma_weight_l0_flag = FALSE;
2159 memset (slice_param->chroma_weight_l0, 0,
2160 sizeof (slice_param->chroma_weight_l0));
2161 memset (slice_param->chroma_offset_l0, 0,
2162 sizeof (slice_param->chroma_offset_l0));
2163 slice_param->luma_weight_l1_flag = FALSE;
2164 memset (slice_param->luma_weight_l1, 0,
2165 sizeof (slice_param->luma_weight_l1));
2166 memset (slice_param->luma_offset_l1, 0,
2167 sizeof (slice_param->luma_offset_l1));
2168 slice_param->chroma_weight_l1_flag = FALSE;
2169 memset (slice_param->chroma_weight_l1, 0,
2170 sizeof (slice_param->chroma_weight_l1));
2171 memset (slice_param->chroma_offset_l1, 0,
2172 sizeof (slice_param->chroma_offset_l1));
2173
2174 slice_param->cabac_init_idc = 0;
2175 slice_param->slice_qp_delta = encoder->init_qp - encoder->min_qp;
2176 if (slice_param->slice_qp_delta > 4)
2177 slice_param->slice_qp_delta = 4;
2178 slice_param->disable_deblocking_filter_idc = 0;
2179 slice_param->slice_alpha_c0_offset_div2 = 2;
2180 slice_param->slice_beta_offset_div2 = 2;
2181
2182 /* set calculation for next slice */
2183 last_mb_index += cur_slice_mbs;
2184
2185 /* add packed Prefix NAL unit before each Coded slice NAL in base view */
2186 if (encoder->is_mvc && !encoder->view_idx &&
2187 (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2188 VA_ENC_PACKED_HEADER_RAW_DATA)
2189 && !add_packed_prefix_nal_header (encoder, picture, slice))
2190 goto error_create_packed_prefix_nal_hdr;
2191 if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2192 VA_ENC_PACKED_HEADER_SLICE)
2193 && !add_packed_slice_header (encoder, picture, slice))
2194 goto error_create_packed_slice_hdr;
2195
2196 gst_vaapi_enc_picture_add_slice (picture, slice);
2197 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & slice, NULL);
2198 }
2199 g_assert (last_mb_index == mb_size);
2200 return TRUE;
2201
2202 error_create_packed_slice_hdr:
2203 {
2204 GST_ERROR ("failed to create packed slice header buffer");
2205 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & slice, NULL);
2206 return FALSE;
2207 }
2208 error_create_packed_prefix_nal_hdr:
2209 {
2210 GST_ERROR ("failed to create packed prefix nal header buffer");
2211 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & slice, NULL);
2212 return FALSE;
2213 }
2214 }
2215
2216 /* Generates and submits SPS header accordingly into the bitstream */
2217 static gboolean
ensure_sequence(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture)2218 ensure_sequence (GstVaapiEncoderH264Fei * encoder, GstVaapiEncPicture * picture)
2219 {
2220 GstVaapiEncSequence *sequence = NULL;
2221
2222 /* submit an SPS header before every new I-frame, if codec config changed */
2223 if (!encoder->config_changed || picture->type != GST_VAAPI_PICTURE_TYPE_I)
2224 return TRUE;
2225
2226 sequence = GST_VAAPI_ENC_SEQUENCE_NEW (H264, encoder);
2227 if (!sequence || !fill_sequence (encoder, sequence))
2228 goto error_create_seq_param;
2229
2230 /* add subset sps for non-base view and sps for base view */
2231 if (encoder->is_mvc && encoder->view_idx) {
2232 if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2233 VA_ENC_PACKED_HEADER_SEQUENCE)
2234 && !add_packed_sequence_header_mvc (encoder, picture, sequence))
2235 goto error_create_packed_seq_hdr;
2236 } else {
2237 if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2238 VA_ENC_PACKED_HEADER_SEQUENCE)
2239 && !add_packed_sequence_header (encoder, picture, sequence))
2240 goto error_create_packed_seq_hdr;
2241 }
2242
2243 if (sequence) {
2244 gst_vaapi_enc_picture_set_sequence (picture, sequence);
2245 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & sequence, NULL);
2246 }
2247
2248 if (!encoder->is_mvc || encoder->view_idx > 0)
2249 encoder->config_changed = FALSE;
2250 return TRUE;
2251
2252 /* ERRORS */
2253 error_create_seq_param:
2254 {
2255 GST_ERROR ("failed to create sequence parameter buffer (SPS)");
2256 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & sequence, NULL);
2257 return FALSE;
2258 }
2259 error_create_packed_seq_hdr:
2260 {
2261 GST_ERROR ("failed to create packed sequence header buffer");
2262 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & sequence, NULL);
2263 return FALSE;
2264 }
2265 }
2266
2267 /* Generates additional fei control parameters */
2268 static gboolean
ensure_fei_misc_params(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiCodedBufferProxy * codedbuf_proxy)2269 ensure_fei_misc_params (GstVaapiEncoderH264Fei * encoder,
2270 GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf_proxy)
2271 {
2272 GstVaapiEncMiscParam *misc = NULL;
2273 GstVaapiSurfaceProxy *surface_proxy = NULL;
2274
2275 VAEncMiscParameterFEIFrameControlH264 *misc_fei_pic_control_param;
2276 guint mbcode_size = 0;
2277 guint mv_size = 0;
2278 guint dist_size = 0;
2279 gboolean enable_out = FALSE;
2280
2281 /* fei pic control params */
2282 misc = GST_VAAPI_ENC_FEI_MISC_PARAM_NEW (H264, encoder);
2283 g_assert (misc);
2284 if (!misc)
2285 return FALSE;
2286 misc_fei_pic_control_param = misc->data;
2287 surface_proxy = picture->proxy;
2288
2289 enable_out = ((encoder->is_stats_out_enabled &&
2290 (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC_PAK)) ||
2291 (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC)) ? TRUE : FALSE;
2292
2293 misc_fei_pic_control_param->function = encoder->fei_mode;
2294 misc_fei_pic_control_param->search_path = encoder->search_path;
2295 misc_fei_pic_control_param->num_mv_predictors_l0 =
2296 encoder->num_mv_predictors_l0;
2297 misc_fei_pic_control_param->num_mv_predictors_l1 =
2298 encoder->num_mv_predictors_l1;
2299 misc_fei_pic_control_param->len_sp = encoder->len_sp;
2300 misc_fei_pic_control_param->sub_mb_part_mask = encoder->submb_part_mask;
2301 if (!encoder->use_dct8x8)
2302 misc_fei_pic_control_param->intra_part_mask = encoder->intra_part_mask | 2;
2303 misc_fei_pic_control_param->multi_pred_l0 = encoder->multi_predL0;
2304 misc_fei_pic_control_param->multi_pred_l1 = encoder->multi_predL1;
2305 misc_fei_pic_control_param->sub_pel_mode = encoder->subpel_mode;
2306 misc_fei_pic_control_param->inter_sad = encoder->inter_sad;
2307 misc_fei_pic_control_param->intra_sad = encoder->intra_sad;
2308 misc_fei_pic_control_param->distortion_type = 0;
2309 misc_fei_pic_control_param->repartition_check_enable = 0;
2310 misc_fei_pic_control_param->adaptive_search = encoder->adaptive_search;
2311 misc_fei_pic_control_param->mb_size_ctrl = 0;
2312 misc_fei_pic_control_param->ref_width = encoder->ref_width;
2313 misc_fei_pic_control_param->ref_height = encoder->ref_height;
2314 misc_fei_pic_control_param->search_window = encoder->search_window;
2315
2316 if ((encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC_PAK) ||
2317 (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC)) {
2318
2319 /***** ENC_PAK/ENC input: mv_predictor *****/
2320 if (surface_proxy->mvpred) {
2321 misc_fei_pic_control_param->mv_predictor =
2322 GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->mvpred)->param_id;
2323 misc_fei_pic_control_param->mv_predictor_enable = TRUE;
2324 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) &
2325 picture->mvpred, surface_proxy->mvpred);
2326 } else {
2327 misc_fei_pic_control_param->mv_predictor = VA_INVALID_ID;
2328 misc_fei_pic_control_param->mv_predictor_enable = FALSE;
2329 picture->mvpred = NULL;
2330 }
2331
2332 /***** ENC_PAK/ENC input: qp ******/
2333 if (surface_proxy->qp) {
2334 misc_fei_pic_control_param->qp =
2335 GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->qp)->param_id;
2336 misc_fei_pic_control_param->mb_qp = TRUE;
2337 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) &
2338 picture->qp, surface_proxy->qp);
2339 } else {
2340 misc_fei_pic_control_param->qp = VA_INVALID_ID;
2341 misc_fei_pic_control_param->mb_qp = FALSE;
2342 picture->qp = NULL;
2343 }
2344
2345 /***** ENC_PAK/ENC input: mb_control ******/
2346 if (surface_proxy->mbcntrl) {
2347 misc_fei_pic_control_param->mb_ctrl =
2348 GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->mbcntrl)->param_id;
2349 misc_fei_pic_control_param->mb_input = TRUE;
2350 gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) &
2351 picture->mbcntrl, surface_proxy->mbcntrl);
2352 } else {
2353 misc_fei_pic_control_param->mb_ctrl = VA_INVALID_ID;
2354 misc_fei_pic_control_param->mb_input = FALSE;
2355 picture->mbcntrl = NULL;
2356 }
2357 }
2358
2359 if (enable_out) {
2360
2361 mbcode_size = sizeof (VAEncFEIMBCodeH264) *
2362 encoder->mb_width * encoder->mb_height;
2363 mv_size = sizeof (VAMotionVector) * 16 *
2364 encoder->mb_width * encoder->mb_height;
2365 dist_size = sizeof (VAEncFEIDistortionH264) *
2366 encoder->mb_width * encoder->mb_height;
2367
2368 /***** ENC_PAK/ENC output: macroblock code buffer *****/
2369 codedbuf_proxy->mbcode =
2370 gst_vaapi_enc_fei_mb_code_new (GST_VAAPI_ENCODER_CAST (encoder),
2371 NULL, mbcode_size);
2372 misc_fei_pic_control_param->mb_code_data =
2373 GST_VAAPI_FEI_CODEC_OBJECT (codedbuf_proxy->mbcode)->param_id;
2374 picture->mbcode = gst_vaapi_codec_object_ref (codedbuf_proxy->mbcode);
2375
2376 /***** ENC_PAK/ENC output: motion vector buffer *****/
2377 codedbuf_proxy->mv =
2378 gst_vaapi_enc_fei_mv_new (GST_VAAPI_ENCODER_CAST (encoder), NULL,
2379 mv_size);
2380 misc_fei_pic_control_param->mv_data =
2381 GST_VAAPI_FEI_CODEC_OBJECT (codedbuf_proxy->mv)->param_id;
2382 picture->mv = gst_vaapi_codec_object_ref (codedbuf_proxy->mv);
2383
2384 /***** ENC_PAK/ENC output: distortion buffer *****/
2385 codedbuf_proxy->dist =
2386 gst_vaapi_enc_fei_distortion_new (GST_VAAPI_ENCODER_CAST (encoder),
2387 NULL, dist_size);
2388 misc_fei_pic_control_param->distortion =
2389 GST_VAAPI_FEI_CODEC_OBJECT (codedbuf_proxy->dist)->param_id;
2390 picture->dist = gst_vaapi_codec_object_ref (codedbuf_proxy->dist);
2391
2392 } else if (encoder->fei_mode == GST_VAAPI_FEI_MODE_PAK) {
2393
2394 g_assert (surface_proxy->mbcode != NULL);
2395 g_assert (surface_proxy->mv != NULL);
2396
2397 /***** PAK input: macroblock code buffer *****/
2398 misc_fei_pic_control_param->mb_code_data =
2399 GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->mbcode)->param_id;
2400 picture->mbcode = gst_vaapi_codec_object_ref (surface_proxy->mbcode);
2401
2402 /***** PAK input: motion vector buffer *****/
2403 misc_fei_pic_control_param->mv_data =
2404 GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->mv)->param_id;
2405 picture->mv = gst_vaapi_codec_object_ref (surface_proxy->mv);
2406 } else {
2407
2408 codedbuf_proxy->mbcode = picture->mbcode = NULL;
2409 codedbuf_proxy->mv = picture->mv = NULL;
2410 codedbuf_proxy->dist = picture->dist = NULL;
2411 misc_fei_pic_control_param->mb_code_data = VA_INVALID_ID;
2412 misc_fei_pic_control_param->mv_data = VA_INVALID_ID;
2413 misc_fei_pic_control_param->distortion = VA_INVALID_ID;
2414 }
2415
2416 gst_vaapi_enc_picture_add_misc_param (picture, misc);
2417 gst_vaapi_codec_object_replace (&misc, NULL);
2418 return TRUE;
2419 }
2420
2421 /* Generates additional control parameters */
2422 static gboolean
ensure_misc_params(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture)2423 ensure_misc_params (GstVaapiEncoderH264Fei * encoder,
2424 GstVaapiEncPicture * picture)
2425 {
2426 GstVaapiEncMiscParam *misc = NULL;
2427 VAEncMiscParameterRateControl *rate_control;
2428
2429 /* HRD params */
2430 misc = GST_VAAPI_ENC_MISC_PARAM_NEW (HRD, encoder);
2431 g_assert (misc);
2432 if (!misc)
2433 return FALSE;
2434 fill_hrd_params (encoder, misc->data);
2435 gst_vaapi_enc_picture_add_misc_param (picture, misc);
2436 gst_vaapi_codec_object_replace (&misc, NULL);
2437
2438 /* RateControl params */
2439 if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR ||
2440 GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_VBR) {
2441 misc = GST_VAAPI_ENC_MISC_PARAM_NEW (RateControl, encoder);
2442 g_assert (misc);
2443 if (!misc)
2444 return FALSE;
2445 rate_control = misc->data;
2446 memset (rate_control, 0, sizeof (VAEncMiscParameterRateControl));
2447 rate_control->bits_per_second = encoder->bitrate_bits;
2448 rate_control->target_percentage = 70;
2449 rate_control->window_size = encoder->cpb_length;
2450 rate_control->initial_qp = encoder->init_qp;
2451 rate_control->min_qp = encoder->min_qp;
2452
2453 #if VA_CHECK_VERSION(1,1,0)
2454 /* @FIXME: should not set this value, should be ignored if set to zero *
2455 * https://github.com/intel/media-driver/issues/587 */
2456 if (rate_control->min_qp > 0)
2457 rate_control->max_qp = 51;
2458 #endif
2459
2460 rate_control->basic_unit_size = 0;
2461 gst_vaapi_enc_picture_add_misc_param (picture, misc);
2462 gst_vaapi_codec_object_replace (&misc, NULL);
2463
2464 if (!encoder->view_idx) {
2465 if ((GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) &&
2466 (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2467 VA_ENC_PACKED_HEADER_MISC) &&
2468 !add_packed_sei_header (encoder, picture,
2469 GST_VAAPI_H264_SEI_BUF_PERIOD | GST_VAAPI_H264_SEI_PIC_TIMING))
2470 goto error_create_packed_sei_hdr;
2471
2472 else if (!GST_VAAPI_ENC_PICTURE_IS_IDR (picture) &&
2473 (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2474 VA_ENC_PACKED_HEADER_MISC) &&
2475 !add_packed_sei_header (encoder, picture,
2476 GST_VAAPI_H264_SEI_PIC_TIMING))
2477 goto error_create_packed_sei_hdr;
2478 }
2479
2480 }
2481 return TRUE;
2482
2483 error_create_packed_sei_hdr:
2484 {
2485 GST_ERROR ("failed to create packed SEI header");
2486 return FALSE;
2487 }
2488 }
2489
2490 /* Generates and submits PPS header accordingly into the bitstream */
2491 static gboolean
ensure_picture(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture,GstVaapiCodedBufferProxy * codedbuf_proxy,GstVaapiSurfaceProxy * surface)2492 ensure_picture (GstVaapiEncoderH264Fei * encoder, GstVaapiEncPicture * picture,
2493 GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
2494 {
2495 GstVaapiCodedBuffer *const codedbuf =
2496 GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
2497 gboolean res = FALSE;
2498
2499 res = fill_picture (encoder, picture, codedbuf, surface);
2500
2501 if (!res)
2502 return FALSE;
2503
2504 if (picture->type == GST_VAAPI_PICTURE_TYPE_I &&
2505 (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2506 VA_ENC_PACKED_HEADER_PICTURE)
2507 && !add_packed_picture_header (encoder, picture)) {
2508 GST_ERROR ("set picture packed header failed");
2509 return FALSE;
2510 }
2511 return TRUE;
2512 }
2513
2514 /* Generates slice headers */
2515 static gboolean
ensure_slices(GstVaapiEncoderH264Fei * encoder,GstVaapiEncPicture * picture)2516 ensure_slices (GstVaapiEncoderH264Fei * encoder, GstVaapiEncPicture * picture)
2517 {
2518 GstVaapiEncoderH264FeiRef *reflist_0[16];
2519 GstVaapiEncoderH264FeiRef *reflist_1[16];
2520 GstVaapiH264ViewRefPool *const ref_pool =
2521 &encoder->ref_pools[encoder->view_idx];
2522 guint reflist_0_count = 0, reflist_1_count = 0;
2523
2524 g_assert (picture);
2525
2526 if (picture->type != GST_VAAPI_PICTURE_TYPE_I &&
2527 !reference_list_init (encoder, picture,
2528 reflist_0, &reflist_0_count, reflist_1, &reflist_1_count)) {
2529 GST_ERROR ("reference list reorder failed");
2530 return FALSE;
2531 }
2532
2533 g_assert (reflist_0_count + reflist_1_count <= ref_pool->max_ref_frames);
2534 if (reflist_0_count > ref_pool->max_reflist0_count)
2535 reflist_0_count = ref_pool->max_reflist0_count;
2536 if (reflist_1_count > ref_pool->max_reflist1_count)
2537 reflist_1_count = ref_pool->max_reflist1_count;
2538
2539 if (!add_slice_headers (encoder, picture,
2540 reflist_0, reflist_0_count, reflist_1, reflist_1_count))
2541 return FALSE;
2542
2543 return TRUE;
2544 }
2545
2546 /* Normalizes bitrate (and CPB size) for HRD conformance */
2547 static void
ensure_bitrate_hrd(GstVaapiEncoderH264Fei * encoder)2548 ensure_bitrate_hrd (GstVaapiEncoderH264Fei * encoder)
2549 {
2550 GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
2551 guint bitrate, cpb_size;
2552
2553 if (!base_encoder->bitrate) {
2554 encoder->bitrate_bits = 0;
2555 return;
2556 }
2557
2558 /* Round down bitrate. This is a hard limit mandated by the user */
2559 g_assert (SX_BITRATE >= 6);
2560 bitrate = (base_encoder->bitrate * 1000) & ~((1U << SX_BITRATE) - 1);
2561 if (bitrate != encoder->bitrate_bits) {
2562 GST_DEBUG ("HRD bitrate: %u bits/sec", bitrate);
2563 encoder->bitrate_bits = bitrate;
2564 encoder->config_changed = TRUE;
2565 }
2566
2567 /* Round up CPB size. This is an HRD compliance detail */
2568 g_assert (SX_CPB_SIZE >= 4);
2569 cpb_size = gst_util_uint64_scale (bitrate, encoder->cpb_length, 1000) &
2570 ~((1U << SX_CPB_SIZE) - 1);
2571 if (cpb_size != encoder->cpb_length_bits) {
2572 GST_DEBUG ("HRD CPB size: %u bits", cpb_size);
2573 encoder->cpb_length_bits = cpb_size;
2574 encoder->config_changed = TRUE;
2575 }
2576 }
2577
2578 /* Estimates a good enough bitrate if none was supplied */
2579 static void
ensure_bitrate(GstVaapiEncoderH264Fei * encoder)2580 ensure_bitrate (GstVaapiEncoderH264Fei * encoder)
2581 {
2582 GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
2583
2584 /* Default compression: 48 bits per macroblock in "high-compression" mode */
2585 switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
2586 case GST_VAAPI_RATECONTROL_CBR:
2587 case GST_VAAPI_RATECONTROL_VBR:
2588 case GST_VAAPI_RATECONTROL_VBR_CONSTRAINED:
2589 if (!base_encoder->bitrate) {
2590 /* According to the literature and testing, CABAC entropy coding
2591 mode could provide for +10% to +18% improvement in general,
2592 thus estimating +15% here ; and using adaptive 8x8 transforms
2593 in I-frames could bring up to +10% improvement. */
2594 guint bits_per_mb = 48;
2595 guint64 factor;
2596
2597 if (!encoder->use_cabac)
2598 bits_per_mb += (bits_per_mb * 15) / 100;
2599 if (!encoder->use_dct8x8)
2600 bits_per_mb += (bits_per_mb * 10) / 100;
2601
2602 factor = encoder->mb_width * encoder->mb_height * bits_per_mb;
2603 base_encoder->bitrate =
2604 gst_util_uint64_scale (factor, GST_VAAPI_ENCODER_FPS_N (encoder),
2605 GST_VAAPI_ENCODER_FPS_D (encoder)) / 1000;
2606 GST_INFO ("target bitrate computed to %u kbps", base_encoder->bitrate);
2607 }
2608 break;
2609 default:
2610 base_encoder->bitrate = 0;
2611 break;
2612 }
2613 ensure_bitrate_hrd (encoder);
2614 }
2615
2616 /* Constructs profile and level information based on user-defined limits */
2617 static GstVaapiEncoderStatus
ensure_profile_and_level(GstVaapiEncoderH264Fei * encoder)2618 ensure_profile_and_level (GstVaapiEncoderH264Fei * encoder)
2619 {
2620 const GstVaapiProfile profile = encoder->profile;
2621 const GstVaapiLevelH264 level = encoder->level;
2622
2623 if (!ensure_tuning (encoder))
2624 GST_WARNING ("Failed to set some of the tuning option as expected! ");
2625
2626 if (!ensure_profile (encoder) || !ensure_profile_limits (encoder))
2627 return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
2628
2629 /* Check HW constraints */
2630 if (!ensure_hw_profile_limits (encoder))
2631 return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
2632 if (encoder->profile_idc > encoder->hw_max_profile_idc)
2633 return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
2634
2635 /* Ensure bitrate if not set already and derive the right level to use */
2636 ensure_bitrate (encoder);
2637 if (!ensure_level (encoder))
2638 return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
2639
2640 if (encoder->profile != profile || encoder->level != level) {
2641 GST_DEBUG ("selected %s profile at level %s",
2642 gst_vaapi_utils_h264_get_profile_string (encoder->profile),
2643 gst_vaapi_utils_h264_get_level_string (encoder->level));
2644 encoder->config_changed = TRUE;
2645 }
2646 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
2647 }
2648
2649 static void
reset_properties(GstVaapiEncoderH264Fei * encoder)2650 reset_properties (GstVaapiEncoderH264Fei * encoder)
2651 {
2652 GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
2653 guint mb_size, i;
2654
2655 if (encoder->idr_period < base_encoder->keyframe_period)
2656 encoder->idr_period = base_encoder->keyframe_period;
2657
2658 if (encoder->min_qp > encoder->init_qp ||
2659 (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP &&
2660 encoder->min_qp < encoder->init_qp))
2661 encoder->min_qp = encoder->init_qp;
2662
2663 mb_size = encoder->mb_width * encoder->mb_height;
2664 if (encoder->num_slices > (mb_size + 1) / 2)
2665 encoder->num_slices = (mb_size + 1) / 2;
2666 g_assert (encoder->num_slices);
2667
2668 if (encoder->num_bframes > (base_encoder->keyframe_period + 1) / 2)
2669 encoder->num_bframes = (base_encoder->keyframe_period + 1) / 2;
2670
2671 /* Workaround : vaapi-intel-driver doesn't have support for
2672 * B-frame encode when utilizing low-power encode hardware block.
2673 * So Disabling b-frame encoding in low-pwer encode.
2674 *
2675 * Fixme :We should query the VAConfigAttribEncMaxRefFrames
2676 * instead of blindly disabling b-frame support and set b/p frame count,
2677 * buffer pool size etc based on that.*/
2678 if ((encoder->num_bframes > 0)
2679 && (encoder->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP)) {
2680 GST_WARNING
2681 ("Disabling b-frame since the driver doesn't supporting it in low-power encode");
2682 encoder->num_bframes = 0;
2683 }
2684
2685 if (encoder->num_bframes > 0 && GST_VAAPI_ENCODER_FPS_N (encoder) > 0)
2686 encoder->cts_offset = gst_util_uint64_scale (GST_SECOND,
2687 GST_VAAPI_ENCODER_FPS_D (encoder), GST_VAAPI_ENCODER_FPS_N (encoder));
2688 else
2689 encoder->cts_offset = 0;
2690
2691 /* init max_frame_num, max_poc */
2692 encoder->log2_max_frame_num =
2693 h264_get_log2_max_frame_num (encoder->idr_period);
2694 g_assert (encoder->log2_max_frame_num >= 4);
2695 encoder->max_frame_num = (1 << encoder->log2_max_frame_num);
2696 encoder->log2_max_pic_order_cnt = encoder->log2_max_frame_num + 1;
2697 encoder->max_pic_order_cnt = (1 << encoder->log2_max_pic_order_cnt);
2698 encoder->idr_num = 0;
2699
2700 for (i = 0; i < encoder->num_views; i++) {
2701 GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i];
2702 GstVaapiH264ViewReorderPool *const reorder_pool =
2703 &encoder->reorder_pools[i];
2704
2705 ref_pool->max_reflist0_count = 1;
2706 ref_pool->max_reflist1_count = encoder->num_bframes > 0;
2707 ref_pool->max_ref_frames = ref_pool->max_reflist0_count
2708 + ref_pool->max_reflist1_count;
2709
2710 reorder_pool->frame_index = 0;
2711 }
2712 }
2713
2714 static gboolean
copy_picture_attrib(GstVaapiEncPicture * dst,GstVaapiEncPicture * src)2715 copy_picture_attrib (GstVaapiEncPicture * dst, GstVaapiEncPicture * src)
2716 {
2717 if (!dst || !src)
2718 return FALSE;
2719
2720 dst->proxy = src->proxy;
2721 dst->surface = src->surface;
2722 dst->type = src->type;
2723 dst->surface_id = src->surface_id;
2724 dst->frame_num = src->frame_num;
2725 dst->poc = src->poc;
2726
2727 return TRUE;
2728 }
2729
2730 static GstVaapiEncoderStatus
gst_vaapi_encoder_h264_fei_encode(GstVaapiEncoder * base_encoder,GstVaapiEncPicture * picture,GstVaapiCodedBufferProxy * codedbuf)2731 gst_vaapi_encoder_h264_fei_encode (GstVaapiEncoder * base_encoder,
2732 GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
2733 {
2734 GstVaapiEncoderH264Fei *const encoder =
2735 GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
2736 GstVaapiEncoder *enc_base_encoder = GST_VAAPI_ENCODER_CAST (encoder->feienc);
2737 GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
2738 GstVaapiSurfaceProxy *reconstruct = NULL;
2739 GstVaapiEncPicture *picture2 = NULL;
2740 GstVaapiFeiInfoToPakH264 info_to_pak;
2741
2742 reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
2743
2744 g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
2745
2746 if ((encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC_PAK)
2747 || (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC)
2748 || (encoder->fei_mode == GST_VAAPI_FEI_MODE_PAK)) {
2749
2750 if (!ensure_sequence (encoder, picture))
2751 goto error;
2752 if (!ensure_misc_params (encoder, picture))
2753 goto error;
2754 if (!encoder->is_fei_disabled
2755 && !ensure_fei_misc_params (encoder, picture, codedbuf))
2756 goto error;
2757 if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
2758 goto error;
2759 if (!ensure_slices (encoder, picture))
2760 goto error;
2761 if (!gst_vaapi_enc_picture_encode (picture))
2762 goto error;
2763
2764 if (!reference_list_update (encoder, picture, reconstruct))
2765 goto error;
2766
2767 } else if (encoder->fei_mode ==
2768 (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK)) {
2769 /*
2770 * ref pool is managed by pak.
2771 * enc will copy from it.
2772 */
2773 if (picture->type != GST_VAAPI_PICTURE_TYPE_I
2774 && !gst_vaapi_feipak_h264_get_ref_pool (encoder->feipak,
2775 &encoder->ref_pool_ptr)) {
2776 GST_ERROR ("failed to get pak ref pool");
2777 status = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
2778 goto error;
2779 }
2780
2781 if (picture->type != GST_VAAPI_PICTURE_TYPE_I
2782 && !gst_vaapi_feienc_h264_set_ref_pool (encoder->feienc,
2783 encoder->ref_pool_ptr)) {
2784 GST_ERROR ("failed to set enc ref pool");
2785 status = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
2786 goto error;
2787 }
2788
2789 status =
2790 gst_vaapi_feienc_h264_encode (enc_base_encoder, picture, reconstruct,
2791 codedbuf, &info_to_pak);
2792 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
2793 GST_ERROR ("failed to process enc class encode");
2794 goto error;
2795 }
2796
2797 /* duplicate a picture for pak */
2798 picture2 = GST_VAAPI_ENC_PICTURE_NEW (H264, base_encoder, picture->frame);
2799 if (!picture2) {
2800 GST_WARNING ("create H264 picture failed, frame timestamp:%"
2801 GST_TIME_FORMAT, GST_TIME_ARGS (picture->frame->pts));
2802 status = GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
2803 goto error;
2804 }
2805 if (!copy_picture_attrib (picture2, picture)) {
2806 status = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
2807 goto error;
2808 }
2809 /* need set picture IDR info for PAK */
2810 if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
2811 GST_VAAPI_ENC_PICTURE_FLAG_SET (picture2, GST_VAAPI_ENC_PICTURE_FLAG_IDR);
2812
2813 status =
2814 gst_vaapi_feipak_h264_encode (encoder->feipak, picture2, codedbuf,
2815 reconstruct, &info_to_pak);
2816 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
2817 GST_ERROR ("failed to process pak class encode");
2818 goto error;
2819 }
2820
2821 /* Free the slice array */
2822 if (info_to_pak.h264_slice_headers)
2823 g_array_free (info_to_pak.h264_slice_headers, TRUE);
2824
2825 gst_vaapi_enc_picture_unref (picture2);
2826
2827 }
2828
2829 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
2830
2831 /* ERRORS */
2832 error:
2833 {
2834 if (reconstruct)
2835 gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
2836 reconstruct);
2837 if (picture2)
2838 gst_vaapi_enc_picture_unref (picture2);
2839 return status;
2840 }
2841 }
2842
2843 static GstVaapiEncoderStatus
gst_vaapi_encoder_h264_fei_flush(GstVaapiEncoder * base_encoder)2844 gst_vaapi_encoder_h264_fei_flush (GstVaapiEncoder * base_encoder)
2845 {
2846 GstVaapiEncoderH264Fei *const encoder =
2847 GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
2848 GstVaapiEncoder *enc_base_encoder = GST_VAAPI_ENCODER_CAST (encoder->feienc);
2849 GstVaapiH264ViewReorderPool *reorder_pool;
2850 GstVaapiEncPicture *pic;
2851 GstVaapiEncoderStatus status;
2852 guint i;
2853
2854 if ((encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC_PAK)
2855 || (encoder->fei_mode == GST_VAAPI_FEI_MODE_PAK)) {
2856 for (i = 0; i < encoder->num_views; i++) {
2857 reorder_pool = &encoder->reorder_pools[i];
2858 reorder_pool->frame_index = 0;
2859 reorder_pool->cur_frame_num = 0;
2860 reorder_pool->cur_present_index = 0;
2861
2862 while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
2863 pic = (GstVaapiEncPicture *)
2864 g_queue_pop_head (&reorder_pool->reorder_frame_list);
2865 gst_vaapi_enc_picture_unref (pic);
2866 }
2867 g_queue_clear (&reorder_pool->reorder_frame_list);
2868 }
2869 } else if (encoder->fei_mode ==
2870 (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK)) {
2871
2872 status = gst_vaapi_feienc_h264_flush (enc_base_encoder);
2873 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
2874 GST_ERROR ("failed to process enc class flush");
2875 return status;
2876 }
2877
2878 status = gst_vaapi_feipak_h264_flush (encoder->feipak);
2879 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
2880 GST_ERROR ("failed to process pak class flush");
2881 return status;
2882 }
2883 } else {
2884 g_assert (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC);
2885 }
2886
2887 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
2888 }
2889
2890 /* Generate "codec-data" buffer */
2891 static GstVaapiEncoderStatus
gst_vaapi_encoder_h264_fei_get_codec_data(GstVaapiEncoder * base_encoder,GstBuffer ** out_buffer_ptr)2892 gst_vaapi_encoder_h264_fei_get_codec_data (GstVaapiEncoder * base_encoder,
2893 GstBuffer ** out_buffer_ptr)
2894 {
2895 GstVaapiEncoderH264Fei *const encoder =
2896 GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
2897 const guint32 configuration_version = 0x01;
2898 const guint32 nal_length_size = 4;
2899 guint8 profile_idc, profile_comp, level_idc;
2900 GstMapInfo sps_info, pps_info;
2901 GstBitWriter bs;
2902 GstBuffer *buffer;
2903
2904 if (!encoder->sps_data || !encoder->pps_data)
2905 return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER;
2906 if (gst_buffer_get_size (encoder->sps_data) < 4)
2907 return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER;
2908
2909 if (!gst_buffer_map (encoder->sps_data, &sps_info, GST_MAP_READ))
2910 goto error_map_sps_buffer;
2911
2912 if (!gst_buffer_map (encoder->pps_data, &pps_info, GST_MAP_READ))
2913 goto error_map_pps_buffer;
2914
2915 /* skip sps_data[0], which is the nal_unit_type */
2916 profile_idc = sps_info.data[1];
2917 profile_comp = sps_info.data[2];
2918 level_idc = sps_info.data[3];
2919
2920 /* Header */
2921 gst_bit_writer_init_with_size (&bs, (sps_info.size + pps_info.size + 64),
2922 FALSE);
2923 WRITE_UINT32 (&bs, configuration_version, 8);
2924 WRITE_UINT32 (&bs, profile_idc, 8);
2925 WRITE_UINT32 (&bs, profile_comp, 8);
2926 WRITE_UINT32 (&bs, level_idc, 8);
2927 WRITE_UINT32 (&bs, 0x3f, 6); /* 111111 */
2928 WRITE_UINT32 (&bs, nal_length_size - 1, 2);
2929 WRITE_UINT32 (&bs, 0x07, 3); /* 111 */
2930
2931 /* Write SPS */
2932 WRITE_UINT32 (&bs, 1, 5); /* SPS count = 1 */
2933 g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
2934 WRITE_UINT32 (&bs, sps_info.size, 16);
2935 gst_bit_writer_put_bytes (&bs, sps_info.data, sps_info.size);
2936
2937 /* Write PPS */
2938 WRITE_UINT32 (&bs, 1, 8); /* PPS count = 1 */
2939 WRITE_UINT32 (&bs, pps_info.size, 16);
2940 gst_bit_writer_put_bytes (&bs, pps_info.data, pps_info.size);
2941
2942 gst_buffer_unmap (encoder->pps_data, &pps_info);
2943 gst_buffer_unmap (encoder->sps_data, &sps_info);
2944
2945 buffer = gst_bit_writer_reset_and_get_buffer (&bs);
2946 if (!buffer)
2947 goto error_alloc_buffer;
2948 *out_buffer_ptr = buffer;
2949
2950 gst_bit_writer_reset (&bs);
2951 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
2952
2953 /* ERRORS */
2954 bs_error:
2955 {
2956 GST_ERROR ("failed to write codec-data");
2957 gst_buffer_unmap (encoder->sps_data, &sps_info);
2958 gst_buffer_unmap (encoder->pps_data, &pps_info);
2959 gst_bit_writer_reset (&bs);
2960 return FALSE;
2961 }
2962 error_map_sps_buffer:
2963 {
2964 GST_ERROR ("failed to map SPS packed header");
2965 return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
2966 }
2967 error_map_pps_buffer:
2968 {
2969 GST_ERROR ("failed to map PPS packed header");
2970 gst_buffer_unmap (encoder->sps_data, &sps_info);
2971 return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
2972 }
2973 error_alloc_buffer:
2974 {
2975 GST_ERROR ("failed to allocate codec-data buffer");
2976 gst_bit_writer_reset (&bs);
2977 return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
2978 }
2979 }
2980
2981 static GstVaapiEncoderStatus
gst_vaapi_encoder_h264_fei_reordering(GstVaapiEncoder * base_encoder,GstVideoCodecFrame * frame,GstVaapiEncPicture ** output)2982 gst_vaapi_encoder_h264_fei_reordering (GstVaapiEncoder * base_encoder,
2983 GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
2984 {
2985 GstVaapiEncoderH264Fei *const encoder =
2986 GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
2987 GstVaapiH264ViewReorderPool *reorder_pool = NULL;
2988 GstVaapiEncPicture *picture;
2989 gboolean is_idr = FALSE;
2990
2991 *output = NULL;
2992
2993 if ((encoder->fei_mode != GST_VAAPI_FEI_MODE_ENC_PAK)
2994 && (encoder->fei_mode != GST_VAAPI_FEI_MODE_PAK)) {
2995 GstVaapiEncoder *enc_base_encoder =
2996 GST_VAAPI_ENCODER_CAST (encoder->feienc);
2997 GstVaapiEncoderStatus status;
2998
2999 status = gst_vaapi_feienc_h264_reordering (enc_base_encoder, frame, output);
3000 if ((status != GST_VAAPI_ENCODER_STATUS_SUCCESS) &&
3001 (status != GST_VAAPI_ENCODER_STATUS_NO_SURFACE))
3002 GST_ERROR ("failed to process enc reordering");
3003
3004 return status;
3005 }
3006
3007 /* encoding views alternatively for MVC */
3008 if (encoder->is_mvc) {
3009 /* FIXME: Use first-in-bundle flag on buffers to reset view idx? */
3010 if (frame)
3011 encoder->view_idx = frame->system_frame_number % encoder->num_views;
3012 else
3013 encoder->view_idx = (encoder->view_idx + 1) % encoder->num_views;
3014 }
3015 reorder_pool = &encoder->reorder_pools[encoder->view_idx];
3016
3017 if (!frame) {
3018 if (reorder_pool->reorder_state != GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES)
3019 return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
3020
3021 /* reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES
3022 dump B frames from queue, sometime, there may also have P frame or I frame */
3023 g_assert (encoder->num_bframes > 0);
3024 g_return_val_if_fail (!g_queue_is_empty (&reorder_pool->reorder_frame_list),
3025 GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN);
3026 picture = g_queue_pop_head (&reorder_pool->reorder_frame_list);
3027 g_assert (picture);
3028 if (g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
3029 reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES;
3030 }
3031 goto end;
3032 }
3033
3034 /* new frame coming */
3035 picture = GST_VAAPI_ENC_PICTURE_NEW (H264, encoder, frame);
3036 if (!picture) {
3037 GST_WARNING ("create H264 picture failed, frame timestamp:%"
3038 GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
3039 return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
3040 }
3041 ++reorder_pool->cur_present_index;
3042 picture->poc = ((reorder_pool->cur_present_index * 2) %
3043 encoder->max_pic_order_cnt);
3044
3045 is_idr = (reorder_pool->frame_index == 0 ||
3046 reorder_pool->frame_index >= encoder->idr_period);
3047
3048 /* check key frames */
3049 if (is_idr || GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame) ||
3050 (reorder_pool->frame_index %
3051 GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder)) == 0) {
3052 ++reorder_pool->cur_frame_num;
3053 ++reorder_pool->frame_index;
3054
3055 /* b frame enabled, check queue of reorder_frame_list */
3056 if (encoder->num_bframes
3057 && !g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
3058 GstVaapiEncPicture *p_pic;
3059
3060 p_pic = g_queue_pop_tail (&reorder_pool->reorder_frame_list);
3061 set_p_frame (p_pic, encoder);
3062 g_queue_foreach (&reorder_pool->reorder_frame_list,
3063 (GFunc) set_b_frame, encoder);
3064 ++reorder_pool->cur_frame_num;
3065 set_key_frame (picture, encoder, is_idr);
3066 g_queue_push_tail (&reorder_pool->reorder_frame_list, picture);
3067 picture = p_pic;
3068 reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES;
3069 } else { /* no b frames in queue */
3070 set_key_frame (picture, encoder, is_idr);
3071 g_assert (g_queue_is_empty (&reorder_pool->reorder_frame_list));
3072 if (encoder->num_bframes)
3073 reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES;
3074 }
3075 goto end;
3076 }
3077
3078 /* new p/b frames coming */
3079 ++reorder_pool->frame_index;
3080 if (reorder_pool->reorder_state == GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES &&
3081 g_queue_get_length (&reorder_pool->reorder_frame_list) <
3082 encoder->num_bframes) {
3083 g_queue_push_tail (&reorder_pool->reorder_frame_list, picture);
3084 return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
3085 }
3086
3087 ++reorder_pool->cur_frame_num;
3088 set_p_frame (picture, encoder);
3089
3090 if (reorder_pool->reorder_state == GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES) {
3091 g_queue_foreach (&reorder_pool->reorder_frame_list, (GFunc) set_b_frame,
3092 encoder);
3093 reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES;
3094 g_assert (!g_queue_is_empty (&reorder_pool->reorder_frame_list));
3095 }
3096
3097 end:
3098 g_assert (picture);
3099 frame = picture->frame;
3100 if (GST_CLOCK_TIME_IS_VALID (frame->pts))
3101 frame->pts += encoder->cts_offset;
3102 *output = picture;
3103
3104 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
3105 }
3106
3107 static GstVaapiEncoderStatus
set_context_info(GstVaapiEncoder * base_encoder)3108 set_context_info (GstVaapiEncoder * base_encoder)
3109 {
3110 GstVaapiEncoderH264Fei *const encoder =
3111 GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
3112 GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
3113 const guint DEFAULT_SURFACES_COUNT = 3;
3114
3115 /* Maximum sizes for common headers (in bits) */
3116 enum
3117 {
3118 MAX_SPS_HDR_SIZE = 16473,
3119 MAX_VUI_PARAMS_SIZE = 210,
3120 MAX_HRD_PARAMS_SIZE = 4103,
3121 MAX_PPS_HDR_SIZE = 101,
3122 MAX_SLICE_HDR_SIZE = 397 + 2572 + 6670 + 2402,
3123 };
3124
3125 if (!ensure_hw_profile (encoder))
3126 return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
3127
3128 base_encoder->num_ref_frames =
3129 ((encoder->num_bframes ? 2 : 1) + DEFAULT_SURFACES_COUNT)
3130 * encoder->num_views;
3131
3132 /* Only YUV 4:2:0 formats are supported for now. This means that we
3133 have a limit of 3200 bits per macroblock. */
3134 /* XXX: check profile and compute RawMbBits */
3135 base_encoder->codedbuf_size = (GST_ROUND_UP_16 (vip->width) *
3136 GST_ROUND_UP_16 (vip->height) / 256) * 400;
3137
3138 /* Account for SPS header */
3139 /* XXX: exclude scaling lists, MVC/SVC extensions */
3140 base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE +
3141 MAX_VUI_PARAMS_SIZE + 2 * MAX_HRD_PARAMS_SIZE) / 8;
3142
3143 /* Account for PPS header */
3144 /* XXX: exclude slice groups, scaling lists, MVC/SVC extensions */
3145 base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8;
3146
3147 /* Account for slice header */
3148 base_encoder->codedbuf_size += encoder->num_slices * (4 +
3149 GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE) / 8);
3150
3151 base_encoder->context_info.entrypoint = encoder->entrypoint;
3152
3153 /* Fixme: Add a method to get VA_FEI_FUNCTION_* from GstVaapiFeiMode */
3154 base_encoder->context_info.config.encoder.fei_function = encoder->fei_mode;
3155
3156 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
3157 }
3158
3159 static gboolean
copy_encoder_common_property(GstVaapiEncoder * dst,GstVaapiEncoder * src)3160 copy_encoder_common_property (GstVaapiEncoder * dst, GstVaapiEncoder * src)
3161 {
3162 if (!dst || !src)
3163 return FALSE;
3164
3165 dst->tune = src->tune;
3166 dst->rate_control = src->rate_control;
3167 dst->rate_control_mask = src->rate_control_mask;
3168 dst->bitrate = src->bitrate;
3169 dst->keyframe_period = src->keyframe_period;
3170
3171 return TRUE;
3172 }
3173
3174 static GstVaapiEncoderStatus
gst_vaapi_encoder_h264_fei_reconfigure(GstVaapiEncoder * base_encoder)3175 gst_vaapi_encoder_h264_fei_reconfigure (GstVaapiEncoder * base_encoder)
3176 {
3177 GstVaapiEncoderH264Fei *const encoder =
3178 GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
3179 GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
3180 GstVaapiEncoder *enc_base_encoder = GST_VAAPI_ENCODER_CAST (encoder->feienc);
3181 GstVideoInfo *vip_enc = GST_VAAPI_ENCODER_VIDEO_INFO (encoder->feienc);
3182 GstVaapiEncoderStatus status;
3183 guint mb_width, mb_height;
3184 const guint DEFAULT_SURFACES_COUNT = 3;
3185
3186 if (encoder->fei_mode != (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK)) {
3187 /* ENC_PAK, ENC and PAK modes doesn't need to care about ENC and PAK
3188 * abstrct objects */
3189 mb_width = (GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16;
3190 mb_height = (GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16;
3191 if (mb_width != encoder->mb_width || mb_height != encoder->mb_height) {
3192 GST_DEBUG ("resolution: %dx%d", GST_VAAPI_ENCODER_WIDTH (encoder),
3193 GST_VAAPI_ENCODER_HEIGHT (encoder));
3194 encoder->mb_width = mb_width;
3195 encoder->mb_height = mb_height;
3196 encoder->config_changed = TRUE;
3197 }
3198
3199 /* Take number of MVC views from input caps if provided */
3200 if (GST_VIDEO_INFO_MULTIVIEW_MODE (vip) ==
3201 GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME
3202 || GST_VIDEO_INFO_MULTIVIEW_MODE (vip) ==
3203 GST_VIDEO_MULTIVIEW_MODE_MULTIVIEW_FRAME_BY_FRAME)
3204 encoder->num_views = GST_VIDEO_INFO_VIEWS (vip);
3205
3206 encoder->is_mvc = encoder->num_views > 1;
3207
3208 status = ensure_profile_and_level (encoder);
3209 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
3210 return status;
3211
3212 reset_properties (encoder);
3213 status = set_context_info (base_encoder);
3214 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
3215 return status;
3216
3217 } else {
3218 /* ENC+PAK mode requires two separate objects
3219 for ENC and PAK */
3220
3221 /* Maximum sizes for common headers (in bits) */
3222 enum
3223 {
3224 MAX_SPS_HDR_SIZE = 16473,
3225 MAX_VUI_PARAMS_SIZE = 210,
3226 MAX_HRD_PARAMS_SIZE = 4103,
3227 MAX_PPS_HDR_SIZE = 101,
3228 MAX_SLICE_HDR_SIZE = 397 + 2572 + 6670 + 2402,
3229 };
3230
3231 /* copy encoder-fei common property to feienc */
3232 if (!copy_encoder_common_property (enc_base_encoder, base_encoder))
3233 return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
3234
3235 /* copy video info to feienc */
3236 *vip_enc = *vip;
3237
3238 status = gst_vaapi_feienc_h264_reconfigure (enc_base_encoder);
3239 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
3240 GST_ERROR ("failed to process enc reconfigure");
3241 return status;
3242 }
3243
3244 if (!gst_vaapi_feienc_h264_get_profile_and_idc (encoder->feienc,
3245 &encoder->profile, &encoder->profile_idc))
3246 return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
3247
3248 base_encoder->profile = enc_base_encoder->profile;
3249
3250 mb_width = (GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16;
3251 mb_height = (GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16;
3252 if (mb_width != encoder->mb_width || mb_height != encoder->mb_height) {
3253 GST_DEBUG ("resolution: %dx%d", GST_VAAPI_ENCODER_WIDTH (encoder),
3254 GST_VAAPI_ENCODER_HEIGHT (encoder));
3255 encoder->mb_width = mb_width;
3256 encoder->mb_height = mb_height;
3257 encoder->config_changed = TRUE;
3258 }
3259
3260 status =
3261 gst_vaapi_feipak_h264_reconfigure (encoder->feipak,
3262 base_encoder->va_context, encoder->profile, encoder->profile_idc,
3263 encoder->mb_width, encoder->mb_height, encoder->num_views,
3264 encoder->num_slices, encoder->num_ref_frames);
3265 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
3266 GST_ERROR ("failed to process pak reconfigure");
3267 return status;
3268 }
3269
3270 base_encoder->num_ref_frames =
3271 (encoder->num_ref_frames + DEFAULT_SURFACES_COUNT) * encoder->num_views;
3272
3273 /* Only YUV 4:2:0 formats are supported for now. This means that we
3274 have a limit of 3200 bits per macroblock. */
3275 /* XXX: check profile and compute RawMbBits */
3276 base_encoder->codedbuf_size = (GST_ROUND_UP_16 (vip->width) *
3277 GST_ROUND_UP_16 (vip->height) / 256) * 400;
3278
3279 /* Account for SPS header */
3280 /* XXX: exclude scaling lists, MVC/SVC extensions */
3281 base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE +
3282 MAX_VUI_PARAMS_SIZE + 2 * MAX_HRD_PARAMS_SIZE) / 8;
3283
3284 /* Account for PPS header */
3285 /* XXX: exclude slice groups, scaling lists, MVC/SVC extensions */
3286 base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8;
3287
3288 /* Account for slice header */
3289 base_encoder->codedbuf_size += encoder->num_slices * (4 +
3290 GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE) / 8);
3291
3292 base_encoder->context_info.entrypoint = encoder->entrypoint;
3293
3294 /* ENC+PAK mode use the base encoder context for PAK
3295 * ENC handled separately */
3296 if (encoder->fei_mode == (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK))
3297 base_encoder->context_info.config.encoder.fei_function =
3298 GST_VAAPI_FEI_MODE_PAK;
3299 }
3300
3301 return status;
3302 }
3303
3304 static gboolean
gst_vaapi_encoder_h264_fei_init(GstVaapiEncoder * base_encoder)3305 gst_vaapi_encoder_h264_fei_init (GstVaapiEncoder * base_encoder)
3306 {
3307 GstVaapiEncoderH264Fei *const encoder =
3308 GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
3309 guint32 i;
3310
3311 /* Default encoding entrypoint */
3312 encoder->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
3313 encoder->is_fei_disabled = FALSE;
3314 encoder->is_stats_out_enabled = FALSE;
3315 encoder->fei_mode = GST_VAAPI_FEI_MODE_ENC_PAK;
3316 encoder->search_path = GST_VAAPI_FEI_H264_SEARCH_PATH_DEFAULT;
3317 encoder->len_sp = GST_VAAPI_FEI_H264_SEARCH_PATH_LENGTH_DEFAULT;
3318 encoder->ref_width = GST_VAAPI_FEI_H264_REF_WIDTH_DEFAULT;
3319 encoder->ref_height = GST_VAAPI_FEI_H264_REF_HEIGHT_DEFAULT;
3320 encoder->intra_part_mask = GST_VAAPI_FEI_H264_INTRA_PART_MASK_DEFAULT;
3321 encoder->submb_part_mask = GST_VAAPI_FEI_H264_SUB_MB_PART_MASK_DEFAULT;
3322 /* default num ref frames */
3323 encoder->num_ref_frames = 1;
3324 /* Multi-view coding information */
3325 encoder->is_mvc = FALSE;
3326 encoder->num_views = 1;
3327 encoder->view_idx = 0;
3328 memset (encoder->view_ids, 0, sizeof (encoder->view_ids));
3329
3330 /* re-ordering list initialize */
3331 for (i = 0; i < MAX_NUM_VIEWS; i++) {
3332 GstVaapiH264ViewReorderPool *const reorder_pool =
3333 &encoder->reorder_pools[i];
3334 g_queue_init (&reorder_pool->reorder_frame_list);
3335 reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_NONE;
3336 reorder_pool->frame_index = 0;
3337 reorder_pool->cur_frame_num = 0;
3338 reorder_pool->cur_present_index = 0;
3339 }
3340
3341 /* reference list info initialize */
3342 for (i = 0; i < MAX_NUM_VIEWS; i++) {
3343 GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i];
3344 g_queue_init (&ref_pool->ref_list);
3345 ref_pool->max_ref_frames = 0;
3346 ref_pool->max_reflist0_count = 1;
3347 ref_pool->max_reflist1_count = 1;
3348 }
3349
3350 return TRUE;
3351 }
3352
3353 static void
gst_vaapi_encoder_h264_fei_finalize(GstVaapiEncoder * base_encoder)3354 gst_vaapi_encoder_h264_fei_finalize (GstVaapiEncoder * base_encoder)
3355 {
3356 /*free private buffers */
3357 GstVaapiEncoderH264Fei *const encoder =
3358 GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
3359 GstVaapiEncoder *enc_base_encoder = GST_VAAPI_ENCODER_CAST (encoder->feienc);
3360 GstVaapiMiniObject *object = GST_VAAPI_MINI_OBJECT (encoder->feipak);
3361 GstVaapiEncPicture *pic;
3362 GstVaapiEncoderH264FeiRef *ref;
3363 guint32 i;
3364
3365 if ((encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC_PAK)
3366 || (encoder->fei_mode == GST_VAAPI_FEI_MODE_PAK)) {
3367
3368 gst_buffer_replace (&encoder->sps_data, NULL);
3369 gst_buffer_replace (&encoder->subset_sps_data, NULL);
3370 gst_buffer_replace (&encoder->pps_data, NULL);
3371
3372 /* reference list info de-init */
3373 for (i = 0; i < MAX_NUM_VIEWS; i++) {
3374 GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i];
3375 while (!g_queue_is_empty (&ref_pool->ref_list)) {
3376 ref = (GstVaapiEncoderH264FeiRef *)
3377 g_queue_pop_head (&ref_pool->ref_list);
3378 reference_pic_free (encoder, ref);
3379 }
3380 g_queue_clear (&ref_pool->ref_list);
3381 }
3382
3383 /* re-ordering list initialize */
3384 for (i = 0; i < MAX_NUM_VIEWS; i++) {
3385 GstVaapiH264ViewReorderPool *const reorder_pool =
3386 &encoder->reorder_pools[i];
3387 while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
3388 pic = (GstVaapiEncPicture *)
3389 g_queue_pop_head (&reorder_pool->reorder_frame_list);
3390 gst_vaapi_enc_picture_unref (pic);
3391 }
3392 g_queue_clear (&reorder_pool->reorder_frame_list);
3393 }
3394
3395 } else {
3396 if (encoder->coded_buf != VA_INVALID_ID) {
3397 GST_VAAPI_DISPLAY_LOCK (base_encoder->display);
3398 vaapi_destroy_buffer (base_encoder->va_display, &encoder->coded_buf);
3399 GST_VAAPI_DISPLAY_UNLOCK (base_encoder->display);
3400 encoder->coded_buf = VA_INVALID_ID;
3401 }
3402
3403 if (enc_base_encoder->va_context != VA_INVALID_ID) {
3404 GST_VAAPI_DISPLAY_LOCK (base_encoder->display);
3405 vaDestroyContext (base_encoder->va_display, enc_base_encoder->va_context);
3406 GST_VAAPI_DISPLAY_UNLOCK (base_encoder->display);
3407 enc_base_encoder->va_context = VA_INVALID_ID;
3408 }
3409
3410 if (encoder->va_config != VA_INVALID_ID) {
3411 GST_VAAPI_DISPLAY_LOCK (base_encoder->display);
3412 vaDestroyConfig (base_encoder->va_display, encoder->va_config);
3413 GST_VAAPI_DISPLAY_UNLOCK (base_encoder->display);
3414 encoder->va_config = VA_INVALID_ID;
3415 }
3416
3417 gst_vaapi_encoder_replace (&enc_base_encoder, NULL);
3418 gst_vaapi_mini_object_replace (&object, NULL);
3419
3420 encoder->ref_pool_ptr = NULL;
3421 encoder->feienc = NULL;
3422 }
3423 }
3424
3425 static void
set_view_ids(GstVaapiEncoderH264Fei * const encoder,const GValue * value)3426 set_view_ids (GstVaapiEncoderH264Fei * const encoder, const GValue * value)
3427 {
3428 guint i, j;
3429 guint len = gst_value_array_get_size (value);
3430
3431 if (len == 0)
3432 goto set_default_ids;
3433
3434 if (len != encoder->num_views) {
3435 GST_WARNING ("The view number is %d, but %d view IDs are provided. Just "
3436 "fallback to use default view IDs.", encoder->num_views, len);
3437 goto set_default_ids;
3438 }
3439
3440 for (i = 0; i < len; i++) {
3441 const GValue *val = gst_value_array_get_value (value, i);
3442 encoder->view_ids[i] = g_value_get_uint (val);
3443 }
3444
3445 /* check whether duplicated ID */
3446 for (i = 0; i < len; i++) {
3447 for (j = i + 1; j < len; j++) {
3448 if (encoder->view_ids[i] == encoder->view_ids[j]) {
3449 GST_WARNING ("The view %d and view %d have same view ID %d. Just "
3450 "fallback to use default view IDs.", i, j, encoder->view_ids[i]);
3451 goto set_default_ids;
3452 }
3453 }
3454 }
3455
3456 return;
3457
3458 set_default_ids:
3459 {
3460 for (i = 0; i < encoder->num_views; i++)
3461 encoder->view_ids[i] = i;
3462 }
3463 }
3464
3465 static GstVaapiEncoderStatus
gst_vaapi_encoder_h264_fei_set_property(GstVaapiEncoder * base_encoder,gint prop_id,const GValue * value)3466 gst_vaapi_encoder_h264_fei_set_property (GstVaapiEncoder * base_encoder,
3467 gint prop_id, const GValue * value)
3468 {
3469 GstVaapiEncoderH264Fei *const encoder =
3470 GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
3471 GstVaapiEncoder *enc_base_encoder = GST_VAAPI_ENCODER_CAST (encoder->feienc);
3472 GstVaapiEncoderStatus status;
3473
3474 switch (prop_id) {
3475 case GST_VAAPI_ENCODER_H264_FEI_PROP_MAX_BFRAMES:
3476 encoder->num_bframes = g_value_get_uint (value);
3477 break;
3478 case GST_VAAPI_ENCODER_H264_FEI_PROP_INIT_QP:
3479 encoder->init_qp = g_value_get_uint (value);
3480 break;
3481 case GST_VAAPI_ENCODER_H264_FEI_PROP_MIN_QP:
3482 encoder->min_qp = g_value_get_uint (value);
3483 break;
3484 case GST_VAAPI_ENCODER_H264_FEI_PROP_NUM_SLICES:
3485 encoder->num_slices = g_value_get_uint (value);
3486 break;
3487 case GST_VAAPI_ENCODER_H264_FEI_PROP_CABAC:
3488 encoder->use_cabac = g_value_get_boolean (value);
3489 break;
3490 case GST_VAAPI_ENCODER_H264_FEI_PROP_DCT8X8:
3491 encoder->use_dct8x8 = g_value_get_boolean (value);
3492 break;
3493 case GST_VAAPI_ENCODER_H264_FEI_PROP_CPB_LENGTH:
3494 encoder->cpb_length = g_value_get_uint (value);
3495 break;
3496 case GST_VAAPI_ENCODER_H264_FEI_PROP_NUM_VIEWS:
3497 encoder->num_views = g_value_get_uint (value);
3498 break;
3499 case GST_VAAPI_ENCODER_H264_FEI_PROP_VIEW_IDS:
3500 set_view_ids (encoder, value);
3501 break;
3502 case GST_VAAPI_ENCODER_H264_PROP_FEI_DISABLE:
3503 encoder->is_fei_disabled = g_value_get_boolean (value);
3504 if (!encoder->is_fei_disabled)
3505 encoder->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_FEI;
3506 break;
3507 case GST_VAAPI_ENCODER_H264_PROP_NUM_MV_PREDICT_L0:
3508 encoder->num_mv_predictors_l0 = g_value_get_uint (value);
3509 break;
3510 case GST_VAAPI_ENCODER_H264_PROP_NUM_MV_PREDICT_L1:
3511 encoder->num_mv_predictors_l1 = g_value_get_uint (value);
3512 break;
3513 case GST_VAAPI_ENCODER_H264_PROP_SEARCH_WINDOW:
3514 encoder->search_window = g_value_get_enum (value);
3515 break;
3516 case GST_VAAPI_ENCODER_H264_PROP_LEN_SP:
3517 encoder->len_sp = g_value_get_uint (value);
3518 break;
3519 case GST_VAAPI_ENCODER_H264_PROP_SEARCH_PATH:
3520 encoder->search_path = g_value_get_enum (value);
3521 break;
3522 case GST_VAAPI_ENCODER_H264_PROP_REF_WIDTH:
3523 encoder->ref_width = g_value_get_uint (value);
3524 break;
3525 case GST_VAAPI_ENCODER_H264_PROP_REF_HEIGHT:
3526 encoder->ref_height = g_value_get_uint (value);
3527 break;
3528 case GST_VAAPI_ENCODER_H264_PROP_SUBMB_MASK:
3529 encoder->submb_part_mask = g_value_get_flags (value);
3530 break;
3531 case GST_VAAPI_ENCODER_H264_PROP_SUBPEL_MODE:
3532 encoder->subpel_mode = g_value_get_enum (value);
3533 break;
3534 case GST_VAAPI_ENCODER_H264_PROP_INTRA_PART_MASK:
3535 encoder->intra_part_mask = g_value_get_flags (value);
3536 break;
3537 case GST_VAAPI_ENCODER_H264_PROP_INTRA_SAD:
3538 encoder->intra_sad = g_value_get_enum (value);
3539 break;
3540 case GST_VAAPI_ENCODER_H264_PROP_INTER_SAD:
3541 encoder->inter_sad = g_value_get_enum (value);
3542 break;
3543 case GST_VAAPI_ENCODER_H264_PROP_ADAPT_SEARCH:
3544 encoder->adaptive_search = g_value_get_boolean (value) ? 1 : 0;
3545 break;
3546 case GST_VAAPI_ENCODER_H264_PROP_MULTI_PRED_L0:
3547 encoder->multi_predL0 = g_value_get_boolean (value) ? 1 : 0;
3548 break;
3549 case GST_VAAPI_ENCODER_H264_PROP_MULTI_PRED_L1:
3550 encoder->multi_predL1 = g_value_get_boolean (value) ? 1 : 0;
3551 break;
3552 case GST_VAAPI_ENCODER_H264_PROP_ENABLE_STATS_OUT:
3553 encoder->is_stats_out_enabled = g_value_get_boolean (value);
3554 break;
3555 case GST_VAAPI_ENCODER_H264_PROP_FEI_MODE:
3556 encoder->fei_mode = g_value_get_flags (value);
3557 if (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC) {
3558 g_warning ("============= ENC only mode selected ============ \n"
3559 "We internally run the PAK stage because, the ENC operation requires the reconstructed output of PAK mode. Right now we have no infrastructure to provide reconstructed surfaces to ENC with out running the PAK \n");
3560 /*Fixme: Support ENC only mode with out running PAK */
3561 encoder->fei_mode = GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK;
3562 } else if (encoder->fei_mode == GST_VAAPI_FEI_MODE_PAK) {
3563 g_warning ("============ PAK only mode selected ============ \n"
3564 "This mode can work as expected, only if there is a custom user specific upstream element which provides mb_code and mv_vectors. If you are running the pipeline only for verification, We recommand to use the fei-mod ENC+PAK which will run the ENC operation and generate what ever input needed for PAK \n");
3565 }
3566
3567 break;
3568
3569 default:
3570 return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
3571 }
3572
3573 if ((prop_id != GST_VAAPI_ENCODER_H264_PROP_FEI_MODE) &&
3574 (prop_id != GST_VAAPI_ENCODER_H264_PROP_FEI_DISABLE) &&
3575 (prop_id != GST_VAAPI_ENCODER_H264_PROP_ENABLE_STATS_OUT)) {
3576
3577 if (enc_base_encoder) {
3578 status =
3579 gst_vaapi_feienc_h264_set_property (enc_base_encoder, prop_id, value);
3580 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
3581 GST_ERROR ("failed to set enc property");
3582 return status;
3583 }
3584 }
3585
3586 if ((prop_id == GST_VAAPI_ENCODER_H264_FEI_PROP_MAX_BFRAMES) ||
3587 (prop_id == GST_VAAPI_ENCODER_H264_FEI_PROP_VIEW_IDS) ||
3588 (prop_id == GST_VAAPI_ENCODER_H264_FEI_PROP_NUM_VIEWS)) {
3589 if (encoder->feipak) {
3590 status =
3591 gst_vaapi_feipak_h264_set_property (encoder->feipak, prop_id,
3592 value);
3593 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
3594 GST_ERROR ("failed to set pak property");
3595 return status;
3596 }
3597 }
3598 }
3599 }
3600 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
3601 }
3602
3603
3604 static inline gboolean
context_get_attribute(GstVaapiContext * context,VAConfigAttribType type,guint * out_value_ptr)3605 context_get_attribute (GstVaapiContext * context, VAConfigAttribType type,
3606 guint * out_value_ptr)
3607 {
3608 return gst_vaapi_get_config_attribute (GST_VAAPI_OBJECT_DISPLAY (context),
3609 context->va_profile, context->va_entrypoint, type, out_value_ptr);
3610 }
3611
3612 static gboolean
create_context_for_enc(GstVaapiEncoder * fei_encoder,GstVaapiEncoder * enc_encoder)3613 create_context_for_enc (GstVaapiEncoder * fei_encoder,
3614 GstVaapiEncoder * enc_encoder)
3615 {
3616 GstVaapiEncoderH264Fei *const feiencoder =
3617 GST_VAAPI_ENCODER_H264_FEI (fei_encoder);
3618 GstVaapiContext *context = fei_encoder->context;
3619 const GstVaapiContextInfo *const cip = &context->info;
3620 GstVaapiDisplay *const display = fei_encoder->display;
3621 const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
3622 guint va_rate_control;
3623 VAConfigAttrib attribs[5], *attrib = attribs;
3624 VASurfaceID surface_id;
3625 VAStatus status;
3626 GArray *surfaces = NULL;
3627 gboolean success = FALSE;
3628 guint i, value, va_chroma_format;
3629
3630 if (!context->surfaces)
3631 goto cleanup;
3632
3633 /* Create VA surfaces list for vaCreateContext() */
3634 surfaces = g_array_sized_new (FALSE,
3635 FALSE, sizeof (VASurfaceID), context->surfaces->len);
3636 if (!surfaces)
3637 goto cleanup;
3638
3639 for (i = 0; i < context->surfaces->len; i++) {
3640 GstVaapiSurface *const surface = g_ptr_array_index (context->surfaces, i);
3641 if (!surface)
3642 goto cleanup;
3643 surface_id = GST_VAAPI_OBJECT_ID (surface);
3644 g_array_append_val (surfaces, surface_id);
3645 }
3646 g_assert (surfaces->len == context->surfaces->len);
3647 if (!cip->profile || !cip->entrypoint)
3648 goto cleanup;
3649
3650 /* Validate VA surface format */
3651 va_chroma_format = from_GstVaapiChromaType (cip->chroma_type);
3652 if (!va_chroma_format)
3653 goto cleanup;
3654 attrib->type = VAConfigAttribRTFormat;
3655 if (!context_get_attribute (context, attrib->type, &value))
3656 goto cleanup;
3657 if (!(value & va_chroma_format)) {
3658 GST_ERROR ("unsupported chroma format (%s)",
3659 string_of_va_chroma_format (va_chroma_format));
3660 goto cleanup;
3661 }
3662 attrib->value = va_chroma_format;
3663 attrib++;
3664
3665 /* Rate control */
3666 va_rate_control = from_GstVaapiRateControl (config->rc_mode);
3667 if (va_rate_control != VA_RC_NONE) {
3668 attrib->type = VAConfigAttribRateControl;
3669 if (!context_get_attribute (context, attrib->type, &value))
3670 goto cleanup;
3671
3672 if ((value & va_rate_control) != va_rate_control) {
3673 GST_ERROR ("unsupported %s rate control",
3674 string_of_VARateControl (va_rate_control));
3675 goto cleanup;
3676 }
3677 attrib->value = va_rate_control;
3678 attrib++;
3679 }
3680
3681 /* Packed headers */
3682 if (config->packed_headers) {
3683 attrib->type = VAConfigAttribEncPackedHeaders;
3684 attrib->value = VA_ENC_PACKED_HEADER_NONE;
3685 attrib++;
3686 }
3687
3688 if (cip->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_FEI) {
3689 attrib->type = (VAConfigAttribType) VAConfigAttribFEIFunctionType;
3690 attrib->value = VA_FEI_FUNCTION_ENC;
3691 attrib++;
3692 attrib->type = (VAConfigAttribType) VAConfigAttribFEIMVPredictors;
3693 attrib->value = 1;
3694 attrib++;
3695 }
3696
3697 GST_VAAPI_DISPLAY_LOCK (display);
3698 status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
3699 context->va_profile, context->va_entrypoint, attribs, attrib - attribs,
3700 &feiencoder->va_config);
3701 GST_VAAPI_DISPLAY_UNLOCK (display);
3702 if (!vaapi_check_status (status, "vaCreateConfig()"))
3703 goto cleanup;
3704
3705 GST_VAAPI_DISPLAY_LOCK (display);
3706 status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
3707 feiencoder->va_config, GST_ROUND_UP_16 (cip->width),
3708 GST_ROUND_UP_16 (cip->height), VA_PROGRESSIVE,
3709 (VASurfaceID *) surfaces->data, surfaces->len, &enc_encoder->va_context);
3710 GST_VAAPI_DISPLAY_UNLOCK (display);
3711 if (!vaapi_check_status (status, "vaCreateContext()"))
3712 goto cleanup;
3713
3714 success = TRUE;
3715
3716 cleanup:
3717 if (surfaces)
3718 g_array_free (surfaces, TRUE);
3719 return success;
3720 }
3721
3722 /**
3723 * gst_vaapi_encoder_h264_get_fei_properties:
3724 *
3725 * Determines the set of common and H.264 Fei specific encoder properties.
3726 * The caller owns an extra reference to the resulting array of
3727 * #GstVaapiEncoderPropInfo elements, so it shall be released with
3728 * g_ptr_array_unref() after usage.
3729 *
3730 * Return value: the set of encoder properties for #GstVaapiEncoderH264,
3731 * or %NULL if an error occurred.
3732 */
3733 static GPtrArray *
gst_vaapi_encoder_h264_get_fei_properties(GPtrArray * props)3734 gst_vaapi_encoder_h264_get_fei_properties (GPtrArray * props)
3735 {
3736 /**
3737 * GstVaapiEncoderH264: disable-fei:
3738 *
3739 * Disable FEI mode Encode: disabling fei will results
3740 * the encoder to use VAEntrypointEncSlice, which means
3741 * vaapi-intel-driver will be using a different media kerenl.
3742 * And most of the properties associated with this element
3743 * will be non functional.
3744 */
3745 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3746 GST_VAAPI_ENCODER_H264_PROP_FEI_DISABLE,
3747 g_param_spec_boolean ("disable-fei",
3748 "Disable FEI Mode Encode",
3749 "Disable Flexible Encoding Infrasturcture", FALSE,
3750 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3751
3752
3753 /**
3754 * GstVaapiEncoderH264: stats-out:
3755 *
3756 * Enable outputting fei buffers MV, MBCode and Distortion.
3757 * If enabled, encoder will allocate memory for these buffers
3758 * and submit to the driver even for ENC_PAK mode so that
3759 * the output data can be extraced for analysis after the
3760 * complettion of each frame ncode
3761 */
3762 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3763 GST_VAAPI_ENCODER_H264_PROP_ENABLE_STATS_OUT,
3764 g_param_spec_boolean ("stats-out",
3765 "stats out",
3766 "Enable stats out for fei",
3767 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3768
3769 /**
3770 * GstVaapiEncoderH264:num_mv_predictors_l0:
3771 * Indicate how many mv predictors should be used for l0 frames.
3772 * Only valid if MVPredictor input has been enabled.
3773 */
3774 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3775 GST_VAAPI_ENCODER_H264_PROP_NUM_MV_PREDICT_L0,
3776 g_param_spec_uint ("num-mvpredict-l0",
3777 "Num mv predict l0",
3778 "Indicate how many predictors should be used for l0,"
3779 "only valid if MVPredictor input enabled",
3780 0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3781 /**
3782 * GstVaapiEncoderH264:num_mv_predictors_l1:
3783 * Indicate how many mv predictors should be used for l1 frames.
3784 * Only valid if MVPredictor input has been enabled.
3785 *
3786 */
3787 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3788 GST_VAAPI_ENCODER_H264_PROP_NUM_MV_PREDICT_L1,
3789 g_param_spec_uint ("num-mvpredict-l1",
3790 "Num mv predict l1",
3791 "Indicate how many predictors should be used for l1,"
3792 "only valid if MVPredictor input enabled",
3793 0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3794 /**
3795 * GstVaapiEncoderH264:search-window:
3796 * Use predefined Search Window
3797 */
3798 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3799 GST_VAAPI_ENCODER_H264_PROP_SEARCH_WINDOW,
3800 g_param_spec_enum ("search-window",
3801 "search window",
3802 "Specify one of the predefined search path",
3803 GST_VAAPI_TYPE_FEI_H264_SEARCH_WINDOW,
3804 GST_VAAPI_FEI_H264_SEARCH_WINDOW_DEFAULT,
3805 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3806
3807 /**
3808 * GstVaapiEncoderH264:len-sp:
3809 * Defines the maximum number of Search Units per reference.
3810 */
3811 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3812 GST_VAAPI_ENCODER_H264_PROP_LEN_SP,
3813 g_param_spec_uint ("len-sp",
3814 "length of search path",
3815 "This value defines number of search units in search path",
3816 1, 63, 32, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3817
3818 /**
3819 * GstVaapiEncoderH264:search-path:
3820 * SearchPath defines the motion search method.
3821 * Zero means full search, 1 indicate diamond search.
3822 */
3823 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3824 GST_VAAPI_ENCODER_H264_PROP_SEARCH_PATH,
3825 g_param_spec_enum ("search-path",
3826 "search path",
3827 "Specify search path",
3828 GST_VAAPI_TYPE_FEI_H264_SEARCH_PATH,
3829 GST_VAAPI_FEI_H264_SEARCH_PATH_DEFAULT,
3830 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3831
3832 /**
3833 * GstVaapiEncoderH264:ref-width:
3834 * Specifies the search region width in pixels.
3835 */
3836 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3837 GST_VAAPI_ENCODER_H264_PROP_REF_WIDTH,
3838 g_param_spec_uint ("ref-width",
3839 "ref width",
3840 "Width of search region in pixel, must be multiple of 4",
3841 4, 64, 32, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3842
3843 /**
3844 * GstVaapiEncoderH264:ref-height:
3845 * Specifies the search region height in pixels.
3846 */
3847 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3848 GST_VAAPI_ENCODER_H264_PROP_REF_HEIGHT,
3849 g_param_spec_uint ("ref-height",
3850 "ref height",
3851 "Height of search region in pixel, must be multiple of 4",
3852 4, 32, 32, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3853 /**
3854 * GstVaapiEncoderH264:submb-mask:
3855 * Defines the bit-mask for disabling sub-partition
3856 *
3857 */
3858 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3859 GST_VAAPI_ENCODER_H264_PROP_SUBMB_MASK,
3860 g_param_spec_flags ("submbpart-mask",
3861 "submb part mask",
3862 "defines the bit-mask for disabling sub mb partition",
3863 GST_VAAPI_TYPE_FEI_H264_SUB_MB_PART_MASK,
3864 GST_VAAPI_FEI_H264_SUB_MB_PART_MASK_DEFAULT,
3865 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3866
3867 /**
3868 * GstVaapiEncoderH264:subpel-mode:
3869 * defines the half/quarter pel modes
3870 * 00: integer mode searching
3871 * 01: half-pel mode searching
3872 * 11: quarter-pel mode searching
3873 */
3874 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3875 GST_VAAPI_ENCODER_H264_PROP_SUBPEL_MODE,
3876 g_param_spec_enum ("subpel-mode",
3877 "subpel mode",
3878 "Sub pixel precision for motion estimation",
3879 GST_VAAPI_TYPE_FEI_H264_SUB_PEL_MODE,
3880 GST_VAAPI_FEI_H264_SUB_PEL_MODE_DEFAULT,
3881 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3882 /**
3883 * GstVaapiEncoderH264:intrapart-mask:
3884 * Specifies which Luma Intra partition is enabled/disabled
3885 * for intra mode decision
3886 */
3887 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3888 GST_VAAPI_ENCODER_H264_PROP_INTRA_PART_MASK,
3889 g_param_spec_flags ("intrapart-mask",
3890 "intra part mask",
3891 "Specifies which Luma Intra partition is enabled/disabled for"
3892 "intra mode decision",
3893 GST_VAAPI_TYPE_FEI_H264_INTRA_PART_MASK,
3894 GST_VAAPI_FEI_H264_INTRA_PART_MASK_DEFAULT,
3895 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3896
3897 /**
3898 * GstVaapiEncoderH264:intra-sad:
3899 * Specifies distortion measure adjustments used for
3900 * the motion search SAD comparison.
3901 */
3902 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3903 GST_VAAPI_ENCODER_H264_PROP_INTRA_SAD,
3904 g_param_spec_enum ("intra-sad",
3905 "intra sad",
3906 "Specifies distortion measure adjustments used"
3907 "in the motion search SAD comparison for intra MB",
3908 GST_VAAPI_TYPE_FEI_H264_SAD_MODE, GST_VAAPI_FEI_H264_SAD_MODE_DEFAULT,
3909 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3910
3911 /**
3912 * GstVaapiEncoderH264:inter-sad:
3913 * Specifies distortion measure adjustments used
3914 * in the motion search SAD comparison for inter MB
3915 */
3916 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3917 GST_VAAPI_ENCODER_H264_PROP_INTER_SAD,
3918 g_param_spec_enum ("inter-sad",
3919 "inter sad",
3920 "Specifies distortion measure adjustments used"
3921 "in the motion search SAD comparison for inter MB",
3922 GST_VAAPI_TYPE_FEI_H264_SAD_MODE, GST_VAAPI_FEI_H264_SAD_MODE_DEFAULT,
3923 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3924
3925 /**
3926 * GstVaapiEncoderH264:adaptive-search:
3927 * Defines whether adaptive searching is enabled for IME
3928 */
3929 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3930 GST_VAAPI_ENCODER_H264_PROP_ADAPT_SEARCH,
3931 g_param_spec_boolean ("adaptive-search",
3932 "adaptive-search",
3933 "Enable adaptive search",
3934 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3935 /**
3936 * GstVaapiEncoderH264:multi-predL0:
3937 * When set to 1, neighbor MV will be used as predictor for list L0,
3938 * otherwise no neighbor MV will be used as predictor
3939 */
3940 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3941 GST_VAAPI_ENCODER_H264_PROP_MULTI_PRED_L0,
3942 g_param_spec_boolean ("multi-predL0",
3943 "multi predL0",
3944 "Enable multi prediction for ref L0 list, when set neighbor MV will be used"
3945 "as predictor, no neighbor MV will be used otherwise",
3946 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3947
3948 /**
3949 * GstVaapiEncoderH264:multi-predL1:
3950 * When set to 1, neighbor MV will be used as predictor
3951 * when set to 0, no neighbor MV will be used as predictor.
3952 */
3953 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3954 GST_VAAPI_ENCODER_H264_PROP_MULTI_PRED_L1,
3955 g_param_spec_boolean ("multi-predL1",
3956 "multi predL1",
3957 "Enable multi prediction for ref L1 list, when set neighbor MV will be used"
3958 "as predictor, no neighbor MV will be used otherwise",
3959 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3960
3961 /**
3962 * GstVaapiEncoderH264Fei: fei-mode:
3963 *
3964 * Cose ENC, PAK, ENC_PAK, or ENC+PAK
3965 * ENC: Only the Motion Estimation, no transformation or entropy coding
3966 * PAK: transformation, quantization and entropy coding
3967 * ENC_PAK: default mode, enc an pak are invoked by driver, middleware has
3968 control over ENC input only
3969 * ENC+PAK: enc and pak invoked separately, middleware has control over the ENC input,
3970 ENC output, and PAK input
3971 * Encoding mode which can be used for FEI
3972 */
3973 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
3974 GST_VAAPI_ENCODER_H264_PROP_FEI_MODE,
3975 g_param_spec_flags ("fei-mode",
3976 "FEI Encoding Mode",
3977 "Functional mode of FEI Encoding",
3978 GST_VAAPI_TYPE_FEI_MODE, GST_VAAPI_FEI_MODE_DEFAULT,
3979 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
3980
3981 return props;
3982
3983 }
3984
3985 static const GstVaapiEncoderClassData fei_encoder_class_data = {
3986 .codec = GST_VAAPI_CODEC_H264,
3987 .packed_headers = SUPPORTED_PACKED_HEADERS,
3988 .rate_control_get_type = gst_vaapi_rate_control_get_type,
3989 .default_rate_control = DEFAULT_RATECONTROL,
3990 .rate_control_mask = SUPPORTED_RATECONTROLS,
3991 .encoder_tune_get_type = gst_vaapi_encoder_tune_get_type,
3992 .default_encoder_tune = GST_VAAPI_ENCODER_TUNE_NONE,
3993 .encoder_tune_mask = SUPPORTED_TUNE_OPTIONS,
3994 };
3995
3996 static inline const GstVaapiEncoderClass *
gst_vaapi_encoder_h264_fei_class(void)3997 gst_vaapi_encoder_h264_fei_class (void)
3998 {
3999 static const GstVaapiEncoderClass GstVaapiEncoderH264FeiClass = {
4000 .parent_class = {
4001 .size = sizeof (GstVaapiEncoderH264Fei),
4002 .finalize = (GDestroyNotify) gst_vaapi_encoder_finalize,
4003 }
4004 ,
4005 .class_data = &fei_encoder_class_data,
4006 .init = gst_vaapi_encoder_h264_fei_init,
4007 .finalize = gst_vaapi_encoder_h264_fei_finalize,
4008 .reconfigure = gst_vaapi_encoder_h264_fei_reconfigure,
4009 .get_default_properties = gst_vaapi_encoder_h264_fei_get_default_properties,
4010 .reordering = gst_vaapi_encoder_h264_fei_reordering,
4011 .encode = gst_vaapi_encoder_h264_fei_encode,
4012 .flush = gst_vaapi_encoder_h264_fei_flush,
4013 .set_property = gst_vaapi_encoder_h264_fei_set_property,
4014 .get_codec_data = gst_vaapi_encoder_h264_fei_get_codec_data,
4015 .ensure_secondary_context =
4016 gst_vaapi_encoder_h264_fei_ensure_secondary_context,
4017 };
4018 return &GstVaapiEncoderH264FeiClass;
4019 }
4020
4021 /**
4022 * gst_vaapi_encoder_h264_fei_get_default_properties:
4023 *
4024 * Determines the set of common and H.264 specific encoder properties.
4025 * The caller owns an extra reference to the resulting array of
4026 * #GstVaapiEncoderPropInfo elements, so it shall be released with
4027 * g_ptr_array_unref() after usage.
4028 *
4029 * Return value: the set of encoder properties for #GstVaapiEncoderH264Fei,
4030 * or %NULL if an error occurred.
4031 */
4032 GPtrArray *
gst_vaapi_encoder_h264_fei_get_default_properties(void)4033 gst_vaapi_encoder_h264_fei_get_default_properties (void)
4034 {
4035 const GstVaapiEncoderClass *const klass = gst_vaapi_encoder_h264_fei_class ();
4036 GPtrArray *props;
4037
4038 props = gst_vaapi_encoder_properties_get_default (klass);
4039 if (!props)
4040 return NULL;
4041
4042 /**
4043 * GstVaapiEncoderH264Fei:max-bframes:
4044 *
4045 * The number of B-frames between I and P.
4046 */
4047 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
4048 GST_VAAPI_ENCODER_H264_FEI_PROP_MAX_BFRAMES,
4049 g_param_spec_uint ("max-bframes",
4050 "Max B-Frames", "Number of B-frames between I and P", 0, 10, 1,
4051 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4052
4053 /**
4054 * GstVaapiEncoderH264Fei:init-qp:
4055 *
4056 * The initial quantizer value.
4057 */
4058 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
4059 GST_VAAPI_ENCODER_H264_FEI_PROP_INIT_QP,
4060 g_param_spec_uint ("init-qp",
4061 "Initial QP", "Initial quantizer value", 0, 51, 26,
4062 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4063
4064 /**
4065 * GstVaapiEncoderH264Fei:min-qp:
4066 *
4067 * The minimum quantizer value.
4068 */
4069 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
4070 GST_VAAPI_ENCODER_H264_FEI_PROP_MIN_QP,
4071 g_param_spec_uint ("min-qp",
4072 "Minimum QP", "Minimum quantizer value", 0, 51, 1,
4073 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4074
4075 /**
4076 * GstVaapiEncoderH264Fei:num-slices:
4077 *
4078 * The number of slices per frame.
4079 */
4080 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
4081 GST_VAAPI_ENCODER_H264_FEI_PROP_NUM_SLICES,
4082 g_param_spec_uint ("num-slices",
4083 "Number of Slices",
4084 "Number of slices per frame",
4085 1, 200, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4086
4087 /**
4088 * GstVaapiEncoderH264Fei:cabac:
4089 *
4090 * Enable CABAC entropy coding mode for improved compression ratio,
4091 * at the expense that the minimum target profile is Main. Default
4092 * is CAVLC entropy coding mode.
4093 */
4094 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
4095 GST_VAAPI_ENCODER_H264_FEI_PROP_CABAC,
4096 g_param_spec_boolean ("cabac",
4097 "Enable CABAC",
4098 "Enable CABAC entropy coding mode",
4099 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4100
4101 /**
4102 * GstVaapiEncoderH264Fei:dct8x8:
4103 *
4104 * Enable adaptive use of 8x8 transforms in I-frames. This improves
4105 * the compression ratio by the minimum target profile is High.
4106 * Default is to use 4x4 DCT only.
4107 */
4108 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
4109 GST_VAAPI_ENCODER_H264_FEI_PROP_DCT8X8,
4110 g_param_spec_boolean ("dct8x8",
4111 "Enable 8x8 DCT",
4112 "Enable adaptive use of 8x8 transforms in I-frames",
4113 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4114
4115 /**
4116 * GstVaapiEncoderH264Fei:cpb-length:
4117 *
4118 * The size of the CPB buffer in milliseconds.
4119 */
4120 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
4121 GST_VAAPI_ENCODER_H264_FEI_PROP_CPB_LENGTH,
4122 g_param_spec_uint ("cpb-length",
4123 "CPB Length", "Length of the CPB buffer in milliseconds",
4124 1, 10000, DEFAULT_CPB_LENGTH,
4125 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4126
4127 /**
4128 * GstVaapiEncoderH264Fei:num-views:
4129 *
4130 * The number of views for MVC encoding .
4131 */
4132 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
4133 GST_VAAPI_ENCODER_H264_FEI_PROP_NUM_VIEWS,
4134 g_param_spec_uint ("num-views",
4135 "Number of Views",
4136 "Number of Views for MVC encoding",
4137 1, MAX_NUM_VIEWS, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4138 /**
4139 * GstVaapiEncoderH264Fei:view-ids:
4140 *
4141 * The view ids for MVC encoding .
4142 */
4143 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
4144 GST_VAAPI_ENCODER_H264_FEI_PROP_VIEW_IDS,
4145 gst_param_spec_array ("view-ids",
4146 "View IDs", "Set of View Ids used for MVC encoding",
4147 g_param_spec_uint ("view-id-value", "View id value",
4148 "view id values used for mvc encoding", 0, MAX_VIEW_ID, 0,
4149 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
4150 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
4151
4152 props = gst_vaapi_encoder_h264_get_fei_properties (props);
4153
4154 return props;
4155 }
4156
4157 /**
4158 * gst_vaapi_encoder_h264_fei_set_max_profile:
4159 * @encoder: a #GstVaapiEncoderH264Fei
4160 * @profile: an H.264 #GstVaapiProfile
4161 *
4162 * Notifies the @encoder to use coding tools from the supplied
4163 * @profile at most.
4164 *
4165 * This means that if the minimal profile derived to
4166 * support the specified coding tools is greater than this @profile,
4167 * then an error is returned when the @encoder is configured.
4168 *
4169 * Return value: %TRUE on success
4170 */
4171 gboolean
gst_vaapi_encoder_h264_fei_set_max_profile(GstVaapiEncoderH264Fei * encoder,GstVaapiProfile profile)4172 gst_vaapi_encoder_h264_fei_set_max_profile (GstVaapiEncoderH264Fei *
4173 encoder, GstVaapiProfile profile)
4174 {
4175 guint8 profile_idc;
4176
4177 g_return_val_if_fail (encoder != NULL, FALSE);
4178 g_return_val_if_fail (profile != GST_VAAPI_PROFILE_UNKNOWN, FALSE);
4179
4180 if (encoder->fei_mode == (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK)) {
4181 if (!gst_vaapi_feienc_h264_set_max_profile (encoder->feienc, profile))
4182 return FALSE;
4183 return TRUE;
4184 }
4185
4186 if (gst_vaapi_profile_get_codec (profile) != GST_VAAPI_CODEC_H264)
4187 return FALSE;
4188
4189 profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
4190 if (!profile_idc)
4191 return FALSE;
4192
4193 encoder->max_profile_idc = profile_idc;
4194 return TRUE;
4195 }
4196
4197 /**
4198 * gst_vaapi_encoder_h264_fei_get_profile_and_level:
4199 * @encoder: a #GstVaapiEncoderH264Fei
4200 * @out_profile_ptr: return location for the #GstVaapiProfile
4201 * @out_level_ptr: return location for the #GstVaapiLevelH264
4202 *
4203 * Queries the H.264 @encoder for the active profile and level. That
4204 * information is only constructed and valid after the encoder is
4205 * configured, i.e. after the gst_vaapi_encoder_set_codec_state()
4206 * function is called.
4207 *
4208 * Return value: %TRUE on success
4209 */
4210 gboolean
gst_vaapi_encoder_h264_fei_get_profile_and_level(GstVaapiEncoderH264Fei * encoder,GstVaapiProfile * out_profile_ptr,GstVaapiLevelH264 * out_level_ptr)4211 gst_vaapi_encoder_h264_fei_get_profile_and_level (GstVaapiEncoderH264Fei *
4212 encoder, GstVaapiProfile * out_profile_ptr,
4213 GstVaapiLevelH264 * out_level_ptr)
4214 {
4215 g_return_val_if_fail (encoder != NULL, FALSE);
4216
4217 if (!encoder->profile || !encoder->level)
4218 return FALSE;
4219
4220 if (out_profile_ptr)
4221 *out_profile_ptr = encoder->profile;
4222 if (out_level_ptr)
4223 *out_level_ptr = encoder->level;
4224 return TRUE;
4225 }
4226
4227 /**
4228 * gst_vaapi_encoder_h264_is_fei_stats_out_enabled
4229 * @encoder: a #GstVaapiEncoderH264
4230 *
4231 * check if fei output statis is needed
4232 *
4233 * Return value: %TRUE if output statistic is needed
4234 */
4235 gboolean
gst_vaapi_encoder_h264_is_fei_stats_out_enabled(GstVaapiEncoderH264Fei * encoder)4236 gst_vaapi_encoder_h264_is_fei_stats_out_enabled (GstVaapiEncoderH264Fei *
4237 encoder)
4238 {
4239 return !encoder->is_fei_disabled && encoder->is_stats_out_enabled;
4240 }
4241
4242 /**
4243 * gst_vaapi_encoder_h264_fei_get_function_mode
4244 * @encoder: a #GstVaapiEncoderH264Fei
4245 *
4246 * return the configured FEI Encoding mode
4247 *
4248 * Return value: a #GstVaapiFeiMode
4249 */
4250 GstVaapiFeiMode
gst_vaapi_encoder_h264_fei_get_function_mode(GstVaapiEncoderH264Fei * encoder)4251 gst_vaapi_encoder_h264_fei_get_function_mode (GstVaapiEncoderH264Fei * encoder)
4252 {
4253 return encoder->fei_mode;
4254 }
4255
4256 /**
4257 * gst_vaapi_encoder_h264_fei_set_function_mode
4258 * @encoder: a #GstVaapiEncoderH264Fei
4259 *
4260 * set the configured FEI Encoding mode
4261 *
4262 */
4263 void
gst_vaapi_encoder_h264_fei_set_function_mode(GstVaapiEncoderH264Fei * encoder,guint fei_mode)4264 gst_vaapi_encoder_h264_fei_set_function_mode (GstVaapiEncoderH264Fei * encoder,
4265 guint fei_mode)
4266 {
4267 encoder->fei_mode = fei_mode;
4268 }
4269
4270 static gboolean
gst_vaapi_encoder_h264_fei_ensure_secondary_context(GstVaapiEncoder * base_encoder)4271 gst_vaapi_encoder_h264_fei_ensure_secondary_context (GstVaapiEncoder *
4272 base_encoder)
4273 {
4274 GstVaapiEncoderH264Fei *const feiencoder =
4275 GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
4276 GstVaapiEncoder *enc_base_encoder =
4277 GST_VAAPI_ENCODER_CAST (feiencoder->feienc);
4278 gboolean success;
4279
4280 if (feiencoder->fei_mode != (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK))
4281 return TRUE;
4282
4283 /* Create separate context for ENC */
4284 if (!create_context_for_enc (base_encoder, enc_base_encoder)) {
4285 GST_ERROR ("create vacontext for enc failed.\n");
4286 return FALSE;
4287 }
4288
4289 /*
4290 * create coded-buf for ENC.
4291 * PAK coded-buf is created by parent encoder.
4292 */
4293 success =
4294 vaapi_create_buffer (enc_base_encoder->va_display,
4295 enc_base_encoder->va_context, VAEncCodedBufferType,
4296 base_encoder->codedbuf_size, NULL, &feiencoder->coded_buf, NULL);
4297 if (!success) {
4298 g_error ("failed to create coded buf for feienc.\n");
4299 return FALSE;
4300 }
4301
4302 return TRUE;
4303 }
4304
4305 /**
4306 * gst_vaapi_encoder_h264_fei_new:
4307 * @display: a #GstVaapiDisplay
4308 *
4309 * Creates a new #GstVaapiEncoder for H.264 encoding. Note that the
4310 * only supported output stream format is "byte-stream" format.
4311 *
4312 * Return value: the newly allocated #GstVaapiEncoder object
4313 */
4314 GstVaapiEncoder *
gst_vaapi_encoder_h264_fei_new(GstVaapiDisplay * display)4315 gst_vaapi_encoder_h264_fei_new (GstVaapiDisplay * display)
4316 {
4317 GstVaapiEncoder *base_encoder;
4318 GstVaapiEncoderH264Fei *feiencoder;
4319 GstVaapiFeiEncH264 *feienc;
4320 GstVaapiFEIPakH264 *feipak;
4321
4322 /* create FEIEncoderObject: Default mode of operation in ENC_PAK */
4323 base_encoder =
4324 gst_vaapi_encoder_new (gst_vaapi_encoder_h264_fei_class (), display);
4325 if (!base_encoder)
4326 return NULL;
4327 feiencoder = GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
4328
4329 /* create an enc object */
4330 feienc = GST_VAAPI_FEI_H264_ENC (gst_vaapi_feienc_h264_new (display));
4331 if (!feienc)
4332 return NULL;
4333
4334 /* create a pak object */
4335 feipak =
4336 gst_vaapi_feipak_h264_new (base_encoder, display,
4337 base_encoder->va_context);
4338 if (!feipak)
4339 return NULL;
4340
4341 feiencoder->feienc = feienc;
4342 feiencoder->feipak = feipak;
4343
4344 return base_encoder;
4345 }
4346