12c6493eafda41bab209d9546245b53bdc866029
[platform/upstream/gstreamer.git] / gst-libs / gst / vaapi / gstvaapiencoder_h264_fei.c
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 static gboolean
51 gst_vaapi_encoder_h264_fei_ensure_secondary_context (GstVaapiEncoder *
52     base_encoder);
53
54 /* Define the maximum number of views supported */
55 #define MAX_NUM_VIEWS 10
56
57 /* Define the maximum value for view-id */
58 #define MAX_VIEW_ID 1023
59
60 /* Default CPB length (in milliseconds) */
61 #define DEFAULT_CPB_LENGTH 1500
62
63 /* Scale factor for CPB size (HRD cpb_size_scale: min = 4) */
64 #define SX_CPB_SIZE 4
65
66 /* Scale factor for bitrate (HRD bit_rate_scale: min = 6) */
67 #define SX_BITRATE 6
68
69 /* Define default rate control mode ("constant-qp") */
70 #define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP
71
72 /* Supported set of VA rate controls, within this implementation */
73 #define SUPPORTED_RATECONTROLS                          \
74   (GST_VAAPI_RATECONTROL_MASK (CQP)  |                  \
75    GST_VAAPI_RATECONTROL_MASK (CBR)  |                  \
76    GST_VAAPI_RATECONTROL_MASK (VBR)  |                  \
77    GST_VAAPI_RATECONTROL_MASK (VBR_CONSTRAINED))
78
79 /* Supported set of tuning options, within this implementation */
80 #define SUPPORTED_TUNE_OPTIONS                          \
81   (GST_VAAPI_ENCODER_TUNE_MASK (NONE) |                 \
82    GST_VAAPI_ENCODER_TUNE_MASK (HIGH_COMPRESSION) |     \
83    GST_VAAPI_ENCODER_TUNE_MASK (LOW_POWER))
84
85 /* Supported set of VA packed headers, within this implementation */
86 #define SUPPORTED_PACKED_HEADERS                \
87   (VA_ENC_PACKED_HEADER_SEQUENCE |              \
88    VA_ENC_PACKED_HEADER_PICTURE  |              \
89    VA_ENC_PACKED_HEADER_SLICE    |              \
90    VA_ENC_PACKED_HEADER_RAW_DATA |              \
91    VA_ENC_PACKED_HEADER_MISC)
92
93 #define GST_H264_NAL_REF_IDC_NONE        0
94 #define GST_H264_NAL_REF_IDC_LOW         1
95 #define GST_H264_NAL_REF_IDC_MEDIUM      2
96 #define GST_H264_NAL_REF_IDC_HIGH        3
97
98 /* only for internal usage, values won't be equal to actual payload type */
99 typedef enum
100 {
101   GST_VAAPI_H264_SEI_UNKNOWN = 0,
102   GST_VAAPI_H264_SEI_BUF_PERIOD = (1 << 0),
103   GST_VAAPI_H264_SEI_PIC_TIMING = (1 << 1)
104 } GstVaapiH264SeiPayloadType;
105
106 typedef struct
107 {
108   GstVaapiSurfaceProxy *pic;
109   guint poc;
110   guint frame_num;
111 } GstVaapiEncoderH264FeiRef;
112
113 typedef enum
114 {
115   GST_VAAPI_ENC_H264_REORD_NONE = 0,
116   GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES = 1,
117   GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES = 2
118 } GstVaapiEncH264ReorderState;
119
120 typedef struct _GstVaapiH264ViewRefPool
121 {
122   GQueue ref_list;
123   guint max_ref_frames;
124   guint max_reflist0_count;
125   guint max_reflist1_count;
126 } GstVaapiH264ViewRefPool;
127
128 typedef struct _GstVaapiH264ViewReorderPool
129 {
130   GQueue reorder_frame_list;
131   guint reorder_state;
132   guint frame_index;
133   guint frame_count;            /* monotonically increasing with in every idr period */
134   guint cur_frame_num;
135   guint cur_present_index;
136 } GstVaapiH264ViewReorderPool;
137
138 static inline gboolean
139 _poc_greater_than (guint poc1, guint poc2, guint max_poc)
140 {
141   return (((poc1 - poc2) & (max_poc - 1)) < max_poc / 2);
142 }
143
144 /* Get slice_type value for H.264 specification */
145 static guint8
146 h264_get_slice_type (GstVaapiPictureType type)
147 {
148   switch (type) {
149     case GST_VAAPI_PICTURE_TYPE_I:
150       return GST_H264_I_SLICE;
151     case GST_VAAPI_PICTURE_TYPE_P:
152       return GST_H264_P_SLICE;
153     case GST_VAAPI_PICTURE_TYPE_B:
154       return GST_H264_B_SLICE;
155     default:
156       break;
157   }
158   return -1;
159 }
160
161 /* Get log2_max_frame_num value for H.264 specification */
162 static guint
163 h264_get_log2_max_frame_num (guint num)
164 {
165   guint ret = 0;
166
167   while (num) {
168     ++ret;
169     num >>= 1;
170   }
171   if (ret <= 4)
172     ret = 4;
173   else if (ret > 10)
174     ret = 10;
175   /* must be greater than 4 */
176   return ret;
177 }
178
179 /* Determines the cpbBrNalFactor based on the supplied profile */
180 static guint
181 h264_get_cpb_nal_factor (GstVaapiProfile profile)
182 {
183   guint f;
184
185   /* Table A-2 */
186   switch (profile) {
187     case GST_VAAPI_PROFILE_H264_HIGH:
188       f = 1500;
189       break;
190     case GST_VAAPI_PROFILE_H264_HIGH10:
191       f = 3600;
192       break;
193     case GST_VAAPI_PROFILE_H264_HIGH_422:
194     case GST_VAAPI_PROFILE_H264_HIGH_444:
195       f = 4800;
196       break;
197     case GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH:
198     case GST_VAAPI_PROFILE_H264_STEREO_HIGH:
199       f = 1500;                 /* H.10.2.1 (r) */
200       break;
201     default:
202       f = 1200;
203       break;
204   }
205   return f;
206 }
207
208 /* ------------------------------------------------------------------------- */
209 /* --- H.264 Bitstream Writer                                            --- */
210 /* ------------------------------------------------------------------------- */
211
212 #define WRITE_UINT32(bs, val, nbits) do {                       \
213     if (!gst_bit_writer_put_bits_uint32 (bs, val, nbits)) {     \
214       GST_WARNING ("failed to write uint32, nbits: %d", nbits); \
215       goto bs_error;                                            \
216     }                                                           \
217   } while (0)
218
219 #define WRITE_UE(bs, val) do {                  \
220     if (!bs_write_ue (bs, val)) {               \
221       GST_WARNING ("failed to write ue(v)");    \
222       goto bs_error;                            \
223     }                                           \
224   } while (0)
225
226 #define WRITE_SE(bs, val) do {                  \
227     if (!bs_write_se (bs, val)) {               \
228       GST_WARNING ("failed to write se(v)");    \
229       goto bs_error;                            \
230     }                                           \
231   } while (0)
232
233 /* Write an unsigned integer Exp-Golomb-coded syntax element. i.e. ue(v) */
234 static gboolean
235 bs_write_ue (GstBitWriter * bs, guint32 value)
236 {
237   guint32 size_in_bits = 0;
238   guint32 tmp_value = ++value;
239
240   while (tmp_value) {
241     ++size_in_bits;
242     tmp_value >>= 1;
243   }
244   if (size_in_bits > 1
245       && !gst_bit_writer_put_bits_uint32 (bs, 0, size_in_bits - 1))
246     return FALSE;
247   if (!gst_bit_writer_put_bits_uint32 (bs, value, size_in_bits))
248     return FALSE;
249   return TRUE;
250 }
251
252 /* Write a signed integer Exp-Golomb-coded syntax element. i.e. se(v) */
253 static gboolean
254 bs_write_se (GstBitWriter * bs, gint32 value)
255 {
256   guint32 new_val;
257
258   if (value <= 0)
259     new_val = -(value << 1);
260   else
261     new_val = (value << 1) - 1;
262
263   if (!bs_write_ue (bs, new_val))
264     return FALSE;
265   return TRUE;
266 }
267
268 /* Write the NAL unit header */
269 static gboolean
270 bs_write_nal_header (GstBitWriter * bs, guint32 nal_ref_idc,
271     guint32 nal_unit_type)
272 {
273   WRITE_UINT32 (bs, 0, 1);
274   WRITE_UINT32 (bs, nal_ref_idc, 2);
275   WRITE_UINT32 (bs, nal_unit_type, 5);
276   return TRUE;
277
278   /* ERRORS */
279 bs_error:
280   {
281     GST_WARNING ("failed to write NAL unit header");
282     return FALSE;
283   }
284 }
285
286 /* Write the MVC NAL unit header extension */
287 static gboolean
288 bs_write_nal_header_mvc_extension (GstBitWriter * bs,
289     GstVaapiEncPicture * picture, guint32 view_id)
290 {
291   guint32 svc_extension_flag = 0;
292   guint32 non_idr_flag = 1;
293   guint32 priority_id = 0;
294   guint32 temporal_id = 0;
295   guint32 anchor_pic_flag = 0;
296   guint32 inter_view_flag = 0;
297
298   if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
299     non_idr_flag = 0;
300
301   if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
302     anchor_pic_flag = 1;
303   /* svc_extension_flag == 0 for mvc stream */
304   WRITE_UINT32 (bs, svc_extension_flag, 1);
305
306   WRITE_UINT32 (bs, non_idr_flag, 1);
307   WRITE_UINT32 (bs, priority_id, 6);
308   WRITE_UINT32 (bs, view_id, 10);
309   WRITE_UINT32 (bs, temporal_id, 3);
310   WRITE_UINT32 (bs, anchor_pic_flag, 1);
311   WRITE_UINT32 (bs, inter_view_flag, 1);
312   WRITE_UINT32 (bs, 1, 1);
313
314   return TRUE;
315
316   /* ERRORS */
317 bs_error:
318   {
319     GST_WARNING ("failed to write NAL unit header");
320     return FALSE;
321   }
322 }
323
324 /* Write the NAL unit trailing bits */
325 static gboolean
326 bs_write_trailing_bits (GstBitWriter * bs)
327 {
328   if (!gst_bit_writer_put_bits_uint32 (bs, 1, 1))
329     goto bs_error;
330   gst_bit_writer_align_bytes_unchecked (bs, 0);
331   return TRUE;
332
333   /* ERRORS */
334 bs_error:
335   {
336     GST_WARNING ("failed to write NAL unit trailing bits");
337     return FALSE;
338   }
339 }
340
341 /* Write an SPS NAL unit */
342 static gboolean
343 bs_write_sps_data (GstBitWriter * bs,
344     const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile,
345     const VAEncMiscParameterHRD * hrd_params)
346 {
347   guint8 profile_idc;
348   guint32 constraint_set0_flag, constraint_set1_flag;
349   guint32 constraint_set2_flag, constraint_set3_flag;
350   guint32 gaps_in_frame_num_value_allowed_flag = 0;     // ??
351   gboolean nal_hrd_parameters_present_flag;
352
353   guint32 b_qpprime_y_zero_transform_bypass = 0;
354   guint32 residual_color_transform_flag = 0;
355   guint32 pic_height_in_map_units =
356       (seq_param->seq_fields.bits.frame_mbs_only_flag ?
357       seq_param->picture_height_in_mbs : seq_param->picture_height_in_mbs / 2);
358   guint32 mb_adaptive_frame_field =
359       !seq_param->seq_fields.bits.frame_mbs_only_flag;
360   guint32 i = 0;
361
362   profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
363   constraint_set0_flag =        /* A.2.1 (baseline profile constraints) */
364       profile == GST_VAAPI_PROFILE_H264_BASELINE ||
365       profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
366   constraint_set1_flag =        /* A.2.2 (main profile constraints) */
367       profile == GST_VAAPI_PROFILE_H264_MAIN ||
368       profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
369   constraint_set2_flag = 0;
370   constraint_set3_flag = 0;
371
372   /* profile_idc */
373   WRITE_UINT32 (bs, profile_idc, 8);
374   /* constraint_set0_flag */
375   WRITE_UINT32 (bs, constraint_set0_flag, 1);
376   /* constraint_set1_flag */
377   WRITE_UINT32 (bs, constraint_set1_flag, 1);
378   /* constraint_set2_flag */
379   WRITE_UINT32 (bs, constraint_set2_flag, 1);
380   /* constraint_set3_flag */
381   WRITE_UINT32 (bs, constraint_set3_flag, 1);
382   /* reserved_zero_4bits */
383   WRITE_UINT32 (bs, 0, 4);
384   /* level_idc */
385   WRITE_UINT32 (bs, seq_param->level_idc, 8);
386   /* seq_parameter_set_id */
387   WRITE_UE (bs, seq_param->seq_parameter_set_id);
388
389   if (profile == GST_VAAPI_PROFILE_H264_HIGH ||
390       profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH ||
391       profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH) {
392     /* for high profile */
393     /* chroma_format_idc  = 1, 4:2:0 */
394     WRITE_UE (bs, seq_param->seq_fields.bits.chroma_format_idc);
395     if (3 == seq_param->seq_fields.bits.chroma_format_idc) {
396       WRITE_UINT32 (bs, residual_color_transform_flag, 1);
397     }
398     /* bit_depth_luma_minus8 */
399     WRITE_UE (bs, seq_param->bit_depth_luma_minus8);
400     /* bit_depth_chroma_minus8 */
401     WRITE_UE (bs, seq_param->bit_depth_chroma_minus8);
402     /* b_qpprime_y_zero_transform_bypass */
403     WRITE_UINT32 (bs, b_qpprime_y_zero_transform_bypass, 1);
404
405     /* seq_scaling_matrix_present_flag  */
406     g_assert (seq_param->seq_fields.bits.seq_scaling_matrix_present_flag == 0);
407     WRITE_UINT32 (bs,
408         seq_param->seq_fields.bits.seq_scaling_matrix_present_flag, 1);
409
410 #if 0
411     if (seq_param->seq_fields.bits.seq_scaling_matrix_present_flag) {
412       for (i = 0;
413           i < (seq_param->seq_fields.bits.chroma_format_idc != 3 ? 8 : 12);
414           i++) {
415         gst_bit_writer_put_bits_uint8 (bs,
416             seq_param->seq_fields.bits.seq_scaling_list_present_flag, 1);
417         if (seq_param->seq_fields.bits.seq_scaling_list_present_flag) {
418           g_assert (0);
419           /* FIXME, need write scaling list if seq_scaling_matrix_present_flag ==1 */
420         }
421       }
422     }
423 #endif
424   }
425
426   /* log2_max_frame_num_minus4 */
427   WRITE_UE (bs, seq_param->seq_fields.bits.log2_max_frame_num_minus4);
428   /* pic_order_cnt_type */
429   WRITE_UE (bs, seq_param->seq_fields.bits.pic_order_cnt_type);
430
431   if (seq_param->seq_fields.bits.pic_order_cnt_type == 0) {
432     /* log2_max_pic_order_cnt_lsb_minus4 */
433     WRITE_UE (bs, seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4);
434   } else if (seq_param->seq_fields.bits.pic_order_cnt_type == 1) {
435     g_assert (0 && "only POC type 0 is supported");
436     WRITE_UINT32 (bs,
437         seq_param->seq_fields.bits.delta_pic_order_always_zero_flag, 1);
438     WRITE_SE (bs, seq_param->offset_for_non_ref_pic);
439     WRITE_SE (bs, seq_param->offset_for_top_to_bottom_field);
440     WRITE_UE (bs, seq_param->num_ref_frames_in_pic_order_cnt_cycle);
441     for (i = 0; i < seq_param->num_ref_frames_in_pic_order_cnt_cycle; i++) {
442       WRITE_SE (bs, seq_param->offset_for_ref_frame[i]);
443     }
444   }
445
446   /* num_ref_frames */
447   WRITE_UE (bs, seq_param->max_num_ref_frames);
448   /* gaps_in_frame_num_value_allowed_flag */
449   WRITE_UINT32 (bs, gaps_in_frame_num_value_allowed_flag, 1);
450
451   /* pic_width_in_mbs_minus1 */
452   WRITE_UE (bs, seq_param->picture_width_in_mbs - 1);
453   /* pic_height_in_map_units_minus1 */
454   WRITE_UE (bs, pic_height_in_map_units - 1);
455   /* frame_mbs_only_flag */
456   WRITE_UINT32 (bs, seq_param->seq_fields.bits.frame_mbs_only_flag, 1);
457
458   if (!seq_param->seq_fields.bits.frame_mbs_only_flag) {        //ONLY mbs
459     g_assert (0 && "only progressive frames encoding is supported");
460     WRITE_UINT32 (bs, mb_adaptive_frame_field, 1);
461   }
462
463   /* direct_8x8_inference_flag */
464   WRITE_UINT32 (bs, 0, 1);
465   /* frame_cropping_flag */
466   WRITE_UINT32 (bs, seq_param->frame_cropping_flag, 1);
467
468   if (seq_param->frame_cropping_flag) {
469     /* frame_crop_left_offset */
470     WRITE_UE (bs, seq_param->frame_crop_left_offset);
471     /* frame_crop_right_offset */
472     WRITE_UE (bs, seq_param->frame_crop_right_offset);
473     /* frame_crop_top_offset */
474     WRITE_UE (bs, seq_param->frame_crop_top_offset);
475     /* frame_crop_bottom_offset */
476     WRITE_UE (bs, seq_param->frame_crop_bottom_offset);
477   }
478
479   /* vui_parameters_present_flag */
480   WRITE_UINT32 (bs, seq_param->vui_parameters_present_flag, 1);
481   if (seq_param->vui_parameters_present_flag) {
482     /* aspect_ratio_info_present_flag */
483     WRITE_UINT32 (bs,
484         seq_param->vui_fields.bits.aspect_ratio_info_present_flag, 1);
485     if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) {
486       WRITE_UINT32 (bs, seq_param->aspect_ratio_idc, 8);
487       if (seq_param->aspect_ratio_idc == 0xFF) {
488         WRITE_UINT32 (bs, seq_param->sar_width, 16);
489         WRITE_UINT32 (bs, seq_param->sar_height, 16);
490       }
491     }
492
493     /* overscan_info_present_flag */
494     WRITE_UINT32 (bs, 0, 1);
495     /* video_signal_type_present_flag */
496     WRITE_UINT32 (bs, 0, 1);
497     /* chroma_loc_info_present_flag */
498     WRITE_UINT32 (bs, 0, 1);
499
500     /* timing_info_present_flag */
501     WRITE_UINT32 (bs, seq_param->vui_fields.bits.timing_info_present_flag, 1);
502     if (seq_param->vui_fields.bits.timing_info_present_flag) {
503       WRITE_UINT32 (bs, seq_param->num_units_in_tick, 32);
504       WRITE_UINT32 (bs, seq_param->time_scale, 32);
505       WRITE_UINT32 (bs, 1, 1);  /* fixed_frame_rate_flag */
506     }
507
508     /* nal_hrd_parameters_present_flag */
509     nal_hrd_parameters_present_flag = seq_param->bits_per_second > 0;
510     WRITE_UINT32 (bs, nal_hrd_parameters_present_flag, 1);
511     if (nal_hrd_parameters_present_flag) {
512       /* hrd_parameters */
513       /* cpb_cnt_minus1 */
514       WRITE_UE (bs, 0);
515       WRITE_UINT32 (bs, SX_BITRATE - 6, 4);     /* bit_rate_scale */
516       WRITE_UINT32 (bs, SX_CPB_SIZE - 4, 4);    /* cpb_size_scale */
517
518       for (i = 0; i < 1; ++i) {
519         /* bit_rate_value_minus1[0] */
520         WRITE_UE (bs, (seq_param->bits_per_second >> SX_BITRATE) - 1);
521         /* cpb_size_value_minus1[0] */
522         WRITE_UE (bs, (hrd_params->buffer_size >> SX_CPB_SIZE) - 1);
523         /* cbr_flag[0] */
524         WRITE_UINT32 (bs, 1, 1);
525       }
526       /* initial_cpb_removal_delay_length_minus1 */
527       WRITE_UINT32 (bs, 23, 5);
528       /* cpb_removal_delay_length_minus1 */
529       WRITE_UINT32 (bs, 23, 5);
530       /* dpb_output_delay_length_minus1 */
531       WRITE_UINT32 (bs, 23, 5);
532       /* time_offset_length  */
533       WRITE_UINT32 (bs, 23, 5);
534     }
535
536     /* vcl_hrd_parameters_present_flag */
537     WRITE_UINT32 (bs, 0, 1);
538
539     if (nal_hrd_parameters_present_flag
540         || 0 /*vcl_hrd_parameters_present_flag */ ) {
541       /* low_delay_hrd_flag */
542       WRITE_UINT32 (bs, 0, 1);
543     }
544     /* pic_struct_present_flag */
545     WRITE_UINT32 (bs, 1, 1);
546     /* bs_restriction_flag */
547     WRITE_UINT32 (bs, 0, 1);
548   }
549   return TRUE;
550
551   /* ERRORS */
552 bs_error:
553   {
554     GST_WARNING ("failed to write SPS NAL unit");
555     return FALSE;
556   }
557 }
558
559 static gboolean
560 bs_write_sps (GstBitWriter * bs,
561     const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile,
562     const VAEncMiscParameterHRD * hrd_params)
563 {
564   if (!bs_write_sps_data (bs, seq_param, profile, hrd_params))
565     return FALSE;
566
567   /* rbsp_trailing_bits */
568   bs_write_trailing_bits (bs);
569
570   return FALSE;
571 }
572
573 static gboolean
574 bs_write_subset_sps (GstBitWriter * bs,
575     const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile,
576     guint num_views, guint16 * view_ids,
577     const VAEncMiscParameterHRD * hrd_params)
578 {
579   guint32 i, j, k;
580
581   if (!bs_write_sps_data (bs, seq_param, profile, hrd_params))
582     return FALSE;
583
584   if (profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH ||
585       profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH) {
586     guint32 num_views_minus1, num_level_values_signalled_minus1;
587
588     num_views_minus1 = num_views - 1;
589     g_assert (num_views_minus1 < 1024);
590
591     /* bit equal to one */
592     WRITE_UINT32 (bs, 1, 1);
593
594     WRITE_UE (bs, num_views_minus1);
595
596     for (i = 0; i <= num_views_minus1; i++)
597       WRITE_UE (bs, view_ids[i]);
598
599     for (i = 1; i <= num_views_minus1; i++) {
600       guint32 num_anchor_refs_l0 = 0;
601       guint32 num_anchor_refs_l1 = 0;
602
603       WRITE_UE (bs, num_anchor_refs_l0);
604       for (j = 0; j < num_anchor_refs_l0; j++)
605         WRITE_UE (bs, 0);
606
607       WRITE_UE (bs, num_anchor_refs_l1);
608       for (j = 0; j < num_anchor_refs_l1; j++)
609         WRITE_UE (bs, 0);
610     }
611
612     for (i = 1; i <= num_views_minus1; i++) {
613       guint32 num_non_anchor_refs_l0 = 0;
614       guint32 num_non_anchor_refs_l1 = 0;
615
616       WRITE_UE (bs, num_non_anchor_refs_l0);
617       for (j = 0; j < num_non_anchor_refs_l0; j++)
618         WRITE_UE (bs, 0);
619
620       WRITE_UE (bs, num_non_anchor_refs_l1);
621       for (j = 0; j < num_non_anchor_refs_l1; j++)
622         WRITE_UE (bs, 0);
623     }
624
625     /* num level values signalled minus1 */
626     num_level_values_signalled_minus1 = 0;
627     g_assert (num_level_values_signalled_minus1 < 64);
628     WRITE_UE (bs, num_level_values_signalled_minus1);
629
630     for (i = 0; i <= num_level_values_signalled_minus1; i++) {
631       guint16 num_applicable_ops_minus1 = 0;
632       g_assert (num_applicable_ops_minus1 < 1024);
633
634       WRITE_UINT32 (bs, seq_param->level_idc, 8);
635       WRITE_UE (bs, num_applicable_ops_minus1);
636
637       for (j = 0; j <= num_applicable_ops_minus1; j++) {
638         guint8 temporal_id = 0;
639         guint16 num_target_views_minus1 = 1;
640
641         WRITE_UINT32 (bs, temporal_id, 3);
642         WRITE_UE (bs, num_target_views_minus1);
643
644         for (k = 0; k <= num_target_views_minus1; k++)
645           WRITE_UE (bs, k);
646
647         WRITE_UE (bs, num_views_minus1);
648       }
649     }
650
651     /* mvc_vui_parameters_present_flag */
652     WRITE_UINT32 (bs, 0, 1);
653   }
654
655   /* additional_extension2_flag */
656   WRITE_UINT32 (bs, 0, 1);
657
658   /* rbsp_trailing_bits */
659   bs_write_trailing_bits (bs);
660   return TRUE;
661
662   /* ERRORS */
663 bs_error:
664   {
665     GST_WARNING ("failed to write subset SPS NAL unit");
666     return FALSE;
667   }
668   return FALSE;
669 }
670
671 /* Write a PPS NAL unit */
672 static gboolean
673 bs_write_pps (GstBitWriter * bs,
674     const VAEncPictureParameterBufferH264 * pic_param, GstVaapiProfile profile)
675 {
676   guint32 num_slice_groups_minus1 = 0;
677   guint32 pic_init_qs_minus26 = 0;
678   guint32 redundant_pic_cnt_present_flag = 0;
679
680   /* pic_parameter_set_id */
681   WRITE_UE (bs, pic_param->pic_parameter_set_id);
682   /* seq_parameter_set_id */
683   WRITE_UE (bs, pic_param->seq_parameter_set_id);
684   /* entropy_coding_mode_flag */
685   WRITE_UINT32 (bs, pic_param->pic_fields.bits.entropy_coding_mode_flag, 1);
686   /* pic_order_present_flag */
687   WRITE_UINT32 (bs, pic_param->pic_fields.bits.pic_order_present_flag, 1);
688   /* slice_groups-1 */
689   WRITE_UE (bs, num_slice_groups_minus1);
690
691   if (num_slice_groups_minus1 > 0) {
692      /*FIXME*/ g_assert (0 && "unsupported arbitrary slice ordering (ASO)");
693   }
694   WRITE_UE (bs, pic_param->num_ref_idx_l0_active_minus1);
695   WRITE_UE (bs, pic_param->num_ref_idx_l1_active_minus1);
696   WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_pred_flag, 1);
697   WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_bipred_idc, 2);
698   /* pic_init_qp_minus26 */
699   WRITE_SE (bs, pic_param->pic_init_qp - 26);
700   /* pic_init_qs_minus26 */
701   WRITE_SE (bs, pic_init_qs_minus26);
702   /* chroma_qp_index_offset */
703   WRITE_SE (bs, pic_param->chroma_qp_index_offset);
704
705   WRITE_UINT32 (bs,
706       pic_param->pic_fields.bits.deblocking_filter_control_present_flag, 1);
707   WRITE_UINT32 (bs, pic_param->pic_fields.bits.constrained_intra_pred_flag, 1);
708   WRITE_UINT32 (bs, redundant_pic_cnt_present_flag, 1);
709
710   /* more_rbsp_data */
711   if (profile == GST_VAAPI_PROFILE_H264_HIGH
712       || profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH
713       || profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH) {
714     WRITE_UINT32 (bs, pic_param->pic_fields.bits.transform_8x8_mode_flag, 1);
715     WRITE_UINT32 (bs,
716         pic_param->pic_fields.bits.pic_scaling_matrix_present_flag, 1);
717     if (pic_param->pic_fields.bits.pic_scaling_matrix_present_flag) {
718       g_assert (0 && "unsupported scaling lists");
719       /* FIXME */
720       /*
721          for (i = 0; i <
722          (6+(-( (chroma_format_idc ! = 3) ? 2 : 6) * -pic_param->pic_fields.bits.transform_8x8_mode_flag));
723          i++) {
724          gst_bit_writer_put_bits_uint8(bs, pic_param->pic_fields.bits.pic_scaling_list_present_flag, 1);
725          }
726        */
727     }
728     WRITE_SE (bs, pic_param->second_chroma_qp_index_offset);
729   }
730
731   /* rbsp_trailing_bits */
732   bs_write_trailing_bits (bs);
733   return TRUE;
734
735   /* ERRORS */
736 bs_error:
737   {
738     GST_WARNING ("failed to write PPS NAL unit");
739     return FALSE;
740   }
741 }
742
743 /* ------------------------------------------------------------------------- */
744 /* --- H.264 Encoder                                                     --- */
745 /* ------------------------------------------------------------------------- */
746
747 #define GST_VAAPI_ENCODER_H264_FEI_CAST(encoder) \
748     ((GstVaapiEncoderH264Fei *)(encoder))
749
750 struct _GstVaapiEncoderH264Fei
751 {
752   GstVaapiEncoder parent_instance;
753   GstVaapiFeiEncH264 *feienc;
754   GstVaapiFEIPakH264 *feipak;
755
756   GstVaapiProfile profile;
757   GstVaapiLevelH264 level;
758   GstVaapiEntrypoint entrypoint;
759   VAConfigID va_config;
760   guint8 profile_idc;
761   VABufferID coded_buf;
762   guint8 max_profile_idc;
763   guint8 hw_max_profile_idc;
764   guint8 level_idc;
765   guint32 idr_period;
766   guint32 init_qp;
767   guint32 min_qp;
768   guint32 max_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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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     if ((gint) encoder->init_qp + slice_param->slice_qp_delta >
2179         (gint) encoder->max_qp) {
2180       slice_param->slice_qp_delta = encoder->max_qp - encoder->init_qp;
2181     }
2182     slice_param->disable_deblocking_filter_idc = 0;
2183     slice_param->slice_alpha_c0_offset_div2 = 2;
2184     slice_param->slice_beta_offset_div2 = 2;
2185
2186     /* set calculation for next slice */
2187     last_mb_index += cur_slice_mbs;
2188
2189     /* add packed Prefix NAL unit before each Coded slice NAL in base view */
2190     if (encoder->is_mvc && !encoder->view_idx &&
2191         (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2192             VA_ENC_PACKED_HEADER_RAW_DATA)
2193         && !add_packed_prefix_nal_header (encoder, picture, slice))
2194       goto error_create_packed_prefix_nal_hdr;
2195     if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2196             VA_ENC_PACKED_HEADER_SLICE)
2197         && !add_packed_slice_header (encoder, picture, slice))
2198       goto error_create_packed_slice_hdr;
2199
2200     gst_vaapi_enc_picture_add_slice (picture, slice);
2201     gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & slice, NULL);
2202   }
2203   g_assert (last_mb_index == mb_size);
2204   return TRUE;
2205
2206 error_create_packed_slice_hdr:
2207   {
2208     GST_ERROR ("failed to create packed slice header buffer");
2209     gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & slice, NULL);
2210     return FALSE;
2211   }
2212 error_create_packed_prefix_nal_hdr:
2213   {
2214     GST_ERROR ("failed to create packed prefix nal header buffer");
2215     gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & slice, NULL);
2216     return FALSE;
2217   }
2218 }
2219
2220 /* Generates and submits SPS header accordingly into the bitstream */
2221 static gboolean
2222 ensure_sequence (GstVaapiEncoderH264Fei * encoder, GstVaapiEncPicture * picture)
2223 {
2224   GstVaapiEncSequence *sequence = NULL;
2225
2226   /* submit an SPS header before every new I-frame, if codec config changed */
2227   if (!encoder->config_changed || picture->type != GST_VAAPI_PICTURE_TYPE_I)
2228     return TRUE;
2229
2230   sequence = GST_VAAPI_ENC_SEQUENCE_NEW (H264, encoder);
2231   if (!sequence || !fill_sequence (encoder, sequence))
2232     goto error_create_seq_param;
2233
2234   /* add subset sps for non-base view and sps for base view */
2235   if (encoder->is_mvc && encoder->view_idx) {
2236     if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2237             VA_ENC_PACKED_HEADER_SEQUENCE)
2238         && !add_packed_sequence_header_mvc (encoder, picture, sequence))
2239       goto error_create_packed_seq_hdr;
2240   } else {
2241     if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2242             VA_ENC_PACKED_HEADER_SEQUENCE)
2243         && !add_packed_sequence_header (encoder, picture, sequence))
2244       goto error_create_packed_seq_hdr;
2245   }
2246
2247   if (sequence) {
2248     gst_vaapi_enc_picture_set_sequence (picture, sequence);
2249     gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & sequence, NULL);
2250   }
2251
2252   if (!encoder->is_mvc || encoder->view_idx > 0)
2253     encoder->config_changed = FALSE;
2254   return TRUE;
2255
2256   /* ERRORS */
2257 error_create_seq_param:
2258   {
2259     GST_ERROR ("failed to create sequence parameter buffer (SPS)");
2260     gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & sequence, NULL);
2261     return FALSE;
2262   }
2263 error_create_packed_seq_hdr:
2264   {
2265     GST_ERROR ("failed to create packed sequence header buffer");
2266     gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) & sequence, NULL);
2267     return FALSE;
2268   }
2269 }
2270
2271 /* Generates additional fei control parameters */
2272 static gboolean
2273 ensure_fei_misc_params (GstVaapiEncoderH264Fei * encoder,
2274     GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf_proxy)
2275 {
2276   GstVaapiEncMiscParam *misc = NULL;
2277   GstVaapiSurfaceProxy *surface_proxy = NULL;
2278
2279   VAEncMiscParameterFEIFrameControlH264 *misc_fei_pic_control_param;
2280   guint mbcode_size = 0;
2281   guint mv_size = 0;
2282   guint dist_size = 0;
2283   gboolean enable_out = FALSE;
2284
2285   /* fei pic control params */
2286   misc = GST_VAAPI_ENC_FEI_MISC_PARAM_NEW (H264, encoder);
2287   g_assert (misc);
2288   if (!misc)
2289     return FALSE;
2290   misc_fei_pic_control_param = misc->data;
2291   surface_proxy = picture->proxy;
2292
2293   enable_out = ((encoder->is_stats_out_enabled &&
2294           (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC_PAK)) ||
2295       (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC)) ? TRUE : FALSE;
2296
2297   misc_fei_pic_control_param->function = encoder->fei_mode;
2298   misc_fei_pic_control_param->search_path = encoder->search_path;
2299   misc_fei_pic_control_param->num_mv_predictors_l0 =
2300       encoder->num_mv_predictors_l0;
2301   misc_fei_pic_control_param->num_mv_predictors_l1 =
2302       encoder->num_mv_predictors_l1;
2303   misc_fei_pic_control_param->len_sp = encoder->len_sp;
2304   misc_fei_pic_control_param->sub_mb_part_mask = encoder->submb_part_mask;
2305   if (!encoder->use_dct8x8)
2306     misc_fei_pic_control_param->intra_part_mask = encoder->intra_part_mask | 2;
2307   misc_fei_pic_control_param->multi_pred_l0 = encoder->multi_predL0;
2308   misc_fei_pic_control_param->multi_pred_l1 = encoder->multi_predL1;
2309   misc_fei_pic_control_param->sub_pel_mode = encoder->subpel_mode;
2310   misc_fei_pic_control_param->inter_sad = encoder->inter_sad;
2311   misc_fei_pic_control_param->intra_sad = encoder->intra_sad;
2312   misc_fei_pic_control_param->distortion_type = 0;
2313   misc_fei_pic_control_param->repartition_check_enable = 0;
2314   misc_fei_pic_control_param->adaptive_search = encoder->adaptive_search;
2315   misc_fei_pic_control_param->mb_size_ctrl = 0;
2316   misc_fei_pic_control_param->ref_width = encoder->ref_width;
2317   misc_fei_pic_control_param->ref_height = encoder->ref_height;
2318   misc_fei_pic_control_param->search_window = encoder->search_window;
2319
2320   if ((encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC_PAK) ||
2321       (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC)) {
2322
2323     /*****  ENC_PAK/ENC input: mv_predictor *****/
2324     if (surface_proxy->mvpred) {
2325       misc_fei_pic_control_param->mv_predictor =
2326           GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->mvpred)->param_id;
2327       misc_fei_pic_control_param->mv_predictor_enable = TRUE;
2328       gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) &
2329           picture->mvpred, surface_proxy->mvpred);
2330     } else {
2331       misc_fei_pic_control_param->mv_predictor = VA_INVALID_ID;
2332       misc_fei_pic_control_param->mv_predictor_enable = FALSE;
2333       picture->mvpred = NULL;
2334     }
2335
2336     /*****  ENC_PAK/ENC input: qp ******/
2337     if (surface_proxy->qp) {
2338       misc_fei_pic_control_param->qp =
2339           GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->qp)->param_id;
2340       misc_fei_pic_control_param->mb_qp = TRUE;
2341       gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) &
2342           picture->qp, surface_proxy->qp);
2343     } else {
2344       misc_fei_pic_control_param->qp = VA_INVALID_ID;
2345       misc_fei_pic_control_param->mb_qp = FALSE;
2346       picture->qp = NULL;
2347     }
2348
2349     /*****  ENC_PAK/ENC input: mb_control ******/
2350     if (surface_proxy->mbcntrl) {
2351       misc_fei_pic_control_param->mb_ctrl =
2352           GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->mbcntrl)->param_id;
2353       misc_fei_pic_control_param->mb_input = TRUE;
2354       gst_vaapi_codec_object_replace ((GstVaapiCodecObject **) &
2355           picture->mbcntrl, surface_proxy->mbcntrl);
2356     } else {
2357       misc_fei_pic_control_param->mb_ctrl = VA_INVALID_ID;
2358       misc_fei_pic_control_param->mb_input = FALSE;
2359       picture->mbcntrl = NULL;
2360     }
2361   }
2362
2363   if (enable_out) {
2364
2365     mbcode_size = sizeof (VAEncFEIMBCodeH264) *
2366         encoder->mb_width * encoder->mb_height;
2367     mv_size = sizeof (VAMotionVector) * 16 *
2368         encoder->mb_width * encoder->mb_height;
2369     dist_size = sizeof (VAEncFEIDistortionH264) *
2370         encoder->mb_width * encoder->mb_height;
2371
2372     /***** ENC_PAK/ENC output: macroblock code buffer *****/
2373     codedbuf_proxy->mbcode =
2374         gst_vaapi_enc_fei_mb_code_new (GST_VAAPI_ENCODER_CAST (encoder),
2375         NULL, mbcode_size);
2376     misc_fei_pic_control_param->mb_code_data =
2377         GST_VAAPI_FEI_CODEC_OBJECT (codedbuf_proxy->mbcode)->param_id;
2378     picture->mbcode = gst_vaapi_codec_object_ref (codedbuf_proxy->mbcode);
2379
2380     /***** ENC_PAK/ENC output: motion vector buffer *****/
2381     codedbuf_proxy->mv =
2382         gst_vaapi_enc_fei_mv_new (GST_VAAPI_ENCODER_CAST (encoder), NULL,
2383         mv_size);
2384     misc_fei_pic_control_param->mv_data =
2385         GST_VAAPI_FEI_CODEC_OBJECT (codedbuf_proxy->mv)->param_id;
2386     picture->mv = gst_vaapi_codec_object_ref (codedbuf_proxy->mv);
2387
2388     /***** ENC_PAK/ENC output: distortion buffer *****/
2389     codedbuf_proxy->dist =
2390         gst_vaapi_enc_fei_distortion_new (GST_VAAPI_ENCODER_CAST (encoder),
2391         NULL, dist_size);
2392     misc_fei_pic_control_param->distortion =
2393         GST_VAAPI_FEI_CODEC_OBJECT (codedbuf_proxy->dist)->param_id;
2394     picture->dist = gst_vaapi_codec_object_ref (codedbuf_proxy->dist);
2395
2396   } else if (encoder->fei_mode == GST_VAAPI_FEI_MODE_PAK) {
2397
2398     g_assert (surface_proxy->mbcode != NULL);
2399     g_assert (surface_proxy->mv != NULL);
2400
2401     /***** PAK input: macroblock code buffer *****/
2402     misc_fei_pic_control_param->mb_code_data =
2403         GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->mbcode)->param_id;
2404     picture->mbcode = gst_vaapi_codec_object_ref (surface_proxy->mbcode);
2405
2406     /***** PAK input: motion vector buffer  *****/
2407     misc_fei_pic_control_param->mv_data =
2408         GST_VAAPI_FEI_CODEC_OBJECT (surface_proxy->mv)->param_id;
2409     picture->mv = gst_vaapi_codec_object_ref (surface_proxy->mv);
2410   } else {
2411
2412     codedbuf_proxy->mbcode = picture->mbcode = NULL;
2413     codedbuf_proxy->mv = picture->mv = NULL;
2414     codedbuf_proxy->dist = picture->dist = NULL;
2415     misc_fei_pic_control_param->mb_code_data = VA_INVALID_ID;
2416     misc_fei_pic_control_param->mv_data = VA_INVALID_ID;
2417     misc_fei_pic_control_param->distortion = VA_INVALID_ID;
2418   }
2419
2420   gst_vaapi_enc_picture_add_misc_param (picture, misc);
2421   gst_vaapi_codec_object_replace (&misc, NULL);
2422   return TRUE;
2423 }
2424
2425 /* Generates additional control parameters */
2426 static gboolean
2427 ensure_misc_params (GstVaapiEncoderH264Fei * encoder,
2428     GstVaapiEncPicture * picture)
2429 {
2430   GstVaapiEncMiscParam *misc = NULL;
2431   VAEncMiscParameterRateControl *rate_control;
2432
2433   /* HRD params */
2434   misc = GST_VAAPI_ENC_MISC_PARAM_NEW (HRD, encoder);
2435   g_assert (misc);
2436   if (!misc)
2437     return FALSE;
2438   fill_hrd_params (encoder, misc->data);
2439   gst_vaapi_enc_picture_add_misc_param (picture, misc);
2440   gst_vaapi_codec_object_replace (&misc, NULL);
2441
2442   /* RateControl params */
2443   if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR ||
2444       GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_VBR) {
2445     misc = GST_VAAPI_ENC_MISC_PARAM_NEW (RateControl, encoder);
2446     g_assert (misc);
2447     if (!misc)
2448       return FALSE;
2449     rate_control = misc->data;
2450     memset (rate_control, 0, sizeof (VAEncMiscParameterRateControl));
2451     rate_control->bits_per_second = encoder->bitrate_bits;
2452     rate_control->target_percentage = 70;
2453     rate_control->window_size = encoder->cpb_length;
2454     rate_control->initial_qp = encoder->init_qp;
2455     rate_control->min_qp = encoder->min_qp;
2456
2457 #if VA_CHECK_VERSION(1,1,0)
2458     rate_control->max_qp = encoder->max_qp;
2459 #endif
2460
2461     rate_control->basic_unit_size = 0;
2462     gst_vaapi_enc_picture_add_misc_param (picture, misc);
2463     gst_vaapi_codec_object_replace (&misc, NULL);
2464
2465     if (!encoder->view_idx) {
2466       if ((GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) &&
2467           (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2468               VA_ENC_PACKED_HEADER_MISC) &&
2469           !add_packed_sei_header (encoder, picture,
2470               GST_VAAPI_H264_SEI_BUF_PERIOD | GST_VAAPI_H264_SEI_PIC_TIMING))
2471         goto error_create_packed_sei_hdr;
2472
2473       else if (!GST_VAAPI_ENC_PICTURE_IS_IDR (picture) &&
2474           (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2475               VA_ENC_PACKED_HEADER_MISC) &&
2476           !add_packed_sei_header (encoder, picture,
2477               GST_VAAPI_H264_SEI_PIC_TIMING))
2478         goto error_create_packed_sei_hdr;
2479     }
2480
2481   }
2482   return TRUE;
2483
2484 error_create_packed_sei_hdr:
2485   {
2486     GST_ERROR ("failed to create packed SEI header");
2487     return FALSE;
2488   }
2489 }
2490
2491 /* Generates and submits PPS header accordingly into the bitstream */
2492 static gboolean
2493 ensure_picture (GstVaapiEncoderH264Fei * encoder, GstVaapiEncPicture * picture,
2494     GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
2495 {
2496   GstVaapiCodedBuffer *const codedbuf =
2497       GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
2498   gboolean res = FALSE;
2499
2500   res = fill_picture (encoder, picture, codedbuf, surface);
2501
2502   if (!res)
2503     return FALSE;
2504
2505   if (picture->type == GST_VAAPI_PICTURE_TYPE_I &&
2506       (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
2507           VA_ENC_PACKED_HEADER_PICTURE)
2508       && !add_packed_picture_header (encoder, picture)) {
2509     GST_ERROR ("set picture packed header failed");
2510     return FALSE;
2511   }
2512   return TRUE;
2513 }
2514
2515 /* Generates slice headers */
2516 static gboolean
2517 ensure_slices (GstVaapiEncoderH264Fei * encoder, GstVaapiEncPicture * picture)
2518 {
2519   GstVaapiEncoderH264FeiRef *reflist_0[16];
2520   GstVaapiEncoderH264FeiRef *reflist_1[16];
2521   GstVaapiH264ViewRefPool *const ref_pool =
2522       &encoder->ref_pools[encoder->view_idx];
2523   guint reflist_0_count = 0, reflist_1_count = 0;
2524
2525   g_assert (picture);
2526
2527   if (picture->type != GST_VAAPI_PICTURE_TYPE_I &&
2528       !reference_list_init (encoder, picture,
2529           reflist_0, &reflist_0_count, reflist_1, &reflist_1_count)) {
2530     GST_ERROR ("reference list reorder failed");
2531     return FALSE;
2532   }
2533
2534   g_assert (reflist_0_count + reflist_1_count <= ref_pool->max_ref_frames);
2535   if (reflist_0_count > ref_pool->max_reflist0_count)
2536     reflist_0_count = ref_pool->max_reflist0_count;
2537   if (reflist_1_count > ref_pool->max_reflist1_count)
2538     reflist_1_count = ref_pool->max_reflist1_count;
2539
2540   if (!add_slice_headers (encoder, picture,
2541           reflist_0, reflist_0_count, reflist_1, reflist_1_count))
2542     return FALSE;
2543
2544   return TRUE;
2545 }
2546
2547 /* Normalizes bitrate (and CPB size) for HRD conformance */
2548 static void
2549 ensure_bitrate_hrd (GstVaapiEncoderH264Fei * encoder)
2550 {
2551   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
2552   guint bitrate, cpb_size;
2553
2554   if (!base_encoder->bitrate) {
2555     encoder->bitrate_bits = 0;
2556     return;
2557   }
2558
2559   /* Round down bitrate. This is a hard limit mandated by the user */
2560   g_assert (SX_BITRATE >= 6);
2561   bitrate = (base_encoder->bitrate * 1000) & ~((1U << SX_BITRATE) - 1);
2562   if (bitrate != encoder->bitrate_bits) {
2563     GST_DEBUG ("HRD bitrate: %u bits/sec", bitrate);
2564     encoder->bitrate_bits = bitrate;
2565     encoder->config_changed = TRUE;
2566   }
2567
2568   /* Round up CPB size. This is an HRD compliance detail */
2569   g_assert (SX_CPB_SIZE >= 4);
2570   cpb_size = gst_util_uint64_scale (bitrate, encoder->cpb_length, 1000) &
2571       ~((1U << SX_CPB_SIZE) - 1);
2572   if (cpb_size != encoder->cpb_length_bits) {
2573     GST_DEBUG ("HRD CPB size: %u bits", cpb_size);
2574     encoder->cpb_length_bits = cpb_size;
2575     encoder->config_changed = TRUE;
2576   }
2577 }
2578
2579 /* Estimates a good enough bitrate if none was supplied */
2580 static void
2581 ensure_bitrate (GstVaapiEncoderH264Fei * encoder)
2582 {
2583   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
2584
2585   /* Default compression: 48 bits per macroblock in "high-compression" mode */
2586   switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
2587     case GST_VAAPI_RATECONTROL_CBR:
2588     case GST_VAAPI_RATECONTROL_VBR:
2589     case GST_VAAPI_RATECONTROL_VBR_CONSTRAINED:
2590       if (!base_encoder->bitrate) {
2591         /* According to the literature and testing, CABAC entropy coding
2592            mode could provide for +10% to +18% improvement in general,
2593            thus estimating +15% here ; and using adaptive 8x8 transforms
2594            in I-frames could bring up to +10% improvement. */
2595         guint bits_per_mb = 48;
2596         guint64 factor;
2597
2598         if (!encoder->use_cabac)
2599           bits_per_mb += (bits_per_mb * 15) / 100;
2600         if (!encoder->use_dct8x8)
2601           bits_per_mb += (bits_per_mb * 10) / 100;
2602
2603         factor = encoder->mb_width * encoder->mb_height * bits_per_mb;
2604         base_encoder->bitrate =
2605             gst_util_uint64_scale (factor, GST_VAAPI_ENCODER_FPS_N (encoder),
2606             GST_VAAPI_ENCODER_FPS_D (encoder)) / 1000;
2607         GST_INFO ("target bitrate computed to %u kbps", base_encoder->bitrate);
2608       }
2609       break;
2610     default:
2611       base_encoder->bitrate = 0;
2612       break;
2613   }
2614   ensure_bitrate_hrd (encoder);
2615 }
2616
2617 /* Constructs profile and level information based on user-defined limits */
2618 static GstVaapiEncoderStatus
2619 ensure_profile_and_level (GstVaapiEncoderH264Fei * encoder)
2620 {
2621   const GstVaapiProfile profile = encoder->profile;
2622   const GstVaapiLevelH264 level = encoder->level;
2623
2624   if (!ensure_tuning (encoder))
2625     GST_WARNING ("Failed to set some of the tuning option as expected! ");
2626
2627   if (!ensure_profile (encoder) || !ensure_profile_limits (encoder))
2628     return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
2629
2630   /* Check HW constraints */
2631   if (!ensure_hw_profile_limits (encoder))
2632     return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
2633   if (encoder->profile_idc > encoder->hw_max_profile_idc)
2634     return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
2635
2636   /* Ensure bitrate if not set already and derive the right level to use */
2637   ensure_bitrate (encoder);
2638   if (!ensure_level (encoder))
2639     return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
2640
2641   if (encoder->profile != profile || encoder->level != level) {
2642     GST_DEBUG ("selected %s profile at level %s",
2643         gst_vaapi_utils_h264_get_profile_string (encoder->profile),
2644         gst_vaapi_utils_h264_get_level_string (encoder->level));
2645     encoder->config_changed = TRUE;
2646   }
2647   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
2648 }
2649
2650 static void
2651 reset_properties (GstVaapiEncoderH264Fei * encoder)
2652 {
2653   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
2654   guint mb_size, i;
2655
2656   if (encoder->idr_period < base_encoder->keyframe_period)
2657     encoder->idr_period = base_encoder->keyframe_period;
2658
2659   g_assert (encoder->min_qp <= encoder->max_qp);
2660   if (encoder->min_qp > encoder->init_qp ||
2661       (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP &&
2662           encoder->min_qp < encoder->init_qp))
2663     encoder->min_qp = encoder->init_qp;
2664   if (encoder->max_qp < encoder->init_qp)
2665     encoder->max_qp = encoder->init_qp;
2666
2667   mb_size = encoder->mb_width * encoder->mb_height;
2668   if (encoder->num_slices > (mb_size + 1) / 2)
2669     encoder->num_slices = (mb_size + 1) / 2;
2670   g_assert (encoder->num_slices);
2671
2672   if (encoder->num_bframes > (base_encoder->keyframe_period + 1) / 2)
2673     encoder->num_bframes = (base_encoder->keyframe_period + 1) / 2;
2674
2675   /* Workaround : vaapi-intel-driver doesn't have support for
2676    * B-frame encode when utilizing low-power encode hardware block.
2677    * So Disabling b-frame encoding in low-pwer encode.
2678    *
2679    * Fixme :We should query the VAConfigAttribEncMaxRefFrames
2680    * instead of blindly disabling b-frame support and set b/p frame count,
2681    * buffer pool size etc based on that.*/
2682   if ((encoder->num_bframes > 0)
2683       && (encoder->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP)) {
2684     GST_WARNING
2685         ("Disabling b-frame since the driver doesn't supporting it in low-power encode");
2686     encoder->num_bframes = 0;
2687   }
2688
2689   if (encoder->num_bframes > 0 && GST_VAAPI_ENCODER_FPS_N (encoder) > 0)
2690     encoder->cts_offset = gst_util_uint64_scale (GST_SECOND,
2691         GST_VAAPI_ENCODER_FPS_D (encoder), GST_VAAPI_ENCODER_FPS_N (encoder));
2692   else
2693     encoder->cts_offset = 0;
2694
2695   /* init max_frame_num, max_poc */
2696   encoder->log2_max_frame_num =
2697       h264_get_log2_max_frame_num (encoder->idr_period);
2698   g_assert (encoder->log2_max_frame_num >= 4);
2699   encoder->max_frame_num = (1 << encoder->log2_max_frame_num);
2700   encoder->log2_max_pic_order_cnt = encoder->log2_max_frame_num + 1;
2701   encoder->max_pic_order_cnt = (1 << encoder->log2_max_pic_order_cnt);
2702   encoder->idr_num = 0;
2703
2704   for (i = 0; i < encoder->num_views; i++) {
2705     GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i];
2706     GstVaapiH264ViewReorderPool *const reorder_pool =
2707         &encoder->reorder_pools[i];
2708
2709     ref_pool->max_reflist0_count = 1;
2710     ref_pool->max_reflist1_count = encoder->num_bframes > 0;
2711     ref_pool->max_ref_frames = ref_pool->max_reflist0_count
2712         + ref_pool->max_reflist1_count;
2713
2714     reorder_pool->frame_index = 0;
2715   }
2716 }
2717
2718 static gboolean
2719 copy_picture_attrib (GstVaapiEncPicture * dst, GstVaapiEncPicture * src)
2720 {
2721   if (!dst || !src)
2722     return FALSE;
2723
2724   dst->proxy = src->proxy;
2725   dst->surface = src->surface;
2726   dst->type = src->type;
2727   dst->surface_id = src->surface_id;
2728   dst->frame_num = src->frame_num;
2729   dst->poc = src->poc;
2730
2731   return TRUE;
2732 }
2733
2734 static GstVaapiEncoderStatus
2735 gst_vaapi_encoder_h264_fei_encode (GstVaapiEncoder * base_encoder,
2736     GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
2737 {
2738   GstVaapiEncoderH264Fei *const encoder =
2739       GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
2740   GstVaapiEncoder *enc_base_encoder = GST_VAAPI_ENCODER_CAST (encoder->feienc);
2741   GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
2742   GstVaapiSurfaceProxy *reconstruct = NULL;
2743   GstVaapiEncPicture *picture2 = NULL;
2744   GstVaapiFeiInfoToPakH264 info_to_pak;
2745
2746   reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
2747
2748   g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
2749
2750   if ((encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC_PAK)
2751       || (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC)
2752       || (encoder->fei_mode == GST_VAAPI_FEI_MODE_PAK)) {
2753
2754     if (!ensure_sequence (encoder, picture))
2755       goto error;
2756     if (!ensure_misc_params (encoder, picture))
2757       goto error;
2758     if (!encoder->is_fei_disabled
2759         && !ensure_fei_misc_params (encoder, picture, codedbuf))
2760       goto error;
2761     if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
2762       goto error;
2763     if (!ensure_slices (encoder, picture))
2764       goto error;
2765     if (!gst_vaapi_enc_picture_encode (picture))
2766       goto error;
2767
2768     if (!reference_list_update (encoder, picture, reconstruct))
2769       goto error;
2770
2771   } else if (encoder->fei_mode ==
2772       (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK)) {
2773     /*
2774      * ref pool is managed by pak.
2775      * enc will copy from it.
2776      */
2777     if (picture->type != GST_VAAPI_PICTURE_TYPE_I
2778         && !gst_vaapi_feipak_h264_get_ref_pool (encoder->feipak,
2779             &encoder->ref_pool_ptr)) {
2780       GST_ERROR ("failed to get pak ref pool");
2781       status = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
2782       goto error;
2783     }
2784
2785     if (picture->type != GST_VAAPI_PICTURE_TYPE_I
2786         && !gst_vaapi_feienc_h264_set_ref_pool (encoder->feienc,
2787             encoder->ref_pool_ptr)) {
2788       GST_ERROR ("failed to set enc ref pool");
2789       status = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
2790       goto error;
2791     }
2792
2793     status =
2794         gst_vaapi_feienc_h264_encode (enc_base_encoder, picture, reconstruct,
2795         codedbuf, &info_to_pak);
2796     if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
2797       GST_ERROR ("failed to process enc class encode");
2798       goto error;
2799     }
2800
2801     /* duplicate a picture for pak */
2802     picture2 = GST_VAAPI_ENC_PICTURE_NEW (H264, base_encoder, picture->frame);
2803     if (!picture2) {
2804       GST_WARNING ("create H264 picture failed, frame timestamp:%"
2805           GST_TIME_FORMAT, GST_TIME_ARGS (picture->frame->pts));
2806       status = GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
2807       goto error;
2808     }
2809     if (!copy_picture_attrib (picture2, picture)) {
2810       status = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
2811       goto error;
2812     }
2813     /* need set picture IDR info for PAK */
2814     if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
2815       GST_VAAPI_ENC_PICTURE_FLAG_SET (picture2, GST_VAAPI_ENC_PICTURE_FLAG_IDR);
2816
2817     status =
2818         gst_vaapi_feipak_h264_encode (encoder->feipak, picture2, codedbuf,
2819         reconstruct, &info_to_pak);
2820     if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
2821       GST_ERROR ("failed to process pak class encode");
2822       goto error;
2823     }
2824
2825     /* Free the slice array */
2826     if (info_to_pak.h264_slice_headers)
2827       g_array_free (info_to_pak.h264_slice_headers, TRUE);
2828
2829     gst_vaapi_enc_picture_unref (picture2);
2830
2831   }
2832
2833   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
2834
2835   /* ERRORS */
2836 error:
2837   {
2838     if (reconstruct)
2839       gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
2840           reconstruct);
2841     if (picture2)
2842       gst_vaapi_enc_picture_unref (picture2);
2843     return status;
2844   }
2845 }
2846
2847 static GstVaapiEncoderStatus
2848 gst_vaapi_encoder_h264_fei_flush (GstVaapiEncoder * base_encoder)
2849 {
2850   GstVaapiEncoderH264Fei *const encoder =
2851       GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
2852   GstVaapiEncoder *enc_base_encoder = GST_VAAPI_ENCODER_CAST (encoder->feienc);
2853   GstVaapiH264ViewReorderPool *reorder_pool;
2854   GstVaapiEncPicture *pic;
2855   GstVaapiEncoderStatus status;
2856   guint i;
2857
2858   if ((encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC_PAK)
2859       || (encoder->fei_mode == GST_VAAPI_FEI_MODE_PAK)) {
2860     for (i = 0; i < encoder->num_views; i++) {
2861       reorder_pool = &encoder->reorder_pools[i];
2862       reorder_pool->frame_index = 0;
2863       reorder_pool->cur_frame_num = 0;
2864       reorder_pool->cur_present_index = 0;
2865
2866       while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
2867         pic = (GstVaapiEncPicture *)
2868             g_queue_pop_head (&reorder_pool->reorder_frame_list);
2869         gst_vaapi_enc_picture_unref (pic);
2870       }
2871       g_queue_clear (&reorder_pool->reorder_frame_list);
2872     }
2873   } else if (encoder->fei_mode ==
2874       (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK)) {
2875
2876     status = gst_vaapi_feienc_h264_flush (enc_base_encoder);
2877     if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
2878       GST_ERROR ("failed to process enc class flush");
2879       return status;
2880     }
2881
2882     status = gst_vaapi_feipak_h264_flush (encoder->feipak);
2883     if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
2884       GST_ERROR ("failed to process pak class flush");
2885       return status;
2886     }
2887   } else {
2888     g_assert (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC);
2889   }
2890
2891   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
2892 }
2893
2894 /* Generate "codec-data" buffer */
2895 static GstVaapiEncoderStatus
2896 gst_vaapi_encoder_h264_fei_get_codec_data (GstVaapiEncoder * base_encoder,
2897     GstBuffer ** out_buffer_ptr)
2898 {
2899   GstVaapiEncoderH264Fei *const encoder =
2900       GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
2901   const guint32 configuration_version = 0x01;
2902   const guint32 nal_length_size = 4;
2903   guint8 profile_idc, profile_comp, level_idc;
2904   GstMapInfo sps_info, pps_info;
2905   GstBitWriter bs;
2906   GstBuffer *buffer;
2907
2908   if (!encoder->sps_data || !encoder->pps_data)
2909     return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER;
2910   if (gst_buffer_get_size (encoder->sps_data) < 4)
2911     return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER;
2912
2913   if (!gst_buffer_map (encoder->sps_data, &sps_info, GST_MAP_READ))
2914     goto error_map_sps_buffer;
2915
2916   if (!gst_buffer_map (encoder->pps_data, &pps_info, GST_MAP_READ))
2917     goto error_map_pps_buffer;
2918
2919   /* skip sps_data[0], which is the nal_unit_type */
2920   profile_idc = sps_info.data[1];
2921   profile_comp = sps_info.data[2];
2922   level_idc = sps_info.data[3];
2923
2924   /* Header */
2925   gst_bit_writer_init_with_size (&bs, (sps_info.size + pps_info.size + 64),
2926       FALSE);
2927   WRITE_UINT32 (&bs, configuration_version, 8);
2928   WRITE_UINT32 (&bs, profile_idc, 8);
2929   WRITE_UINT32 (&bs, profile_comp, 8);
2930   WRITE_UINT32 (&bs, level_idc, 8);
2931   WRITE_UINT32 (&bs, 0x3f, 6);  /* 111111 */
2932   WRITE_UINT32 (&bs, nal_length_size - 1, 2);
2933   WRITE_UINT32 (&bs, 0x07, 3);  /* 111 */
2934
2935   /* Write SPS */
2936   WRITE_UINT32 (&bs, 1, 5);     /* SPS count = 1 */
2937   g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
2938   WRITE_UINT32 (&bs, sps_info.size, 16);
2939   gst_bit_writer_put_bytes (&bs, sps_info.data, sps_info.size);
2940
2941   /* Write PPS */
2942   WRITE_UINT32 (&bs, 1, 8);     /* PPS count = 1 */
2943   WRITE_UINT32 (&bs, pps_info.size, 16);
2944   gst_bit_writer_put_bytes (&bs, pps_info.data, pps_info.size);
2945
2946   gst_buffer_unmap (encoder->pps_data, &pps_info);
2947   gst_buffer_unmap (encoder->sps_data, &sps_info);
2948
2949   buffer = gst_bit_writer_reset_and_get_buffer (&bs);
2950   if (!buffer)
2951     goto error_alloc_buffer;
2952   *out_buffer_ptr = buffer;
2953
2954   gst_bit_writer_reset (&bs);
2955   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
2956
2957   /* ERRORS */
2958 bs_error:
2959   {
2960     GST_ERROR ("failed to write codec-data");
2961     gst_buffer_unmap (encoder->sps_data, &sps_info);
2962     gst_buffer_unmap (encoder->pps_data, &pps_info);
2963     gst_bit_writer_reset (&bs);
2964     return FALSE;
2965   }
2966 error_map_sps_buffer:
2967   {
2968     GST_ERROR ("failed to map SPS packed header");
2969     return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
2970   }
2971 error_map_pps_buffer:
2972   {
2973     GST_ERROR ("failed to map PPS packed header");
2974     gst_buffer_unmap (encoder->sps_data, &sps_info);
2975     return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
2976   }
2977 error_alloc_buffer:
2978   {
2979     GST_ERROR ("failed to allocate codec-data buffer");
2980     gst_bit_writer_reset (&bs);
2981     return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
2982   }
2983 }
2984
2985 static GstVaapiEncoderStatus
2986 gst_vaapi_encoder_h264_fei_reordering (GstVaapiEncoder * base_encoder,
2987     GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
2988 {
2989   GstVaapiEncoderH264Fei *const encoder =
2990       GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
2991   GstVaapiH264ViewReorderPool *reorder_pool = NULL;
2992   GstVaapiEncPicture *picture;
2993   gboolean is_idr = FALSE;
2994
2995   *output = NULL;
2996
2997   if ((encoder->fei_mode != GST_VAAPI_FEI_MODE_ENC_PAK)
2998       && (encoder->fei_mode != GST_VAAPI_FEI_MODE_PAK)) {
2999     GstVaapiEncoder *enc_base_encoder =
3000         GST_VAAPI_ENCODER_CAST (encoder->feienc);
3001     GstVaapiEncoderStatus status;
3002
3003     status = gst_vaapi_feienc_h264_reordering (enc_base_encoder, frame, output);
3004     if ((status != GST_VAAPI_ENCODER_STATUS_SUCCESS) &&
3005         (status != GST_VAAPI_ENCODER_STATUS_NO_SURFACE))
3006       GST_ERROR ("failed to process enc reordering");
3007
3008     return status;
3009   }
3010
3011   /* encoding views alternatively for MVC */
3012   if (encoder->is_mvc) {
3013     /* FIXME: Use first-in-bundle flag on buffers to reset view idx? */
3014     if (frame)
3015       encoder->view_idx = frame->system_frame_number % encoder->num_views;
3016     else
3017       encoder->view_idx = (encoder->view_idx + 1) % encoder->num_views;
3018   }
3019   reorder_pool = &encoder->reorder_pools[encoder->view_idx];
3020
3021   if (!frame) {
3022     if (reorder_pool->reorder_state != GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES)
3023       return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
3024
3025     /* reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES
3026        dump B frames from queue, sometime, there may also have P frame or I frame */
3027     g_assert (encoder->num_bframes > 0);
3028     g_return_val_if_fail (!g_queue_is_empty (&reorder_pool->reorder_frame_list),
3029         GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN);
3030     picture = g_queue_pop_head (&reorder_pool->reorder_frame_list);
3031     g_assert (picture);
3032     if (g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
3033       reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES;
3034     }
3035     goto end;
3036   }
3037
3038   /* new frame coming */
3039   picture = GST_VAAPI_ENC_PICTURE_NEW (H264, encoder, frame);
3040   if (!picture) {
3041     GST_WARNING ("create H264 picture failed, frame timestamp:%"
3042         GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
3043     return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
3044   }
3045   ++reorder_pool->cur_present_index;
3046   picture->poc = ((reorder_pool->cur_present_index * 2) %
3047       encoder->max_pic_order_cnt);
3048
3049   is_idr = (reorder_pool->frame_index == 0 ||
3050       reorder_pool->frame_index >= encoder->idr_period);
3051
3052   /* check key frames */
3053   if (is_idr || GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame) ||
3054       (reorder_pool->frame_index %
3055           GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder)) == 0) {
3056     ++reorder_pool->cur_frame_num;
3057     ++reorder_pool->frame_index;
3058
3059     /* b frame enabled,  check queue of reorder_frame_list */
3060     if (encoder->num_bframes
3061         && !g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
3062       GstVaapiEncPicture *p_pic;
3063
3064       p_pic = g_queue_pop_tail (&reorder_pool->reorder_frame_list);
3065       set_p_frame (p_pic, encoder);
3066       g_queue_foreach (&reorder_pool->reorder_frame_list,
3067           (GFunc) set_b_frame, encoder);
3068       ++reorder_pool->cur_frame_num;
3069       set_key_frame (picture, encoder, is_idr);
3070       g_queue_push_tail (&reorder_pool->reorder_frame_list, picture);
3071       picture = p_pic;
3072       reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES;
3073     } else {                    /* no b frames in queue */
3074       set_key_frame (picture, encoder, is_idr);
3075       g_assert (g_queue_is_empty (&reorder_pool->reorder_frame_list));
3076       if (encoder->num_bframes)
3077         reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES;
3078     }
3079     goto end;
3080   }
3081
3082   /* new p/b frames coming */
3083   ++reorder_pool->frame_index;
3084   if (reorder_pool->reorder_state == GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES &&
3085       g_queue_get_length (&reorder_pool->reorder_frame_list) <
3086       encoder->num_bframes) {
3087     g_queue_push_tail (&reorder_pool->reorder_frame_list, picture);
3088     return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
3089   }
3090
3091   ++reorder_pool->cur_frame_num;
3092   set_p_frame (picture, encoder);
3093
3094   if (reorder_pool->reorder_state == GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES) {
3095     g_queue_foreach (&reorder_pool->reorder_frame_list, (GFunc) set_b_frame,
3096         encoder);
3097     reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES;
3098     g_assert (!g_queue_is_empty (&reorder_pool->reorder_frame_list));
3099   }
3100
3101 end:
3102   g_assert (picture);
3103   frame = picture->frame;
3104   if (GST_CLOCK_TIME_IS_VALID (frame->pts))
3105     frame->pts += encoder->cts_offset;
3106   *output = picture;
3107
3108   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
3109 }
3110
3111 static GstVaapiEncoderStatus
3112 set_context_info (GstVaapiEncoder * base_encoder)
3113 {
3114   GstVaapiEncoderH264Fei *const encoder =
3115       GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
3116   GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
3117   const guint DEFAULT_SURFACES_COUNT = 3;
3118
3119   /* Maximum sizes for common headers (in bits) */
3120   enum
3121   {
3122     MAX_SPS_HDR_SIZE = 16473,
3123     MAX_VUI_PARAMS_SIZE = 210,
3124     MAX_HRD_PARAMS_SIZE = 4103,
3125     MAX_PPS_HDR_SIZE = 101,
3126     MAX_SLICE_HDR_SIZE = 397 + 2572 + 6670 + 2402,
3127   };
3128
3129   if (!ensure_hw_profile (encoder))
3130     return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
3131
3132   base_encoder->num_ref_frames =
3133       ((encoder->num_bframes ? 2 : 1) + DEFAULT_SURFACES_COUNT)
3134       * encoder->num_views;
3135
3136   /* Only YUV 4:2:0 formats are supported for now. This means that we
3137      have a limit of 3200 bits per macroblock. */
3138   /* XXX: check profile and compute RawMbBits */
3139   base_encoder->codedbuf_size = (GST_ROUND_UP_16 (vip->width) *
3140       GST_ROUND_UP_16 (vip->height) / 256) * 400;
3141
3142   /* Account for SPS header */
3143   /* XXX: exclude scaling lists, MVC/SVC extensions */
3144   base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE +
3145       MAX_VUI_PARAMS_SIZE + 2 * MAX_HRD_PARAMS_SIZE) / 8;
3146
3147   /* Account for PPS header */
3148   /* XXX: exclude slice groups, scaling lists, MVC/SVC extensions */
3149   base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8;
3150
3151   /* Account for slice header */
3152   base_encoder->codedbuf_size += encoder->num_slices * (4 +
3153       GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE) / 8);
3154
3155   base_encoder->context_info.entrypoint = encoder->entrypoint;
3156
3157   /* Fixme:  Add a method to get VA_FEI_FUNCTION_* from GstVaapiFeiMode */
3158   base_encoder->context_info.config.encoder.fei_function = encoder->fei_mode;
3159
3160   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
3161 }
3162
3163 static gboolean
3164 copy_encoder_common_property (GstVaapiEncoder * dst, GstVaapiEncoder * src)
3165 {
3166   if (!dst || !src)
3167     return FALSE;
3168
3169   dst->tune = src->tune;
3170   dst->rate_control = src->rate_control;
3171   dst->rate_control_mask = src->rate_control_mask;
3172   dst->bitrate = src->bitrate;
3173   dst->keyframe_period = src->keyframe_period;
3174
3175   return TRUE;
3176 }
3177
3178 static GstVaapiEncoderStatus
3179 gst_vaapi_encoder_h264_fei_reconfigure (GstVaapiEncoder * base_encoder)
3180 {
3181   GstVaapiEncoderH264Fei *const encoder =
3182       GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
3183   GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
3184   GstVaapiEncoder *enc_base_encoder = GST_VAAPI_ENCODER_CAST (encoder->feienc);
3185   GstVideoInfo *vip_enc = GST_VAAPI_ENCODER_VIDEO_INFO (encoder->feienc);
3186   GstVaapiEncoderStatus status;
3187   guint mb_width, mb_height;
3188   const guint DEFAULT_SURFACES_COUNT = 3;
3189
3190   if (encoder->fei_mode != (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK)) {
3191     /* ENC_PAK, ENC and PAK modes doesn't need to care about ENC and PAK
3192      * abstrct objects */
3193     mb_width = (GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16;
3194     mb_height = (GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16;
3195     if (mb_width != encoder->mb_width || mb_height != encoder->mb_height) {
3196       GST_DEBUG ("resolution: %dx%d", GST_VAAPI_ENCODER_WIDTH (encoder),
3197           GST_VAAPI_ENCODER_HEIGHT (encoder));
3198       encoder->mb_width = mb_width;
3199       encoder->mb_height = mb_height;
3200       encoder->config_changed = TRUE;
3201     }
3202
3203     /* Take number of MVC views from input caps if provided */
3204     if (GST_VIDEO_INFO_MULTIVIEW_MODE (vip) ==
3205         GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME
3206         || GST_VIDEO_INFO_MULTIVIEW_MODE (vip) ==
3207         GST_VIDEO_MULTIVIEW_MODE_MULTIVIEW_FRAME_BY_FRAME)
3208       encoder->num_views = GST_VIDEO_INFO_VIEWS (vip);
3209
3210     encoder->is_mvc = encoder->num_views > 1;
3211
3212     status = ensure_profile_and_level (encoder);
3213     if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
3214       return status;
3215
3216     reset_properties (encoder);
3217     status = set_context_info (base_encoder);
3218     if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
3219       return status;
3220
3221   } else {
3222     /* ENC+PAK mode requires two separate objects
3223        for ENC and PAK */
3224
3225     /* Maximum sizes for common headers (in bits) */
3226     enum
3227     {
3228       MAX_SPS_HDR_SIZE = 16473,
3229       MAX_VUI_PARAMS_SIZE = 210,
3230       MAX_HRD_PARAMS_SIZE = 4103,
3231       MAX_PPS_HDR_SIZE = 101,
3232       MAX_SLICE_HDR_SIZE = 397 + 2572 + 6670 + 2402,
3233     };
3234
3235     /* copy encoder-fei common property to feienc */
3236     if (!copy_encoder_common_property (enc_base_encoder, base_encoder))
3237       return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
3238
3239     /* copy video info to feienc */
3240     *vip_enc = *vip;
3241
3242     status = gst_vaapi_feienc_h264_reconfigure (enc_base_encoder);
3243     if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
3244       GST_ERROR ("failed to process enc reconfigure");
3245       return status;
3246     }
3247
3248     if (!gst_vaapi_feienc_h264_get_profile_and_idc (encoder->feienc,
3249             &encoder->profile, &encoder->profile_idc))
3250       return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
3251
3252     base_encoder->profile = enc_base_encoder->profile;
3253
3254     mb_width = (GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16;
3255     mb_height = (GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16;
3256     if (mb_width != encoder->mb_width || mb_height != encoder->mb_height) {
3257       GST_DEBUG ("resolution: %dx%d", GST_VAAPI_ENCODER_WIDTH (encoder),
3258           GST_VAAPI_ENCODER_HEIGHT (encoder));
3259       encoder->mb_width = mb_width;
3260       encoder->mb_height = mb_height;
3261       encoder->config_changed = TRUE;
3262     }
3263
3264     status =
3265         gst_vaapi_feipak_h264_reconfigure (encoder->feipak,
3266         base_encoder->va_context, encoder->profile, encoder->profile_idc,
3267         encoder->mb_width, encoder->mb_height, encoder->num_views,
3268         encoder->num_slices, encoder->num_ref_frames);
3269     if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
3270       GST_ERROR ("failed to process pak reconfigure");
3271       return status;
3272     }
3273
3274     base_encoder->num_ref_frames =
3275         (encoder->num_ref_frames + DEFAULT_SURFACES_COUNT) * encoder->num_views;
3276
3277     /* Only YUV 4:2:0 formats are supported for now. This means that we
3278        have a limit of 3200 bits per macroblock. */
3279     /* XXX: check profile and compute RawMbBits */
3280     base_encoder->codedbuf_size = (GST_ROUND_UP_16 (vip->width) *
3281         GST_ROUND_UP_16 (vip->height) / 256) * 400;
3282
3283     /* Account for SPS header */
3284     /* XXX: exclude scaling lists, MVC/SVC extensions */
3285     base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE +
3286         MAX_VUI_PARAMS_SIZE + 2 * MAX_HRD_PARAMS_SIZE) / 8;
3287
3288     /* Account for PPS header */
3289     /* XXX: exclude slice groups, scaling lists, MVC/SVC extensions */
3290     base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8;
3291
3292     /* Account for slice header */
3293     base_encoder->codedbuf_size += encoder->num_slices * (4 +
3294         GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE) / 8);
3295
3296     base_encoder->context_info.entrypoint = encoder->entrypoint;
3297
3298     /* ENC+PAK mode use the base encoder context for PAK
3299      * ENC handled separately */
3300     if (encoder->fei_mode == (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK))
3301       base_encoder->context_info.config.encoder.fei_function =
3302           GST_VAAPI_FEI_MODE_PAK;
3303   }
3304
3305   return status;
3306 }
3307
3308 struct _GstVaapiEncoderH264FeiClass
3309 {
3310   GstVaapiEncoderClass parent_class;
3311 };
3312
3313 G_DEFINE_TYPE (GstVaapiEncoderH264Fei, gst_vaapi_encoder_h264_fei,
3314     GST_TYPE_VAAPI_ENCODER);
3315
3316 static void
3317 gst_vaapi_encoder_h264_fei_init (GstVaapiEncoderH264Fei * encoder)
3318 {
3319   guint32 i;
3320
3321   /* Default encoding entrypoint */
3322   encoder->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
3323   encoder->is_fei_disabled = FALSE;
3324   encoder->is_stats_out_enabled = FALSE;
3325   encoder->fei_mode = GST_VAAPI_FEI_MODE_ENC_PAK;
3326   encoder->search_path = GST_VAAPI_FEI_H264_SEARCH_PATH_DEFAULT;
3327   encoder->len_sp = GST_VAAPI_FEI_H264_SEARCH_PATH_LENGTH_DEFAULT;
3328   encoder->ref_width = GST_VAAPI_FEI_H264_REF_WIDTH_DEFAULT;
3329   encoder->ref_height = GST_VAAPI_FEI_H264_REF_HEIGHT_DEFAULT;
3330   encoder->intra_part_mask = GST_VAAPI_FEI_H264_INTRA_PART_MASK_DEFAULT;
3331   encoder->submb_part_mask = GST_VAAPI_FEI_H264_SUB_MB_PART_MASK_DEFAULT;
3332   /* default num ref frames */
3333   encoder->num_ref_frames = 1;
3334   /* Multi-view coding information */
3335   encoder->is_mvc = FALSE;
3336   encoder->num_views = 1;
3337   encoder->view_idx = 0;
3338   memset (encoder->view_ids, 0, sizeof (encoder->view_ids));
3339
3340   /* re-ordering  list initialize */
3341   for (i = 0; i < MAX_NUM_VIEWS; i++) {
3342     GstVaapiH264ViewReorderPool *const reorder_pool =
3343         &encoder->reorder_pools[i];
3344     g_queue_init (&reorder_pool->reorder_frame_list);
3345     reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_NONE;
3346     reorder_pool->frame_index = 0;
3347     reorder_pool->cur_frame_num = 0;
3348     reorder_pool->cur_present_index = 0;
3349   }
3350
3351   /* reference list info initialize */
3352   for (i = 0; i < MAX_NUM_VIEWS; i++) {
3353     GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i];
3354     g_queue_init (&ref_pool->ref_list);
3355     ref_pool->max_ref_frames = 0;
3356     ref_pool->max_reflist0_count = 1;
3357     ref_pool->max_reflist1_count = 1;
3358   }
3359 }
3360
3361 static void
3362 gst_vaapi_encoder_h264_fei_finalize (GObject * gobject)
3363 {
3364   /*free private buffers */
3365   GstVaapiEncoderH264Fei *const encoder = GST_VAAPI_ENCODER_H264_FEI (gobject);
3366   GstVaapiEncoder *base_encoder = GST_VAAPI_ENCODER (gobject);
3367   GstVaapiEncoder *enc_base_encoder = GST_VAAPI_ENCODER_CAST (encoder->feienc);
3368   GstVaapiMiniObject *object = GST_VAAPI_MINI_OBJECT (encoder->feipak);
3369   GstVaapiEncPicture *pic;
3370   GstVaapiEncoderH264FeiRef *ref;
3371   guint32 i;
3372
3373   if ((encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC_PAK)
3374       || (encoder->fei_mode == GST_VAAPI_FEI_MODE_PAK)) {
3375
3376     gst_buffer_replace (&encoder->sps_data, NULL);
3377     gst_buffer_replace (&encoder->subset_sps_data, NULL);
3378     gst_buffer_replace (&encoder->pps_data, NULL);
3379
3380     /* reference list info de-init */
3381     for (i = 0; i < MAX_NUM_VIEWS; i++) {
3382       GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i];
3383       while (!g_queue_is_empty (&ref_pool->ref_list)) {
3384         ref = (GstVaapiEncoderH264FeiRef *)
3385             g_queue_pop_head (&ref_pool->ref_list);
3386         reference_pic_free (encoder, ref);
3387       }
3388       g_queue_clear (&ref_pool->ref_list);
3389     }
3390
3391     /* re-ordering  list initialize */
3392     for (i = 0; i < MAX_NUM_VIEWS; i++) {
3393       GstVaapiH264ViewReorderPool *const reorder_pool =
3394           &encoder->reorder_pools[i];
3395       while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
3396         pic = (GstVaapiEncPicture *)
3397             g_queue_pop_head (&reorder_pool->reorder_frame_list);
3398         gst_vaapi_enc_picture_unref (pic);
3399       }
3400       g_queue_clear (&reorder_pool->reorder_frame_list);
3401     }
3402
3403   } else {
3404     if (encoder->coded_buf != VA_INVALID_ID) {
3405       GST_VAAPI_DISPLAY_LOCK (base_encoder->display);
3406       vaapi_destroy_buffer (base_encoder->va_display, &encoder->coded_buf);
3407       GST_VAAPI_DISPLAY_UNLOCK (base_encoder->display);
3408       encoder->coded_buf = VA_INVALID_ID;
3409     }
3410
3411     if (enc_base_encoder->va_context != VA_INVALID_ID) {
3412       GST_VAAPI_DISPLAY_LOCK (base_encoder->display);
3413       vaDestroyContext (base_encoder->va_display, enc_base_encoder->va_context);
3414       GST_VAAPI_DISPLAY_UNLOCK (base_encoder->display);
3415       enc_base_encoder->va_context = VA_INVALID_ID;
3416     }
3417
3418     if (encoder->va_config != VA_INVALID_ID) {
3419       GST_VAAPI_DISPLAY_LOCK (base_encoder->display);
3420       vaDestroyConfig (base_encoder->va_display, encoder->va_config);
3421       GST_VAAPI_DISPLAY_UNLOCK (base_encoder->display);
3422       encoder->va_config = VA_INVALID_ID;
3423     }
3424
3425     gst_vaapi_encoder_replace (&enc_base_encoder, NULL);
3426     gst_vaapi_mini_object_replace (&object, NULL);
3427
3428     encoder->ref_pool_ptr = NULL;
3429     encoder->feienc = NULL;
3430   }
3431
3432   G_OBJECT_CLASS (gst_vaapi_encoder_h264_fei_parent_class)->finalize (gobject);
3433 }
3434
3435 static void
3436 set_view_ids (GstVaapiEncoderH264Fei * const encoder, const GValue * value)
3437 {
3438   guint i, j;
3439   guint len = gst_value_array_get_size (value);
3440
3441   if (len == 0)
3442     goto set_default_ids;
3443
3444   if (len != encoder->num_views) {
3445     GST_WARNING ("The view number is %d, but %d view IDs are provided. Just "
3446         "fallback to use default view IDs.", encoder->num_views, len);
3447     goto set_default_ids;
3448   }
3449
3450   for (i = 0; i < len; i++) {
3451     const GValue *val = gst_value_array_get_value (value, i);
3452     encoder->view_ids[i] = g_value_get_uint (val);
3453   }
3454
3455   /* check whether duplicated ID */
3456   for (i = 0; i < len; i++) {
3457     for (j = i + 1; j < len; j++) {
3458       if (encoder->view_ids[i] == encoder->view_ids[j]) {
3459         GST_WARNING ("The view %d and view %d have same view ID %d. Just "
3460             "fallback to use default view IDs.", i, j, encoder->view_ids[i]);
3461         goto set_default_ids;
3462       }
3463     }
3464   }
3465
3466   return;
3467
3468 set_default_ids:
3469   {
3470     for (i = 0; i < encoder->num_views; i++)
3471       encoder->view_ids[i] = i;
3472   }
3473 }
3474
3475 static void
3476 get_view_ids (GstVaapiEncoderH264Fei * const encoder, GValue * value)
3477 {
3478   guint i;
3479   GValue id = G_VALUE_INIT;
3480
3481   g_value_reset (value);
3482   g_value_init (&id, G_TYPE_UINT);
3483
3484   for (i = 0; i < encoder->num_views; i++) {
3485     g_value_set_uint (&id, encoder->view_ids[i]);
3486     gst_value_array_append_value (value, &id);
3487   }
3488   g_value_unset (&id);
3489 }
3490
3491 /**
3492  * @ENCODER_H264_FEI_PROP_RATECONTROL: Rate control (#GstVaapiRateControl).
3493  * @ENCODER_H264_FEI_PROP_TUNE: The tuning options (#GstVaapiEncoderTune).
3494  * @ENCODER_H264_FEI_PROP_MAX_BFRAMES: Number of B-frames between I
3495  *   and P (uint).
3496  * @ENCODER_H264_FEI_PROP_INIT_QP: Initial quantizer value (uint).
3497  * @ENCODER_H264_FEI_PROP_MIN_QP: Minimal quantizer value (uint).
3498  * @ENCODER_H264_FEI_PROP_NUM_SLICES: Number of slices per frame (uint).
3499  * @ENCODER_H264_FEI_PROP_CABAC: Enable CABAC entropy coding mode (bool).
3500  * @ENCODER_H264_FEI_PROP_DCT8X8: Enable adaptive use of 8x8
3501  *   transforms in I-frames (bool).
3502  * @ENCODER_H264_FEI_PROP_CPB_LENGTH: Length of the CPB buffer
3503  *   in milliseconds (uint).
3504  * @ENCODER_H264_FEI_PROP_NUM_VIEWS: Number of views per frame.
3505  * @ENCODER_H264_FEI_PROP_VIEW_IDS: View IDs
3506  * @ENCODER_H264_FEI_PROP_MAX_QP: Maximal quantizer value (uint).
3507  *
3508  * The set of H.264 encoder specific configurable properties.
3509  */
3510 enum
3511 {
3512   ENCODER_H264_FEI_PROP_RATECONTROL = 1,
3513   ENCODER_H264_FEI_PROP_TUNE,
3514   ENCODER_H264_FEI_PROP_MAX_BFRAMES,
3515   ENCODER_H264_FEI_PROP_INIT_QP,
3516   ENCODER_H264_FEI_PROP_MIN_QP,
3517   ENCODER_H264_FEI_PROP_NUM_SLICES,
3518   ENCODER_H264_FEI_PROP_CABAC,
3519   ENCODER_H264_FEI_PROP_DCT8X8,
3520   ENCODER_H264_FEI_PROP_CPB_LENGTH,
3521   ENCODER_H264_FEI_PROP_NUM_VIEWS,
3522   ENCODER_H264_FEI_PROP_VIEW_IDS,
3523   ENCODER_H264_PROP_FEI_DISABLE,
3524   ENCODER_H264_PROP_NUM_MV_PREDICT_L0,
3525   ENCODER_H264_PROP_NUM_MV_PREDICT_L1,
3526   ENCODER_H264_PROP_SEARCH_WINDOW,
3527   ENCODER_H264_PROP_LEN_SP,
3528   ENCODER_H264_PROP_SEARCH_PATH,
3529   ENCODER_H264_PROP_REF_WIDTH,
3530   ENCODER_H264_PROP_REF_HEIGHT,
3531   ENCODER_H264_PROP_SUBMB_MASK,
3532   ENCODER_H264_PROP_SUBPEL_MODE,
3533   ENCODER_H264_PROP_INTRA_PART_MASK,
3534   ENCODER_H264_PROP_INTRA_SAD,
3535   ENCODER_H264_PROP_INTER_SAD,
3536   ENCODER_H264_PROP_ADAPT_SEARCH,
3537   ENCODER_H264_PROP_MULTI_PRED_L0,
3538   ENCODER_H264_PROP_MULTI_PRED_L1,
3539   ENCODER_H264_PROP_ENABLE_STATS_OUT,
3540   ENCODER_H264_PROP_FEI_MODE,
3541   ENCODER_H264_FEI_PROP_MAX_QP,
3542   ENCODER_H264_FEI_N_PROPERTIES
3543 };
3544
3545 static GParamSpec *properties[ENCODER_H264_FEI_N_PROPERTIES];
3546
3547 static void
3548 gst_vaapi_encoder_h264_fei_set_property (GObject * object, guint prop_id,
3549     const GValue * value, GParamSpec * pspec)
3550 {
3551   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
3552   GstVaapiEncoderH264Fei *const encoder =
3553       GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
3554   GstVaapiEncoder *enc_base_encoder = GST_VAAPI_ENCODER_CAST (encoder->feienc);
3555   GstVaapiEncoderStatus status;
3556
3557   switch (prop_id) {
3558     case ENCODER_H264_FEI_PROP_RATECONTROL:
3559       gst_vaapi_encoder_set_rate_control (base_encoder,
3560           g_value_get_enum (value));
3561       break;
3562     case ENCODER_H264_FEI_PROP_TUNE:
3563       gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value));
3564       break;
3565     case ENCODER_H264_FEI_PROP_MAX_BFRAMES:
3566       encoder->num_bframes = g_value_get_uint (value);
3567       break;
3568     case ENCODER_H264_FEI_PROP_INIT_QP:
3569       encoder->init_qp = g_value_get_uint (value);
3570       break;
3571     case ENCODER_H264_FEI_PROP_MIN_QP:
3572       encoder->min_qp = g_value_get_uint (value);
3573       break;
3574     case ENCODER_H264_FEI_PROP_NUM_SLICES:
3575       encoder->num_slices = g_value_get_uint (value);
3576       break;
3577     case ENCODER_H264_FEI_PROP_CABAC:
3578       encoder->use_cabac = g_value_get_boolean (value);
3579       break;
3580     case ENCODER_H264_FEI_PROP_DCT8X8:
3581       encoder->use_dct8x8 = g_value_get_boolean (value);
3582       break;
3583     case ENCODER_H264_FEI_PROP_CPB_LENGTH:
3584       encoder->cpb_length = g_value_get_uint (value);
3585       break;
3586     case ENCODER_H264_FEI_PROP_NUM_VIEWS:
3587       encoder->num_views = g_value_get_uint (value);
3588       break;
3589     case ENCODER_H264_FEI_PROP_VIEW_IDS:
3590       set_view_ids (encoder, value);
3591       break;
3592     case ENCODER_H264_PROP_FEI_DISABLE:
3593       encoder->is_fei_disabled = g_value_get_boolean (value);
3594       if (!encoder->is_fei_disabled)
3595         encoder->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_FEI;
3596       break;
3597     case ENCODER_H264_PROP_NUM_MV_PREDICT_L0:
3598       encoder->num_mv_predictors_l0 = g_value_get_uint (value);
3599       break;
3600     case ENCODER_H264_PROP_NUM_MV_PREDICT_L1:
3601       encoder->num_mv_predictors_l1 = g_value_get_uint (value);
3602       break;
3603     case ENCODER_H264_PROP_SEARCH_WINDOW:
3604       encoder->search_window = g_value_get_enum (value);
3605       break;
3606     case ENCODER_H264_PROP_LEN_SP:
3607       encoder->len_sp = g_value_get_uint (value);
3608       break;
3609     case ENCODER_H264_PROP_SEARCH_PATH:
3610       encoder->search_path = g_value_get_enum (value);
3611       break;
3612     case ENCODER_H264_PROP_REF_WIDTH:
3613       encoder->ref_width = g_value_get_uint (value);
3614       break;
3615     case ENCODER_H264_PROP_REF_HEIGHT:
3616       encoder->ref_height = g_value_get_uint (value);
3617       break;
3618     case ENCODER_H264_PROP_SUBMB_MASK:
3619       encoder->submb_part_mask = g_value_get_flags (value);
3620       break;
3621     case ENCODER_H264_PROP_SUBPEL_MODE:
3622       encoder->subpel_mode = g_value_get_enum (value);
3623       break;
3624     case ENCODER_H264_PROP_INTRA_PART_MASK:
3625       encoder->intra_part_mask = g_value_get_flags (value);
3626       break;
3627     case ENCODER_H264_PROP_INTRA_SAD:
3628       encoder->intra_sad = g_value_get_enum (value);
3629       break;
3630     case ENCODER_H264_PROP_INTER_SAD:
3631       encoder->inter_sad = g_value_get_enum (value);
3632       break;
3633     case ENCODER_H264_PROP_ADAPT_SEARCH:
3634       encoder->adaptive_search = g_value_get_boolean (value) ? 1 : 0;
3635       break;
3636     case ENCODER_H264_PROP_MULTI_PRED_L0:
3637       encoder->multi_predL0 = g_value_get_boolean (value) ? 1 : 0;
3638       break;
3639     case ENCODER_H264_PROP_MULTI_PRED_L1:
3640       encoder->multi_predL1 = g_value_get_boolean (value) ? 1 : 0;
3641       break;
3642     case ENCODER_H264_PROP_ENABLE_STATS_OUT:
3643       encoder->is_stats_out_enabled = g_value_get_boolean (value);
3644       break;
3645     case ENCODER_H264_PROP_FEI_MODE:
3646       encoder->fei_mode = g_value_get_flags (value);
3647       if (encoder->fei_mode == GST_VAAPI_FEI_MODE_ENC) {
3648         g_warning ("============= ENC only mode selected ============ \n"
3649             "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");
3650         /*Fixme: Support ENC only mode with out running PAK */
3651         encoder->fei_mode = GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK;
3652       } else if (encoder->fei_mode == GST_VAAPI_FEI_MODE_PAK) {
3653         g_warning ("============ PAK only mode selected ============ \n"
3654             "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");
3655       }
3656
3657       break;
3658     case ENCODER_H264_FEI_PROP_MAX_QP:
3659       encoder->max_qp = g_value_get_uint (value);
3660       break;
3661
3662     default:
3663       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3664   }
3665
3666   if ((prop_id != ENCODER_H264_PROP_FEI_MODE) &&
3667       (prop_id != ENCODER_H264_PROP_FEI_DISABLE) &&
3668       (prop_id != ENCODER_H264_PROP_ENABLE_STATS_OUT)) {
3669
3670     if (enc_base_encoder) {
3671       g_object_set_property ((GObject *) enc_base_encoder,
3672           g_param_spec_get_name (pspec), value);
3673     }
3674
3675     if ((prop_id == ENCODER_H264_FEI_PROP_MAX_BFRAMES) ||
3676         (prop_id == ENCODER_H264_FEI_PROP_VIEW_IDS) ||
3677         (prop_id == ENCODER_H264_FEI_PROP_NUM_VIEWS)) {
3678       if (encoder->feipak) {
3679         status =
3680             gst_vaapi_feipak_h264_set_property (encoder->feipak, prop_id,
3681             value);
3682         if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS) {
3683           GST_ERROR ("failed to set pak property");
3684           return;
3685         }
3686       }
3687     }
3688   }
3689 }
3690
3691 static void
3692 gst_vaapi_encoder_h264_fei_get_property (GObject * object, guint prop_id,
3693     GValue * value, GParamSpec * pspec)
3694 {
3695   GstVaapiEncoderH264Fei *const encoder =
3696       GST_VAAPI_ENCODER_H264_FEI_CAST (object);
3697   GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
3698
3699   switch (prop_id) {
3700     case ENCODER_H264_FEI_PROP_RATECONTROL:
3701       g_value_set_enum (value, base_encoder->rate_control);
3702       break;
3703     case ENCODER_H264_FEI_PROP_TUNE:
3704       g_value_set_enum (value, base_encoder->tune);
3705       break;
3706     case ENCODER_H264_FEI_PROP_MAX_BFRAMES:
3707       g_value_set_uint (value, encoder->num_bframes);
3708       break;
3709     case ENCODER_H264_FEI_PROP_INIT_QP:
3710       g_value_set_uint (value, encoder->init_qp);
3711       break;
3712     case ENCODER_H264_FEI_PROP_MIN_QP:
3713       g_value_set_uint (value, encoder->min_qp);
3714       break;
3715     case ENCODER_H264_FEI_PROP_NUM_SLICES:
3716       g_value_set_uint (value, encoder->num_slices);
3717       break;
3718     case ENCODER_H264_FEI_PROP_CABAC:
3719       g_value_set_boolean (value, encoder->use_cabac);
3720       break;
3721     case ENCODER_H264_FEI_PROP_DCT8X8:
3722       g_value_set_boolean (value, encoder->use_dct8x8);
3723       break;
3724     case ENCODER_H264_FEI_PROP_CPB_LENGTH:
3725       g_value_set_uint (value, encoder->cpb_length);
3726       break;
3727     case ENCODER_H264_FEI_PROP_NUM_VIEWS:
3728       g_value_set_uint (value, encoder->num_views);
3729       break;
3730     case ENCODER_H264_FEI_PROP_VIEW_IDS:
3731       get_view_ids (encoder, value);
3732       break;
3733     case ENCODER_H264_PROP_FEI_DISABLE:
3734       g_value_set_boolean (value, encoder->is_fei_disabled);
3735       break;
3736     case ENCODER_H264_PROP_NUM_MV_PREDICT_L0:
3737       g_value_set_uint (value, encoder->num_mv_predictors_l0);
3738       break;
3739     case ENCODER_H264_PROP_NUM_MV_PREDICT_L1:
3740       g_value_set_uint (value, encoder->num_mv_predictors_l1);
3741       break;
3742     case ENCODER_H264_PROP_SEARCH_WINDOW:
3743       g_value_set_enum (value, encoder->search_window);
3744       break;
3745     case ENCODER_H264_PROP_LEN_SP:
3746       g_value_set_uint (value, encoder->len_sp);
3747       break;
3748     case ENCODER_H264_PROP_SEARCH_PATH:
3749       g_value_set_enum (value, encoder->search_path);
3750       break;
3751     case ENCODER_H264_PROP_REF_WIDTH:
3752       g_value_set_uint (value, encoder->ref_width);
3753       break;
3754     case ENCODER_H264_PROP_REF_HEIGHT:
3755       g_value_set_uint (value, encoder->ref_height);
3756       break;
3757     case ENCODER_H264_PROP_SUBMB_MASK:
3758       g_value_set_flags (value, encoder->submb_part_mask);
3759       break;
3760     case ENCODER_H264_PROP_SUBPEL_MODE:
3761       g_value_set_enum (value, encoder->subpel_mode);
3762       break;
3763     case ENCODER_H264_PROP_INTRA_PART_MASK:
3764       g_value_set_flags (value, encoder->intra_part_mask);
3765       break;
3766     case ENCODER_H264_PROP_INTRA_SAD:
3767       g_value_set_enum (value, encoder->intra_sad);
3768       break;
3769     case ENCODER_H264_PROP_INTER_SAD:
3770       g_value_set_enum (value, encoder->inter_sad);
3771       break;
3772     case ENCODER_H264_PROP_ADAPT_SEARCH:
3773       g_value_set_boolean (value, encoder->adaptive_search);
3774       break;
3775     case ENCODER_H264_PROP_MULTI_PRED_L0:
3776       g_value_set_boolean (value, encoder->multi_predL0);
3777       break;
3778     case ENCODER_H264_PROP_MULTI_PRED_L1:
3779       g_value_set_boolean (value, encoder->multi_predL1);
3780       break;
3781     case ENCODER_H264_PROP_ENABLE_STATS_OUT:
3782       g_value_set_boolean (value, encoder->is_stats_out_enabled);
3783       break;
3784     case ENCODER_H264_PROP_FEI_MODE:
3785       g_value_set_flags (value, encoder->fei_mode);
3786       break;
3787     case ENCODER_H264_FEI_PROP_MAX_QP:
3788       g_value_set_uint (value, encoder->max_qp);
3789       break;
3790     default:
3791       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3792   }
3793 }
3794
3795 static inline gboolean
3796 context_get_attribute (GstVaapiContext * context, VAConfigAttribType type,
3797     guint * out_value_ptr)
3798 {
3799   return gst_vaapi_get_config_attribute (GST_VAAPI_OBJECT_DISPLAY (context),
3800       context->va_profile, context->va_entrypoint, type, out_value_ptr);
3801 }
3802
3803 static gboolean
3804 create_context_for_enc (GstVaapiEncoder * fei_encoder,
3805     GstVaapiEncoder * enc_encoder)
3806 {
3807   GstVaapiEncoderH264Fei *const feiencoder =
3808       GST_VAAPI_ENCODER_H264_FEI (fei_encoder);
3809   GstVaapiContext *context = fei_encoder->context;
3810   const GstVaapiContextInfo *const cip = &context->info;
3811   GstVaapiDisplay *const display = fei_encoder->display;
3812   const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
3813   guint va_rate_control;
3814   VAConfigAttrib attribs[5], *attrib = attribs;
3815   VASurfaceID surface_id;
3816   VAStatus status;
3817   GArray *surfaces = NULL;
3818   gboolean success = FALSE;
3819   guint i, value, va_chroma_format;
3820
3821   if (!context->surfaces)
3822     goto cleanup;
3823
3824   /* Create VA surfaces list for vaCreateContext() */
3825   surfaces = g_array_sized_new (FALSE,
3826       FALSE, sizeof (VASurfaceID), context->surfaces->len);
3827   if (!surfaces)
3828     goto cleanup;
3829
3830   for (i = 0; i < context->surfaces->len; i++) {
3831     GstVaapiSurface *const surface = g_ptr_array_index (context->surfaces, i);
3832     if (!surface)
3833       goto cleanup;
3834     surface_id = GST_VAAPI_OBJECT_ID (surface);
3835     g_array_append_val (surfaces, surface_id);
3836   }
3837   g_assert (surfaces->len == context->surfaces->len);
3838   if (!cip->profile || !cip->entrypoint)
3839     goto cleanup;
3840
3841   /* Validate VA surface format */
3842   va_chroma_format = from_GstVaapiChromaType (cip->chroma_type);
3843   if (!va_chroma_format)
3844     goto cleanup;
3845   attrib->type = VAConfigAttribRTFormat;
3846   if (!context_get_attribute (context, attrib->type, &value))
3847     goto cleanup;
3848   if (!(value & va_chroma_format)) {
3849     GST_ERROR ("unsupported chroma format (%s)",
3850         string_of_va_chroma_format (va_chroma_format));
3851     goto cleanup;
3852   }
3853   attrib->value = va_chroma_format;
3854   attrib++;
3855
3856   /* Rate control */
3857   va_rate_control = from_GstVaapiRateControl (config->rc_mode);
3858   if (va_rate_control != VA_RC_NONE) {
3859     attrib->type = VAConfigAttribRateControl;
3860     if (!context_get_attribute (context, attrib->type, &value))
3861       goto cleanup;
3862
3863     if ((value & va_rate_control) != va_rate_control) {
3864       GST_ERROR ("unsupported %s rate control",
3865           string_of_VARateControl (va_rate_control));
3866       goto cleanup;
3867     }
3868     attrib->value = va_rate_control;
3869     attrib++;
3870   }
3871
3872   /* Packed headers */
3873   if (config->packed_headers) {
3874     attrib->type = VAConfigAttribEncPackedHeaders;
3875     attrib->value = VA_ENC_PACKED_HEADER_NONE;
3876     attrib++;
3877   }
3878
3879   if (cip->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_FEI) {
3880     attrib->type = (VAConfigAttribType) VAConfigAttribFEIFunctionType;
3881     attrib->value = VA_FEI_FUNCTION_ENC;
3882     attrib++;
3883     attrib->type = (VAConfigAttribType) VAConfigAttribFEIMVPredictors;
3884     attrib->value = 1;
3885     attrib++;
3886   }
3887
3888   GST_VAAPI_DISPLAY_LOCK (display);
3889   status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
3890       context->va_profile, context->va_entrypoint, attribs, attrib - attribs,
3891       &feiencoder->va_config);
3892   GST_VAAPI_DISPLAY_UNLOCK (display);
3893   if (!vaapi_check_status (status, "vaCreateConfig()"))
3894     goto cleanup;
3895
3896   GST_VAAPI_DISPLAY_LOCK (display);
3897   status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
3898       feiencoder->va_config, GST_ROUND_UP_16 (cip->width),
3899       GST_ROUND_UP_16 (cip->height), VA_PROGRESSIVE,
3900       (VASurfaceID *) surfaces->data, surfaces->len, &enc_encoder->va_context);
3901   GST_VAAPI_DISPLAY_UNLOCK (display);
3902   if (!vaapi_check_status (status, "vaCreateContext()"))
3903     goto cleanup;
3904
3905   success = TRUE;
3906
3907 cleanup:
3908   if (surfaces)
3909     g_array_free (surfaces, TRUE);
3910   return success;
3911 }
3912
3913 static const GstVaapiEncoderClassData fei_encoder_class_data = {
3914   .codec = GST_VAAPI_CODEC_H264,
3915   .packed_headers = SUPPORTED_PACKED_HEADERS,
3916   .rate_control_get_type = gst_vaapi_rate_control_get_type,
3917   .default_rate_control = DEFAULT_RATECONTROL,
3918   .rate_control_mask = SUPPORTED_RATECONTROLS,
3919   .encoder_tune_get_type = gst_vaapi_encoder_tune_get_type,
3920   .default_encoder_tune = GST_VAAPI_ENCODER_TUNE_NONE,
3921   .encoder_tune_mask = SUPPORTED_TUNE_OPTIONS,
3922 };
3923
3924 static void
3925 gst_vaapi_encoder_h264_fei_class_init (GstVaapiEncoderH264FeiClass * klass)
3926 {
3927   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
3928   GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass);
3929
3930   encoder_class->class_data = &fei_encoder_class_data;
3931   encoder_class->reconfigure = gst_vaapi_encoder_h264_fei_reconfigure;
3932   encoder_class->reordering = gst_vaapi_encoder_h264_fei_reordering;
3933   encoder_class->encode = gst_vaapi_encoder_h264_fei_encode;
3934   encoder_class->flush = gst_vaapi_encoder_h264_fei_flush;
3935   encoder_class->get_codec_data = gst_vaapi_encoder_h264_fei_get_codec_data;
3936   encoder_class->ensure_secondary_context =
3937       gst_vaapi_encoder_h264_fei_ensure_secondary_context;
3938
3939   object_class->set_property = gst_vaapi_encoder_h264_fei_set_property;
3940   object_class->get_property = gst_vaapi_encoder_h264_fei_get_property;
3941   object_class->finalize = gst_vaapi_encoder_h264_fei_finalize;
3942
3943   /**
3944    * GstVaapiEncoderH264Fei:rate-control:
3945    *
3946    * The desired rate control mode, expressed as a #GstVaapiRateControl.
3947    */
3948   properties[ENCODER_H264_FEI_PROP_RATECONTROL] =
3949       g_param_spec_enum ("rate-control", "Rate Control", "Rate control mode",
3950       fei_encoder_class_data.rate_control_get_type (),
3951       fei_encoder_class_data.default_rate_control,
3952       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
3953       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
3954
3955   /**
3956    * GstVaapiEncoderH264Fei:tune:
3957    *
3958    * The desired encoder tuning option.
3959    */
3960   properties[ENCODER_H264_FEI_PROP_TUNE] =
3961       g_param_spec_enum ("tune",
3962       "Encoder Tuning",
3963       "Encoder tuning option",
3964       fei_encoder_class_data.encoder_tune_get_type (),
3965       fei_encoder_class_data.default_encoder_tune,
3966       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
3967       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
3968
3969   /**
3970    * GstVaapiEncoderH264Fei:max-bframes:
3971    *
3972    * The number of B-frames between I and P.
3973    */
3974   properties[ENCODER_H264_FEI_PROP_MAX_BFRAMES] =
3975       g_param_spec_uint ("max-bframes",
3976       "Max B-Frames", "Number of B-frames between I and P", 0, 10, 1,
3977       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
3978       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
3979
3980   /**
3981    * GstVaapiEncoderH264Fei:init-qp:
3982    *
3983    * The initial quantizer value.
3984    */
3985   properties[ENCODER_H264_FEI_PROP_INIT_QP] =
3986       g_param_spec_uint ("init-qp",
3987       "Initial QP", "Initial quantizer value", 0, 51, 26,
3988       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
3989       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
3990
3991   /**
3992    * GstVaapiEncoderH264Fei:min-qp:
3993    *
3994    * The minimum quantizer value.
3995    */
3996   properties[ENCODER_H264_FEI_PROP_MIN_QP] =
3997       g_param_spec_uint ("min-qp",
3998       "Minimum QP", "Minimum quantizer value", 0, 51, 1,
3999       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4000       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4001
4002   /**
4003    * GstVaapiEncoderH264Fei:max-qp:
4004    *
4005    * The maximum quantizer value.
4006    *
4007    * Since: 1.18
4008    */
4009   properties[ENCODER_H264_FEI_PROP_MAX_QP] =
4010       g_param_spec_uint ("max-qp",
4011       "Maximum QP", "Maximum quantizer value", 0, 51, 51,
4012       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4013       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4014
4015   /**
4016    * GstVaapiEncoderH264Fei:num-slices:
4017    *
4018    * The number of slices per frame.
4019    */
4020   properties[ENCODER_H264_FEI_PROP_NUM_SLICES] =
4021       g_param_spec_uint ("num-slices",
4022       "Number of Slices",
4023       "Number of slices per frame",
4024       1, 200, 1,
4025       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4026       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4027
4028   /**
4029    * GstVaapiEncoderH264Fei:cabac:
4030    *
4031    * Enable CABAC entropy coding mode for improved compression ratio,
4032    * at the expense that the minimum target profile is Main. Default
4033    * is CAVLC entropy coding mode.
4034    */
4035   properties[ENCODER_H264_FEI_PROP_CABAC] =
4036       g_param_spec_boolean ("cabac",
4037       "Enable CABAC",
4038       "Enable CABAC entropy coding mode",
4039       TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4040       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4041
4042   /**
4043    * GstVaapiEncoderH264Fei:dct8x8:
4044    *
4045    * Enable adaptive use of 8x8 transforms in I-frames. This improves
4046    * the compression ratio by the minimum target profile is High.
4047    * Default is to use 4x4 DCT only.
4048    */
4049   properties[ENCODER_H264_FEI_PROP_DCT8X8] =
4050       g_param_spec_boolean ("dct8x8",
4051       "Enable 8x8 DCT",
4052       "Enable adaptive use of 8x8 transforms in I-frames",
4053       TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4054       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4055
4056   /**
4057    * GstVaapiEncoderH264Fei:cpb-length:
4058    *
4059    * The size of the CPB buffer in milliseconds.
4060    */
4061   properties[ENCODER_H264_FEI_PROP_CPB_LENGTH] =
4062       g_param_spec_uint ("cpb-length",
4063       "CPB Length", "Length of the CPB buffer in milliseconds",
4064       1, 10000, DEFAULT_CPB_LENGTH,
4065       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4066       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4067
4068   /**
4069    * GstVaapiEncoderH264Fei:num-views:
4070    *
4071    * The number of views for MVC encoding .
4072    */
4073   properties[ENCODER_H264_FEI_PROP_NUM_VIEWS] =
4074       g_param_spec_uint ("num-views",
4075       "Number of Views",
4076       "Number of Views for MVC encoding",
4077       1, MAX_NUM_VIEWS, 1,
4078       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4079       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4080   /**
4081    * GstVaapiEncoderH264Fei:view-ids:
4082    *
4083    * The view ids for MVC encoding .
4084    */
4085   properties[ENCODER_H264_FEI_PROP_VIEW_IDS] =
4086       gst_param_spec_array ("view-ids",
4087       "View IDs", "Set of View Ids used for MVC encoding",
4088       g_param_spec_uint ("view-id-value", "View id value",
4089           "view id values used for mvc encoding", 0, MAX_VIEW_ID, 0,
4090           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
4091       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4092       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4093
4094   /**
4095    * GstVaapiEncoderH264: disable-fei:
4096    *
4097    * Disable FEI mode Encode: disabling fei will results
4098    * the encoder to use VAEntrypointEncSlice, which means
4099    * vaapi-intel-driver will be using a different media kerenl.
4100    * And most of the properties associated with this element
4101    * will be non functional.
4102    */
4103   properties[ENCODER_H264_PROP_FEI_DISABLE] =
4104       g_param_spec_boolean ("disable-fei",
4105       "Disable FEI Mode Encode",
4106       "Disable Flexible Encoding Infrasturcture", FALSE,
4107       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4108       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4109
4110
4111   /**
4112    * GstVaapiEncoderH264: stats-out:
4113    *
4114    * Enable outputting fei buffers MV, MBCode and Distortion.
4115    * If enabled, encoder will allocate memory for these buffers
4116    * and submit to the driver even for ENC_PAK mode so that
4117    * the output data can be extraced for analysis after the
4118    * complettion of each frame ncode
4119    */
4120   properties[ENCODER_H264_PROP_ENABLE_STATS_OUT] =
4121       g_param_spec_boolean ("stats-out",
4122       "stats out",
4123       "Enable stats out for fei",
4124       TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4125       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4126
4127   /**
4128    * GstVaapiEncoderH264:num_mv_predictors_l0:
4129    * Indicate how many mv predictors should be used for l0 frames.
4130    * Only valid if MVPredictor input has been enabled.
4131    */
4132   properties[ENCODER_H264_PROP_NUM_MV_PREDICT_L0] =
4133       g_param_spec_uint ("num-mvpredict-l0",
4134       "Num mv predict l0",
4135       "Indicate how many predictors should be used for l0,"
4136       "only valid if MVPredictor input enabled",
4137       0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4138       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4139   /**
4140    * GstVaapiEncoderH264:num_mv_predictors_l1:
4141    * Indicate how many mv predictors should be used for l1 frames.
4142    * Only valid if MVPredictor input has been enabled.
4143    *
4144    */
4145   properties[ENCODER_H264_PROP_NUM_MV_PREDICT_L1] =
4146       g_param_spec_uint ("num-mvpredict-l1",
4147       "Num mv predict l1",
4148       "Indicate how many predictors should be used for l1,"
4149       "only valid if MVPredictor input enabled",
4150       0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4151       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4152   /**
4153    * GstVaapiEncoderH264:search-window:
4154    * Use predefined Search Window
4155    */
4156   properties[ENCODER_H264_PROP_SEARCH_WINDOW] =
4157       g_param_spec_enum ("search-window",
4158       "search window",
4159       "Specify one of the predefined search path",
4160       GST_VAAPI_TYPE_FEI_H264_SEARCH_WINDOW,
4161       GST_VAAPI_FEI_H264_SEARCH_WINDOW_DEFAULT,
4162       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4163       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4164
4165   /**
4166    * GstVaapiEncoderH264:len-sp:
4167    * Defines the maximum number of Search Units per reference.
4168    */
4169   properties[ENCODER_H264_PROP_LEN_SP] =
4170       g_param_spec_uint ("len-sp",
4171       "length of search path",
4172       "This value defines number of search units in search path",
4173       1, 63, 32,
4174       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4175       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4176
4177   /**
4178    * GstVaapiEncoderH264:search-path:
4179    * SearchPath defines the motion search method.
4180    * Zero means full search, 1 indicate diamond search.
4181    */
4182   properties[ENCODER_H264_PROP_SEARCH_PATH] =
4183       g_param_spec_enum ("search-path",
4184       "search path",
4185       "Specify search path",
4186       GST_VAAPI_TYPE_FEI_H264_SEARCH_PATH,
4187       GST_VAAPI_FEI_H264_SEARCH_PATH_DEFAULT,
4188       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4189       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4190
4191   /**
4192    * GstVaapiEncoderH264:ref-width:
4193    * Specifies the search region width in pixels.
4194    */
4195   properties[ENCODER_H264_PROP_REF_WIDTH] =
4196       g_param_spec_uint ("ref-width",
4197       "ref width",
4198       "Width of search region in pixel, must be multiple of 4",
4199       4, 64, 32,
4200       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4201       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4202
4203   /**
4204    * GstVaapiEncoderH264:ref-height:
4205    * Specifies the search region height in pixels.
4206    */
4207   properties[ENCODER_H264_PROP_REF_HEIGHT] =
4208       g_param_spec_uint ("ref-height",
4209       "ref height",
4210       "Height of search region in pixel, must be multiple of 4",
4211       4, 32, 32,
4212       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4213       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4214   /**
4215    * GstVaapiEncoderH264:submb-mask:
4216    * Defines the bit-mask for disabling sub-partition
4217    *
4218    */
4219   properties[ENCODER_H264_PROP_SUBMB_MASK] =
4220       g_param_spec_flags ("submbpart-mask",
4221       "submb part mask",
4222       "defines the bit-mask for disabling sub mb partition",
4223       GST_VAAPI_TYPE_FEI_H264_SUB_MB_PART_MASK,
4224       GST_VAAPI_FEI_H264_SUB_MB_PART_MASK_DEFAULT,
4225       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4226       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4227
4228   /**
4229    * GstVaapiEncoderH264:subpel-mode:
4230    * defines the half/quarter pel modes
4231    * 00: integer mode searching
4232    * 01: half-pel mode searching
4233    * 11: quarter-pel mode searching
4234    */
4235   properties[ENCODER_H264_PROP_SUBPEL_MODE] =
4236       g_param_spec_enum ("subpel-mode",
4237       "subpel mode",
4238       "Sub pixel precision for motion estimation",
4239       GST_VAAPI_TYPE_FEI_H264_SUB_PEL_MODE,
4240       GST_VAAPI_FEI_H264_SUB_PEL_MODE_DEFAULT,
4241       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4242       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4243   /**
4244    * GstVaapiEncoderH264:intrapart-mask:
4245    * Specifies which Luma Intra partition is enabled/disabled
4246    * for intra mode decision
4247    */
4248   properties[ENCODER_H264_PROP_INTRA_PART_MASK] =
4249       g_param_spec_flags ("intrapart-mask",
4250       "intra part mask",
4251       "Specifies which Luma Intra partition is enabled/disabled for"
4252       "intra mode decision",
4253       GST_VAAPI_TYPE_FEI_H264_INTRA_PART_MASK,
4254       GST_VAAPI_FEI_H264_INTRA_PART_MASK_DEFAULT,
4255       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4256       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4257
4258   /**
4259    * GstVaapiEncoderH264:intra-sad:
4260    * Specifies distortion measure adjustments used for
4261    * the motion search SAD comparison.
4262    */
4263   properties[ENCODER_H264_PROP_INTRA_SAD] =
4264       g_param_spec_enum ("intra-sad",
4265       "intra sad",
4266       "Specifies distortion measure adjustments used"
4267       "in the motion search SAD comparison for intra MB",
4268       GST_VAAPI_TYPE_FEI_H264_SAD_MODE, GST_VAAPI_FEI_H264_SAD_MODE_DEFAULT,
4269       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4270       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4271
4272   /**
4273    * GstVaapiEncoderH264:inter-sad:
4274    * Specifies distortion measure adjustments used
4275    * in the motion search SAD comparison for inter MB
4276    */
4277   properties[ENCODER_H264_PROP_INTER_SAD] =
4278       g_param_spec_enum ("inter-sad",
4279       "inter sad",
4280       "Specifies distortion measure adjustments used"
4281       "in the motion search SAD comparison for inter MB",
4282       GST_VAAPI_TYPE_FEI_H264_SAD_MODE, GST_VAAPI_FEI_H264_SAD_MODE_DEFAULT,
4283       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4284       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4285
4286   /**
4287    * GstVaapiEncoderH264:adaptive-search:
4288    * Defines whether adaptive searching is enabled for IME
4289    */
4290   properties[ENCODER_H264_PROP_ADAPT_SEARCH] =
4291       g_param_spec_boolean ("adaptive-search",
4292       "adaptive-search",
4293       "Enable adaptive search",
4294       FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4295       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4296   /**
4297    * GstVaapiEncoderH264:multi-predL0:
4298    * When set to 1, neighbor MV will be used as predictor for list L0,
4299    * otherwise no neighbor MV will be used as predictor
4300    */
4301   properties[ENCODER_H264_PROP_MULTI_PRED_L0] =
4302       g_param_spec_boolean ("multi-predL0",
4303       "multi predL0",
4304       "Enable multi prediction for ref L0 list, when set neighbor MV will be used"
4305       "as predictor, no neighbor MV will be used otherwise",
4306       FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4307       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4308
4309   /**
4310    * GstVaapiEncoderH264:multi-predL1:
4311    * When set to 1, neighbor MV will be used as predictor
4312    * when set to 0, no neighbor MV will be used as predictor.
4313    */
4314   properties[ENCODER_H264_PROP_MULTI_PRED_L1] =
4315       g_param_spec_boolean ("multi-predL1",
4316       "multi predL1",
4317       "Enable multi prediction for ref L1 list, when set neighbor MV will be used"
4318       "as predictor, no neighbor MV will be used otherwise",
4319       FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4320       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4321
4322   /**
4323    * GstVaapiEncoderH264Fei: fei-mode:
4324    *
4325    * Cose ENC, PAK, ENC_PAK, or ENC+PAK
4326    * ENC: Only the Motion Estimation, no transformation or entropy coding
4327    * PAK: transformation, quantization and entropy coding
4328    * ENC_PAK: default mode, enc an pak are invoked by driver, middleware has
4329    control over ENC input only
4330    * ENC+PAK: enc and pak invoked separately, middleware has control over the ENC input,
4331    ENC output, and PAK input
4332    * Encoding mode which can be used for FEI
4333    */
4334   properties[ENCODER_H264_PROP_FEI_MODE] =
4335       g_param_spec_flags ("fei-mode",
4336       "FEI Encoding Mode",
4337       "Functional mode of FEI Encoding",
4338       GST_VAAPI_TYPE_FEI_MODE, GST_VAAPI_FEI_MODE_DEFAULT,
4339       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
4340       GST_VAAPI_PARAM_ENCODER_EXPOSURE);
4341
4342   g_object_class_install_properties (object_class,
4343       ENCODER_H264_FEI_N_PROPERTIES, properties);
4344 }
4345
4346 /**
4347  * gst_vaapi_encoder_h264_fei_set_max_profile:
4348  * @encoder: a #GstVaapiEncoderH264Fei
4349  * @profile: an H.264 #GstVaapiProfile
4350  *
4351  * Notifies the @encoder to use coding tools from the supplied
4352  * @profile at most.
4353  *
4354  * This means that if the minimal profile derived to
4355  * support the specified coding tools is greater than this @profile,
4356  * then an error is returned when the @encoder is configured.
4357  *
4358  * Return value: %TRUE on success
4359  */
4360 gboolean
4361 gst_vaapi_encoder_h264_fei_set_max_profile (GstVaapiEncoderH264Fei *
4362     encoder, GstVaapiProfile profile)
4363 {
4364   guint8 profile_idc;
4365
4366   g_return_val_if_fail (encoder != NULL, FALSE);
4367   g_return_val_if_fail (profile != GST_VAAPI_PROFILE_UNKNOWN, FALSE);
4368
4369   if (encoder->fei_mode == (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK)) {
4370     if (!gst_vaapi_feienc_h264_set_max_profile (encoder->feienc, profile))
4371       return FALSE;
4372     return TRUE;
4373   }
4374
4375   if (gst_vaapi_profile_get_codec (profile) != GST_VAAPI_CODEC_H264)
4376     return FALSE;
4377
4378   profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
4379   if (!profile_idc)
4380     return FALSE;
4381
4382   encoder->max_profile_idc = profile_idc;
4383   return TRUE;
4384 }
4385
4386 /**
4387  * gst_vaapi_encoder_h264_fei_get_profile_and_level:
4388  * @encoder: a #GstVaapiEncoderH264Fei
4389  * @out_profile_ptr: return location for the #GstVaapiProfile
4390  * @out_level_ptr: return location for the #GstVaapiLevelH264
4391  *
4392  * Queries the H.264 @encoder for the active profile and level. That
4393  * information is only constructed and valid after the encoder is
4394  * configured, i.e. after the gst_vaapi_encoder_set_codec_state()
4395  * function is called.
4396  *
4397  * Return value: %TRUE on success
4398  */
4399 gboolean
4400 gst_vaapi_encoder_h264_fei_get_profile_and_level (GstVaapiEncoderH264Fei *
4401     encoder, GstVaapiProfile * out_profile_ptr,
4402     GstVaapiLevelH264 * out_level_ptr)
4403 {
4404   g_return_val_if_fail (encoder != NULL, FALSE);
4405
4406   if (!encoder->profile || !encoder->level)
4407     return FALSE;
4408
4409   if (out_profile_ptr)
4410     *out_profile_ptr = encoder->profile;
4411   if (out_level_ptr)
4412     *out_level_ptr = encoder->level;
4413   return TRUE;
4414 }
4415
4416 /**
4417  * gst_vaapi_encoder_h264_is_fei_stats_out_enabled
4418  * @encoder: a #GstVaapiEncoderH264
4419  *
4420  * check if fei output statis is needed
4421  *
4422  * Return value: %TRUE if output statistic is needed
4423  */
4424 gboolean
4425 gst_vaapi_encoder_h264_is_fei_stats_out_enabled (GstVaapiEncoderH264Fei *
4426     encoder)
4427 {
4428   return !encoder->is_fei_disabled && encoder->is_stats_out_enabled;
4429 }
4430
4431 /**
4432  * gst_vaapi_encoder_h264_fei_get_function_mode
4433  * @encoder: a #GstVaapiEncoderH264Fei
4434  *
4435  * return the configured FEI Encoding mode
4436  *
4437  * Return value: a #GstVaapiFeiMode
4438  */
4439 GstVaapiFeiMode
4440 gst_vaapi_encoder_h264_fei_get_function_mode (GstVaapiEncoderH264Fei * encoder)
4441 {
4442   return encoder->fei_mode;
4443 }
4444
4445 /**
4446  * gst_vaapi_encoder_h264_fei_set_function_mode
4447  * @encoder: a #GstVaapiEncoderH264Fei
4448  *
4449  * set the configured FEI Encoding mode
4450  *
4451  */
4452 void
4453 gst_vaapi_encoder_h264_fei_set_function_mode (GstVaapiEncoderH264Fei * encoder,
4454     guint fei_mode)
4455 {
4456   encoder->fei_mode = fei_mode;
4457 }
4458
4459 static gboolean
4460 gst_vaapi_encoder_h264_fei_ensure_secondary_context (GstVaapiEncoder *
4461     base_encoder)
4462 {
4463   GstVaapiEncoderH264Fei *const feiencoder =
4464       GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
4465   GstVaapiEncoder *enc_base_encoder =
4466       GST_VAAPI_ENCODER_CAST (feiencoder->feienc);
4467   gboolean success;
4468
4469   if (feiencoder->fei_mode != (GST_VAAPI_FEI_MODE_ENC | GST_VAAPI_FEI_MODE_PAK))
4470     return TRUE;
4471
4472   /* Create separate context for ENC */
4473   if (!create_context_for_enc (base_encoder, enc_base_encoder)) {
4474     GST_ERROR ("create vacontext for enc failed.\n");
4475     return FALSE;
4476   }
4477
4478   /*
4479    * create coded-buf for ENC.
4480    * PAK coded-buf is created by parent encoder.
4481    */
4482   success =
4483       vaapi_create_buffer (enc_base_encoder->va_display,
4484       enc_base_encoder->va_context, VAEncCodedBufferType,
4485       base_encoder->codedbuf_size, NULL, &feiencoder->coded_buf, NULL);
4486   if (!success) {
4487     g_error ("failed to create coded buf for feienc.\n");
4488     return FALSE;
4489   }
4490
4491   return TRUE;
4492 }
4493
4494 /**
4495  * gst_vaapi_encoder_h264_fei_new:
4496  * @display: a #GstVaapiDisplay
4497  *
4498  * Creates a new #GstVaapiEncoder for H.264 encoding. Note that the
4499  * only supported output stream format is "byte-stream" format.
4500  *
4501  * Return value: the newly allocated #GstVaapiEncoder object
4502  */
4503 GstVaapiEncoder *
4504 gst_vaapi_encoder_h264_fei_new (GstVaapiDisplay * display)
4505 {
4506   GstVaapiEncoder *base_encoder;
4507   GstVaapiEncoderH264Fei *feiencoder = NULL;
4508   GstVaapiFeiEncH264 *feienc = NULL;
4509   GstVaapiFEIPakH264 *feipak = NULL;
4510
4511   /* create FEIEncoderObject: Default mode of operation in ENC_PAK */
4512   base_encoder =
4513       g_object_new (GST_TYPE_VAAPI_ENCODER_H264_FEI, "display", display, NULL);
4514   if (!base_encoder)
4515     return NULL;
4516   feiencoder = GST_VAAPI_ENCODER_H264_FEI_CAST (base_encoder);
4517
4518   /* create an enc object */
4519   feienc = GST_VAAPI_FEI_ENC_H264 (gst_vaapi_feienc_h264_new (display));
4520   if (!feienc)
4521     goto error;
4522
4523   /* create a pak object */
4524   feipak =
4525       gst_vaapi_feipak_h264_new (base_encoder, display,
4526       base_encoder->va_context);
4527   if (!feipak)
4528     goto error;
4529
4530   feiencoder->feienc = feienc;
4531   feiencoder->feipak = feipak;
4532
4533   return base_encoder;
4534
4535 error:
4536   if (feienc)
4537     g_object_unref (feienc);
4538   if (feipak)
4539     gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) & feipak, NULL);
4540   if (feiencoder)
4541     g_object_unref (feiencoder);
4542
4543   return NULL;
4544 }