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