libxcoder  3.5.1
ni_av_codec_logan.c
Go to the documentation of this file.
1 /*!****************************************************************************
2 *
3 * Copyright (C) 2018 NETINT Technologies.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted.
7 *
8 *******************************************************************************/
9 
10 /*!*****************************************************************************
11 * \file ni_av_codec_logan.c
12 *
13 * \brief NETINT audio/video related utility functions
14 *
15 *******************************************************************************/
16 
17 #include <limits.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <math.h>
21 #ifdef _WIN32
22 #include <winsock.h>
23 #elif defined(__linux__)
24 #include <arpa/inet.h>
25 #endif
26 #include "ni_defs_logan.h"
27 #include "ni_util_logan.h"
28 #include "ni_nvme_logan.h"
29 #include "ni_bitstream_logan.h"
30 #include "ni_av_codec_logan.h"
31 
32 
33 typedef enum
34 {
38  SLICE_TYPE_MP = 3
40 
41 typedef enum
42 {
52  // single_ref
57 
58  // newly added
64 } gop_preset_t;
65 
66 
67 static const int32_t GOP_SIZE[NUM_GOP_PRESET_NUM] =
68 {0, 1, 1, 1, 2, 4, 4, 4, 8, 1, 2, 4, 4};
69 
70 static const int32_t LT_GOP_PRESET_I_1[6] = {SLICE_TYPE_I, 1, 0, 0, 0, 0};
71 static const int32_t LT_GOP_PRESET_P_1[6] = {SLICE_TYPE_MP, 1, 1, 0, 0, -1};
72 static const int32_t LT_GOP_PRESET_B_1[6] = {SLICE_TYPE_B, 1, 1, 0, 0, -1};
73 // gop_size = 2
74 static const int32_t LT_GOP_PRESET_BP_2[12] =
75 {
76  SLICE_TYPE_MP, 2, 1, 0, 0, -2,
77  SLICE_TYPE_B, 1, 3, 0, 0, 2,
78 };
79 // gop_size = 4
80 static const int32_t LT_GOP_PRESET_BBBP_4[24] =
81 {
82  SLICE_TYPE_MP, 4, 1, 0, 0, -4,
83  SLICE_TYPE_B, 2, 3, 0, 0, 4,
84  SLICE_TYPE_B, 1, 5, 0, 0, 2,
85  SLICE_TYPE_B, 3, 5, 0, 2, 4,
86 };
87 
88 static const int32_t LT_GOP_PRESET_LP_4[24] =
89 {
90  SLICE_TYPE_MP, 1, 5, 0, 0, -4,
91  SLICE_TYPE_MP, 2, 3, 0, 1, 0,
92  SLICE_TYPE_MP, 3, 5, 0, 2, 0,
93  SLICE_TYPE_MP, 4, 1, 0, 3, 0,
94 };
95 static const int32_t LT_GOP_PRESET_LD_4[24] =
96 {
97  SLICE_TYPE_B, 1, 5, 0, 0, -4,
98  SLICE_TYPE_B, 2, 3, 0, 1, 0,
99  SLICE_TYPE_B, 3, 5, 0, 2, 0,
100  SLICE_TYPE_B, 4, 1, 0, 3, 0,
101 };
102 
103 // gop_size = 8
104 static const int32_t LT_GOP_PRESET_RA_8[48] =
105 {
106  SLICE_TYPE_B, 8, 1, 0, 0, -8,
107  SLICE_TYPE_B, 4, 3, 0, 0, 8,
108  SLICE_TYPE_B, 2, 5, 0, 0, 4,
109  SLICE_TYPE_B, 1, 8, 0, 0, 2,
110  SLICE_TYPE_B, 3, 8, 0, 2, 4,
111  SLICE_TYPE_B, 6, 5, 0, 4, 8,
112  SLICE_TYPE_B, 5, 8, 0, 4, 6,
113  SLICE_TYPE_B, 7, 8, 0, 6, 8,
114 };
115 // single-ref-P
116 static const int32_t LT_GOP_PRESET_SP_1[6] = {SLICE_TYPE_P, 1, 1, 0, 0, -1};
117 
118 static const int32_t LT_GOP_PRESET_BSP_2[12] =
119 {
120  SLICE_TYPE_P, 2, 1, 0, 0, -2,
121  SLICE_TYPE_B, 1, 3, 0, 0, 2,
122 };
123 static const int32_t LT_GOP_PRESET_BBBSP_4[24] =
124 {
125  SLICE_TYPE_P, 4, 1, 0, 0, -4,
126  SLICE_TYPE_B, 2, 3, 0, 0, 4,
127  SLICE_TYPE_B, 1, 5, 0, 0, 2,
128  SLICE_TYPE_B, 3, 5, 0, 2, 4,
129 };
130 static const int32_t LT_GOP_PRESET_LSP_4[24] =
131 {
132  SLICE_TYPE_P, 1, 5, 0, 0, -4,
133  SLICE_TYPE_P, 2, 3, 0, 1, 0,
134  SLICE_TYPE_P, 3, 5, 0, 2, 0,
135  SLICE_TYPE_P, 4, 1, 0, 3, 0,
136 };
137 
138 static const int32_t LT_GOP_PRESET_BBP_3[18] =
139 {
140  SLICE_TYPE_MP, 3, 1, 0, 0, -3,
141  SLICE_TYPE_B, 1, 3, 0, 0, 3,
142  SLICE_TYPE_B, 2, 6, 0, 1, 3,
143 };
144 
145 static const int32_t LT_GOP_PRESET_BBSP_3[18] =
146 {
147  SLICE_TYPE_P, 3, 1, 0, 0, 0,
148  SLICE_TYPE_B, 1, 3, 0, 0, 3,
149  SLICE_TYPE_B, 2, 6, 0, 1, 3,
150 };
151 
152 static const int32_t LT_GOP_PRESET_BBBBBBBP_8[48] =
153 {
154  SLICE_TYPE_MP, 8, 1, 0, 0, -8,
155  SLICE_TYPE_B, 4, 3, 0, 0, 8,
156  SLICE_TYPE_B, 2, 5, 0, 0, 4,
157  SLICE_TYPE_B, 1, 8, 0, 0, 2,
158  SLICE_TYPE_B, 3, 8, 0, 2, 4,
159  SLICE_TYPE_B, 6, 5, 0, 4, 8,
160  SLICE_TYPE_B, 5, 8, 0, 4, 6,
161  SLICE_TYPE_B, 7, 8, 0, 6, 8,
162 };
163 
164 static const int32_t LT_GOP_PRESET_BBBBBBBSP_8[48] =
165 {
166  SLICE_TYPE_P, 8, 1, 0, 0, 0,
167  SLICE_TYPE_B, 4, 3, 0, 0, 8,
168  SLICE_TYPE_B, 2, 5, 0, 0, 4,
169  SLICE_TYPE_B, 1, 8, 0, 0, 2,
170  SLICE_TYPE_B, 3, 8, 0, 2, 4,
171  SLICE_TYPE_B, 6, 5, 0, 4, 8,
172  SLICE_TYPE_B, 5, 8, 0, 4, 6,
173  SLICE_TYPE_B, 7, 8, 0, 6, 8,
174 };
175 static const int32_t* GOP_PRESET[NUM_GOP_PRESET_NUM] =
176 {
177  NULL,
178  LT_GOP_PRESET_I_1,
179  LT_GOP_PRESET_P_1,
180  LT_GOP_PRESET_B_1,
181  LT_GOP_PRESET_BP_2,
182  LT_GOP_PRESET_BBBP_4,
183  LT_GOP_PRESET_LP_4,
184  LT_GOP_PRESET_LD_4,
185  LT_GOP_PRESET_RA_8,
186 
187  LT_GOP_PRESET_SP_1,
188  LT_GOP_PRESET_BSP_2,
189  LT_GOP_PRESET_BBBSP_4,
190  LT_GOP_PRESET_LSP_4,
191 
192  LT_GOP_PRESET_BBP_3 ,
193  LT_GOP_PRESET_BBSP_3 ,
194  LT_GOP_PRESET_BBBBBBBP_8 ,
195  LT_GOP_PRESET_BBBBBBBSP_8,
196 };
197 
198 static void init_gop_param(ni_logan_custom_gop_params_t *gopParam,
200 {
201  int i;
202  int j;
203  int gopSize;
204  int gopPreset = param->enc_input_params.gop_preset_index;
205 
206  // GOP_PRESET_IDX_CUSTOM
207  if (gopPreset == 0)
208  {
209  memcpy(gopParam, &param->enc_input_params.custom_gop_params,
211  }
212  else
213  {
214  const int32_t* src_gop = GOP_PRESET[gopPreset];
215  gopSize = GOP_SIZE[gopPreset];
216  gopParam->custom_gop_size = gopSize;
217  for(i = 0, j = 0; i < gopSize; i++)
218  {
219  gopParam->pic_param[i].pic_type = src_gop[j++];
220  gopParam->pic_param[i].poc_offset = src_gop[j++];
221  gopParam->pic_param[i].pic_qp = src_gop[j++] + param->enc_input_params.rc.intra_qp;
222  gopParam->pic_param[i].temporal_id = src_gop[j++];
223  gopParam->pic_param[i].ref_poc_L0 = src_gop[j++];
224  gopParam->pic_param[i].ref_poc_L1 = src_gop[j++];
225  }
226  }
227 }
228 
229 static int check_low_delay_flag(ni_logan_encoder_params_t *param,
231 {
232  int i;
233  int minVal = 0;
234  int low_delay = 0;
235  int gopPreset = param->enc_input_params.gop_preset_index;
236 
237  if (gopPreset == 0) // // GOP_PRESET_IDX_CUSTOM
238  {
239  if (gopParam->custom_gop_size > 1)
240  {
241  minVal = gopParam->pic_param[0].poc_offset;
242  low_delay = 1;
243  for (i = 1; i < gopParam->custom_gop_size; i++)
244  {
245  if (minVal > gopParam->pic_param[i].poc_offset)
246  {
247  low_delay = 0;
248  break;
249  }
250  else
251  {
252  minVal = gopParam->pic_param[i].poc_offset;
253  }
254  }
255  }
256  }
257  else if (gopPreset == 1 || gopPreset == 2 || gopPreset == 3 ||
258  gopPreset == 6 || gopPreset == 7 || gopPreset == 9)
259  {
260  low_delay = 1;
261  }
262 
263  return low_delay;
264 }
265 
266 static int get_num_reorder_of_gop_structure(ni_logan_encoder_params_t *param)
267 {
268  int i;
269  int j;
270  int ret_num_reorder = 0;
272 
273  init_gop_param(&gopParam, param);
274  for(i = 0; i < gopParam.custom_gop_size; i++)
275  {
276  int check_reordering_num = 0;
277  int num_reorder = 0;
278 
279  ni_logan_gop_params_t *gopPicParam = &gopParam.pic_param[i];
280 
281  for(j = 0; j < gopParam.custom_gop_size; j++)
282  {
283  ni_logan_gop_params_t *gopPicParamCand = &gopParam.pic_param[j];
284  if (gopPicParamCand->poc_offset <= gopPicParam->poc_offset)
285  check_reordering_num = j;
286  }
287 
288  for(j = 0; j < check_reordering_num; j++)
289  {
290  ni_logan_gop_params_t *gopPicParamCand = &gopParam.pic_param[j];
291 
292  if (gopPicParamCand->temporal_id <= gopPicParam->temporal_id &&
293  gopPicParamCand->poc_offset > gopPicParam->poc_offset)
294  num_reorder++;
295  }
296  ret_num_reorder = num_reorder;
297  }
298  return ret_num_reorder;
299 }
300 
301 static inline int ni_logan_min(int a, int b)
302 {
303  return a < b ? a : b;
304 }
305 
306 static inline int ni_logan_max(int a, int b)
307 {
308  return a > b ? a : b;
309 }
310 
311 static inline float ni_logan_minf(float a, float b)
312 {
313  return a < b ? a : b;
314 }
315 
316 static inline float ni_logan_maxf(float a, float b)
317 {
318  return a > b ? a : b;
319 }
320 
321 static int get_max_dec_pic_buffering_of_gop_structure(
323 {
324  int max_dec_pic_buffering;
325  max_dec_pic_buffering = ni_logan_min(16/*MAX_NUM_REF*/, ni_logan_max(get_num_reorder_of_gop_structure(param) + 2, 6 /*maxnumreference in spec*/) + 1);
326  return max_dec_pic_buffering;
327 }
328 
329 static int get_poc_of_gop_structure(ni_logan_encoder_params_t *param,
330  uint32_t frame_idx)
331 {
332  int low_delay;
333  int gopSize;
334  int poc;
335  int gopIdx;
336  int gopNum;
338 
339  init_gop_param(&gopParam, param);
340  gopSize = gopParam.custom_gop_size;
341  low_delay = check_low_delay_flag(param, &gopParam);
342 
343  if (low_delay)
344  {
345  poc = frame_idx;
346  }
347  else
348  {
349  gopIdx = frame_idx % gopSize;
350  gopNum = frame_idx / gopSize;
351  poc = gopParam.pic_param[gopIdx].poc_offset + (gopSize * gopNum);
352  }
353 
354  poc += gopSize - 1; // use gop_size - 1 as offset
355  return poc;
356 }
357 
358 static inline int calc_scale(uint32_t x)
359 {
360  static uint8_t lut[16] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
361  int y, z = (((x & 0xffff) - 1) >> 27) & 16;
362  x >>= z;
363  z += y = (((x & 0xff) - 1) >> 28) & 8;
364  x >>= y;
365  z += y = (((x & 0xf) - 1) >> 29) & 4;
366  x >>= y;
367  return z + lut[x&0xf];
368 }
369 
370 static inline int clip3(int min, int max, int a)
371 {
372  return ni_logan_min(ni_logan_max(min, a), max);
373 }
374 
375 static inline float clip3f(float min, float max, float a)
376 {
377  return ni_logan_minf(ni_logan_maxf(min, a), max);
378 }
379 
380 static inline int calc_length(uint32_t x)
381 {
382  static uint8_t lut[16] = {4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
383  int y, z = (((x >> 16) - 1) >> 27) & 16;
384  x >>= z ^ 16;
385  z += y = ((x - 0x100) >> 28) & 8;
386  x >>= y ^ 8;
387  z += y = ((x - 0x10) >> 29) & 4;
388  x >>= y ^ 4;
389  return z + lut[x];
390 }
391 
392 #define BR_SHIFT 6
393 #define CPB_SHIFT 4
394 
395 #define SAMPLE_SPS_MAX_SUB_LAYERS_MINUS1 0
396 #define MAX_VPS_MAX_SUB_LAYERS 16
397 #define MAX_CPB_COUNT 16
398 #define MAX_DURATION 0.5
399 
400 /*!*****************************************************************************
401  * \brief Whether SEI (HDR) should be sent together with this frame to encoder
402  *
403  * \param[in] p_enc_ctx encoder session context
404  * \param[in] pic_type frame type
405  * \param[in] p_param encoder parameters
406  *
407  * \return 1 if yes, 0 otherwise
408  ******************************************************************************/
410  ni_logan_pic_type_t pic_type,
411  ni_logan_encoder_params_t *p_param)
412 {
413  // repeatHeaders = 0. send on first frame only (IDR)
414  // repeatHeaders = 1. send on every I-frame including I-frames generated
415  // on the intraPeriod interval as well as I-frames that are forced.
416  if (0 == p_enc_ctx->frame_num ||
417  LOGAN_PIC_TYPE_FORCE_IDR == pic_type ||
419  p_param->enc_input_params.intra_period &&
420  0 == (p_enc_ctx->frame_num % p_param->enc_input_params.intra_period)))
421  {
422  return 1;
423  }
424  return 0;
425 }
426 
427 // create a ni_rational_t
428 static ni_rational_t ni_make_rational(int num, int den)
429 {
430  ni_rational_t r = {num, den};
431  return r;
432 }
433 
434 // compare two rationals:
435 // return: 0 if a == b
436 // 1 if a > b
437 // -1 if a < b
438 static int ni_cmp_rational(ni_rational_t a, ni_rational_t b)
439 {
440  const int64_t tmp = a.num * (int64_t)b.den - b.num * (int64_t)a.den;
441 
442  if (tmp) return (int)((tmp ^ a.den ^ b.den)>>63)|1;
443  else if(b.den && a.den) return 0;
444  else if(a.num && b.num) return (a.num>>31) - (b.num>>31);
445  return 0;
446 }
447 
448 /*!*****************************************************************************
449  * \brief Set SPS VUI part of encoded stream header
450  *
451  * \param[in/out] p_param encoder parameters, its VUI data member will be
452  * updated.
453  * \param[out] p_ctx session context, its HRD parameters (hrd_params)
454  * may be updated.
455  * \param[in] color_primaries color primaries
456  * \param[in] color_trc color transfer characteristic
457  * \param[in] color_space YUV colorspace type
458  * \param[in] video_full_range_flag
459  * \param[in] sar_num/sar_den sample aspect ration in numerator/denominator
460  * \param[in] codec_format H.264 or H.265
461  *
462  * \return NONE
463  ******************************************************************************/
466  ni_color_primaries_t color_primaries,
468  ni_color_space_t color_space,
469  int video_full_range_flag,
470  int sar_num,
471  int sar_den,
472  ni_logan_codec_format_t codec_format)
473 {
475  unsigned int aspect_ratio_idc = 255; // default: extended_sar
476  int nal_hrd_parameters_present_flag=1, vcl_hrd_parameters_present_flag=0;
477  int layer, cpb;
478  int maxcpboutputdelay;
479  int maxdpboutputdelay;
480  int maxdelay;
481  uint32_t vbvbuffersize = (p_param->bitrate / 1000) * p_param->enc_input_params.rc.rc_init_delay;
482  uint32_t vbvmaxbitrate = p_param->bitrate;
483  uint32_t vps_max_sub_layers_minus1 = SAMPLE_SPS_MAX_SUB_LAYERS_MINUS1;
484  uint32_t bit_rate_value_minus1[MAX_CPB_COUNT][MAX_VPS_MAX_SUB_LAYERS];
485  uint32_t cpb_size_value_minus1[MAX_CPB_COUNT][MAX_VPS_MAX_SUB_LAYERS];
486  uint32_t cpb_cnt_minus1[MAX_VPS_MAX_SUB_LAYERS];
487 
488  uint32_t fixed_pic_rate_general_flag[MAX_VPS_MAX_SUB_LAYERS];
489  uint32_t fixed_pic_rate_within_cvs_flag[MAX_VPS_MAX_SUB_LAYERS];
490  uint32_t elemental_duration_in_tc_minus1[MAX_VPS_MAX_SUB_LAYERS];
491 
492  uint32_t bit_rate_scale = 2;
493  uint32_t cpb_size_scale = 5;
494  uint32_t numUnitsInTick = 1000;
495  uint32_t timeScale;
496  int32_t i32frameRateInfo = p_param->enc_input_params.frame_rate;
497 
498  ni_log(NI_LOG_TRACE, "%s(): color_primaries:%d, color_trc:%d, color_space:%d, "
499  "video_full_range_flag:%d, sar_num:%d, sar_den:%d, codec_format:%d\n",
500  __FUNCTION__, color_primaries, color_trc, color_space,
501  video_full_range_flag, sar_num, sar_den, codec_format);
502 
503  if (video_full_range_flag < 0)
504  {
505  ni_log(NI_LOG_ERROR, "ERROR %s: The video full range flag is %d should be "
506  "indicated excplicitly as 0 or 1!\n", __func__);
507  return;
508  }
509 
511 
512  if (0 == sar_num)
513  {
514  // sample aspect ratio is 0, don't include aspect_ratio_idc in vui
515  ni_bs_writer_put(&rbsp, 0, 1); // aspect_ratio_info_present_flag=0
516  }
517  else
518  {
519  // sample aspect ratio is non-zero, include aspect_ratio_idc in vui
520  ni_bs_writer_put(&rbsp, 1, 1); // aspect_ratio_info_present_flag=1
521 
522  if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
523  ni_make_rational(1, 1)))
524  {
525  aspect_ratio_idc = 1;
526  }
527  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
528  ni_make_rational(12, 11)))
529  {
530  aspect_ratio_idc = 2;
531  }
532  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
533  ni_make_rational(10, 11)))
534  {
535  aspect_ratio_idc = 3;
536  }
537  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
538  ni_make_rational(16, 11)))
539  {
540  aspect_ratio_idc = 4;
541  }
542  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
543  ni_make_rational(40, 33)))
544  {
545  aspect_ratio_idc = 5;
546  }
547  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
548  ni_make_rational(24, 11)))
549  {
550  aspect_ratio_idc = 6;
551  }
552  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
553  ni_make_rational(20, 11)))
554  {
555  aspect_ratio_idc = 7;
556  }
557  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
558  ni_make_rational(32, 11)))
559  {
560  aspect_ratio_idc = 8;
561  }
562  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
563  ni_make_rational(80, 33)))
564  {
565  aspect_ratio_idc = 9;
566  }
567  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
568  ni_make_rational(18, 11)))
569  {
570  aspect_ratio_idc = 10;
571  }
572  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
573  ni_make_rational(15, 11)))
574  {
575  aspect_ratio_idc = 11;
576  }
577  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
578  ni_make_rational(64, 33)))
579  {
580  aspect_ratio_idc = 12;
581  }
582  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
583  ni_make_rational(160, 99)))
584  {
585  aspect_ratio_idc = 13;
586  }
587  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
588  ni_make_rational(4, 3)))
589  {
590  aspect_ratio_idc = 14;
591  }
592  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
593  ni_make_rational(3, 2)))
594  {
595  aspect_ratio_idc = 15;
596  }
597  else if (! ni_cmp_rational(ni_make_rational(sar_num, sar_den),
598  ni_make_rational(2, 1)))
599  {
600  aspect_ratio_idc = 16;
601  }
602 
603  ni_bs_writer_put(&rbsp, aspect_ratio_idc, 8); // aspect_ratio_idc
604  if (255 == aspect_ratio_idc)
605  {
606  ni_bs_writer_put(&rbsp, sar_num, 16); // sar_width
607  ni_bs_writer_put(&rbsp, sar_den, 16); // sar_height
608  }
609  }
610 
611  ni_bs_writer_put(&rbsp, 0, 1); // overscan_info_present_flag=0
612 
613  // VUI Parameters
614  ni_bs_writer_put(&rbsp, 1, 1); // video_signal_type_present_flag=1
615  ni_bs_writer_put(&rbsp, 5, 3); // video_format=5 (unspecified)
616  ni_bs_writer_put(&rbsp, video_full_range_flag, 1); // video_full_range_flag
617  ni_bs_writer_put(&rbsp, 1, 1); // colour_description_presenty_flag=1
618  ni_bs_writer_put(&rbsp, color_primaries, 8); // color_primaries
619  ni_bs_writer_put(&rbsp, color_trc, 8); // color_trc
620  ni_bs_writer_put(&rbsp, color_space, 8); // color_space
621 
622  ni_bs_writer_put(&rbsp, 0, 1); // chroma_loc_info_present_flag=0
623 
624  if (NI_LOGAN_CODEC_FORMAT_H265 == codec_format)
625  { // H.265 Only VUI parameters
626  ni_bs_writer_put(&rbsp, 0, 1); // neutral_chroma_indication_flag=0
627  ni_bs_writer_put(&rbsp, 0, 1); // field_seq_flag=0
628  ni_bs_writer_put(&rbsp, 0, 1); // frame_field_info_present_flag=0
629  ni_bs_writer_put(&rbsp, 0, 1); // default_display_window_flag=0
630  }
631 
632  if (p_param->disable_timing_info) // disable timing info
633  {
634  ni_bs_writer_put(&rbsp, 0, 1); // vui_timing_info_present_flag=0
635  }
636  else
637  {
638  ni_bs_writer_put(&rbsp, 1, 1); // vui_timing_info_present_flag=1
639  p_param->pos_num_units_in_tick = (uint32_t)ni_bs_writer_tell(&rbsp);
640  ni_bs_writer_put(&rbsp, 0, 32); // vui_num_units_in_tick
641  p_param->pos_time_scale = (uint32_t)ni_bs_writer_tell(&rbsp);
642  ni_bs_writer_put(&rbsp, 0, 32); // vui_time_scale
643  }
644  if (NI_LOGAN_CODEC_FORMAT_H265 == codec_format)
645  {
646  // H.265 Only VUI parameters
647  if (!p_param->disable_timing_info)
648  {
649  ni_bs_writer_put(&rbsp, 0, 1); // vui_poc_proportional_to_timing_flag=0
650  if (! p_param->hrd_enable)
651  {
652  ni_bs_writer_put(&rbsp, 0, 1); // vui_hrd_parameters_present_flag=0
653  }
654  else
655  {
656  ni_bs_writer_put(&rbsp, 1, 1); // vui_hrd_parameters_present_flag=1
657 
658  ni_bs_writer_put(&rbsp, 1, 1); // nal_hrd_parameters_present_flag=1
659  ni_bs_writer_put(&rbsp, 0, 1); // vcl_hrd_parameters_present_flag=0
660 
661  ni_bs_writer_put(&rbsp, 0, 1); // sub_pic_hrd_params_present_flag=0
662 
665 
666  bit_rate_value_minus1[0][0] = 59374;
667  cpb_size_value_minus1[0][0] = 59374;
668  cpb_cnt_minus1[0] = 0;
669  fixed_pic_rate_general_flag[0] = 1;
670  fixed_pic_rate_within_cvs_flag[0] = 1;
671  elemental_duration_in_tc_minus1[0] = 0;
672 
673  // normalize hrd size and rate to the value / scale notation
674  bit_rate_scale = clip3(0, 15, calc_scale(vbvmaxbitrate) - BR_SHIFT);
675  bit_rate_value_minus1[0][0] = (vbvmaxbitrate >> (bit_rate_scale + BR_SHIFT)) - 1;
676 
677  cpb_size_scale = clip3(0, 15, calc_scale(vbvbuffersize) - CPB_SHIFT);
678  cpb_size_value_minus1[0][0] = (vbvbuffersize >> (cpb_size_scale + CPB_SHIFT)) - 1;
679 
680  p_ctx->hrd_params.bit_rate_unscale = (bit_rate_value_minus1[0][0]+1) << (bit_rate_scale + BR_SHIFT);
681  p_ctx->hrd_params.cpb_size_unscale = (cpb_size_value_minus1[0][0]+1) << (cpb_size_scale + CPB_SHIFT);
682 
683  if (p_param->fps_denominator != 0 &&
684  (p_param->fps_number % p_param->fps_denominator) != 0)
685  {
686  numUnitsInTick += 1;
687  i32frameRateInfo += 1;
688  }
689  timeScale = i32frameRateInfo * 1000;
690 
691  maxcpboutputdelay = ni_logan_min((int)(p_param->enc_input_params.intra_period * MAX_DURATION * timeScale / numUnitsInTick), INT_MAX);
692  maxdpboutputdelay = (int)(get_max_dec_pic_buffering_of_gop_structure(p_param) * MAX_DURATION * timeScale / numUnitsInTick);
693  maxdelay = (int)(90000.0 * p_ctx->hrd_params.cpb_size_unscale / p_ctx->hrd_params.bit_rate_unscale + 0.5);
694 
696  2 + clip3(4, 22, 32 - calc_length(maxdelay)) - 1;
698  clip3(4, 31, 32 - calc_length(maxcpboutputdelay)) - 1;
700  clip3(4, 31, 32 - calc_length(maxdpboutputdelay)) - 1;
701 
702  ni_bs_writer_put(&rbsp, bit_rate_scale, 4); // bit_rate_scale
703  ni_bs_writer_put(&rbsp, cpb_size_scale, 4); // cpb_size_scale
704 
708 
709  for (layer = 0; layer <= (int32_t)vps_max_sub_layers_minus1; layer++)
710  {
711  ni_bs_writer_put(&rbsp, fixed_pic_rate_general_flag[layer], 1);
712 
713  if (! fixed_pic_rate_general_flag[layer])
714  {
715  ni_bs_writer_put(&rbsp, fixed_pic_rate_within_cvs_flag[layer], 1);
716  }
717 
718  if (fixed_pic_rate_within_cvs_flag[layer])
719  {
720  ni_bs_writer_put_ue(&rbsp, elemental_duration_in_tc_minus1[layer]);
721  }
722 
723  // low_delay_hrd_flag[layer] is not present and inferred to be 0
724 
725  ni_bs_writer_put_ue(&rbsp, cpb_cnt_minus1[layer]);
726 
727  if ((layer == 0 && nal_hrd_parameters_present_flag) ||
728  (layer == 1 && vcl_hrd_parameters_present_flag))
729  {
730  for (cpb = 0; cpb <= (int32_t)cpb_cnt_minus1[layer]; cpb++)
731  {
732  ni_bs_writer_put_ue(&rbsp, bit_rate_value_minus1[cpb][layer]);
733 
734  ni_bs_writer_put_ue(&rbsp, cpb_size_value_minus1[cpb][layer]);
735 
736  // cbr_flag is inferred to be 0 as well ?
737  ni_bs_writer_put(&rbsp, 0, 1/*cbr_flag[cpb][layer]*/);
738  }
739  }
740  }
741  }
742  }
743  ni_bs_writer_put(&rbsp, 0, 1); // bitstream_restriction_flag=0
744  }
745  else
746  {
747  // H.264 Only VUI parameters
748  if (!p_param->disable_timing_info)
749  {
750  if (p_param->enable_vfr)
751  {
752  ni_bs_writer_put(&rbsp, 0, 1); // fixed_frame_rate_flag=0
753  }
754  else
755  {
756  ni_bs_writer_put(&rbsp, 1, 1); // fixed_frame_rate_flag=1
757  }
758  }
759  ni_bs_writer_put(&rbsp, 0, 1); // nal_hrd_parameters_present_flag=0
760  ni_bs_writer_put(&rbsp, 0, 1); // vui_hrd_parameters_present_flag=0
761  ni_bs_writer_put(&rbsp, 0, 1); // pic_struct_present_flag=0
762 
763  // this flag is set to 1 for H.264 to reduce decode delay, and fill in
764  // the rest of the section accordingly
765  ni_bs_writer_put(&rbsp, 1, 1); // bitstream_restriction_flag=1
766  ni_bs_writer_put(&rbsp, 1, 1); // motion_vectors_over_pic_boundaries_flag=1
767 
768  ni_bs_writer_put_ue(&rbsp, 2); // max_bytes_per_pic_denom=2 (default)
769  ni_bs_writer_put_ue(&rbsp, 1); // max_bits_per_mb_denom=1 (default)
770  ni_bs_writer_put_ue(&rbsp, 15); //log2_max_mv_length_horizontal=15 (default)
771  ni_bs_writer_put_ue(&rbsp, 15); // log2_max_mv_length_vertical=15 (default)
772 
773  // max_num_reorder_frames (0 for low delay gops)
774  int max_num_reorder_frames = ni_logan_get_num_reorder_of_gop_structure(p_param);
775  ni_bs_writer_put_ue(&rbsp, max_num_reorder_frames);
776 
777  // max_dec_frame_buffering
778  int num_ref_frames = ni_logan_get_num_ref_frame_of_gop_structure(p_param);
779  int max_dec_frame_buffering = (num_ref_frames > max_num_reorder_frames ?
780  num_ref_frames : max_num_reorder_frames);
781  ni_bs_writer_put_ue(&rbsp, max_dec_frame_buffering);
782  }
783 
784  p_param->ui32VuiDataSizeBits = (uint32_t)ni_bs_writer_tell(&rbsp);
785  p_param->ui32VuiDataSizeBytes = (p_param->ui32VuiDataSizeBits + 7) / 8;
786 
788 
789  ni_bs_writer_copy(p_param->ui8VuiRbsp, &rbsp);
790  ni_bs_writer_clear(&rbsp);
791 }
792 
794  ni_logan_codec_format_t codec_format)
795 {
797 
798  unsigned int aspect_ratio_idc = 255; // default: extended_sar
799  ni_log(NI_LOG_DEBUG,"ni_logan_reset_vui enter\n");
800 
801  // int32_t i32frameRateInfo = p_param->enc_input_params.frame_rate;
802  if (aux_data->size == sizeof(ni_logan_dec_h265_vui_param_t))
803  {
804  ni_logan_dec_h265_vui_param_t *aux_vui = NULL;
805  aux_vui = (ni_logan_dec_h265_vui_param_t *)aux_data->data;
806  if (aux_vui->video_full_range_flag < 0)
807  {
808  ni_log(NI_LOG_ERROR, "ERROR %s: The video full range flag is %d should be "
809  "indicated excplicitly as 0 or 1!\n", __func__);
810  return;
811  }
812 
815  if (aux_vui->aspect_ratio_info_present_flag)
816  {
817  ni_bs_writer_put(&rbsp, aux_vui->aspect_ratio_idc, 8);
818  if (aux_vui->aspect_ratio_idc == aspect_ratio_idc) //EXTENDED_SAR
819  {
820  ni_bs_writer_put(&rbsp, aux_vui->sar_width, 16);
821  ni_bs_writer_put(&rbsp, aux_vui->sar_height, 16);
822  }
823  }
824  ni_bs_writer_put(&rbsp, aux_vui->overscan_info_present_flag, 1);
825  if (aux_vui->overscan_info_present_flag)
826  {
827  ni_bs_writer_put(&rbsp, aux_vui->overscan_appropriate_flag, 1);
828  }
830 
831  if (aux_vui->video_signal_type_present_flag)
832  {
833  ni_bs_writer_put(&rbsp, aux_vui->video_format, 3);
834  ni_bs_writer_put(&rbsp, aux_vui->video_full_range_flag, 1);
836 
837  if (aux_vui->colour_description_present_flag)
838  {
839  ni_bs_writer_put(&rbsp, aux_vui->colour_primaries, 8);
840  ni_bs_writer_put(&rbsp, aux_vui->transfer_characteristics, 8);
841  ni_bs_writer_put(&rbsp, aux_vui->matrix_coefficients, 8);
842  }
843  }
845  if (aux_vui->chroma_loc_info_present_flag)
846  {
849  }
850  if (codec_format == NI_LOGAN_CODEC_FORMAT_H265)
851  {
852  ni_bs_writer_put(&rbsp, aux_vui->neutral_chroma_indication_flag, 1); // neutral_chroma_indication_flag=0
853  ni_bs_writer_put(&rbsp, aux_vui->field_seq_flag, 1); // field_seq_flag=0
854  ni_bs_writer_put(&rbsp, aux_vui->frame_field_info_present_flag, 1); // frame_field_info_present_flag=0
855  ni_bs_writer_put(&rbsp, aux_vui->default_display_window_flag, 1); // default_display_window_flag=0
856  if (aux_vui->default_display_window_flag)
857  {
858  ni_bs_writer_put_ue(&rbsp, aux_vui->def_disp_win.left);
859  ni_bs_writer_put_ue(&rbsp, aux_vui->def_disp_win.right);
860  ni_bs_writer_put_ue(&rbsp, aux_vui->def_disp_win.top);
861  ni_bs_writer_put_ue(&rbsp, aux_vui->def_disp_win.bottom);
862  }
864  if (aux_vui->vui_timing_info_present_flag)
865  {
866  p_param->pos_num_units_in_tick = (uint32_t)ni_bs_writer_tell(&rbsp);
867  ni_bs_writer_put(&rbsp, aux_vui->vui_num_units_in_tick, 32); // vui_num_units_in_tick
868  p_param->pos_time_scale = (uint32_t)ni_bs_writer_tell(&rbsp);
869  ni_bs_writer_put(&rbsp, aux_vui->vui_time_scale, 32); // vui_time_scale
872  {
874  }
875  if (aux_vui->vui_hrd_parameters_present_flag)
876  {
877  ni_log(NI_LOG_ERROR,"Don't support hrd_parameters set now, so set it to 0 !\n");
878  }
879  ni_bs_writer_put(&rbsp, 0, 1); // vui_hrd_parameters_present_flag
880  ni_bs_writer_put(&rbsp, aux_vui->bitstream_restriction_flag, 1);
881  if (aux_vui->bitstream_restriction_flag)
882  {
883  ni_bs_writer_put(&rbsp, aux_vui->tiles_fixed_structure_flag, 1);
891  }
892  }
893  }
894  else
895  {
897  if (aux_vui->vui_timing_info_present_flag)
898  {
899  ni_bs_writer_put(&rbsp, aux_vui->vui_num_units_in_tick, 32);
900  ni_bs_writer_put(&rbsp, aux_vui->vui_time_scale, 32);
901  ni_bs_writer_put(&rbsp, 1, 1); // fixed_frame_rate_flag
902  }
903 
904  ni_bs_writer_put(&rbsp, 0, 1); // nal_hrd_parameters_present_flag
905  ni_bs_writer_put(&rbsp, 0, 1); // vcl_hrd_parameters_present_flag=0
906  ni_bs_writer_put(&rbsp, 0, 1); // pic_struct_present_flag
907  ni_bs_writer_put(&rbsp, aux_vui->bitstream_restriction_flag, 1);
908  if (aux_vui->bitstream_restriction_flag)
909  {
910  // this flag is set to 1 for H.264 to reduce decode delay, and fill in
911  // the rest of the section accordingly
912  ni_bs_writer_put(&rbsp, 1, 1); // motion_vectors_over_pic_boundaries_flag=1
913 
914  ni_bs_writer_put_ue(&rbsp, 2); // max_bytes_per_pic_denom=2 (default)
915  ni_bs_writer_put_ue(&rbsp, 1); // max_bits_per_mb_denom=1 (default)
916  ni_bs_writer_put_ue(&rbsp, 15); //log2_max_mv_length_horizontal=15 (default)
917  ni_bs_writer_put_ue(&rbsp, 15); // log2_max_mv_length_vertical=15 (default)
918 
919  // max_num_reorder_frames (0 for low delay gops)
920  int max_num_reorder_frames = ni_logan_get_num_reorder_of_gop_structure(p_param);
921  ni_bs_writer_put_ue(&rbsp, max_num_reorder_frames);
922 
923  // max_dec_frame_buffering
924  int num_ref_frames = ni_logan_get_num_ref_frame_of_gop_structure(p_param);
925  int max_dec_frame_buffering = (num_ref_frames > max_num_reorder_frames ?
926  num_ref_frames : max_num_reorder_frames);
927  ni_bs_writer_put_ue(&rbsp, max_dec_frame_buffering);
928  }
929  }
930  }
931  else if (aux_data->size == sizeof(ni_logan_dec_h264_vui_param_t))
932  {
933  ni_logan_dec_h264_vui_param_t *aux_vui = NULL;
934  aux_vui = (ni_logan_dec_h264_vui_param_t *)aux_data->data;
935  if (aux_vui->video_full_range_flag < 0)
936  {
937  ni_log(NI_LOG_ERROR, "ERROR %s: The video full range flag is %d should be "
938  "indicated excplicitly as 0 or 1!\n", __func__);
939  return;
940  }
941 
943 
945  if (aux_vui->aspect_ratio_info_present_flag)
946  {
947  ni_bs_writer_put(&rbsp, aux_vui->aspect_ratio_idc, 8);
948  if (aux_vui->aspect_ratio_idc == aspect_ratio_idc) //EXTENDED_SAR
949  {
950  ni_bs_writer_put(&rbsp, aux_vui->sar_width, 16);
951  ni_bs_writer_put(&rbsp, aux_vui->sar_height, 16);
952  }
953  }
954  ni_bs_writer_put(&rbsp, aux_vui->overscan_info_present_flag, 1);
955  if (aux_vui->overscan_info_present_flag)
956  {
957  ni_bs_writer_put(&rbsp, aux_vui->overscan_appropriate_flag, 1);
958  }
960  if (aux_vui->video_signal_type_present_flag)
961  {
962  ni_bs_writer_put(&rbsp, aux_vui->video_format, 3);
963  ni_bs_writer_put(&rbsp, aux_vui->video_full_range_flag, 1);
965  if (aux_vui->colour_description_present_flag)
966  {
967  ni_bs_writer_put(&rbsp, aux_vui->colour_primaries, 8);
968  ni_bs_writer_put(&rbsp, aux_vui->transfer_characteristics, 8);
969  ni_bs_writer_put(&rbsp, aux_vui->matrix_coefficients, 8);
970  }
971  }
973  if (aux_vui->chroma_loc_info_present_flag)
974  {
977  }
978 
979  if (codec_format == NI_LOGAN_CODEC_FORMAT_H264)
980  {
982  if (aux_vui->vui_timing_info_present_flag)
983  {
984  ni_bs_writer_put(&rbsp, aux_vui->vui_num_units_in_tick, 32);
985  ni_bs_writer_put(&rbsp, aux_vui->vui_time_scale, 32);
986  ni_bs_writer_put(&rbsp, aux_vui->fixed_frame_rate_flag, 1);
987  }
988 
989  ni_bs_writer_put(&rbsp, 0, 1); // nal_hrd_parameters_present_flag
990  ni_bs_writer_put(&rbsp, 0, 1); // vcl_hrd_parameters_present_flag=0
992  {
993  ni_bs_writer_put(&rbsp, aux_vui->low_delay_hrd_flag, 1);
994  ni_log(NI_LOG_ERROR,"h264 don't support hrd_parameters set now, so set it to 0 !\n");
995  }
996 
997  ni_bs_writer_put(&rbsp, aux_vui->pic_struct_present_flag, 1);
998  ni_bs_writer_put(&rbsp, aux_vui->bitstream_restriction_flag, 1);
999  if (aux_vui->bitstream_restriction_flag)
1000  {
1004 
1009  }
1010  }
1011  else
1012  {
1013  ni_bs_writer_put(&rbsp, 0, 1); // neutral_chroma_indication_flag=0
1014  ni_bs_writer_put(&rbsp, 0, 1); // field_seq_flag=0
1015  ni_bs_writer_put(&rbsp, 0, 1); // frame_field_info_present_flag=0
1016  ni_bs_writer_put(&rbsp, 0, 1); // default_display_window_flag=0
1017 
1018  ni_bs_writer_put(&rbsp, aux_vui->vui_timing_info_present_flag, 1);
1019  if (aux_vui->vui_timing_info_present_flag)
1020  {
1021  p_param->pos_num_units_in_tick = (uint32_t)ni_bs_writer_tell(&rbsp);
1022  ni_bs_writer_put(&rbsp, aux_vui->vui_num_units_in_tick, 32); // vui_num_units_in_tick
1023  p_param->pos_time_scale = (uint32_t)ni_bs_writer_tell(&rbsp);
1024  ni_bs_writer_put(&rbsp, aux_vui->vui_time_scale, 32); // vui_time_scale
1025  ni_bs_writer_put(&rbsp, 0, 1); // vui_poc_proportional_to_timing_flag
1026  ni_bs_writer_put(&rbsp, 0, 1); // vui_hrd_parameters_present_flag
1027  ni_bs_writer_put(&rbsp, 0, 1);
1028  }
1029  }
1030  }
1031  p_param->ui32VuiDataSizeBits = (uint32_t)ni_bs_writer_tell(&rbsp);
1032  p_param->ui32VuiDataSizeBytes = (p_param->ui32VuiDataSizeBits + 7) / 8;
1033 
1034  ni_bs_writer_align_zero(&rbsp);
1035 
1036  ni_bs_writer_copy(p_param->ui8VuiRbsp, &rbsp);
1037  ni_bs_writer_clear(&rbsp);
1038 }
1039 
1040 /*!*****************************************************************************
1041  * \brief Buffered period sei
1042  *
1043  * \param[in/out] p_param encoder parameters, its GOP information will be
1044  * updated.
1045  * \param[in] p_ctx session context, use its HRD parameters (hrd_params).
1046  * \param[in] frame_idx frame index
1047  * \param[in] buf_len output buffer length
1048  * \param[out] p_buf output sei buffer.
1049  *
1050  * \return put_bit_byte_size
1051  ******************************************************************************/
1054  uint32_t frame_idx,
1055  int buf_len,
1056  uint8_t *p_buf)
1057 {
1058  ni_bitstream_writer_t rbsp;
1059  int32_t payload_bit_size = 0, payload_byte_size = 0, put_bit_byte_size = 0;
1060  uint32_t nal_initial_cpb_removal_delay, nal_initial_cpb_removal_offset;
1061  int i;
1062  uint32_t concatenation_flag = get_poc_of_gop_structure(p_param, frame_idx) == 0 ? 1 : 0;
1063 
1064  ni_log(NI_LOG_TRACE, "%s(): frame_idx:%d\n", __FUNCTION__, frame_idx);
1065 
1066  if (p_ctx->frame_num == 0)
1067  {
1068  concatenation_flag = 1;
1069  }
1070  ni_bitstream_writer_init(&rbsp);
1071 
1072  payload_bit_size += 1; // bp_seq_parameter_set_id=0, 1 bit
1073  payload_bit_size += 1; // irap_cpb_params_present_flag=0, 1 bit
1074  payload_bit_size += 1; // concatenation_flag, 1 bit
1075  // au_cpb_removal_delay_delta_minus1
1076  payload_bit_size += (p_ctx->hrd_params.au_cpb_removal_delay_length_minus1 + 1);
1077 
1078  // nal_hrd_parameters_present_flag=1
1079  // CpbCnt = cpb_cnt_minus1[0] + 1 = 0 + 1
1080  for (i = 0; i < 1; i++)
1081  {
1082  // nal_initial_cpb_removal_delay
1083  payload_bit_size += p_ctx->hrd_params.initial_cpb_removal_delay_length_minus1 + 1;
1084  // nal_initial_cpb_removal_offset
1085  payload_bit_size += p_ctx->hrd_params.initial_cpb_removal_delay_length_minus1 + 1;
1086  }
1087 
1088  // vcl_hrd_parameters_present_flag=0
1089 
1090  ni_bs_writer_put(&rbsp, 1, 32); // NAL start code
1091  // NAL unit header nal_unit_type=39, layer_id=0, temporal_id_plus1=1
1092  ni_bs_writer_put(&rbsp, (39 << 9) | (0 << 3) | 1, 16);
1093  ni_bs_writer_put(&rbsp, 0, 8); // payload_type=0 (buffering_period)
1094  payload_byte_size = (payload_bit_size + 7) / 8;
1095  ni_bs_writer_put(&rbsp, payload_byte_size, 8);// payload size (byte)
1096 
1097  // buffering period
1098  ni_bs_writer_put_ue(&rbsp, 0); // bp_seq_parameter_set_id=0
1099  ni_bs_writer_put(&rbsp, 0, 1); // irap_cpb_params_present_flag=0
1100  ni_bs_writer_put(&rbsp, concatenation_flag, 1); // concatenation_flag
1101  // au_cpb_removal_delay_delta_minus1=0
1103 
1104  nal_initial_cpb_removal_delay =
1105  (uint32_t)(90000 * p_ctx->hrd_params.cpb_size_unscale / p_ctx->hrd_params.bit_rate_unscale);
1106  nal_initial_cpb_removal_offset =
1107  (uint32_t)((90000 * p_ctx->hrd_params.cpb_size_unscale / p_ctx->hrd_params.bit_rate_unscale) -
1108  nal_initial_cpb_removal_delay);
1109 
1110  // nal_hrd_parameters_present_flag=1
1111  // CpbCnt = cpb_cnt_minus1[0] + 1 = 0 + 1
1112  for (i = 0; i < 1; i++)
1113  {
1114  // nal_initial_cpb_removal_delay
1115  ni_bs_writer_put(&rbsp, nal_initial_cpb_removal_delay,
1117  // nal_initial_cpb_removal_offset
1118  ni_bs_writer_put(&rbsp, nal_initial_cpb_removal_offset,
1120  }
1121 
1122  // vcl_hrd_parameters_present_flag=0
1123 
1124  if (payload_bit_size % 8)
1125  {
1126  // fill in bit 1 and padding 0s for byte alignment
1127  ni_bs_writer_put(&rbsp, 1/*payload_bit_equal_to_one*/, 1);
1128  for (i = 0; i < 8 - (payload_bit_size % 8) - 1; i++)
1129  {
1130  ni_bs_writer_put(&rbsp, 0/*payload_bit_equal_to_zero*/, 1);
1131  }
1132  }
1133 
1134  // rbsp trailing stop bit and alignment padding 0s
1135  ni_bs_writer_put(&rbsp, 0x80, 8);
1136 
1137  ni_bs_writer_align_zero(&rbsp);
1138  put_bit_byte_size = ((uint32_t)ni_bs_writer_tell(&rbsp) + 7) / 8;
1139  if (put_bit_byte_size <= buf_len)
1140  {
1141  ni_bs_writer_copy(p_buf, &rbsp);
1142  }
1143  else
1144  {
1145  ni_log(NI_LOG_TRACE, "%s(): buffer size overflow, size=%d, actual=%d\n",
1146  __FUNCTION__, buf_len, put_bit_byte_size);
1147  put_bit_byte_size = 0;
1148  }
1149 
1150  ni_bs_writer_clear(&rbsp);
1151 
1152  // emulation prevention checking of payload, skipping start code (4B) +
1153  // NAL header (2B) + payload type (1B) + payload size (1B) = 8B
1154  put_bit_byte_size += ni_logan_insert_emulation_prevent_bytes(
1155  p_buf + 8, put_bit_byte_size - 8);
1156 
1157  return put_bit_byte_size;
1158 }
1159 
1160 /*!*****************************************************************************
1161  * \brief Buffered customer sei
1162  *
1163  * \param[in] p_data input side data of customer sei
1164  * \param[out] p_ctx session context, update its pkt_custom_sei.
1165  * \param[in] index fifo index
1166  *
1167  * \return success return NI_LOGAN_RETCODE_SUCCESS
1168  * failure return < 0
1169  ******************************************************************************/
1172  uint32_t index)
1173 {
1175  int i = 0;
1176  ni_logan_all_custom_sei_t *src_all_custom_sei = (ni_logan_all_custom_sei_t *)p_data;
1177  ni_logan_custom_sei_t *src_custom_sei = NULL;
1178  uint8_t *src_sei_data = NULL;
1179  int custom_sei_size = 0;
1180  int custom_sei_size_trans = 0;
1181  uint8_t custom_sei_type;
1182  uint8_t sei_idx;
1183  int sei_len;
1184  ni_logan_all_custom_sei_t *dst_all_custom_sei = NULL;
1185  ni_logan_custom_sei_t *dst_custom_sei = NULL;
1186  uint8_t *dst_sei_data = NULL;
1187 
1188  ni_log(NI_LOG_TRACE, "%s(): index:%d\n", __FUNCTION__, index);
1189 
1190  dst_all_custom_sei = malloc(sizeof(ni_logan_all_custom_sei_t));
1191  if (dst_all_custom_sei == NULL)
1192  {
1193  ni_log(NI_LOG_ERROR, "failed to allocate memory for custom sei "
1194  "data, len:%" PRIu64 ".\n", sizeof(ni_logan_all_custom_sei_t));
1196  return retval;
1197  }
1198  memset(dst_all_custom_sei, 0 ,sizeof(ni_logan_all_custom_sei_t));
1199 
1200  for (sei_idx = 0; sei_idx < src_all_custom_sei->custom_sei_cnt; sei_idx++)
1201  {
1202  src_custom_sei = &src_all_custom_sei->ni_custom_sei[sei_idx];
1203 
1204  custom_sei_type = src_custom_sei->custom_sei_type;
1205  custom_sei_size = src_custom_sei->custom_sei_size;
1206  src_sei_data = src_custom_sei->custom_sei_data;
1207 
1208  dst_custom_sei = &dst_all_custom_sei->ni_custom_sei[sei_idx];
1209  dst_sei_data = dst_custom_sei->custom_sei_data;
1210  sei_len = 0;
1211 
1212  /* fill sei buffer */
1213  // long start code
1214  dst_sei_data[sei_len++] = 0x00;
1215  dst_sei_data[sei_len++] = 0x00;
1216  dst_sei_data[sei_len++] = 0x00;
1217  dst_sei_data[sei_len++] = 0x01;
1219  {
1220  dst_sei_data[sei_len++] = 0x06; //nal type: SEI
1221  }
1222  else
1223  {
1224  dst_sei_data[sei_len++] = 0x4e; //nal type: SEI
1225  dst_sei_data[sei_len++] = 0x01;
1226  }
1227 
1228  // SEI type
1229  dst_sei_data[sei_len++] = custom_sei_type;
1230 
1231  // original payload size
1232  custom_sei_size_trans = custom_sei_size;
1233  while (custom_sei_size_trans >= 0)
1234  {
1235  dst_sei_data[sei_len++] = (custom_sei_size_trans > 0xFF ? 0xFF : (uint8_t)custom_sei_size_trans);
1236  custom_sei_size_trans -= 0xFF;
1237  }
1238 
1239  // payload data
1240  for (i = 0; (i < custom_sei_size) && (sei_len < (NI_LOGAN_MAX_CUSTOM_SEI_SZ - 2)); i++)
1241  {
1242  if ((2 <= i) && !dst_sei_data[sei_len - 2] && !dst_sei_data[sei_len - 1] && (src_sei_data[i] <= 0x03))
1243  {
1244  /* insert 0x3 as emulation_prevention_three_byte */
1245  dst_sei_data[sei_len++] = 0x03;
1246  }
1247  dst_sei_data[sei_len++] = src_sei_data[i];
1248  }
1249 
1250  if (i != custom_sei_size)
1251  {
1252  ni_log(NI_LOG_ERROR, "%s: sei RBSP size out of limit(%d), "
1253  "idx=%u, type=%u, size=%d, custom_sei_loc=%d\n", __FUNCTION__,
1254  NI_LOGAN_MAX_CUSTOM_SEI_SZ, sei_idx, custom_sei_type,
1255  custom_sei_size, src_custom_sei->custom_sei_loc);
1256  free(dst_all_custom_sei);
1257  dst_all_custom_sei = NULL;
1258  break;
1259  }
1260 
1261  // trailing byte
1262  dst_sei_data[sei_len++] = 0x80;
1263 
1264  dst_custom_sei->custom_sei_size = sei_len;
1265  dst_custom_sei->custom_sei_type = custom_sei_type;
1266  dst_custom_sei->custom_sei_loc = src_custom_sei->custom_sei_loc;
1267  ni_log(NI_LOG_TRACE, "%s: sei idx=%u,type=%u, len=%d, "
1268  "custom_sei_loc=%d\n", __FUNCTION__, sei_idx, custom_sei_type,
1269  sei_len, dst_custom_sei->custom_sei_loc);
1270  }
1271 
1272  if (dst_all_custom_sei)
1273  {
1274  dst_all_custom_sei->custom_sei_cnt = src_all_custom_sei->custom_sei_cnt;
1275  p_ctx->pkt_custom_sei[index % NI_LOGAN_FIFO_SZ] = dst_all_custom_sei;
1276  ni_log(NI_LOG_TRACE, "%s: sei number %d pts %" PRId64 ".\n", __FUNCTION__,
1277  dst_all_custom_sei->custom_sei_cnt, index);
1278  }
1279  return retval;
1280 }
1281 
1282 /*!*****************************************************************************
1283  * \brief Generate pic timing sei2
1284  *
1285  * \param[in/out] p_param encoder parameters, its GOP information will be
1286  * updated.
1287  * \param[in/out] p_ctx session context, its HRD parameters (hrd_params)
1288  * may be updated.
1289  * \param[in] is_i_or_idr True if it is i or idr packet.
1290  * \param[in] is_idr True if it is idr packet.
1291  * \param[in] frame_idx frame index
1292  * \param[in] buf_len output buffer length
1293  * \param[out] p_buf output sei buffer.
1294  *
1295  * \return length of pci timing sei2
1296  ******************************************************************************/
1299  int is_i_or_idr,
1300  int is_idr,
1301  uint32_t frame_idx,
1302  int buf_len,
1303  uint8_t *p_buf)
1304 {
1305  ni_bitstream_writer_t rbsp;
1306  int32_t payload_bit_size = 0, payload_byte_size = 0, put_bit_byte_size = 0;
1307  uint32_t pic_dpb_output_delay = 0;
1308  int num_reorder_pic;
1309  uint64_t poc_pic;
1310 
1311  ni_log(NI_LOG_TRACE, "%s(): is_i_or_idr:%d, is_idr:%d, frame_idx:%d\n",
1312  __FUNCTION__, is_i_or_idr, is_idr, frame_idx);
1313 
1314  ni_bitstream_writer_init(&rbsp);
1315 
1316  // frame_field_info_present_flag=0 TBD
1317  //payload_bit_size += 4/*pic_struct*/ + 2/*source_scan_type*/ + 1/*duplicate_flag*/;
1318 
1319  // CpbDpbDelaysPresentFlag=1
1320  // au_cpb_removal_delay_length_minus1
1321  payload_bit_size += (p_ctx->hrd_params.au_cpb_removal_delay_length_minus1 + 1);
1322  // pic_dpb_output_delay
1323  payload_bit_size += (p_ctx->hrd_params.dpb_output_delay_length_minus1+ 1);
1324 
1325  // sub_pic_hrd_params_present_flag=0
1326 
1327  ni_bs_writer_put(&rbsp, 1, 32); // NAL start code
1328  // NAL unit header nal_unit_type=39, layer_id=0, temporal_id_plus1=1
1329  ni_bs_writer_put(&rbsp, (39 << 9) | (0 << 3) | 1, 16);
1330  ni_bs_writer_put(&rbsp, 1, 8); // payload_type=1 (picture_timing)
1331  payload_byte_size = (payload_bit_size + 7) / 8;
1332  ni_bs_writer_put(&rbsp, payload_byte_size, 8);// payload size (byte)
1333 
1334  // pic timing
1335  num_reorder_pic = get_num_reorder_of_gop_structure(p_param);
1336  poc_pic = get_poc_of_gop_structure(p_param, frame_idx);
1337  pic_dpb_output_delay = num_reorder_pic + poc_pic - frame_idx;
1338 
1339  // CpbDpbDelaysPresentFlag=1
1340  // au_cpb_removal_delay_length_minus1
1344 
1345  if (1 == p_param->enc_input_params.gop_preset_index &&
1346  p_param->enc_input_params.intra_period)
1347  {
1348  if (0 == frame_idx || is_idr ||
1350  {
1352  }
1353  }
1354  else if (is_i_or_idr)
1355  {
1357  }
1358 
1359  // pic_dpb_output_delay
1360  ni_bs_writer_put(&rbsp, pic_dpb_output_delay, p_ctx->hrd_params.dpb_output_delay_length_minus1 + 1);
1361 
1362  if (payload_bit_size & 7)
1363  {
1364  ni_bs_writer_put(&rbsp, 1/*payload_bit_equal_to_one*/, 1);
1365  ni_bs_writer_put(&rbsp, 0/*payload_bit_equal_to_zero*/, (8 - (payload_bit_size & 7)-1));
1366  }
1367 
1368  // rbsp trailing stop bit and alignment padding 0s
1369  ni_bs_writer_put(&rbsp, 0x80, 8);
1370 
1371  ni_bs_writer_align_zero(&rbsp);
1372  put_bit_byte_size = ((uint32_t)ni_bs_writer_tell(&rbsp) + 7) / 8;
1373  if (put_bit_byte_size <= buf_len)
1374  {
1375  ni_bs_writer_copy(p_buf, &rbsp);
1376  }
1377  else
1378  {
1379  ni_log(NI_LOG_TRACE, "%s(): buffer size overflow, size=%d, actual=%d\n",
1380  __FUNCTION__, buf_len, put_bit_byte_size);
1381  put_bit_byte_size = 0;
1382  }
1383 
1384  ni_bs_writer_clear(&rbsp);
1385 
1386  // emulation prevention checking of payload, skipping start code (4B) +
1387  // NAL header (2B) + payload type (1B) + payload size (1B) = 8B
1388  put_bit_byte_size += ni_logan_insert_emulation_prevent_bytes(
1389  p_buf + 8, put_bit_byte_size - 8);
1390 
1391  return put_bit_byte_size;
1392 }
1393 
1394 /*!*****************************************************************************
1395  * \brief Retrieve auxiliary data (close caption, various SEI) associated with
1396  * this frame that is returned by decoder, convert them to appropriate
1397  * format and save them in the frame's auxiliary data storage for
1398  * future use by encoding. Usually they would be sent together with
1399  * this frame to encoder at encoding.
1400  *
1401  * \param[in/out] frame that is returned by decoder
1402  *
1403  * \return NONE
1404  ******************************************************************************/
1406 {
1407  uint8_t *sei_buf = NULL;
1408  ni_aux_data_t *aux_data = NULL;
1409 
1410  // User Data Unregistered SEI if available
1412  {
1413  sei_buf = (uint8_t *)frame->p_data[0] + frame->sei_user_data_unreg_offset;
1415  frame, NI_FRAME_AUX_DATA_UDU_SEI, sei_buf,
1416  frame->sei_user_data_unreg_len))
1417  {
1418  ni_log(NI_LOG_ERROR, "ni_logan_dec_retrieve_aux_data error retrieve User "
1419  "data unregisted SEI !\n");
1420  }
1421  }
1422 
1423  // close caption data if available
1424  if (frame->sei_cc_len && frame->sei_cc_offset)
1425  {
1426  sei_buf = (uint8_t *)frame->p_data[0] + frame->sei_cc_offset;
1428  frame, NI_FRAME_AUX_DATA_A53_CC, sei_buf, frame->sei_cc_len))
1429  {
1430  ni_log(NI_LOG_ERROR, "ni_logan_dec_retrieve_aux_data error retrieve close "
1431  "caption SEI !\n");
1432  }
1433  }
1434 
1435  // hdr10 sei data if available
1436 
1437  // mastering display metadata
1440  {
1441  aux_data = ni_logan_frame_new_aux_data(
1444 
1445  if (! aux_data)
1446  {
1447  ni_log(NI_LOG_ERROR, "ni_logan_dec_retrieve_aux_data error retrieve HDR10 "
1448  "mastering display color SEI !\n");
1449  }
1450  else
1451  {
1453  aux_data->data;
1454  const int chroma_den = 50000;
1455  const int luma_den = 10000;
1458  (uint8_t*)frame->p_data[0] +
1460 
1461  // HEVC uses a g,b,r ordering, which we convert to a more natural r,g,b,
1462  // this is so we are compatible with FFmpeg default soft decoder
1463  mdm->display_primaries[0][0].num = pColourVolume->display_primaries_x[2];
1464  mdm->display_primaries[0][0].den = chroma_den;
1465  mdm->display_primaries[0][1].num = pColourVolume->display_primaries_y[2];
1466  mdm->display_primaries[0][1].den = chroma_den;
1467  mdm->display_primaries[1][0].num = pColourVolume->display_primaries_x[0];
1468  mdm->display_primaries[1][0].den = chroma_den;
1469  mdm->display_primaries[1][1].num = pColourVolume->display_primaries_y[0];
1470  mdm->display_primaries[1][1].den = chroma_den;
1471  mdm->display_primaries[2][0].num = pColourVolume->display_primaries_x[1];
1472  mdm->display_primaries[2][0].den = chroma_den;
1473  mdm->display_primaries[2][1].num = pColourVolume->display_primaries_y[1];
1474  mdm->display_primaries[2][1].den = chroma_den;
1475 
1476  mdm->white_point[0].num = pColourVolume->white_point_x;
1477  mdm->white_point[0].den = chroma_den;
1478  mdm->white_point[1].num = pColourVolume->white_point_y;
1479  mdm->white_point[1].den = chroma_den;
1480 
1481  mdm->min_luminance.num = pColourVolume->min_display_mastering_luminance;
1482  mdm->min_luminance.den = luma_den;
1483  mdm->max_luminance.num = pColourVolume->max_display_mastering_luminance;
1484  mdm->max_luminance.den = luma_den;
1485 
1486  mdm->has_luminance = mdm->has_primaries = 1;
1487  }
1488  }
1489 
1490  // hdr10 content light level
1493  {
1494  aux_data = ni_logan_frame_new_aux_data(
1496  sizeof(ni_content_light_level_t));
1497 
1498  if (! aux_data)
1499  {
1500  ni_log(NI_LOG_ERROR, "ni_logan_dec_retrieve_aux_data error retrieve HDR10 "
1501  "content light level SEI !\n");
1502  }
1503  else
1504  {
1506  aux_data->data;
1509  (uint8_t*)frame->p_data[0] +
1511 
1512  clm->max_cll = pLightLevel->max_content_light_level;
1513  clm->max_fall = pLightLevel->max_pic_average_light_level;
1514  }
1515  }
1516 
1517  // hdr10+ sei data if available
1518  if (frame->sei_hdr_plus_len && frame->sei_hdr_plus_offset)
1519  {
1521  sizeof(ni_dynamic_hdr_plus_t));
1522 
1523  if (! aux_data)
1524  {
1525  ni_log(NI_LOG_ERROR, "ni_logan_dec_retrieve_aux_data error retrieve HDR10+ "
1526  "SEI !\n");
1527  }
1528  else
1529  {
1530  int w, i, j, i_limit, j_limit;
1531  ni_dynamic_hdr_plus_t *hdrp = (ni_dynamic_hdr_plus_t *)aux_data->data;
1533 
1534  sei_buf = (uint8_t *)frame->p_data[0] + frame->sei_hdr_plus_offset;
1535  ni_bitstream_reader_init(&br, sei_buf, 8 * frame->sei_hdr_plus_len);
1536  hdrp->itu_t_t35_country_code = 0xB5;
1537  hdrp->application_version = 0;
1538  // first 7 bytes of t35 SEI data header already matched HDR10+, and:
1539  ni_bs_reader_skip_bits(&br, 7 * 8);
1540 
1541  // num_windows u(2)
1542  hdrp->num_windows = ni_bs_reader_get_bits(&br, 2);
1543  ni_log(NI_LOG_TRACE, "hdr10+ num_windows %u\n", hdrp->num_windows);
1544  if (! (1 == hdrp->num_windows || 2 == hdrp->num_windows ||
1545  3 == hdrp->num_windows))
1546  {
1547  // wrong format and skip this HDR10+ SEI
1548  }
1549  else
1550  {
1551  // the following block will be skipped for hdrp->num_windows == 1
1552  for (w = 1; w < hdrp->num_windows; w++)
1553  {
1554  hdrp->params[w - 1].window_upper_left_corner_x = ni_make_q(
1555  ni_bs_reader_get_bits(&br, 16), 1);
1556  hdrp->params[w - 1].window_upper_left_corner_y = ni_make_q(
1557  ni_bs_reader_get_bits(&br, 16), 1);
1558  hdrp->params[w - 1].window_lower_right_corner_x = ni_make_q(
1559  ni_bs_reader_get_bits(&br, 16), 1);
1560  hdrp->params[w - 1].window_lower_right_corner_y = ni_make_q(
1561  ni_bs_reader_get_bits(&br, 16), 1);
1562  hdrp->params[w - 1].center_of_ellipse_x =
1563  ni_bs_reader_get_bits(&br, 16);
1564  hdrp->params[w - 1].center_of_ellipse_y =
1565  ni_bs_reader_get_bits(&br, 16);
1566  hdrp->params[w - 1].rotation_angle = ni_bs_reader_get_bits(&br, 8);
1568  ni_bs_reader_get_bits(&br, 16);
1570  ni_bs_reader_get_bits(&br, 16);
1572  ni_bs_reader_get_bits(&br, 16);
1573  hdrp->params[w - 1].overlap_process_option =
1575  }
1576 
1577  // values are scaled down according to standard spec
1579  ni_bs_reader_get_bits(&br, 27);
1581 
1583  ni_bs_reader_get_bits(&br, 1);
1584 
1585  ni_log(NI_LOG_TRACE, "hdr10+ targeted_system_display_maximum_luminance "
1587  ni_log(NI_LOG_TRACE, "hdr10+ targeted_system_display_actual_peak_lumi"
1588  "nance_flag %u\n",
1590 
1592  {
1593  i_limit =
1595  ni_bs_reader_get_bits(&br, 5);
1596 
1597  j_limit =
1599  ni_bs_reader_get_bits(&br, 5);
1600 
1601  ni_log(NI_LOG_TRACE, "hdr10+ num_rows_targeted_system_display_actual"
1602  "_peak_luminance x num_cols_targeted_system_display_actual_"
1603  "peak_luminance %u x %u\n", i_limit, j_limit);
1604 
1605  i_limit = i_limit > 25 ? 25 : i_limit;
1606  j_limit = j_limit > 25 ? 25 : j_limit;
1607  for (i = 0; i < i_limit; i++)
1608  for (j = 0; j < j_limit; j++)
1609  {
1611  ni_bs_reader_get_bits(&br, 4);
1613  ni_log(NI_LOG_TRACE, "hdr10+ targeted_system_display_actual_peak"
1614  "_luminance[%d][%d] %d\n", i, j,
1616  }
1617  }
1618 
1619  for (w = 0; w < hdrp->num_windows; w++)
1620  {
1621  for (i = 0; i < 3; i++)
1622  {
1623  hdrp->params[w].maxscl[i].num = ni_bs_reader_get_bits(&br, 17);
1624  hdrp->params[w].maxscl[i].den = 100000;
1625  ni_log(NI_LOG_TRACE, "hdr10+ maxscl[%d][%d] %d\n", w, i,
1626  hdrp->params[w].maxscl[i].num);
1627  }
1628  hdrp->params[w].average_maxrgb.num = ni_bs_reader_get_bits(&br, 17);
1629  hdrp->params[w].average_maxrgb.den = 100000;
1630  ni_log(NI_LOG_TRACE, "hdr10+ average_maxrgb[%d] %d\n",
1631  w, hdrp->params[w].average_maxrgb.num);
1632 
1633  i_limit = hdrp->params[w].num_distribution_maxrgb_percentiles =
1634  ni_bs_reader_get_bits(&br, 4);
1636  "hdr10+ num_distribution_maxrgb_percentiles[%d] %d\n",
1638 
1639  i_limit = i_limit > 15 ? 15 : i_limit;
1640  for (i = 0; i < i_limit; i++)
1641  {
1642  hdrp->params[w].distribution_maxrgb[i].percentage =
1643  ni_bs_reader_get_bits(&br, 7);
1645  ni_bs_reader_get_bits(&br, 17);
1646  hdrp->params[w].distribution_maxrgb[i].percentile.den = 100000;
1648  "hdr10+ distribution_maxrgb_percentage[%d][%d] %u\n",
1649  w, i, hdrp->params[w].distribution_maxrgb[i].percentage);
1651  "hdr10+ distribution_maxrgb_percentile[%d][%d] %d\n",
1652  w, i, hdrp->params[w].distribution_maxrgb[i].percentile.num);
1653  }
1654 
1656  &br, 10);
1657  hdrp->params[w].fraction_bright_pixels.den = 1000;
1658  ni_log(NI_LOG_TRACE, "hdr10+ fraction_bright_pixels[%d] %d\n",
1659  w, hdrp->params[w].fraction_bright_pixels.num);
1660  }
1661 
1663  ni_bs_reader_get_bits(&br, 1);
1665  "hdr10+ mastering_display_actual_peak_luminance_flag %u\n",
1668  {
1670  ni_bs_reader_get_bits(&br, 5);
1672  ni_bs_reader_get_bits(&br, 5);
1673  ni_log(NI_LOG_TRACE, "hdr10+ num_rows_mastering_display_actual_peak_"
1674  "luminance x num_cols_mastering_display_actual_peak_luminance "
1675  "%u x %u\n", i_limit, j_limit);
1676 
1677  i_limit = i_limit > 25 ? 25 : i_limit;
1678  j_limit = j_limit > 25 ? 25 : j_limit;
1679  for (i = 0; i < i_limit; i++)
1680  for (j = 0; j < j_limit; j++)
1681  {
1683  ni_bs_reader_get_bits(&br, 4);
1685  ni_log(NI_LOG_TRACE, "hdr10+ mastering_display_actual_peak_lumi"
1686  "nance[%d][%d] %d\n", i, j,
1688  }
1689  }
1690 
1691  for (w = 0; w < hdrp->num_windows; w++)
1692  {
1693  hdrp->params[w].tone_mapping_flag = ni_bs_reader_get_bits(&br, 1);
1694  ni_log(NI_LOG_TRACE, "hdr10+ tone_mapping_flag[%d] %u\n",
1695  w, hdrp->params[w].tone_mapping_flag);
1696 
1697  if (hdrp->params[w].tone_mapping_flag)
1698  {
1699  hdrp->params[w].knee_point_x.num = ni_bs_reader_get_bits(&br, 12);
1700  hdrp->params[w].knee_point_x.den = 4095;
1701  hdrp->params[w].knee_point_y.num = ni_bs_reader_get_bits(&br, 12);
1702  hdrp->params[w].knee_point_y.den = 4095;
1703  ni_log(NI_LOG_TRACE, "hdr10+ knee_point_x[%d] %u\n",
1704  w, hdrp->params[w].knee_point_x.num);
1705  ni_log(NI_LOG_TRACE, "hdr10+ knee_point_y[%d] %u\n",
1706  w, hdrp->params[w].knee_point_y.num);
1707 
1708  hdrp->params[w].num_bezier_curve_anchors =
1709  ni_bs_reader_get_bits(&br, 4);
1710  ni_log(NI_LOG_TRACE, "hdr10+ num_bezier_curve_anchors[%d] %u\n",
1711  w, hdrp->params[w].num_bezier_curve_anchors);
1712  for (i = 0; i < hdrp->params[w].num_bezier_curve_anchors; i++)
1713  {
1714  hdrp->params[w].bezier_curve_anchors[i].num =
1715  ni_bs_reader_get_bits(&br, 10);
1716  hdrp->params[w].bezier_curve_anchors[i].den = 1023;
1717  ni_log(NI_LOG_TRACE, "hdr10+ bezier_curve_anchors[%d][%d] %d\n",
1718  w, i, hdrp->params[w].bezier_curve_anchors[i].num);
1719  }
1720  }
1721 
1723  ni_bs_reader_get_bits(&br, 1);
1724  ni_log(NI_LOG_TRACE, "hdr10+ color_saturation_mapping_flag[%d] %u\n",
1727  {
1729  ni_bs_reader_get_bits(&br, 6);
1730  hdrp->params[w].color_saturation_weight.den = 8;
1731  ni_log(NI_LOG_TRACE, "hdr10+ color_saturation_weight[%d] %d\n",
1732  w, hdrp->params[w].color_saturation_weight.num);
1733  }
1734  } // num_windows
1735 
1736  } // right number of windows
1737  } // alloc memory
1738  } // HDR10+ SEI
1739 
1740  // init source stream info to default values (unspecified)
1744  frame->video_full_range_flag = 0;
1745  frame->aspect_ratio_idc = 0;
1746  frame->sar_width = 0;
1747  frame->sar_height = 0;
1748  frame->vui_num_units_in_tick = 0;
1749  frame->vui_time_scale = 0;
1750  frame->separate_metadata = 0;
1751 
1752  // VUI if retrieved
1753  if (frame->vui_offset || frame->vui_len)
1754  {
1755  sei_buf = (uint8_t *)frame->p_data[0] + frame->vui_offset;
1756 
1757  if (NI_LOGAN_CODEC_FORMAT_H265 == frame->src_codec)
1758  {
1759  if (sizeof(ni_logan_dec_h265_vui_param_t) == frame->vui_len)
1760  {
1762  frame, NI_FRAME_AUX_DATA_VUI_INFO, sei_buf,
1763  frame->vui_len))
1764  {
1765  ni_log(NI_LOG_ERROR, "ni_logan_dec_retrieve_aux_data error retrieve User "
1766  "VUI data !\n");
1767  }
1768 
1771  {
1772  frame->color_primaries = vui->colour_primaries;
1773  frame->color_trc = vui->transfer_characteristics;
1774  frame->color_space = vui->matrix_coefficients;
1775  }
1777 
1779  {
1780  frame->aspect_ratio_idc = vui->aspect_ratio_idc;
1781  if (255 == frame->aspect_ratio_idc)
1782  {
1783  frame->sar_width = vui->sar_width;
1784  frame->sar_height = vui->sar_height;
1785  }
1786  }
1787 
1789  {
1791  frame->vui_time_scale = vui->vui_time_scale;
1792  }
1793 
1794  ni_log(NI_LOG_TRACE, "ni_logan_dec_retrieve_aux_data H.265 VUI "
1795  "aspect_ratio_info_present_flag %u aspect_ratio_idc %u "
1796  "sar_width %u sar_height %u "
1797  "video_signal_type_present_flag %u video_format %d "
1798  "video_full_range_flag %u colour_description_present_flag %u "
1799  "color-pri %u color-trc %u color-space %u "
1800  "vui_timing_info_present_flag %u vui_num_units_in_tick %u\n",
1802  frame->sar_width, frame->sar_height,
1804  frame->video_full_range_flag,
1806  frame->color_primaries, frame->color_trc, frame->color_space,
1808  frame->vui_num_units_in_tick);
1809  }
1810  else
1811  {
1812  ni_log(NI_LOG_ERROR, "ni_logan_dec_retrieve_aux_data VUI, expecting H.265 "
1813  "VUI struct size %d, got %u, dropped!\n",
1814  (int)sizeof(ni_logan_dec_h265_vui_param_t), frame->vui_len);
1815  }
1816  }
1817  else if (NI_LOGAN_CODEC_FORMAT_H264 == frame->src_codec)
1818  {
1819  // aux_data = ni_logan_frame_new_aux_data(frame, NI_FRAME_AUX_DATA_VUI_INFO,
1820  // sizeof(ni_logan_dec_h264_vui_param_t));
1822  frame, NI_FRAME_AUX_DATA_VUI_INFO, sei_buf,
1823  frame->vui_len))
1824  {
1825  ni_log(NI_LOG_ERROR, "ni_logan_dec_retrieve_aux_data error retrieve User "
1826  "VUI data !\n");
1827  }
1828  if (sizeof(ni_logan_dec_h264_vui_param_t) == frame->vui_len)
1829  {
1832  {
1833  frame->color_primaries = vui->colour_primaries;
1834  frame->color_trc = vui->transfer_characteristics;
1835  frame->color_space = vui->matrix_coefficients;
1836  }
1838 
1840  {
1841  frame->aspect_ratio_idc = vui->aspect_ratio_idc;
1842  if (255 == frame->aspect_ratio_idc)
1843  {
1844  frame->sar_width = vui->sar_width;
1845  frame->sar_height = vui->sar_height;
1846  }
1847  }
1848 
1850  {
1852  frame->vui_time_scale = vui->vui_time_scale;
1853  }
1854 
1855  ni_log(NI_LOG_TRACE, "ni_logan_dec_retrieve_aux_data H.264 VUI "
1856  "aspect_ratio_info_present_flag %u aspect_ratio_idc %u "
1857  "sar_width %u sar_height %u "
1858  "video_signal_type_present_flag %u video_format %d "
1859  "video_full_range_flag %u colour_description_present_flag %u "
1860  "color-pri %u color-trc %u color-space %u "
1861  "vui_timing_info_present_flag %u vui_num_units_in_tick %u "
1862  "vui_time_scale %u pic_struct_present_flag %u\n",
1864  frame->sar_width, frame->sar_height,
1866  frame->video_full_range_flag,
1868  frame->color_primaries, frame->color_trc, frame->color_space,
1870  frame->vui_num_units_in_tick, frame->vui_time_scale,
1872  }
1873  else
1874  {
1875  ni_log(NI_LOG_ERROR, "ni_logan_dec_retrieve_aux_data VUI, expecting H.264 "
1876  "VUI struct size %d, got %u, dropped!\n",
1877  (int)sizeof(ni_logan_dec_h264_vui_param_t), frame->vui_len);
1878  }
1879  }
1880  else
1881  {
1882  ni_log(NI_LOG_ERROR, "ni_logan_dec_retrieve_aux_data VUI, unsupported codec: "
1883  "%d, dropped\n", frame->src_codec);
1884  }
1885  }
1886 
1887  // alternative transfer characteristics SEI if available
1890  {
1891  sei_buf = (uint8_t *)frame->p_data[0] +
1893 
1894  // and overwrite the color-trc in the VUI
1895  ni_log(NI_LOG_TRACE, "ni_logan_dec_retrieve_aux_data alt trc SEI value %u over-"
1896  "writting VUI color-trc value %u\n", *sei_buf, frame->color_trc);
1897  frame->color_trc = *sei_buf;
1898  }
1899 }
1900 
1901 // internal function to convert struct of ROIs to NetInt ROI map and store
1902 // them inside the encoder context passed in.
1903 // return 0 if successful, -1 otherwise
1904 static int set_roi_map(ni_logan_session_context_t* p_enc_ctx,
1905  ni_logan_codec_format_t codec_format,
1906  const ni_aux_data_t *aux_data,
1907  int nb_roi, int width, int height, int intra_qp)
1908 {
1909  int i, j, r, ctu;
1910  const ni_region_of_interest_t *roi =
1911  (const ni_region_of_interest_t*)aux_data->data;
1912  uint32_t self_size = roi->self_size;
1913  uint8_t set_qp = 0;
1914  float f_value;
1915 
1916  if (NI_LOGAN_CODEC_FORMAT_H264 == codec_format)
1917  {
1918  // roi for H.264 is specified for 16x16 pixel macroblocks - 1 MB
1919  // is stored in each custom map entry.
1920  // number of MBs in each row/column
1921  int mbWidth = (width + 16 - 1) >> 4;
1922  int mbHeight = (height + 16 - 1) >> 4;
1923  int numMbs = mbWidth * mbHeight;
1924  int customMapSize = sizeof(ni_logan_enc_avc_roi_custom_map_t) * numMbs;
1925  // make the QP map size 16-aligned to meet VPU requirement for subsequent
1926  // SEI due to layout of data sent to encoder
1927  customMapSize = ((customMapSize + 15) / 16) * 16;
1928 
1929  if (! p_enc_ctx->avc_roi_map)
1930  {
1931  p_enc_ctx->avc_roi_map =
1932  (ni_logan_enc_avc_roi_custom_map_t*)malloc(customMapSize);
1933  if (! p_enc_ctx->avc_roi_map)
1934  {
1935  ni_log(NI_LOG_ERROR, "Error set_roi_map malloc failed.\n");
1936  return -1;
1937  }
1938  }
1939 
1940  // init to range midpoint
1941  memset(p_enc_ctx->avc_roi_map, 0, customMapSize);
1942  for (i = 0; i < numMbs; i++)
1943  {
1944  p_enc_ctx->avc_roi_map[i].field.mb_qp = NI_LOGAN_QP_MID_POINT;
1945  }
1946 
1947  // iterate ROI list from the last as regions are defined in order of
1948  // decreasing importance.
1949  for (r = nb_roi - 1; r >= 0; r--)
1950  {
1951  roi = (const ni_region_of_interest_t*)(aux_data->data + self_size * r);
1952  if (! roi->qoffset.den)
1953  {
1954  ni_log(NI_LOG_ERROR, "ni_region_of_interest_t.qoffset.den "
1955  "must not be zero.\n");
1956  continue;
1957  }
1958 
1959  f_value = roi->qoffset.num * 1.0f / roi->qoffset.den;
1960  f_value = clip3f(-1.0, 1.0, f_value);
1961 
1962  set_qp = (int)(f_value * NI_LOGAN_INTRA_QP_RANGE) + NI_LOGAN_QP_MID_POINT;
1963  ni_log(NI_LOG_TRACE, "set_roi_map roi %d top %d bot %d left %d "
1964  "right %d offset %d/%d set_qp %d\n", r, roi->top, roi->bottom,
1965  roi->left, roi->right, roi->qoffset.num, roi->qoffset.den, set_qp);
1966 
1967  // copy ROI MBs QPs into custom map
1968  for (j = 0; j < mbHeight; j++)
1969  for (i = 0; i < mbWidth; i++)
1970  {
1971  if (((int)(i % mbWidth) >= (int)((roi->left + 15) / 16) - 1) &&
1972  ((int)(i % mbWidth) <= (int)((roi->right + 15) / 16) - 1) &&
1973  ((int)(j % mbHeight) >= (int)((roi->top + 15) / 16) - 1) &&
1974  ((int)(j % mbHeight) <= (int)((roi->bottom + 15) / 16) - 1))
1975  {
1976  p_enc_ctx->avc_roi_map[i + j * mbWidth].field.mb_qp = set_qp;
1977  }
1978  }
1979  } // for each roi
1980 
1981  // average qp is set to midpoint of qp range to work with qp offset
1982  p_enc_ctx->roi_len = customMapSize;
1983  p_enc_ctx->roi_avg_qp = NI_LOGAN_QP_MID_POINT;
1984  }
1985  else if (NI_LOGAN_CODEC_FORMAT_H265 == codec_format)
1986  {
1987  // ROI for H.265 is specified for 32x32 pixel subCTU blocks -
1988  // 4 subCTU QPs are stored in each custom CTU map entry.
1989  // number of CTUs/sub CTUs in each row/column
1990  int ctuWidth = (width + 64 - 1) >> 6;
1991  int ctuHeight = (height + 64 - 1) >> 6;
1992  int subCtuWidth = ctuWidth * 2;
1993  int subCtuHeight = ctuHeight * 2;
1994  int numSubCtus = subCtuWidth * subCtuHeight;
1995  int customMapSize = sizeof(ni_logan_enc_hevc_roi_custom_map_t) *
1996  ctuWidth * ctuHeight;
1997  customMapSize = ((customMapSize + 15) / 16) * 16;
1998 
1999  if (! p_enc_ctx->hevc_sub_ctu_roi_buf)
2000  {
2001  p_enc_ctx->hevc_sub_ctu_roi_buf = (uint8_t *)malloc(numSubCtus);
2002  if (! p_enc_ctx->hevc_sub_ctu_roi_buf)
2003  {
2004  ni_log(NI_LOG_ERROR, "Error set_roi_map malloc failed.\n");
2005  return -1;
2006  }
2007  }
2008 
2009  if (! p_enc_ctx->hevc_roi_map)
2010  {
2011  p_enc_ctx->hevc_roi_map =
2012  (ni_logan_enc_hevc_roi_custom_map_t *)malloc(customMapSize);
2013  if (! p_enc_ctx->hevc_roi_map)
2014  {
2015  free(p_enc_ctx->hevc_sub_ctu_roi_buf);
2016  p_enc_ctx->hevc_sub_ctu_roi_buf = NULL;
2017  ni_log(NI_LOG_ERROR, "Error set_roi_map malloc 2 failed.\n");
2018  return -1;
2019  }
2020  }
2021 
2022  // init to range midpoint
2023  memset(p_enc_ctx->hevc_roi_map, 0, customMapSize);
2024  memset(p_enc_ctx->hevc_sub_ctu_roi_buf, NI_LOGAN_QP_MID_POINT, numSubCtus);
2025  for (r = nb_roi - 1; r >= 0; r--)
2026  {
2027  roi = (const ni_region_of_interest_t*)(aux_data->data + self_size * r);
2028  if (! roi->qoffset.den)
2029  {
2030  ni_log(NI_LOG_ERROR, "ni_region_of_interest_t.qoffset.den "
2031  "must not be zero.\n");
2032  continue;
2033  }
2034 
2035  f_value = roi->qoffset.num * 1.0f / roi->qoffset.den;
2036  f_value = clip3f(-1.0, 1.0, f_value);
2037 
2038  set_qp = (int)(f_value * NI_LOGAN_INTRA_QP_RANGE) + NI_LOGAN_QP_MID_POINT;
2039  ni_log(NI_LOG_TRACE, "set_roi_map roi %d top %d bot %d left %d "
2040  "right %d offset %d/%d set_qp %d\n", r, roi->top, roi->bottom,
2041  roi->left, roi->right, roi->qoffset.num, roi->qoffset.den, set_qp);
2042 
2043  for (j = 0; j < subCtuHeight; j++)
2044  for (i = 0; i < subCtuWidth; i++)
2045  {
2046  if (((int)(i % subCtuWidth) >= (int)((roi->left + 31) / 32) - 1) &&
2047  ((int)(i % subCtuWidth) <= (int)((roi->right + 31) / 32) - 1) &&
2048  ((int)(j % subCtuHeight) >= (int)((roi->top + 31) / 32) - 1) &&
2049  ((int)(j % subCtuHeight) <= (int)((roi->bottom + 31) / 32) - 1))
2050  {
2051  p_enc_ctx->hevc_sub_ctu_roi_buf[i + j * subCtuWidth] = set_qp;
2052  }
2053  }
2054  } // for each roi
2055 
2056  // load into final custom map and calculate average qp
2057  for (i = 0; i < ctuHeight; i++)
2058  {
2059  uint8_t *ptr = &p_enc_ctx->hevc_sub_ctu_roi_buf[subCtuWidth * i * 2];
2060  for (j = 0; j < ctuWidth; j++, ptr += 2)
2061  {
2062  ctu = i * ctuWidth + j;
2063  p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_0 = *ptr;
2064  p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_1 = *(ptr + 1);
2065  p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_2 = *(ptr + subCtuWidth);
2066  p_enc_ctx->hevc_roi_map[ctu].field.sub_ctu_qp_3 = *(ptr + subCtuWidth + 1);
2067  }
2068  }
2069  // average qp is set to midpoint of qp range to work with qp offset
2070  p_enc_ctx->roi_len = customMapSize;
2071  p_enc_ctx->roi_avg_qp = NI_LOGAN_QP_MID_POINT;
2072  }
2073  return 0;
2074 }
2075 
2076 /*!*****************************************************************************
2077  * \brief Initialize auxiliary data that should be sent together with this frame
2078  * to encoder based on the auxiliary data of the decoded frame.
2079  *
2080  * \param[in/out] ni_logan_session_data_io_t session data
2081  *
2082  * \return NONE
2083  ******************************************************************************/
2085 {
2087  p_api_fme->data.frame.end_of_stream = 0;
2088  p_api_fme->data.frame.force_key_frame = 0;
2089  p_api_fme->data.frame.use_cur_src_as_long_term_pic = 0;
2090  p_api_fme->data.frame.use_long_term_ref = 0;
2091 
2092  p_api_fme->data.frame.sei_total_len = 0;
2093  p_api_fme->data.frame.sei_cc_offset = 0;
2094  p_api_fme->data.frame.sei_cc_len = 0;
2099  p_api_fme->data.frame.sei_hdr_plus_offset = 0;
2100  p_api_fme->data.frame.sei_hdr_plus_len = 0;
2101 
2102  p_api_fme->data.frame.roi_len = 0;
2103  p_api_fme->data.frame.reconf_len = 0;
2104  p_api_fme->data.frame.force_pic_qp = 0;
2105 }
2106 
2107 /*!*****************************************************************************
2108  * \brief Prepare auxiliary data that should be sent together with this frame
2109  * to encoder based on the auxiliary data of the decoded frame.
2110  *
2111  * Note: Some of the SEI (e.g. HDR) will be updated and stored in encoder
2112  * context whenever received through decoded frame; they will be sent
2113  * out with the encoded frame to encoder only when appropriate, i.e.
2114  * should_send_sei_with_frame is true. When a type of aux data is to be
2115  * sent, its associated length will be set in the encoder frame.
2116  *
2117  * \param[in/out] p_enc_ctx encoder session contextwhose various SEI type
2118  * header can be updated as the result of this function
2119  * \param[out] p_enc_frame frame to be sent to encoder
2120  * \param[in] p_dec_frame frame that is returned by decoder
2121  * \param[in] codec_format H.264 or H.265
2122  * \param[in] should_send_sei_with_frame if need to send a certain type of
2123  * SEI with this frame
2124  * \param[out] mdcv_data SEI for HDR mastering display color volume info
2125  * \param[out] cll_data SEI for HDR content light level info
2126  * \param[out] cc_data SEI for close caption
2127  * \param[out] udu_data SEI for User data unregistered
2128  * \param[out] hdrp_data SEI for HDR10+
2129  *
2130  * \return NONE
2131  ******************************************************************************/
2133  ni_logan_frame_t *p_enc_frame,
2134  ni_logan_frame_t *p_dec_frame,
2135  ni_logan_codec_format_t codec_format,
2136  int should_send_sei_with_frame,
2137  uint8_t *mdcv_data,
2138  uint8_t *cll_data,
2139  uint8_t *cc_data,
2140  uint8_t *udu_data,
2141  uint8_t *hdrp_data)
2142 {
2143  uint8_t *dst = NULL;
2144  ni_aux_data_t *aux_data = NULL;
2145  ni_logan_encoder_params_t *api_params =
2147 
2148  // reset all auxiliary data flag and length of encode frame
2150  = p_enc_frame->use_cur_src_as_long_term_pic
2151  = p_enc_frame->use_long_term_ref = 0;
2152 
2153  p_enc_frame->sei_total_len
2154  = p_enc_frame->sei_cc_offset = p_enc_frame->sei_cc_len
2159  = p_enc_frame->sei_user_data_unreg_offset
2160  = p_enc_frame->sei_user_data_unreg_len
2161  = p_enc_frame->sei_hdr_plus_offset
2162  = p_enc_frame->sei_hdr_plus_len = 0;
2163 
2164  // prep SEI for HDR (mastering display color volume)
2165  aux_data = ni_logan_frame_get_aux_data(
2167  if (aux_data)
2168  {
2169  p_enc_ctx->mdcv_max_min_lum_data_len = 8;
2171  8 + 6*2 + 2*2 + 2*4 + 1;
2172  if (NI_LOGAN_CODEC_FORMAT_H264 == codec_format)
2173  {
2175  }
2176 
2179 
2180  // save a copy
2181  if (! p_enc_ctx->p_master_display_meta_data)
2182  {
2183  p_enc_ctx->p_master_display_meta_data =
2184  malloc(sizeof(ni_mastering_display_metadata_t));
2185  }
2186  if (! p_enc_ctx->p_master_display_meta_data)
2187  {
2188  ni_log(NI_LOG_ERROR, "Error mem alloc for mastering display color vol\n");
2189  }
2190  else
2191  {
2192  memcpy(p_enc_ctx->p_master_display_meta_data, p_src,
2194 
2195  const int luma_den = 10000;
2196 
2197  uint32_t uint32_t_tmp = htonl((uint32_t)(lrint(luma_den * ni_q2d(
2198  p_src->max_luminance))));
2199  memcpy(p_enc_ctx->ui8_mdcv_max_min_lum_data,
2200  &uint32_t_tmp, sizeof(uint32_t));
2201  uint32_t_tmp = htonl((uint32_t)(lrint(luma_den * ni_q2d(
2202  p_src->min_luminance))));
2203  memcpy(p_enc_ctx->ui8_mdcv_max_min_lum_data + 4,
2204  &uint32_t_tmp, sizeof(uint32_t));
2205 
2206  // emulation prevention checking of luminance data
2207  int emu_bytes_inserted = ni_logan_insert_emulation_prevent_bytes(
2208  p_enc_ctx->ui8_mdcv_max_min_lum_data, 2*4);
2209 
2210  p_enc_ctx->mdcv_max_min_lum_data_len += emu_bytes_inserted;
2211  p_enc_ctx->sei_hdr_mastering_display_color_vol_len += emu_bytes_inserted;
2212  }
2213  }
2214 
2215  if (p_enc_ctx->sei_hdr_mastering_display_color_vol_len &&
2216  should_send_sei_with_frame)
2217  {
2218  dst = mdcv_data;
2219  dst[0] = dst[1] = dst[2] = 0;
2220  dst[3] = 1;
2221 
2222  if (NI_LOGAN_CODEC_FORMAT_H264 == codec_format)
2223  {
2224  dst[4] = 0x6;
2225  dst[5] = 0x89; // payload type=137
2226  dst[6] = 0x18; // payload size=24
2227  dst += 7;
2228  }
2229  else
2230  {
2231  dst[4] = 0x4e;
2232  dst[5] = 1;
2233  dst[6] = 0x89; // payload type=137
2234  dst[7] = 0x18; // payload size=24
2235  dst += 8;
2236  }
2237 
2241  p_enc_ctx->p_master_display_meta_data;
2242 
2243  const int chroma_den = 50000;
2244  const int luma_den = 10000;
2245 
2246  uint16_t dp00 = 0, dp01 = 0, dp10 = 0, dp11 = 0, dp20 = 0, dp21 = 0,
2247  wpx = 0, wpy = 0;
2248  // assuming p_src->has_primaries is always true
2249  // this is stored in r,g,b order and needs to be in g.b,r order
2250  // when sent to encoder
2251  dp00 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[1][0]));
2252  p_mdcv->display_primaries[0][0] = htons(dp00);
2253  dp01 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[1][1]));
2254  p_mdcv->display_primaries[0][1] = htons(dp01);
2255  dp10 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[2][0]));
2256  p_mdcv->display_primaries[1][0] = htons(dp10);
2257  dp11 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[2][1]));
2258  p_mdcv->display_primaries[1][1] = htons(dp11);
2259  dp20 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[0][0]));
2260  p_mdcv->display_primaries[2][0] = htons(dp20);
2261  dp21 = (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[0][1]));
2262  p_mdcv->display_primaries[2][1] = htons(dp21);
2263 
2264  wpx = (uint16_t)lrint(chroma_den * ni_q2d(p_src->white_point[0]));
2265  p_mdcv->white_point_x = htons(wpx);
2266  wpy = (uint16_t)lrint(chroma_den * ni_q2d(p_src->white_point[1]));
2267  p_mdcv->white_point_y = htons(wpy);
2268 
2269  ni_log(NI_LOG_TRACE, "mastering display color volume, primaries "
2270  "%u/%u/%u/%u/%u/%u white_point_x/y %u/%u max/min_lumi %u/%u\n",
2271  (uint16_t)dp00, (uint16_t)dp01, (uint16_t)dp10,
2272  (uint16_t)dp11, (uint16_t)dp20, (uint16_t)dp21,
2273  (uint16_t)wpx, (uint16_t)wpy,
2274  (uint32_t)(luma_den * ni_q2d(p_src->max_luminance)),
2275  (uint32_t)(luma_den * ni_q2d(p_src->min_luminance)));
2276 
2277  dst += 6 * 2 + 2 * 2;
2278  memcpy(dst, p_enc_ctx->ui8_mdcv_max_min_lum_data,
2279  p_enc_ctx->mdcv_max_min_lum_data_len);
2280 
2281  dst += p_enc_ctx->mdcv_max_min_lum_data_len;
2282  *dst = 0x80;
2283 
2286 
2287  p_enc_frame->sei_total_len +=
2289  }
2290 
2291  // prep SEI for HDR (content light level info)
2292  aux_data = ni_logan_frame_get_aux_data(p_dec_frame,
2294  if (aux_data)
2295  {
2296  // size of: start code + NAL unit header + payload type byte +
2297  // payload size byte + payload + rbsp trailing bits, default HEVC
2298  p_enc_ctx->light_level_data_len = 4;
2299  p_enc_ctx->sei_hdr_content_light_level_info_len = 8 + 2*2 + 1;
2300  if (NI_LOGAN_CODEC_FORMAT_H264 == codec_format)
2301  {
2303  }
2304 
2305  uint16_t max_content_light_level =
2306  htons(((ni_content_light_level_t*)aux_data->data)->max_cll);
2307  uint16_t max_pic_average_light_level =
2308  htons(((ni_content_light_level_t *)aux_data->data)->max_fall);
2309 
2310  ni_log(NI_LOG_TRACE, "content light level info, MaxCLL %u MaxFALL %u\n",
2311  ((ni_content_light_level_t*)aux_data->data)->max_cll,
2312  ((ni_content_light_level_t*)aux_data->data)->max_fall);
2313 
2314  memcpy(p_enc_ctx->ui8_light_level_data,
2315  &max_content_light_level, sizeof(uint16_t));
2316  memcpy(&(p_enc_ctx->ui8_light_level_data[2]),
2317  &max_pic_average_light_level, sizeof(uint16_t));
2318 
2319  // emulation prevention checking
2320  int emu_bytes_inserted = ni_logan_insert_emulation_prevent_bytes(
2321  p_enc_ctx->ui8_light_level_data, p_enc_ctx->light_level_data_len);
2322 
2323  p_enc_ctx->light_level_data_len += emu_bytes_inserted;
2324  p_enc_ctx->sei_hdr_content_light_level_info_len += emu_bytes_inserted;
2325  }
2326 
2327  if (p_enc_ctx->sei_hdr_content_light_level_info_len &&
2328  should_send_sei_with_frame)
2329  {
2330  dst = cll_data;
2331  dst[0] = dst[1] = dst[2] = 0;
2332  dst[3] = 1;
2333 
2334  if (NI_LOGAN_CODEC_FORMAT_H264 == codec_format)
2335  {
2336  dst[4] = 0x6;
2337  dst[5] = 0x90; // payload type=144
2338  dst[6] = 4; // payload size=4
2339  dst += 7;
2340  }
2341  else
2342  {
2343  dst[4] = 0x4e;
2344  dst[5] = 1;
2345  dst[6] = 0x90; // payload type=144
2346  dst[7] = 4; // payload size=4
2347  dst += 8;
2348  }
2349 
2350  memcpy(dst, p_enc_ctx->ui8_light_level_data,
2351  p_enc_ctx->light_level_data_len);
2352  dst += p_enc_ctx->light_level_data_len;
2353  *dst = 0x80;
2354 
2357 
2358  p_enc_frame->sei_total_len +=
2360  }
2361 
2362  // prep SEI for close caption
2363  aux_data = ni_logan_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_A53_CC);
2364  if (aux_data)
2365  {
2366  ni_log(NI_LOG_TRACE, "ni_logan_enc_prep_aux_data sei_cc_len %u\n",
2367  aux_data->size);
2368 
2369  uint8_t cc_data_emu_prevent[NI_LOGAN_MAX_SEI_DATA];
2370  int cc_size = aux_data->size;
2371  if (cc_size > NI_LOGAN_MAX_SEI_DATA)
2372  {
2373  ni_log(NI_LOG_ERROR, "ni_logan_enc_prep_aux_data sei_cc_len %u > MAX %d !\n",
2374  aux_data->size, (int)NI_LOGAN_MAX_SEI_DATA);
2375  cc_size = NI_LOGAN_MAX_SEI_DATA;
2376  }
2377  memcpy(cc_data_emu_prevent, aux_data->data, cc_size);
2378  int cc_size_emu_prevent = cc_size + ni_logan_insert_emulation_prevent_bytes(
2379  cc_data_emu_prevent, cc_size);
2380  if (cc_size_emu_prevent != cc_size)
2381  {
2382  ni_log(NI_LOG_TRACE, "ni_logan_enc_prep_aux_data: close caption "
2383  "emulation prevention bytes added: %d\n",
2384  cc_size_emu_prevent - cc_size);
2385  }
2386 
2387  dst = cc_data;
2388  // set header info fields and extra size based on codec
2389  if (NI_LOGAN_CODEC_FORMAT_H265 == codec_format)
2390  {
2391  p_enc_frame->sei_cc_len =
2392  NI_CC_SEI_HDR_HEVC_LEN + cc_size_emu_prevent + NI_CC_SEI_TRAILER_LEN;
2393  p_enc_frame->sei_total_len += p_enc_frame->sei_cc_len;
2394 
2395  p_enc_ctx->itu_t_t35_cc_sei_hdr_hevc[7] = cc_size + 11;
2396  p_enc_ctx->itu_t_t35_cc_sei_hdr_hevc[16] = (cc_size / 3) | 0xc0;
2397 
2398  memcpy(dst, p_enc_ctx->itu_t_t35_cc_sei_hdr_hevc, NI_CC_SEI_HDR_HEVC_LEN);
2399  dst += NI_CC_SEI_HDR_HEVC_LEN;
2400  memcpy(dst, cc_data_emu_prevent, cc_size_emu_prevent);
2401  dst += cc_size_emu_prevent;
2402  memcpy(dst, p_enc_ctx->sei_trailer, NI_CC_SEI_TRAILER_LEN);
2403  }
2404  else // H.264
2405  {
2406  p_enc_frame->sei_cc_len =
2407  NI_CC_SEI_HDR_H264_LEN + cc_size_emu_prevent + NI_CC_SEI_TRAILER_LEN;
2408  p_enc_frame->sei_total_len += p_enc_frame->sei_cc_len;
2409 
2410  p_enc_ctx->itu_t_t35_cc_sei_hdr_h264[6] = cc_size + 11;
2411  p_enc_ctx->itu_t_t35_cc_sei_hdr_h264[15] = (cc_size / 3) | 0xc0;
2412 
2413  memcpy(dst, p_enc_ctx->itu_t_t35_cc_sei_hdr_h264, NI_CC_SEI_HDR_H264_LEN);
2414  dst += NI_CC_SEI_HDR_H264_LEN;
2415  memcpy(dst, cc_data_emu_prevent, cc_size_emu_prevent);
2416  dst += cc_size_emu_prevent;
2417  memcpy(dst, p_enc_ctx->sei_trailer, NI_CC_SEI_TRAILER_LEN);
2418  }
2419  }
2420 
2421  // prep SEI for HDR+
2423  if (aux_data)
2424  {
2425  ni_dynamic_hdr_plus_t *hdrp = (ni_dynamic_hdr_plus_t *)aux_data->data;
2426  int w, i, j;
2428  uint32_t ui_tmp;
2429 
2431 
2432  // HDR10+ SEI header bytes
2433 
2434  // itu_t_t35_provider_code and itu_t_t35_provider_oriented_code are
2435  // contained in the first 4 bytes of payload; pb has all the data until
2436  // start of trailer
2437  ni_bs_writer_put(&pb, 0, 8);
2438  ni_bs_writer_put(&pb, 0x3c, 8); // u16 itu_t_t35_provider_code = 0x003c
2439  ni_bs_writer_put(&pb, 0, 8);
2440  // u16 itu_t_t35_provider_oriented_code = 0x0001
2441  ni_bs_writer_put(&pb, 0x01, 8);
2442  ni_bs_writer_put(&pb, 4, 8); // u8 application_identifier = 0x04
2443  ni_bs_writer_put(&pb, 0, 8); // u8 application version = 0x00
2444 
2445  ni_bs_writer_put(&pb, hdrp->num_windows, 2);
2446  ni_log(NI_LOG_TRACE, "hdr10+ num_windows %u\n", hdrp->num_windows);
2447  for (w = 1; w < hdrp->num_windows; w++)
2448  {
2449  ni_bs_writer_put(&pb,
2450  hdrp->params[w - 1].window_upper_left_corner_x.num, 16);
2451  ni_bs_writer_put(&pb,
2452  hdrp->params[w - 1].window_upper_left_corner_y.num, 16);
2453  ni_bs_writer_put(&pb,
2454  hdrp->params[w - 1].window_lower_right_corner_x.num, 16);
2455  ni_bs_writer_put(&pb,
2456  hdrp->params[w - 1].window_lower_right_corner_y.num, 16);
2457  ni_bs_writer_put(&pb, hdrp->params[w - 1].center_of_ellipse_x, 16);
2458  ni_bs_writer_put(&pb, hdrp->params[w - 1].center_of_ellipse_y, 16);
2459  ni_bs_writer_put(&pb, hdrp->params[w - 1].rotation_angle, 8);
2460  ni_bs_writer_put(&pb,
2461  hdrp->params[w - 1].semimajor_axis_internal_ellipse, 16);
2462  ni_bs_writer_put(&pb,
2463  hdrp->params[w - 1].semimajor_axis_external_ellipse, 16);
2464  ni_bs_writer_put(&pb,
2465  hdrp->params[w - 1].semiminor_axis_external_ellipse, 16);
2466  ni_bs_writer_put(&pb, hdrp->params[w - 1].overlap_process_option, 1);
2467  }
2468 
2469  // values are scaled up according to standard spec
2470  ui_tmp = lrint(10000 *
2472  ni_bs_writer_put(&pb, ui_tmp, 27);
2473  ni_bs_writer_put(&pb,
2475  1);
2476  ni_log(NI_LOG_TRACE, "hdr10+ targeted_system_display_maximum_luminance "
2477  "%d\n", ui_tmp);
2478  ni_log(NI_LOG_TRACE, "hdr10+ targeted_system_display_actual_peak_luminance_"
2480 
2482  {
2483  ni_bs_writer_put(&pb,
2485  ni_bs_writer_put(&pb,
2487  ni_log(NI_LOG_TRACE, "hdr10+ num_rows_targeted_system_display_actual_peak_luminance x num_cols_targeted_system_display_actual_peak_luminance %u x %u\n",
2490 
2491  for (i = 0;
2493  i++)
2494  for (j = 0;
2496  j++)
2497  {
2498  ui_tmp = lrint(15 * ni_q2d(hdrp->targeted_system_display_actual_peak_luminance[i][j]));
2499  ni_bs_writer_put(&pb, ui_tmp, 4);
2500  ni_log(NI_LOG_TRACE, "hdr10+ targeted_system_display_actual_peak_"
2501  "luminance[%d][%d] %d\n", i, j, ui_tmp);
2502  }
2503  }
2504 
2505  for (w = 0; w < hdrp->num_windows; w++)
2506  {
2507  for (i = 0; i < 3; i++)
2508  {
2509  ui_tmp = lrint(100000 * ni_q2d(hdrp->params[w].maxscl[i]));
2510  ni_bs_writer_put(&pb, ui_tmp, 17);
2511  ni_log(NI_LOG_TRACE, "hdr10+ maxscl[%d][%d] %d\n", w, i,
2512  ui_tmp);
2513  }
2514  ui_tmp = lrint(100000 * ni_q2d(hdrp->params[w].average_maxrgb));
2515  ni_bs_writer_put(&pb, ui_tmp, 17);
2516  ni_log(NI_LOG_TRACE, "hdr10+ average_maxrgb[%d] %d\n",
2517  w, ui_tmp);
2518 
2519  ni_bs_writer_put(&pb,
2522  "hdr10+ num_distribution_maxrgb_percentiles[%d] %d\n",
2524 
2525  for (i = 0; i < hdrp->params[w].num_distribution_maxrgb_percentiles; i++)
2526  {
2527  ni_bs_writer_put(&pb,
2528  hdrp->params[w].distribution_maxrgb[i].percentage, 7);
2529  ui_tmp = lrint(100000 * ni_q2d(hdrp->params[w].distribution_maxrgb[i].percentile));
2530  ni_bs_writer_put(&pb, ui_tmp, 17);
2532  "hdr10+ distribution_maxrgb_percentage[%d][%d] %u\n",
2533  w, i, hdrp->params[w].distribution_maxrgb[i].percentage);
2535  "hdr10+ distribution_maxrgb_percentile[%d][%d] %d\n",
2536  w, i, ui_tmp);
2537  }
2538 
2539  ui_tmp = lrint(1000 * ni_q2d(hdrp->params[w].fraction_bright_pixels));
2540  ni_bs_writer_put(&pb, ui_tmp, 10);
2541  ni_log(NI_LOG_TRACE, "hdr10+ fraction_bright_pixels[%d] %d\n",
2542  w, ui_tmp);
2543  }
2544 
2545  ni_bs_writer_put(&pb,
2548  "hdr10+ mastering_display_actual_peak_luminance_flag %u\n",
2551  {
2552  ni_bs_writer_put(&pb,
2554  5);
2555  ni_bs_writer_put(&pb,
2557  5);
2558  ni_log(NI_LOG_TRACE, "hdr10+ num_rows_mastering_display_actual_peak_luminance x num_cols_mastering_display_actual_peak_luminance %u x %u\n",
2561 
2562  for (i = 0;
2564  for (j = 0;
2566  {
2567  ui_tmp = lrint(15 * ni_q2d(hdrp->mastering_display_actual_peak_luminance[i][j]));
2568  ni_bs_writer_put(&pb, ui_tmp, 4);
2569  ni_log(NI_LOG_TRACE, "hdr10+ mastering_display_actual_peak_luminance[%d][%d] %d\n", i, j, ui_tmp);
2570  }
2571  }
2572 
2573  for (w = 0; w < hdrp->num_windows; w++)
2574  {
2575  ni_bs_writer_put(&pb, hdrp->params[w].tone_mapping_flag, 1);
2576  ni_log(NI_LOG_TRACE, "hdr10+ tone_mapping_flag[%d] %u\n",
2577  w, hdrp->params[w].tone_mapping_flag);
2578 
2579  if (hdrp->params[w].tone_mapping_flag)
2580  {
2581  ui_tmp = lrint(4095 * ni_q2d(hdrp->params[w].knee_point_x));
2582  ni_bs_writer_put(&pb, ui_tmp, 12);
2583  ni_log(NI_LOG_TRACE, "hdr10+ knee_point_x[%d] %u\n",
2584  w, ui_tmp);
2585 
2586  ui_tmp = lrint(4095 * ni_q2d(hdrp->params[w].knee_point_y));
2587  ni_bs_writer_put(&pb, ui_tmp, 12);
2588  ni_log(NI_LOG_TRACE, "hdr10+ knee_point_y[%d] %u\n",
2589  w, ui_tmp);
2590 
2593  "hdr10+ num_bezier_curve_anchors[%d] %u\n",
2594  w, hdrp->params[w].num_bezier_curve_anchors);
2595  for (i = 0; i < hdrp->params[w].num_bezier_curve_anchors; i++)
2596  {
2597  ui_tmp = lrint(1023 * ni_q2d(hdrp->params[w].bezier_curve_anchors[i]));
2598  ni_bs_writer_put(&pb, ui_tmp, 10);
2600  "hdr10+ bezier_curve_anchors[%d][%d] %d\n", w, i, ui_tmp);
2601  }
2602  }
2603 
2606  "hdr10+ color_saturation_mapping_flag[%d] %u\n",
2609  {
2610  ui_tmp = lrint(8 * ni_q2d(hdrp->params[w].color_saturation_weight));
2611  ni_bs_writer_put(&pb, 6, ui_tmp);
2612  ni_log(NI_LOG_TRACE, "hdr10+ color_saturation_weight[%d] %d\n",
2613  w, ui_tmp);
2614  }
2615  } // num_windows
2616 
2617  uint32_t hdr10p_num_bytes = (uint32_t)((ni_bs_writer_tell(&pb) + 7) / 8);
2618  ni_log(NI_LOG_TRACE, "hdr10+ total bits: %d -> bytes %"PRIu64"\n",
2619  (int)ni_bs_writer_tell(&pb), hdr10p_num_bytes);
2621 
2622  dst = hdrp_data;
2623 
2624  // emulation prevention checking of payload
2625  int emu_bytes_inserted = 0;
2626 
2627  // set header info fields and extra size based on codec
2628  if (NI_LOGAN_CODEC_FORMAT_H265 == codec_format)
2629  {
2630  p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_hevc[7] =
2631  hdr10p_num_bytes + NI_RBSP_TRAILING_BITS_LEN;
2632 
2633  memcpy(dst, p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_hevc,
2636  ni_bs_writer_copy(dst, &pb);
2637 
2638  emu_bytes_inserted = ni_logan_insert_emulation_prevent_bytes(
2639  dst, hdr10p_num_bytes);
2640  dst += hdr10p_num_bytes + emu_bytes_inserted;
2641  *dst = p_enc_ctx->sei_trailer[1];
2643 
2645  hdr10p_num_bytes + emu_bytes_inserted + NI_RBSP_TRAILING_BITS_LEN;
2646  p_enc_frame->sei_total_len += p_enc_frame->sei_hdr_plus_len;
2647  }
2648  else if (NI_LOGAN_CODEC_FORMAT_H264 == codec_format)
2649  {
2650  p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_h264[6] =
2651  hdr10p_num_bytes + NI_RBSP_TRAILING_BITS_LEN;
2652 
2653  memcpy(dst, p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_h264,
2656  ni_bs_writer_copy(dst, &pb);
2657 
2658  emu_bytes_inserted = ni_logan_insert_emulation_prevent_bytes(
2659  dst, hdr10p_num_bytes);
2660  dst += hdr10p_num_bytes + emu_bytes_inserted;
2661  *dst = p_enc_ctx->sei_trailer[1];
2663 
2665  hdr10p_num_bytes + emu_bytes_inserted + NI_RBSP_TRAILING_BITS_LEN;
2666  p_enc_frame->sei_total_len += p_enc_frame->sei_hdr_plus_len;
2667  }
2668  else
2669  {
2670  ni_log(NI_LOG_ERROR, "ni_logan_enc_prep_aux_data: codec %d not "
2671  "supported for HDR10+ SEI !\n", codec_format);
2672  p_enc_frame->sei_hdr_plus_len = 0;
2673  }
2674 
2675  ni_bs_writer_clear(&pb);
2676  } // hdr10+
2677 
2678  // prep SEI for User Data Unregistered
2679  aux_data = ni_logan_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_UDU_SEI);
2680  if (aux_data)
2681  {
2682  ni_log(NI_LOG_TRACE, "ni_logan_enc_prep_aux_data sei_user_data_unreg_len %u\n",
2683  aux_data->size);
2684 
2685  // emulation prevention checking: a working buffer of size in worst case
2686  // that each two bytes comes with 1B emulation prevention byte
2687  int udu_sei_size = aux_data->size;
2688  int ext_udu_sei_size = 0, sei_len = 0;
2689 
2690  uint8_t *sei_data = malloc(udu_sei_size * 3 / 2);
2691  if (sei_data)
2692  {
2693  memcpy(sei_data, (uint8_t *)aux_data->data, udu_sei_size);
2694  int emu_bytes_inserted = ni_logan_insert_emulation_prevent_bytes(
2695  sei_data, udu_sei_size);
2696 
2697  ext_udu_sei_size = udu_sei_size + emu_bytes_inserted;
2698 
2699  if (NI_LOGAN_CODEC_FORMAT_H264 == codec_format)
2700  {
2701  /* 4B long start code + 1B nal header + 1B SEI type + Bytes of
2702  payload length + Bytes of SEI payload + 1B trailing */
2703  sei_len = 6 + ((udu_sei_size + 0xFE) / 0xFF) + ext_udu_sei_size + 1;
2704  }
2705  else
2706  {
2707  /* 4B long start code + 2B nal header + 1B SEI type + Bytes of
2708  payload length + Bytes of SEI payload + 1B trailing */
2709  sei_len = 7 + ((udu_sei_size + 0xFE) / 0xFF) + ext_udu_sei_size + 1;
2710  }
2711 
2712  // discard this UDU SEI if the total SEI size exceeds the max size
2713  if (p_enc_frame->sei_total_len + sei_len > NI_LOGAN_ENC_MAX_SEI_BUF_SIZE)
2714  {
2715  ni_log(NI_LOG_ERROR, "ni_logan_enc_prep_aux_data sei total length %u + "
2716  "sei_len %d exceeds maximum sei size %u, discarding it !\n",
2717  p_enc_frame->sei_total_len, sei_len, NI_LOGAN_ENC_MAX_SEI_BUF_SIZE);
2718  }
2719  else
2720  {
2721  int payload_size = udu_sei_size;
2722 
2723  dst = udu_data;
2724  *dst++ = 0x00; // long start code
2725  *dst++ = 0x00;
2726  *dst++ = 0x00;
2727  *dst++ = 0x01;
2728 
2729  if (NI_LOGAN_CODEC_FORMAT_H264 == codec_format)
2730  {
2731  *dst++ = 0x06; // nal type: SEI
2732  }
2733  else
2734  {
2735  *dst++ = 0x4e; // nal type: SEI
2736  *dst++ = 0x01;
2737  }
2738  *dst++ = 0x05; // SEI type: user data unregistered
2739 
2740  // original payload size
2741  while (payload_size > 0)
2742  {
2743  *dst++ = (payload_size > 0xFF ? 0xFF : (uint8_t)payload_size);
2744  payload_size -= 0xFF;
2745  }
2746 
2747  // payload data after emulation prevention checking
2748  memcpy(dst, sei_data, ext_udu_sei_size);
2749  dst += ext_udu_sei_size;
2750 
2751  // trailing byte
2752  *dst = 0x80;
2753  dst++;
2754 
2755  // save UDU data length
2756  p_enc_frame->sei_user_data_unreg_len = sei_len;
2757  p_enc_frame->sei_total_len += sei_len;
2758  }
2759 
2760  free(sei_data);
2761  sei_data = NULL;
2762  }
2763  }
2764 
2765  // supply QP map if ROI enabled and if ROIs passed in
2766  aux_data = ni_logan_frame_get_aux_data(p_dec_frame,
2768  if (api_params->enc_input_params.roi_enable && aux_data)
2769  {
2770  int is_new_rois = 1;
2771  const ni_region_of_interest_t *roi = NULL;
2772  uint32_t self_size = 0;
2773 
2774  roi = (const ni_region_of_interest_t*)aux_data->data;
2775  self_size = roi->self_size;
2776  if (! self_size || aux_data->size % self_size)
2777  {
2778  ni_log(NI_LOG_ERROR, "Invalid ni_region_of_interest_t.self_size, "
2779  "aux_data size %d self_size %u\n", aux_data->size, self_size);
2780  }
2781  else
2782  {
2783  int nb_roi = aux_data->size / self_size;
2784 
2785  // update ROI(s) if new/different from last one
2786  if (0 == p_enc_ctx->nb_rois || 0 == p_enc_ctx->roi_side_data_size ||
2787  ! p_enc_ctx->av_rois || p_enc_ctx->nb_rois != nb_roi ||
2788  p_enc_ctx->roi_side_data_size != aux_data->size ||
2789  memcmp(p_enc_ctx->av_rois, aux_data->data, aux_data->size))
2790  {
2791  p_enc_ctx->roi_side_data_size = aux_data->size;
2792  p_enc_ctx->nb_rois = nb_roi;
2793 
2794  free(p_enc_ctx->av_rois);
2795  p_enc_ctx->av_rois = malloc(aux_data->size);
2796  if (! p_enc_ctx->av_rois)
2797  {
2798  ni_log(NI_LOG_ERROR, "malloc ROI aux_data failed.\n");
2799  is_new_rois = 0;
2800  }
2801  else
2802  {
2803  memcpy(p_enc_ctx->av_rois, aux_data->data, aux_data->size);
2804  }
2805  }
2806  else
2807  {
2808  is_new_rois = 0;
2809  }
2810 
2811  if (is_new_rois)
2812  {
2813  if (set_roi_map(p_enc_ctx, codec_format, aux_data, nb_roi,
2814  api_params->source_width, api_params->source_height,
2815  api_params->enc_input_params.rc.intra_qp))
2816  {
2817  ni_log(NI_LOG_ERROR, "set_roi_map failed\n");
2818  }
2819  }
2820  }
2821 
2822  // ROI data in the frame
2823  p_enc_frame->extra_data_len += p_enc_ctx->roi_len;
2824  p_enc_frame->roi_len = p_enc_ctx->roi_len;
2825  }
2826 
2827  // if ROI cache is enabled, supply cached QP map if no ROI aux data is
2828  // passed in with this frame
2829  if (api_params->enc_input_params.roi_enable && ! aux_data &&
2830  api_params->cacheRoi)
2831  {
2832  p_enc_frame->extra_data_len += p_enc_ctx->roi_len;
2833  p_enc_frame->roi_len = p_enc_ctx->roi_len;
2834 
2835  ni_log(NI_LOG_TRACE, "ni_logan_enc_prep_aux_data: supply cached QP map.\n");
2836  }
2837 
2838  // prep for NetInt long term reference frame support
2840  if (aux_data)
2841  {
2842  ni_long_term_ref_t *ltr = (ni_long_term_ref_t *)aux_data->data;
2843 
2844  p_enc_frame->use_cur_src_as_long_term_pic =
2846  p_enc_frame->use_long_term_ref = ltr->use_long_term_ref;
2847  }
2848 
2849  // prep for NetInt target bitrate reconfiguration support
2850  aux_data = ni_logan_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_BITRATE);
2851  if (aux_data)
2852  {
2853  int32_t bitrate = *((int32_t *)aux_data->data);
2854  if (! p_enc_ctx->enc_change_params)
2855  {
2856  p_enc_ctx->enc_change_params =
2857  calloc(1, sizeof(ni_logan_encoder_change_params_t));
2858  }
2859 
2860  if (! p_enc_ctx->enc_change_params)
2861  {
2862  ni_log(NI_LOG_ERROR, "Error ni_logan_enc_prep_aux_data malloc for "
2863  "enc_change_params!\n");
2864  }
2865  else
2866  {
2867  p_enc_ctx->enc_change_params->enable_option |=
2869  p_enc_ctx->enc_change_params->bitRate = bitrate;
2870  if (p_enc_frame->reconf_len == 0)
2871  {
2872  p_enc_frame->reconf_len = sizeof(ni_logan_encoder_change_params_t);
2873  p_enc_frame->extra_data_len += p_enc_frame->reconf_len;
2874  }
2875  }
2876  }
2877 
2878  // prep for NetInt target min max qp reconfiguration support
2880  if (aux_data)
2881  {
2882  ni_logan_rc_min_max_qp *rc_qp = (ni_logan_rc_min_max_qp *)aux_data->data;
2883  if (! p_enc_ctx->enc_change_params)
2884  {
2885  p_enc_ctx->enc_change_params =
2886  calloc(1, sizeof(ni_logan_encoder_change_params_t));
2887  }
2888 
2889  if (! p_enc_ctx->enc_change_params)
2890  {
2891  ni_log(NI_LOG_ERROR, "Error ni_logan_enc_prep_aux_data malloc for "
2892  "enc_change_params!\n");
2893  }
2894  else
2895  {
2896  p_enc_ctx->enc_change_params->enable_option |=
2898  p_enc_ctx->enc_change_params->minQpI = rc_qp->minQpI;
2899  p_enc_ctx->enc_change_params->maxQpI = rc_qp->maxQpI;
2900  p_enc_ctx->enc_change_params->maxDeltaQp = rc_qp->maxDeltaQp;
2901  p_enc_ctx->enc_change_params->minQpP = rc_qp->minQpP;
2902  p_enc_ctx->enc_change_params->minQpB = rc_qp->minQpB;
2903  p_enc_ctx->enc_change_params->maxQpP = rc_qp->maxQpP;
2904  p_enc_ctx->enc_change_params->maxQpB = rc_qp->maxQpB;
2905  if (p_enc_frame->reconf_len == 0)
2906  {
2907  p_enc_frame->reconf_len = sizeof(ni_logan_encoder_change_params_t);
2908  p_enc_frame->extra_data_len += p_enc_frame->reconf_len;
2909  }
2910  }
2911  }
2912 
2913  // prep for alternative preferred transfer characteristics SEI
2915  should_send_sei_with_frame)
2916  {
2917  if (NI_LOGAN_CODEC_FORMAT_H264 == codec_format)
2918  {
2919  p_enc_frame->preferred_characteristics_data_len = 9;
2920  }
2921  else
2922  {
2923  p_enc_frame->preferred_characteristics_data_len = 10;
2924  }
2925 
2926  p_enc_ctx->preferred_characteristics_data =
2928  p_enc_frame->sei_total_len +=
2930  }
2931 }
2932 
2933 /*!*****************************************************************************
2934  * \brief Copy auxiliary data that should be sent together with this frame
2935  * to encoder.
2936  *
2937  * \param[in] p_enc_ctx encoder session context
2938  * \param[out] p_enc_frame frame to be sent to encoder
2939  * \param[in] p_dec_frame frame returned by decoder
2940  * \param[in] mdcv_data SEI for HDR mastering display color volume info
2941  * \param[in] cll_data SEI for HDR content light level info
2942  * \param[in] cc_data SEI for close caption
2943  * \param[in] udu_data SEI for User data unregistered
2944  * \param[in] hdrp_data SEI for HDR10+
2945  *
2946  * \return NONE
2947  ******************************************************************************/
2949  ni_logan_frame_t *p_enc_frame,
2950  ni_logan_frame_t *p_dec_frame,
2951  ni_logan_codec_format_t codec_format,
2952  const uint8_t *mdcv_data,
2953  const uint8_t *cll_data,
2954  const uint8_t *cc_data,
2955  const uint8_t *udu_data,
2956  const uint8_t *hdrp_data)
2957 {
2958  // fill in extra data (skipping meta data header)
2959  // Note: this handles both regular YUV layout and YUVbypass cases, while
2960  // the later has no YUV but hwframe_surface_t as actual data and its
2961  // size stored in data_len[3]
2962  // When enc frame is separate_metadata mode,the p_data[3] is extra data
2963  // and no need to jump the data_len[3] for HW frame case.
2964  uint8_t *dst = (uint8_t *)p_enc_frame->p_data[3] +
2965  (p_enc_frame->separate_metadata ? 0 : p_enc_frame->data_len[3]) +
2967 
2968  // fill in reconfig data if enabled; even if it's disabled, keep the space
2969  // for it if SEI or ROI is present;
2970  if (p_enc_frame->reconf_len || p_enc_frame->roi_len ||
2971  p_enc_frame->sei_total_len)
2972  {
2973  ni_log(NI_LOG_TRACE, "ni_logan_enc_copy_aux_data: keep reconfig space: %" PRId64 "\n",
2975 
2976  memset(dst, 0, sizeof(ni_logan_encoder_change_params_t));
2977 
2978  if (p_enc_frame->reconf_len && p_enc_ctx->enc_change_params)
2979  {
2980  memcpy(dst, p_enc_ctx->enc_change_params, p_enc_frame->reconf_len);
2981  }
2982 
2983  dst += sizeof(ni_logan_encoder_change_params_t);
2984  }
2985 
2986  // fill in ROI map, if enabled
2987  if (p_enc_frame->roi_len)
2988  {
2989  if (NI_LOGAN_CODEC_FORMAT_H264 == codec_format && p_enc_ctx->avc_roi_map)
2990  {
2991  memcpy(dst, p_enc_ctx->avc_roi_map, p_enc_frame->roi_len);
2992  }
2993  else if (NI_LOGAN_CODEC_FORMAT_H265 == codec_format && p_enc_ctx->hevc_roi_map)
2994  {
2995  memcpy(dst, p_enc_ctx->hevc_roi_map, p_enc_frame->roi_len);
2996  }
2997  // as long as the frame ROI len is set, even if ctx->roi_map is not init
2998  // (in the case of hardcoding ROI in nienc), still reserve the ROI space
2999  dst += p_enc_frame->roi_len;
3000  }
3001 
3002  // HDR SEI: mastering display color volume
3003  if (p_enc_frame->sei_hdr_mastering_display_color_vol_len)
3004  {
3005  ni_log(NI_LOG_TRACE, "ni_logan_enc_copy_aux_data: HDR SEI mdcv size: %u\n",
3007  memcpy(dst, mdcv_data,p_enc_frame->sei_hdr_mastering_display_color_vol_len);
3008  dst += p_enc_frame->sei_hdr_mastering_display_color_vol_len;
3009  }
3010 
3011  // HDR SEI: content light level info
3012  if (p_enc_frame->sei_hdr_content_light_level_info_len)
3013  {
3014  ni_log(NI_LOG_TRACE, "ni_logan_enc_copy_aux_data: HDR SEI cll size: %u\n",
3016 
3017  memcpy(dst, cll_data, p_enc_frame->sei_hdr_content_light_level_info_len);
3018  dst += p_enc_frame->sei_hdr_content_light_level_info_len;
3019  }
3020 
3021  // HLG SEI: preferred characteristics
3022  if (p_enc_frame->preferred_characteristics_data_len)
3023  {
3024  dst[0] = dst[1] = dst[2] = 0;
3025  dst[3] = 1;
3026  if (NI_LOGAN_CODEC_FORMAT_H265 == codec_format)
3027  {
3028  dst[4] = 0x4e;
3029  dst[5] = 1;
3030  dst[6] = 0x93; // payload type=147
3031  dst[7] = 1; // payload size=1
3032  dst += 8;
3033  }
3034  else
3035  {
3036  dst[4] = 0x6;
3037  dst[5] = 0x93; // payload type=147
3038  dst[6] = 1; // payload size=1
3039  dst += 7;
3040  }
3041  *dst = p_enc_ctx->preferred_characteristics_data;
3042  dst++;
3043  *dst = 0x80;
3044  dst++;
3045  }
3046 
3047  // close caption
3048  if (p_enc_frame->sei_cc_len)
3049  {
3050  ni_log(NI_LOG_TRACE, "ni_logan_enc_copy_aux_data: close caption size: %u\n",
3051  p_enc_frame->sei_cc_len);
3052 
3053  memcpy(dst, cc_data, p_enc_frame->sei_cc_len);
3054  dst += p_enc_frame->sei_cc_len;
3055  }
3056 
3057  // HDR10+
3058  if (p_enc_frame->sei_hdr_plus_len)
3059  {
3060  memcpy(dst, hdrp_data, p_enc_frame->sei_hdr_plus_len);
3061  dst += p_enc_frame->sei_hdr_plus_len;
3062  }
3063 
3064  // User data unregistered SEI
3065  if (p_enc_frame->sei_user_data_unreg_len)
3066  {
3067  memcpy(dst, udu_data, p_enc_frame->sei_user_data_unreg_len);
3068  dst += p_enc_frame->sei_user_data_unreg_len;
3069  }
3070 }
3071 
3072 /*!*****************************************************************************
3073  * \brief Fill reconfig params
3074  *
3075  * \param[in] p_param encoder parameters.
3076  * \param[in/out] p_ctx session context, its enc_change_params may be updated.
3077  * \param[in/out] p_api_fme extra_data_len and reconf_len may be updated
3078  * \param[in] reconfigCount reconfig count, may be updated.
3079  *
3080  * \return reconfigCount on success
3081  * < 0 on failure, NI_LOGAN_RETCODE_INVALID_PARAM
3082  * NI_LOGAN_RETCODE_ERROR_MEM_ALOC
3083  ******************************************************************************/
3086  ni_logan_frame_t *p_api_fme,
3087  int reconfigCount)
3088 {
3089  if (!p_param || !p_ctx || !p_api_fme || reconfigCount < 0)
3090  {
3091  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter\n",
3092  __FUNCTION__, __LINE__);
3094  }
3095  // allocate memory for reconf parameters only once and reuse it
3096  if (!p_ctx->enc_change_params &&
3099  {
3100  p_ctx->enc_change_params = malloc(sizeof(ni_logan_encoder_change_params_t));
3101  if (!p_ctx->enc_change_params)
3102  {
3104  }
3105  }
3106  if (p_ctx->enc_change_params)
3107  {
3108  memset(p_ctx->enc_change_params, 0,
3110  }
3111 
3112  switch (p_param->reconf_demo_mode)
3113  {
3115  if (p_ctx->frame_num == p_param->reconf_hash[reconfigCount][0])
3116  {
3118  p_ctx->enc_change_params->bitRate = p_param->reconf_hash[reconfigCount][1];
3119 
3120  p_api_fme->extra_data_len += sizeof(ni_logan_encoder_change_params_t);
3121  p_api_fme->reconf_len = sizeof(ni_logan_encoder_change_params_t);
3122  reconfigCount++;
3123  }
3124  break;
3126  if (p_ctx->frame_num == p_param->reconf_hash[reconfigCount][0])
3127  {
3129  p_ctx->enc_change_params->intraQP = p_param->reconf_hash[reconfigCount][1];
3130  p_ctx->enc_change_params->intraPeriod = p_param->reconf_hash[reconfigCount][2];
3131  p_ctx->enc_change_params->repeatHeaders = p_param->reconf_hash[reconfigCount][3];
3132  ni_log(NI_LOG_TRACE, "xcoder_logan_send_frame: frame #%lu reconf "
3133  "intraQP %d intraPeriod %d repeatHeaders %d\n",
3134  p_ctx->frame_num,
3135  p_ctx->enc_change_params->intraQP,
3138 
3139  p_api_fme->extra_data_len += sizeof(ni_logan_encoder_change_params_t);
3140  p_api_fme->reconf_len = sizeof(ni_logan_encoder_change_params_t);
3141  reconfigCount++;
3142  }
3143  break;
3145  // the reconf file data line format for this is:
3146  // <frame-number>:useCurSrcAsLongtermPic,useLongtermRef where
3147  // values will stay the same on every frame until changed.
3148  if (p_ctx->frame_num >= p_param->reconf_hash[reconfigCount][0])
3149  {
3150  p_api_fme->use_cur_src_as_long_term_pic = p_param->reconf_hash[reconfigCount][1];
3151  p_api_fme->use_long_term_ref = p_param->reconf_hash[reconfigCount][2];
3152  }
3153  if (p_ctx->frame_num + 1 == p_param->reconf_hash[reconfigCount + 1][0])
3154  {
3155  reconfigCount++;
3156  }
3157  break;
3159  // the reconf file format for this is:
3160  // <frame-number>:<vui-file-name-in-digits>,<number-of-bits-of-vui-rbsp>
3161  if (p_ctx->frame_num == p_param->reconf_hash[reconfigCount][0])
3162  {
3163  char file_name[64];
3164  FILE *vui_file;
3165  snprintf(file_name, 64, "%d", p_param->reconf_hash[reconfigCount][1]);
3166  vui_file = fopen(file_name, "rb");
3167  if (! vui_file)
3168  {
3169  ni_log(NI_LOG_ERROR, "Error VUI reconf file: %s\n", file_name);
3170  }
3171  else
3172  {
3173  int nb_bytes_by_bits =
3174  (p_param->reconf_hash[reconfigCount][2] + 7) / 8;
3175  size_t nb_bytes = fread(p_ctx->enc_change_params->vuiRbsp,
3176  1, NI_LOGAN_MAX_VUI_SIZE, vui_file);
3177  if (nb_bytes != nb_bytes_by_bits)
3178  {
3179  ni_log(NI_LOG_ERROR, "Error VUI file size %d bytes != "
3180  "specified %d bits (%d bytes) !\n", (int)nb_bytes,
3181  p_param->reconf_hash[reconfigCount][2], nb_bytes_by_bits);
3182  }
3183  else
3184  {
3186  p_ctx->enc_change_params->encodeVuiRbsp = 1;
3187  p_ctx->enc_change_params->vuiDataSizeBits = p_param->reconf_hash[reconfigCount][2];
3188  p_ctx->enc_change_params->vuiDataSizeBytes = nb_bytes;
3189  ni_log(NI_LOG_TRACE, "Reconf VUI %d bytes (%d bits)\n",
3190  (int)nb_bytes, p_param->reconf_hash[reconfigCount][2]);
3191 
3192  p_api_fme->extra_data_len += sizeof(ni_logan_encoder_change_params_t);
3193  p_api_fme->reconf_len = sizeof(ni_logan_encoder_change_params_t);
3194  reconfigCount++;
3195  }
3196 
3197  fclose(vui_file);
3198  }
3199  }
3200  break;
3202  if (p_ctx->frame_num == p_param->reconf_hash[reconfigCount][0])
3203  {
3205  p_ctx->enc_change_params->hvsQPEnable = p_param->reconf_hash[reconfigCount][1];
3206  p_ctx->enc_change_params->hvsQpScale = p_param->reconf_hash[reconfigCount][2];
3207  p_ctx->enc_change_params->vbvBufferSize = p_param->reconf_hash[reconfigCount][3];
3208  p_ctx->enc_change_params->mbLevelRcEnable = p_param->reconf_hash[reconfigCount][4];
3209  p_ctx->enc_change_params->fillerEnable = p_param->reconf_hash[reconfigCount][5];
3210  p_ctx->enc_change_params->maxFrameMode = p_param->reconf_hash[reconfigCount][6];
3211  p_ctx->enc_change_params->maxFrameArg = p_param->reconf_hash[reconfigCount][7];
3212  ni_log(NI_LOG_TRACE, "xcoder_logan_send_frame: frame #%lu reconf "
3213  "hvsQPEnable %d hvsQpScale %d vbvBufferSize %d mbLevelRcEnable "
3214  "%d fillerEnable %d maxFrameMode %d maxFrameArg %d\n",
3215  p_ctx->frame_num,
3217  p_ctx->enc_change_params->hvsQpScale,
3222  p_ctx->enc_change_params->maxFrameArg);
3223 
3224  p_api_fme->extra_data_len += sizeof(ni_logan_encoder_change_params_t);
3225  p_api_fme->reconf_len = sizeof(ni_logan_encoder_change_params_t);
3226  reconfigCount++;
3227  }
3228  break;
3230  if (p_ctx->frame_num == p_param->reconf_hash[reconfigCount][0])
3231  {
3233  p_ctx->enc_change_params->minQpI = p_param->reconf_hash[reconfigCount][1];
3234  p_ctx->enc_change_params->maxQpI = p_param->reconf_hash[reconfigCount][2];
3235  p_ctx->enc_change_params->maxDeltaQp = p_param->reconf_hash[reconfigCount][3];
3236  p_ctx->enc_change_params->minQpP = p_param->reconf_hash[reconfigCount][4];
3237  p_ctx->enc_change_params->minQpB = p_param->reconf_hash[reconfigCount][5];
3238  p_ctx->enc_change_params->maxQpP = p_param->reconf_hash[reconfigCount][6];
3239  p_ctx->enc_change_params->maxQpB = p_param->reconf_hash[reconfigCount][7];
3240  ni_log(NI_LOG_TRACE, "xcoder_logan_send_frame: frame #%lu reconf "
3241  "minQpI %d maxQpI %d maxDeltaQp %d minQpP "
3242  "%d minQpB %d maxQpP %d maxQpB %d\n",
3243  p_ctx->frame_num,
3244  p_ctx->enc_change_params->minQpI,
3245  p_ctx->enc_change_params->maxQpI,
3246  p_ctx->enc_change_params->maxDeltaQp,
3247  p_ctx->enc_change_params->minQpP,
3248  p_ctx->enc_change_params->minQpB,
3249  p_ctx->enc_change_params->maxQpP,
3250  p_ctx->enc_change_params->maxQpB);
3251 
3252  p_api_fme->extra_data_len += sizeof(ni_logan_encoder_change_params_t);
3253  p_api_fme->reconf_len = sizeof(ni_logan_encoder_change_params_t);
3254  reconfigCount++;
3255  }
3256  break;
3258  if (p_ctx->frame_num == p_param->reconf_hash[reconfigCount][0])
3259  {
3261  p_ctx->enc_change_params->crfQpInt = p_param->reconf_hash[reconfigCount][1];
3262  p_ctx->enc_change_params->crfQpFraction = p_param->reconf_hash[reconfigCount][2];
3263  p_ctx->enc_change_params->crfIpRatioInt = p_param->reconf_hash[reconfigCount][3];
3264  p_ctx->enc_change_params->crfIpRatioFraction = p_param->reconf_hash[reconfigCount][4];
3265  p_ctx->enc_change_params->crfPbRatioInt = p_param->reconf_hash[reconfigCount][5];
3266  p_ctx->enc_change_params->crfPbRatioFraction = p_param->reconf_hash[reconfigCount][6];
3267  ni_log(NI_LOG_TRACE, "xcoder_logan_send_frame: frame #%lu reconf "
3268  "crfQpInt %d crfQpFraction %d crfIpRatioInt %d crfIpRatioFraction %d"
3269  "crfPbRatioInt %d crfPbRatioFraction %d\n",
3270  p_ctx->frame_num,
3271  p_ctx->enc_change_params->crfQpInt,
3277 
3278  p_api_fme->extra_data_len += sizeof(ni_logan_encoder_change_params_t);
3279  p_api_fme->reconf_len = sizeof(ni_logan_encoder_change_params_t);
3280  reconfigCount++;
3281  }
3282  break;
3284  default:
3285  break;
3286  }
3287  return reconfigCount;
3288 }
3289 
3292  ni_logan_frame_t *p_api_fme,
3293  int reconfigCount,
3294  ni_aux_data_t *aux_data)
3295 {
3296  if (!p_param || !p_ctx || !p_api_fme || reconfigCount < 0)
3297  {
3298  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter\n",
3299  __FUNCTION__, __LINE__);
3301  }
3302  ni_logan_reset_vui(p_param, aux_data, p_ctx->codec_format);
3303  if (!strcmp(p_param->ui8VuiRbsp, p_param->ui8LastVuiRbsp))
3304  return reconfigCount;
3305 
3306  // allocate memory for reconf parameters only once and reuse it
3307  if (!p_ctx->enc_change_params)
3308  {
3309  p_ctx->enc_change_params = malloc(sizeof(ni_logan_encoder_change_params_t));
3310  if (!p_ctx->enc_change_params)
3311  {
3313  }
3314  }
3315  if (p_ctx->enc_change_params)
3316  {
3317  memset(p_ctx->enc_change_params, 0, sizeof(ni_logan_encoder_change_params_t));
3318  }
3319 
3323  p_ctx->enc_change_params->encodeVuiRbsp = 1;
3324  memcpy(p_ctx->enc_change_params->vuiRbsp, p_param->ui8VuiRbsp, NI_LOGAN_MAX_VUI_SIZE);
3325  p_api_fme->extra_data_len += sizeof(ni_logan_encoder_change_params_t);
3326  p_api_fme->reconf_len = sizeof(ni_logan_encoder_change_params_t);
3327  reconfigCount++;
3328 
3329  return reconfigCount;
3330 }
3331 
3332 /*!*****************************************************************************
3333  * \brief Find the next start code
3334  *
3335  * \param[in] p pointer to buffer start address.
3336  * \param[in] end pointer to buffer end address.
3337  * \param[state] state pointer to nalu type address
3338  *
3339  * \return search end address
3340  ******************************************************************************/
3341 const uint8_t *ni_logan_find_start_code(const uint8_t *p,
3342  const uint8_t *end,
3343  uint32_t *state)
3344 {
3345  int i;
3346 
3347  if (p >= end)
3348  return end;
3349 
3350  for (i = 0; i < 3; i++) {
3351  uint32_t tmp = *state << 8;
3352  *state = tmp + *(p++);
3353  if (tmp == 0x100 || p == end)
3354  return p;
3355  }
3356 
3357  while (p < end) {
3358  if (p[-1] > 1 ) p += 3;
3359  else if (p[-2] ) p += 2;
3360  else if (p[-3]|(p[-1]-1)) p++;
3361  else {
3362  p++;
3363  break;
3364  }
3365  }
3366 
3367  p = ((p) < (end) ? (p - 4) : (end - 4)); // min
3368  *state = (((uint32_t)(p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3]);
3369 
3370  return p + 4;
3371 }
3372 
3373 /*!******************************************************************************
3374  * \brief Extract custom sei payload data from Packet,
3375  * and save it to ni_logan_packet_t
3376  *
3377  * \param uint8_t *data - packet data
3378  * \param int size - pkt data size
3379  * \param int start_index - pkt data index of custom sei first byte after SEI type
3380  * \param ni_logan_packet_t *p_packet - netint internal packet
3381  * \param uint8_t sei_type - type of SEI
3382  * \param int got_slice - whether got vcl in the pkt data, 1 means got
3383  *
3384  * \return - 0 on success, non-0 on failure
3385  *******************************************************************************/
3386 static int ni_logan_extract_custom_sei(const uint8_t *data,
3387  int size,
3388  int start_index,
3389  ni_logan_packet_t *p_packet,
3390  uint8_t sei_type,
3391  int got_slice)
3392 {
3393  int i;
3394  const uint8_t *udata;
3395  uint8_t *sei_data;
3396  int len = 0;
3397  int sei_size = 0; // default is 0
3398  int index = start_index;
3399  int sei_index = 0;
3400 
3401  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
3402  if (p_packet->p_all_custom_sei == NULL)
3403  {
3404  /* max size */
3406  if (p_packet->p_all_custom_sei == NULL)
3407  {
3408  ni_log(NI_LOG_ERROR, "failed to allocate all custom sei buffer.\n");
3410  }
3411  memset(p_packet->p_all_custom_sei, 0, sizeof(ni_logan_custom_sei_t));
3412  }
3413 
3414  sei_index = p_packet->p_all_custom_sei->custom_sei_cnt;
3415  if (sei_index >= NI_LOGAN_MAX_CUSTOM_SEI_CNT)
3416  {
3417  ni_log(NI_LOG_INFO, "number of custom sei in current frame is out of limit(%d).\n",
3419  return NI_LOGAN_RETCODE_FAILURE;
3420  }
3421  sei_data = p_packet->p_all_custom_sei->ni_custom_sei[sei_index].custom_sei_data;
3422 
3430  while ((index < size) && (data[index] == 255))
3431  {
3432  sei_size += data[index++];
3433  }
3434 
3435  if (index >= size)
3436  {
3437  ni_log(NI_LOG_INFO, "custom sei corrupted: length truncated.\n");
3438  return NI_LOGAN_RETCODE_FAILURE;
3439  }
3440  sei_size += data[index++];
3441 
3442  /* check sei size*/
3443  if (sei_size > NI_LOGAN_MAX_CUSTOM_SEI_SZ)
3444  {
3445  ni_log(NI_LOG_INFO, "custom sei corrupted: size(%d) out of limit(%d).\n",
3446  sei_size, NI_LOGAN_MAX_CUSTOM_SEI_SZ);
3447  return NI_LOGAN_RETCODE_FAILURE;
3448  }
3449 
3450  udata = &data[index];
3451 
3452  /* extract SEI payload data
3453  * SEI payload data in NAL is EBSP(Encapsulated Byte Sequence Payload),
3454  * need change EBSP to RBSP(Raw Byte Sequence Payload) for exact size
3455  */
3456  for (i = 0; (i < (size - index)) && len < sei_size; i++)
3457  {
3458  /* if the latest 3-byte data pattern matchs '00 00 03' which means udata[i] is an escaping byte,
3459  * discard udata[i]. */
3460  if (i >= 2 && udata[i - 2] == 0 && udata[i - 1] == 0 && udata[i] == 3)
3461  {
3462  continue;
3463  }
3464  sei_data[len++] = udata[i];
3465  }
3466 
3467  if (len != sei_size)
3468  {
3469  ni_log(NI_LOG_INFO, "custom sei corrupted: data truncated, "
3470  "requied size:%d, actual size:%d.\n", sei_size, len);
3471  return NI_LOGAN_RETCODE_FAILURE;
3472  }
3473 
3474  p_packet->p_all_custom_sei->ni_custom_sei[sei_index].custom_sei_size = sei_size;
3475  p_packet->p_all_custom_sei->ni_custom_sei[sei_index].custom_sei_type = sei_type;
3476  if (got_slice)
3477  {
3479  }
3480  else
3481  {
3483  }
3484  p_packet->p_all_custom_sei->custom_sei_cnt ++;
3485  ni_log(NI_LOG_TRACE, "%s() exit, custom_sei_cnt=%d, size=%d type=%d\n",
3486  __FUNCTION__, p_packet->p_all_custom_sei->custom_sei_cnt, sei_size, sei_type);
3487 
3488  return 0;
3489 }
3490 
3491 /*!******************************************************************************
3492  * \brief detect custom SEI payload data in Packet data,
3493  * custom SEI has two meanings:
3494  * a. the SEI type is not in the standard protocol, which is added by customes,
3495  * for example SEI type 100, note that custom SEI is not user data unregistered SEI.
3496  * b. the SEI NAL location does not conform to protocol. It's after VCL NALs.
3497  * So there are cases to handle here:
3498  * case a: enable custom_sei, detext custom SEIs before VCL.
3499  * case b: enable custom_sei and enable_check_packet, detect custom SEIs before VCL,
3500  * and all SEIs after VCL.
3501  * all of these SEIs are passthroughed in the same places after encoding.
3502  *
3503  * \param uint8_t *data - packet data
3504  * \param int size - pkt data size
3505  * \param ni_logan_session_context_t *p_api_ctx - Netint session context
3506  * \param ni_logan_decoder_params_t *api_param - Netint xcoder params
3507  * \param ni_logan_packet_t *p_packet - netint internal packet
3508  *
3509  * \return - 0 on success or not detect correct custom sei, non-0 on failure
3510  *******************************************************************************/
3511 int ni_logan_detect_custom_sei(const uint8_t *data,
3512  int size,
3513  ni_logan_session_context_t *p_api_ctx,
3514  ni_logan_decoder_params_t *p_api_param,
3515  ni_logan_packet_t *p_packet)
3516 {
3517  int ret = 0;
3518  const uint8_t *ptr = NULL;
3519  const uint8_t *end = NULL;
3520  uint8_t custom_sei_type = NI_LOGAN_INVALID_SEI_TYPE;
3521  uint8_t chk_pkt = 0;
3522  uint8_t nalu_type;
3523  uint8_t sei_type;
3524  uint32_t stc = -1;
3525  int got_slice = 0;
3526 
3527  if (!data || !p_api_ctx || !p_api_param)
3528  {
3529  return ret;
3530  }
3531 
3532  if (!p_api_ctx || !p_api_param)
3533  {
3534  ni_log(NI_LOG_ERROR, "%s(): invalid parameter %p, %p\n",
3535  __FUNCTION__, p_api_ctx, p_api_param);
3537  }
3538 
3539  custom_sei_type = p_api_param->dec_input_params.custom_sei_passthru;
3540  chk_pkt = p_api_param->dec_input_params.check_packet;
3541  ni_log(NI_LOG_TRACE, "%s(): custom SEI type %d\n", __FUNCTION__, custom_sei_type);
3542 
3543  // search custom sei in the lone buffer
3544  // if there is a custom sei in the lone sei, the firmware can't recoginze it.
3545  // passthrough the custom sei here.
3546  if (p_api_ctx->lone_sei_size)
3547  {
3548  ni_log(NI_LOG_TRACE, "%s(): detect in lone SEI, size=%d\n",
3549  __FUNCTION__, p_api_ctx->lone_sei_size);
3550  ptr = p_api_ctx->buf_lone_sei;
3551  end = p_api_ctx->buf_lone_sei + p_api_ctx->lone_sei_size;
3552  stc = -1;
3553  ptr = ni_logan_find_start_code(ptr, end, &stc);
3554  while (ptr < end)
3555  {
3556  if (p_api_ctx->codec_format == NI_LOGAN_CODEC_FORMAT_H264)
3557  { // if h264
3558  nalu_type = stc & 0x1F;
3559  sei_type = *ptr;
3560  if ((nalu_type == NI_LOGAN_H264_NAL_SEI) && (sei_type == custom_sei_type))
3561  {
3562  /* extract SEI payload, store in ni_logan_packet and pass to libxcoder. */
3563  ret = ni_logan_extract_custom_sei(data, size, ptr + 1 - data, p_packet, sei_type, got_slice);
3565  {
3566  return ret;
3567  }
3568  else if (ret != 0)
3569  {
3570  if ((p_packet->p_all_custom_sei) && (p_packet->p_all_custom_sei->custom_sei_cnt == 0))
3571  {
3572  free(p_packet->p_all_custom_sei);
3573  p_packet->p_all_custom_sei = NULL;
3574  }
3575  return 0;
3576  }
3577  }
3578  }
3579  else if (p_api_ctx->codec_format == NI_LOGAN_CODEC_FORMAT_H265)
3580  { //if hevc
3581  nalu_type = (stc >> 1) & 0x3F;
3582  sei_type = *(ptr + 1);
3583  // check nalu_type, check nuh_temporal_id_plus1 = 1, check sei_pype
3584  if ((nalu_type == NI_LOGAN_HEVC_NAL_SEI_PREFIX) && (*ptr == 1) && (sei_type == custom_sei_type))
3585  {
3586  /* extract SEI payload, store in ni_logan_packet and pass to libxcoder. */
3587  ret = ni_logan_extract_custom_sei(data, size, ptr + 2 - data, p_packet, sei_type, got_slice);
3589  {
3590  return ret;
3591  }
3592  else if (ret != 0)
3593  {
3594  if ((p_packet->p_all_custom_sei) && (p_packet->p_all_custom_sei->custom_sei_cnt == 0))
3595  {
3596  free(p_packet->p_all_custom_sei);
3597  p_packet->p_all_custom_sei = NULL;
3598  }
3599  return 0;
3600  }
3601  }
3602  }
3603  else
3604  {
3605  ni_log(NI_LOG_ERROR, "%s wrong codec format %d !\n", __FUNCTION__, p_api_ctx->codec_format);
3606  break;
3607  }
3608 
3609  stc = -1;
3610  ptr = ni_logan_find_start_code(ptr, end, &stc);
3611  }
3612  }
3613 
3614  // search custom sei in the packet
3615  ni_log(NI_LOG_TRACE, "%s(): detect in packet, size=%d\n", __FUNCTION__, size);
3616  ptr = data;
3617  end = data + size;
3618  stc = -1;
3619  ptr = ni_logan_find_start_code(ptr, end, &stc);
3620  while (ptr < end)
3621  {
3622  if (p_api_ctx->codec_format == NI_LOGAN_CODEC_FORMAT_H264)
3623  { // if h264
3624  nalu_type = stc & 0x1F;
3625  sei_type = *ptr;
3626  if ((nalu_type == NI_LOGAN_H264_NAL_SEI) &&
3627  ((sei_type == custom_sei_type) || (got_slice && chk_pkt)))
3628  {
3629  /* extract SEI payload, store in ni_logan_packet and pass to libxcoder. */
3630  ret = ni_logan_extract_custom_sei(data, size, ptr + 1 - data, p_packet, sei_type, got_slice);
3632  {
3633  return ret;
3634  }
3635  else if (ret != 0)
3636  {
3637  return 0;
3638  }
3639  }
3640  else if ((nalu_type >= NI_LOGAN_H264_NAL_SLICE) && (nalu_type <= NI_LOGAN_H264_NAL_IDR_SLICE)) //VCL
3641  {
3642  ret = 0;
3643  got_slice = 1;
3644  /* if disable check packet and VCL is found, then stop searching for SEI after VCL. */
3645  if (!chk_pkt)
3646  {
3647  break;
3648  }
3649  }
3650  }
3651  else if (p_api_ctx->codec_format == NI_LOGAN_CODEC_FORMAT_H265)
3652  { //if hevc
3653  nalu_type = (stc >> 1) & 0x3F;
3654  sei_type = *(ptr + 1);
3655  // check nalu_type, check nuh_temporal_id_plus1 = 1, check sei_pype
3656  // if enable chk_pkt, continue search SEI after VCL
3657  if ((nalu_type == NI_LOGAN_HEVC_NAL_SEI_PREFIX) && (*ptr == 1) &&
3658  ((sei_type == custom_sei_type) || (got_slice && chk_pkt)))
3659  {
3660  /* extract SEI payload, store in ni_logan_packet and pass to libxcoder. */
3661  ret = ni_logan_extract_custom_sei(data, size, ptr + 2 - data, p_packet, sei_type, got_slice);
3663  {
3664  return ret;
3665  }
3666  else if (ret != 0)
3667  {
3668  return 0;
3669  }
3670  }
3671  else if (nalu_type >= NI_LOGAN_HEVC_NAL_TRAIL_N && nalu_type <= NI_LOGAN_HEVC_NAL_RSV_VCL31) //found VCL
3672  {
3673  ret = 0;
3674  got_slice = 1;
3675  /* if disable check packet and VCL is found, then stop searching for SEI after VCL. */
3676  if (!chk_pkt)
3677  {
3678  break;
3679  }
3680  }
3681  }
3682  else
3683  {
3684  ni_log(NI_LOG_ERROR, "%s wrong codec format %d !\n", __FUNCTION__, p_api_ctx->codec_format);
3685  break;
3686  }
3687 
3688  stc = -1;
3689  ptr = ni_logan_find_start_code(ptr, end, &stc);
3690  }
3691 
3692  if (p_packet->p_all_custom_sei)
3693  {
3694  ni_log(NI_LOG_TRACE, "%s(): total custom SEI number %d\n", __FUNCTION__,
3695  p_packet->p_all_custom_sei->custom_sei_cnt);
3696  }
3697  else
3698  {
3699  ni_log(NI_LOG_TRACE, "%s(): no custom SEI detected\n", __FUNCTION__);
3700  }
3701 
3702  return ret;
3703 }
3704 
3705 /*!*****************************************************************************
3706  * \brief Fill reconfig vfr
3707  *
3708  * \param[in/out] p_session_ctx session context, some parameters may be updated.
3709  * \param[in] p_param encoder parameters.
3710  * \param[in/out] ni_frame aux_data may be updated
3711  * \param[in] pts frame pts
3712  * \param[in] timebase timebase
3713  *
3714  * \return
3715  ******************************************************************************/
3717  ni_logan_encoder_params_t *p_encoder_params,
3718  ni_logan_frame_t *ni_frame,
3719  int64_t pts,
3720  uint32_t timebase)
3721 {
3722  ni_aux_data_t *aux_data = NULL;
3723  int32_t cur_fps = 0, bit_rate = 0;
3724 
3725  if (pts > p_session_ctx->prev_pts)
3726  {
3727  p_session_ctx->passed_time_in_timebase_unit += pts - p_session_ctx->prev_pts;
3728  p_session_ctx->count_frame_num_in_sec++;
3729  //change the bitrate for VFR
3730  //1. Only when the fps change, setting the new bitrate
3731  //2. The interval between two bitrate change settings shall be greater than 1 seconds(hardware limiation)
3732  // or at the start the transcoding, we should detect the init frame rate(30) and the actual framerate
3733  if (p_session_ctx->passed_time_in_timebase_unit >= timebase)
3734  {
3735  cur_fps = p_session_ctx->count_frame_num_in_sec;
3736  bit_rate = (int)(p_encoder_params->enc_input_params.frame_rate * (p_session_ctx->init_bitrate / cur_fps));
3737  if ((p_session_ctx->frame_num != 0) && (bit_rate != p_session_ctx->prev_bitrate) &&
3738  ((p_session_ctx->frame_num < p_encoder_params->enc_input_params.frame_rate) ||
3739  ((uint32_t)(p_session_ctx->frame_num - p_session_ctx->last_change_framenum) >= p_encoder_params->enc_input_params.frame_rate)))
3740  {
3741  //adjust the upper and lower limits of bitrate each time
3742  bit_rate = clip3(bit_rate, p_session_ctx->prev_bitrate / 2, p_session_ctx->prev_bitrate * 3 / 2);
3743 
3745  sizeof(int32_t));
3746  if (aux_data)
3747  {
3748  memcpy(aux_data->data, &bit_rate, sizeof(int32_t));
3749  }
3750  p_session_ctx->prev_bitrate = bit_rate;
3751  p_session_ctx->last_change_framenum = p_session_ctx->frame_num;
3752  p_session_ctx->prev_fps = cur_fps;
3753  }
3754  p_session_ctx->count_frame_num_in_sec = 0;
3755  p_session_ctx->passed_time_in_timebase_unit = 0;
3756  }
3757  p_session_ctx->prev_pts = pts;
3758  }
3759  else if (pts < p_session_ctx->prev_pts)
3760  {
3761  //error handle for the case that pts jump back
3762  //this may cause a little error in the bitrate setting, This little error is acceptable.
3763  //As long as the subsequent, PTS is normal, it will be repaired quickly.
3764  p_session_ctx->prev_pts = pts;
3765  }
3766  else
3767  {
3768  //do nothing, when the pts of two adjacent frames are the same
3769  //this may cause a little error in the bitrate setting, This little error is acceptable.
3770  //As long as the subsequent, PTS is normal, it will be repaired quickly.
3771  }
3772  return;
3773 }
void ni_logan_enc_reconfig_vfr(ni_logan_session_context_t *p_session_ctx, ni_logan_encoder_params_t *p_encoder_params, ni_logan_frame_t *ni_frame, int64_t pts, uint32_t timebase)
Fill reconfig vfr.
void ni_logan_enc_init_aux_params(ni_logan_session_data_io_t *p_api_fme)
Initialize auxiliary data that should be sent together with this frame to encoder based on the auxili...
const uint8_t * ni_logan_find_start_code(const uint8_t *p, const uint8_t *end, uint32_t *state)
Find the next start code.
uint32_t ni_logan_enc_buffering_custom_sei(void *p_data, ni_logan_session_context_t *p_ctx, uint32_t index)
Buffered customer sei.
#define MAX_VPS_MAX_SUB_LAYERS
uint32_t ni_logan_enc_pic_timing_sei2(ni_logan_encoder_params_t *p_param, ni_logan_session_context_t *p_ctx, int is_i_or_idr, int is_idr, uint32_t frame_idx, int buf_len, uint8_t *p_buf)
Generate pic timing sei2.
void ni_logan_dec_retrieve_aux_data(ni_logan_frame_t *frame)
Retrieve auxiliary data (close caption, various SEI) associated with this frame that is returned by d...
#define SAMPLE_SPS_MAX_SUB_LAYERS_MINUS1
int ni_logan_detect_custom_sei(const uint8_t *data, int size, ni_logan_session_context_t *p_api_ctx, ni_logan_decoder_params_t *p_api_param, ni_logan_packet_t *p_packet)
detect custom SEI payload data in Packet data, custom SEI has two meanings: a. the SEI type is not in...
#define MAX_DURATION
int ni_logan_enc_fill_reconfig_params(ni_logan_encoder_params_t *p_param, ni_logan_session_context_t *p_ctx, ni_logan_frame_t *p_api_fme, int reconfigCount)
Fill reconfig params.
int ni_logan_enc_fill_reconfig_vui(ni_logan_encoder_params_t *p_param, ni_logan_session_context_t *p_ctx, ni_logan_frame_t *p_api_fme, int reconfigCount, ni_aux_data_t *aux_data)
Fill reconfig vui.
uint32_t ni_logan_enc_buffering_period_sei(ni_logan_encoder_params_t *p_param, ni_logan_session_context_t *p_ctx, uint32_t frame_idx, int buf_len, uint8_t *p_buf)
Buffered period sei.
gop_preset_t
@ GOP_PRESET_BSP_2
@ GOP_PRESET_BBSP_3
@ NUM_GOP_PRESET_NUM
@ GOP_PRESET_BBP_3
@ GOP_PRESET_LP_4
@ GOP_PRESET_SP_1
@ GOP_PRESET_BBBP_3
@ GOP_PRESET_CUSTOM
@ GOP_PRESET_BP_2
@ GOP_PRESET_B_1
@ GOP_PRESET_P_1
@ GOP_PRESET_BBBSP_3
@ GOP_PRESET_BBBBBBBP_8
@ GOP_PRESET_BBBBBBBSP_8
@ GOP_PRESET_RA_8
@ GOP_PRESET_LD_4
@ GOP_PRESET_LSP_4
@ GOP_PRESET_I_1
void ni_logan_enc_copy_aux_data(ni_logan_session_context_t *p_enc_ctx, ni_logan_frame_t *p_enc_frame, ni_logan_frame_t *p_dec_frame, ni_logan_codec_format_t codec_format, const uint8_t *mdcv_data, const uint8_t *cll_data, const uint8_t *cc_data, const uint8_t *udu_data, const uint8_t *hdrp_data)
Copy auxiliary data that should be sent together with this frame to encoder.
void ni_logan_set_vui(ni_logan_encoder_params_t *p_param, ni_logan_session_context_t *p_ctx, ni_color_primaries_t color_primaries, ni_color_transfer_characteristic_t color_trc, ni_color_space_t color_space, int video_full_range_flag, int sar_num, int sar_den, ni_logan_codec_format_t codec_format)
Set SPS VUI part of encoded stream header.
int ni_logan_should_send_sei_with_frame(ni_logan_session_context_t *p_enc_ctx, ni_logan_pic_type_t pic_type, ni_logan_encoder_params_t *p_param)
Whether SEI (HDR) should be sent together with this frame to encoder.
void ni_logan_reset_vui(ni_logan_encoder_params_t *p_param, ni_aux_data_t *aux_data, ni_logan_codec_format_t codec_format)
Reset vui info from decoder.
void ni_logan_enc_prep_aux_data(ni_logan_session_context_t *p_enc_ctx, ni_logan_frame_t *p_enc_frame, ni_logan_frame_t *p_dec_frame, ni_logan_codec_format_t codec_format, int should_send_sei_with_frame, uint8_t *mdcv_data, uint8_t *cll_data, uint8_t *cc_data, uint8_t *udu_data, uint8_t *hdrp_data)
Prepare auxiliary data that should be sent together with this frame to encoder based on the auxiliary...
slice_type_t
@ SLICE_TYPE_I
@ SLICE_TYPE_P
@ SLICE_TYPE_MP
@ SLICE_TYPE_B
#define MAX_CPB_COUNT
#define CPB_SHIFT
#define BR_SHIFT
NETINT audio/video related utility functions.
@ NI_COL_TRC_UNSPECIFIED
enum _ni_color_primaries ni_color_primaries_t
@ NI_COL_SPC_UNSPECIFIED
@ NI_COL_PRI_UNSPECIFIED
@ NI_LOGAN_HEVC_NAL_TRAIL_N
@ NI_LOGAN_HEVC_NAL_RSV_VCL31
@ NI_LOGAN_HEVC_NAL_SEI_PREFIX
enum _ni_color_transfer_characteristic ni_color_transfer_characteristic_t
enum _ni_hdr_plus_overlap_process_option ni_hdr_plus_overlap_process_option_t
enum _ni_color_space ni_color_space_t
@ NI_LOGAN_H264_NAL_SLICE
@ NI_LOGAN_H264_NAL_SEI
@ NI_LOGAN_H264_NAL_IDR_SLICE
void ni_bs_writer_put_ue(ni_bitstream_writer_t *stream, uint32_t data)
write unsigned Exp-Golomb bit string to bitstream, 2^32-2 at most.
void ni_bitstream_writer_init(ni_bitstream_writer_t *stream)
init a bitstream writer
void ni_bs_writer_copy(uint8_t *dst, const ni_bitstream_writer_t *stream)
copy bitstream data to dst Note: caller must ensure sufficient space in dst
void ni_bs_writer_align_zero(ni_bitstream_writer_t *stream)
align the bitstream with zero
void ni_bitstream_reader_init(ni_bitstream_reader_t *br, const uint8_t *data, int bit_size)
init a bitstream reader Note: bitstream_reader takes reading ownership of the data
uint32_t ni_bs_reader_get_bits(ni_bitstream_reader_t *br, int n)
read bits (up to 32) from the bitstream reader, after reader init
void ni_bs_writer_clear(ni_bitstream_writer_t *stream)
clear and reset bitstream
uint64_t ni_bs_writer_tell(const ni_bitstream_writer_t *const stream)
return the number of bits written to bitstream so far
void ni_bs_writer_put(ni_bitstream_writer_t *stream, uint32_t data, uint8_t bits)
write a specified number (<= 32) of bits to bitstream, buffer individual bits until a full byte is ma...
void ni_bs_reader_skip_bits(ni_bitstream_reader_t *br, int n)
skip a number of bits ahead in the bitstream reader
Utility functions to operate on bits in a bitstream.
Common NETINT definitions used by all modules.
ni_logan_retcode_t
@ NI_LOGAN_RETCODE_INVALID_PARAM
@ NI_LOGAN_RETCODE_ERROR_MEM_ALOC
@ NI_LOGAN_RETCODE_SUCCESS
@ NI_LOGAN_RETCODE_FAILURE
#define NI_LOGAN_INVALID_SEI_TYPE
#define NI_LOGAN_APP_ENC_FRAME_META_DATA_SIZE
#define NI_LOGAN_MAX_CUSTOM_SEI_CNT
#define NI_LOGAN_MAX_CUSTOM_SEI_SZ
#define NI_LOGAN_FIFO_SZ
int ni_logan_get_num_reorder_of_gop_structure(ni_logan_encoder_params_t *p_params)
Get GOP's max number of reorder frames.
ni_aux_data_t * ni_logan_frame_get_aux_data(const ni_logan_frame_t *frame, ni_aux_data_type_t type)
Retrieve from the frame auxiliary data of a given type if exists.
ni_aux_data_t * ni_logan_frame_new_aux_data_from_raw_data(ni_logan_frame_t *frame, ni_aux_data_type_t type, const uint8_t *raw_data, int data_size)
Add a new auxiliary data to a frame and copy in the raw data.
int ni_logan_get_num_ref_frame_of_gop_structure(ni_logan_encoder_params_t *p_params)
Get GOP's number of reference frames.
ni_aux_data_t * ni_logan_frame_new_aux_data(ni_logan_frame_t *frame, ni_aux_data_type_t type, int data_size)
Add a new auxiliary data to a frame.
struct _ni_logan_encoder_change_params_t ni_logan_encoder_change_params_t
This is a data structure for encoding parameters that have changed.
@ NI_FRAME_AUX_DATA_MASTERING_DISPLAY_METADATA
@ NI_FRAME_AUX_DATA_BITRATE
@ NI_FRAME_AUX_DATA_VUI_INFO
@ NI_FRAME_AUX_DATA_UDU_SEI
@ NI_FRAME_AUX_DATA_MIN_MAX_QP
@ NI_FRAME_AUX_DATA_HDR_PLUS
@ NI_FRAME_AUX_DATA_A53_CC
@ NI_FRAME_AUX_DATA_CONTENT_LIGHT_LEVEL
@ NI_FRAME_AUX_DATA_REGIONS_OF_INTEREST
@ NI_FRAME_AUX_DATA_LONG_TERM_REF
#define NI_CC_SEI_TRAILER_LEN
#define NI_LOGAN_MAX_VUI_SIZE
#define NI_LOGAN_QP_MID_POINT
@ LOGAN_XCODER_TEST_RECONF_BR
@ LOGAN_XCODER_TEST_RECONF_VUI_HRD
@ LOGAN_XCODER_TEST_RECONF_CRF
@ LOGAN_XCODER_TEST_RECONF_RC
@ LOGAN_XCODER_TEST_RECONF_INTRAPRD
@ LOGAN_XCODER_TEST_RECONF_RC_MIN_MAX_QP
@ LOGAN_XCODER_TEST_RECONF_OFF
@ LOGAN_XCODER_TEST_RECONF_LONG_TERM_REF
#define NI_LOGAN_INTRA_QP_RANGE
#define NI_CC_SEI_HDR_H264_LEN
@ NI_LOGAN_SET_CHANGE_PARAM_VUI_HRD_PARAM
@ NI_LOGAN_SET_CHANGE_PARAM_CRF
@ NI_LOGAN_SET_CHANGE_PARAM_RC_TARGET_RATE
@ NI_LOGAN_SET_CHANGE_PARAM_RC_MIN_MAX_QP
@ NI_LOGAN_SET_CHANGE_PARAM_INTRA_PARAM
@ NI_LOGAN_SET_CHANGE_PARAM_RC
union _ni_logan_enc_hevc_roi_custom_map ni_logan_enc_hevc_roi_custom_map_t
encoder HEVC ROI custom map (1 CTU = 64bits)
@ NI_LOGAN_CUSTOM_SEI_LOC_BEFORE_VCL
@ NI_LOGAN_CUSTOM_SEI_LOC_AFTER_VCL
#define NI_HDR10P_SEI_HDR_H264_LEN
union _ni_logan_enc_avc_roi_custom_map ni_logan_enc_avc_roi_custom_map_t
encoder AVC ROI custom map (1 MB = 8bits)
ni_logan_pic_type_t
@ LOGAN_PIC_TYPE_FORCE_IDR
#define NI_LOGAN_MAX_SEI_DATA
#define NI_HDR10P_SEI_HDR_HEVC_LEN
#define NI_LOGAN_ENC_MAX_SEI_BUF_SIZE
enum _ni_logan_codec_format ni_logan_codec_format_t
This is an enumeration for supported codec formats.
@ NI_LOGAN_CODEC_FORMAT_H265
@ NI_LOGAN_CODEC_FORMAT_H264
#define NI_CC_SEI_HDR_HEVC_LEN
#define NI_RBSP_TRAILING_BITS_LEN
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition: ni_log_logan.c:120
@ NI_LOG_DEBUG
Definition: ni_log_logan.h:66
@ NI_LOG_TRACE
Definition: ni_log_logan.h:67
@ NI_LOG_ERROR
Definition: ni_log_logan.h:64
@ NI_LOG_INFO
Definition: ni_log_logan.h:65
Definitions related to working with NI T-408 over NVME interface.
int ni_logan_insert_emulation_prevent_bytes(uint8_t *buf, int size)
Insert emulation prevention byte(s) as needed into the data buffer.
Exported utility routines definition.
uint8_t targeted_system_display_actual_peak_luminance_flag
uint8_t num_cols_targeted_system_display_actual_peak_luminance
uint8_t num_rows_mastering_display_actual_peak_luminance
uint8_t num_rows_targeted_system_display_actual_peak_luminance
uint8_t num_cols_mastering_display_actual_peak_luminance
ni_rational_t targeted_system_display_maximum_luminance
ni_rational_t mastering_display_actual_peak_luminance[25][25]
uint8_t mastering_display_actual_peak_luminance_flag
ni_hdr_plus_color_transform_params_t params[3]
ni_rational_t targeted_system_display_actual_peak_luminance[25][25]
ni_hdr_plus_percentile_t distribution_maxrgb[15]
ni_hdr_plus_overlap_process_option_t overlap_process_option
uint32_t initial_cpb_removal_delay_length_minus1
uint32_t au_cpb_removal_delay_minus1
uint32_t dpb_output_delay_length_minus1
uint32_t au_cpb_removal_delay_length_minus1
ni_logan_custom_sei_t ni_custom_sei[NI_LOGAN_MAX_CUSTOM_SEI_CNT]
payload format of HDR SEI content light level info
ni_logan_gop_params_t pic_param[NI_LOGAN_MAX_GOP_NUM]
custom sei payload passthrough
ni_logan_custom_sei_location_t custom_sei_loc
uint8_t custom_sei_data[NI_LOGAN_MAX_CUSTOM_SEI_SZ]
decoded payload format of H.264 VUI
decoded payload format of H.265 VUI
decoded payload format of HDR SEI mastering display colour volume
ni_logan_decoder_input_params_t dec_input_params
encoded payload format of HDR SEI mastering display colour volume
This is a data structure for encoding parameters that have changed.
uint8_t vuiRbsp[NI_LOGAN_MAX_VUI_SIZE]
struct _ni_logan_encoder_input_params::@3 rc
ni_logan_custom_gop_params_t custom_gop_params
ni_logan_encoder_input_params_t enc_input_params
uint8_t ui8VuiRbsp[NI_LOGAN_MAX_VUI_SIZE]
uint8_t ui8LastVuiRbsp[NI_LOGAN_MAX_VUI_SIZE]
unsigned int sei_hdr_mastering_display_color_vol_offset
unsigned int sei_hdr_content_light_level_info_offset
uint8_t preferred_characteristics_data_len
unsigned int sei_hdr_plus_len
uint32_t data_len[NI_LOGAN_MAX_NUM_DATA_POINTERS]
unsigned int sei_hdr_plus_offset
unsigned int extra_data_len
unsigned int sei_total_len
unsigned int sei_cc_offset
unsigned int sei_user_data_unreg_len
uint8_t use_cur_src_as_long_term_pic
ni_logan_codec_format_t src_codec
unsigned int sei_hdr_content_light_level_info_len
void * p_data[NI_LOGAN_MAX_NUM_DATA_POINTERS]
unsigned int sei_hdr_mastering_display_color_vol_len
unsigned int sei_user_data_unreg_offset
unsigned int sei_alt_transfer_characteristics_len
unsigned int sei_alt_transfer_characteristics_offset
ni_logan_all_custom_sei_t * p_all_custom_sei
uint8_t itu_t_t35_hdr10p_sei_hdr_hevc[NI_HDR10P_SEI_HDR_HEVC_LEN]
ni_logan_encoder_change_params_t * enc_change_params
uint8_t ui8_light_level_data[NI_LOGAN_LIGHT_LEVEL_DATA_SZ]
uint8_t ui8_mdcv_max_min_lum_data[NI_LOGAN_MDCV_LUM_DATA_SZ]
uint8_t buf_lone_sei[NI_LOGAN_MAX_SEI_DATA]
ni_logan_enc_avc_roi_custom_map_t * avc_roi_map
uint8_t sei_trailer[NI_CC_SEI_TRAILER_LEN]
uint32_t prev_fps
Params used in VFR mode Start///.
uint8_t itu_t_t35_cc_sei_hdr_hevc[NI_CC_SEI_HDR_HEVC_LEN]
uint8_t itu_t_t35_cc_sei_hdr_h264[NI_CC_SEI_HDR_H264_LEN]
ni_logan_enc_hevc_roi_custom_map_t * hevc_roi_map
uint8_t itu_t_t35_hdr10p_sei_hdr_h264[NI_HDR10P_SEI_HDR_H264_LEN]
ni_region_of_interest_t * av_rois
ni_logan_all_custom_sei_t * pkt_custom_sei[NI_LOGAN_FIFO_SZ]
union _ni_logan_session_data_io::@4 data
ni_rational_t display_primaries[3][2]
encoder AVC ROI custom map (1 MB = 8bits)
struct _ni_logan_enc_avc_roi_custom_map::@2 field
encoder HEVC ROI custom map (1 CTU = 64bits)
struct _ni_logan_enc_hevc_roi_custom_map::@1 field