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