libxcoder 5.9.0
Loading...
Searching...
No Matches
ni_av_codec.c
Go to the documentation of this file.
1/*******************************************************************************
2 *
3 * Copyright (C) 2022 NETINT Technologies
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18 * SOFTWARE.
19 *
20 ******************************************************************************/
21
22/*!*****************************************************************************
23 * \file ni_av_codec.c
24 *
25 * \brief Audio/video related utility definitions
26 ******************************************************************************/
27
28#ifdef _WIN32
29#include <winsock2.h>
30#else
31#include <arpa/inet.h>
32#endif
33#include <limits.h>
34#include <stddef.h>
35#include <string.h>
36#include <stdio.h>
37#include <stdint.h>
38#include <stdlib.h>
39#include <math.h>
40#include <inttypes.h>
41#include "ni_defs.h"
42#include "ni_util.h"
43#include "ni_log.h"
44#include "ni_bitstream.h"
45#include "ni_av_codec.h"
46#include "ni_device_api.h"
47#include "ni_device_api_priv.h"
48
56
81
82NI_UNUSED static const int32_t GOP_SIZE[NUM_GOP_PRESET_NUM] = {0, 1, 1, 1, 2, 4, 4,
83 4, 8, 1, 2, 4, 4};
84
85static const int32_t LT_GOP_PRESET_I_1[6] = {SLICE_TYPE_I, 1, 0, 0, 0, 0};
86static const int32_t LT_GOP_PRESET_P_1[6] = {SLICE_TYPE_MP, 1, 1, 0, 0, -1};
87static const int32_t LT_GOP_PRESET_B_1[6] = {SLICE_TYPE_B, 1, 1, 0, 0, -1};
88// gop_size = 2
89static const int32_t LT_GOP_PRESET_BP_2[12] = {
90 SLICE_TYPE_MP, 2, 1, 0, 0, -2, SLICE_TYPE_B, 1, 3, 0, 0, 2,
91};
92// gop_size = 4
93static const int32_t LT_GOP_PRESET_BBBP_4[24] = {
94 SLICE_TYPE_MP, 4, 1, 0, 0, -4, SLICE_TYPE_B, 2, 3, 0, 0, 4,
95 SLICE_TYPE_B, 1, 5, 0, 0, 2, SLICE_TYPE_B, 3, 5, 0, 2, 4,
96};
97
98static const int32_t LT_GOP_PRESET_LP_4[24] = {
99 SLICE_TYPE_MP, 1, 5, 0, 0, -4, SLICE_TYPE_MP, 2, 3, 0, 1, 0,
100 SLICE_TYPE_MP, 3, 5, 0, 2, 0, SLICE_TYPE_MP, 4, 1, 0, 3, 0,
101};
102static const int32_t LT_GOP_PRESET_LD_4[24] = {
103 SLICE_TYPE_B, 1, 5, 0, 0, -4, SLICE_TYPE_B, 2, 3, 0, 1, 0,
104 SLICE_TYPE_B, 3, 5, 0, 2, 0, SLICE_TYPE_B, 4, 1, 0, 3, 0,
105};
106
107// gop_size = 8
108static const int32_t LT_GOP_PRESET_RA_8[48] = {
109 SLICE_TYPE_B, 8, 1, 0, 0, -8, SLICE_TYPE_B, 4, 3, 0, 0, 8,
110 SLICE_TYPE_B, 2, 5, 0, 0, 4, SLICE_TYPE_B, 1, 8, 0, 0, 2,
111 SLICE_TYPE_B, 3, 8, 0, 2, 4, SLICE_TYPE_B, 6, 5, 0, 4, 8,
112 SLICE_TYPE_B, 5, 8, 0, 4, 6, SLICE_TYPE_B, 7, 8, 0, 6, 8,
113};
114// single-ref-P
115static const int32_t LT_GOP_PRESET_SP_1[6] = {SLICE_TYPE_P, 1, 1, 0, 0, -1};
116
117static const int32_t LT_GOP_PRESET_BSP_2[12] = {
118 SLICE_TYPE_P, 2, 1, 0, 0, -2, SLICE_TYPE_B, 1, 3, 0, 0, 2,
119};
120static const int32_t LT_GOP_PRESET_BBBSP_4[24] = {
121 SLICE_TYPE_P, 4, 1, 0, 0, -4, SLICE_TYPE_B, 2, 3, 0, 0, 4,
122 SLICE_TYPE_B, 1, 5, 0, 0, 2, SLICE_TYPE_B, 3, 5, 0, 2, 4,
123};
124static const int32_t LT_GOP_PRESET_LSP_4[24] = {
125 SLICE_TYPE_P, 1, 5, 0, 0, -4, SLICE_TYPE_P, 2, 3, 0, 1, 0,
126 SLICE_TYPE_P, 3, 5, 0, 2, 0, SLICE_TYPE_P, 4, 1, 0, 3, 0,
127};
128
129static const int32_t LT_GOP_PRESET_BBP_3[18] = {
130 SLICE_TYPE_MP, 3, 1, 0, 0, -3, SLICE_TYPE_B, 1, 3, 0, 0, 3,
131 SLICE_TYPE_B, 2, 6, 0, 1, 3,
132};
133
134static const int32_t LT_GOP_PRESET_BBSP_3[18] = {
135 SLICE_TYPE_P, 3, 1, 0, 0, 0, SLICE_TYPE_B, 1, 3, 0, 0, 3,
136 SLICE_TYPE_B, 2, 6, 0, 1, 3,
137};
138
139static const int32_t LT_GOP_PRESET_BBBBBBBP_8[48] = {
140 SLICE_TYPE_MP, 8, 1, 0, 0, -8, SLICE_TYPE_B, 4, 3, 0, 0, 8,
141 SLICE_TYPE_B, 2, 5, 0, 0, 4, SLICE_TYPE_B, 1, 8, 0, 0, 2,
142 SLICE_TYPE_B, 3, 8, 0, 2, 4, SLICE_TYPE_B, 6, 5, 0, 4, 8,
143 SLICE_TYPE_B, 5, 8, 0, 4, 6, SLICE_TYPE_B, 7, 8, 0, 6, 8,
144};
145
146static const int32_t LT_GOP_PRESET_BBBBBBBSP_8[48] = {
147 SLICE_TYPE_P, 8, 1, 0, 0, 0, SLICE_TYPE_B, 4, 3, 0, 0, 8,
148 SLICE_TYPE_B, 2, 5, 0, 0, 4, SLICE_TYPE_B, 1, 8, 0, 0, 2,
149 SLICE_TYPE_B, 3, 8, 0, 2, 4, SLICE_TYPE_B, 6, 5, 0, 4, 8,
150 SLICE_TYPE_B, 5, 8, 0, 4, 6, SLICE_TYPE_B, 7, 8, 0, 6, 8,
151};
152
153NI_UNUSED static const int32_t *GOP_PRESET[NUM_GOP_PRESET_NUM] = {
154 NULL,
155 LT_GOP_PRESET_I_1,
156 LT_GOP_PRESET_P_1,
157 LT_GOP_PRESET_B_1,
158 LT_GOP_PRESET_BP_2,
159 LT_GOP_PRESET_BBBP_4,
160 LT_GOP_PRESET_LP_4,
161 LT_GOP_PRESET_LD_4,
162 LT_GOP_PRESET_RA_8,
163
164 LT_GOP_PRESET_SP_1,
165 LT_GOP_PRESET_BSP_2,
166 LT_GOP_PRESET_BBBSP_4,
167 LT_GOP_PRESET_LSP_4,
168
169 LT_GOP_PRESET_BBP_3,
170 LT_GOP_PRESET_BBSP_3,
171 LT_GOP_PRESET_BBBBBBBP_8,
172 LT_GOP_PRESET_BBBBBBBSP_8,
173};
174
175#define BR_SHIFT 6
176#define CPB_SHIFT 4
177
178#define SAMPLE_SPS_MAX_SUB_LAYERS_MINUS1 0
179#define MAX_VPS_MAX_SUB_LAYERS 16
180#define MAX_CPB_COUNT 16
181#define MAX_DURATION 0.5
182
183/*!*****************************************************************************
184 * \brief Whether SEI (HDR) should be sent together with this frame to encoder
185 *
186 * \param[in] p_enc_ctx encoder session context
187 * \param[in] pic_type frame type
188 * \param[in] p_param encoder parameters
189 *
190 * \return 1 if yes, 0 otherwise
191 ******************************************************************************/
193 ni_pic_type_t pic_type,
194 ni_xcoder_params_t *p_param)
195{
196 // repeatHeaders = 0. send on first frame only (IDR)
197 // repeatHeaders = 1. send on every I-frame including I-frames generated
198 // on the intraPeriod interval as well as I-frames that are forced.
199 if (0 == p_enc_ctx->frame_num || PIC_TYPE_IDR == pic_type ||
201 p_param->cfg_enc_params.intra_period &&
202 0 ==
203 ((p_enc_ctx->frame_num + p_enc_ctx->force_idr_intra_offset) %
204 p_param->cfg_enc_params.intra_period)))
205 {
206 if (PIC_TYPE_IDR == pic_type &&
208 p_param->cfg_enc_params.intra_period &&
209 0 != (p_enc_ctx->frame_num % p_param->cfg_enc_params.intra_period))
210 {
211 p_enc_ctx->force_idr_intra_offset =
213 (p_enc_ctx->frame_num % p_param->cfg_enc_params.intra_period);
214 }
215 ni_log2(p_enc_ctx, NI_LOG_TRACE, "should send sei? %" PRIu64 " %d %d %d %u\n",
216 p_enc_ctx->frame_num, pic_type,
219 p_enc_ctx->force_idr_intra_offset);
220 return 1;
221 }
222 return 0;
223}
224
225// create a ni_rational_t
226NI_UNUSED static ni_rational_t ni_make_rational(int num, int den)
227{
228 ni_rational_t r = {num, den};
229 return r;
230}
231
232/*!*****************************************************************************
233 * \brief Retrieve auxiliary data (close caption, various SEI) associated with
234 * this frame that is returned by decoder, convert them to appropriate
235 * format and save them in the frame's auxiliary data storage for
236 * future use by encoding. Usually they would be sent together with
237 * this frame to encoder at encoding.
238 *
239 * \param[in/out] frame that is returned by decoder
240 *
241 * \return NONE
242 ******************************************************************************/
244{
245 uint8_t *sei_buf = NULL;
246 ni_aux_data_t *aux_data = NULL;
247 int start_offset = 0;
248 if (frame->data_len[3] != 0)
249 {
250 //HW frame
251 start_offset = 3;
252 }
253 // User Data Unregistered SEI if available
255 {
256 sei_buf = (uint8_t *)frame->p_data[start_offset] +
259 frame, NI_FRAME_AUX_DATA_UDU_SEI, sei_buf,
260 (int)frame->sei_user_data_unreg_len))
261 {
262 ni_log(NI_LOG_ERROR, "ni_dec_retrieve_aux_data error retrieve User data "
263 "unregisted SEI!\n");
264 }
265 }
266
267 // close caption data if available
268 if (frame->sei_cc_len && frame->sei_cc_offset)
269 {
270 sei_buf = (uint8_t *)frame->p_data[start_offset] + frame->sei_cc_offset;
272 frame, NI_FRAME_AUX_DATA_A53_CC, sei_buf,
273 (int)frame->sei_cc_len))
274 {
275 ni_log(NI_LOG_ERROR, "ni_dec_retrieve_aux_data error retrieve close "
276 "caption SEI!\n");
277 }
278 }
279
280 // hdr10 sei data if available
281
282 // mastering display metadata
285 {
286 aux_data = ni_frame_new_aux_data(
289
290 if (!aux_data)
291 {
292 ni_log(NI_LOG_ERROR, "ni_dec_retrieve_aux_data error retrieve HDR10 "
293 "mastering display color SEI!\n");
294 } else
295 {
298
301 ((uint8_t *)frame->p_data[start_offset] +
303
304 int is_av1 = (frame->src_codec == NI_CODEC_FORMAT_AV1);
305
306 // Map destination primary index (R,G,B) to source index.
307 // AV1 stores native R,G,B -> {0,1,2}
308 // H.264/H.265 store G,B,R -> R=src[2], G=src[0], B=src[1]
309 static const int src_idx_av1[3] = {0, 1, 2};
310 static const int src_idx_hevc[3] = {2, 0, 1};
311 const int *src_idx = is_av1 ? src_idx_av1 : src_idx_hevc;
312
313 int chroma_den = is_av1 ? AV1_MASTERING_DISP_CHROMA_DEN
315 int luma_min_den = is_av1 ? AV1_MASTERING_DISP_LUMA_MIN_DEN
317 int luma_max_den = is_av1 ? AV1_MASTERING_DISP_LUMA_MAX_DEN
319
320 for (int dst = 0; dst < 3; dst++)
321 {
322 int s = src_idx[dst];
323 mdm->display_primaries[dst][0].num = ntohs(pColourVolume->display_primaries[s][0]);
324 mdm->display_primaries[dst][0].den = chroma_den;
325 mdm->display_primaries[dst][1].num = ntohs(pColourVolume->display_primaries[s][1]);
326 mdm->display_primaries[dst][1].den = chroma_den;
327 }
328
329 mdm->white_point[0].num = ntohs(pColourVolume->white_point_x);
330 mdm->white_point[0].den = chroma_den;
331 mdm->white_point[1].num = ntohs(pColourVolume->white_point_y);
332 mdm->white_point[1].den = chroma_den;
333
334 mdm->min_luminance.num = (int)ntohl(pColourVolume->min_display_mastering_luminance);
335 mdm->min_luminance.den = luma_min_den;
336 mdm->max_luminance.num = (int)ntohl(pColourVolume->max_display_mastering_luminance);
337 mdm->max_luminance.den = luma_max_den;
338
339 mdm->has_luminance = mdm->has_primaries = 1;
340 }
341 }
342
343 // hdr10 content light level
346 {
347 aux_data =
350
351 if (!aux_data)
352 {
353 ni_log(NI_LOG_ERROR, "ni_dec_retrieve_aux_data error retrieve HDR10 "
354 "content light level SEI !\n");
355 } else
356 {
358 (ni_content_light_level_t *)aux_data->data;
361 *)((uint8_t *)frame->p_data[start_offset] +
363
364 clm->max_cll = ntohs(pLightLevel->max_content_light_level);
365 clm->max_fall = ntohs(pLightLevel->max_pic_average_light_level);
366 }
367 }
368
369 // hdr10+ sei data if available
370 if (frame->sei_hdr_plus_len && frame->sei_hdr_plus_offset)
371 {
373 sizeof(ni_dynamic_hdr_plus_t));
374
375 if (!aux_data)
376 {
377 ni_log(NI_LOG_ERROR, "ni_dec_retrieve_aux_data error retrieve HDR10+ SEI "
378 "!\n");
379 } else
380 {
381 int w, i, j, i_limit, j_limit;
383 (ni_dynamic_hdr_plus_t *)aux_data->data;
385
386 sei_buf = (uint8_t *)frame->p_data[start_offset] +
387 frame->sei_hdr_plus_offset;
388 ni_bitstream_reader_init(&br, sei_buf,
389 8 * (int)frame->sei_hdr_plus_len);
390 hdrp->itu_t_t35_country_code = 0xB5;
391 // first 6 bytes of t35 SEI data header already matched HDR10+, and:
392 ni_bs_reader_skip_bits(&br, 6 * 8);
393 // application_version u(8)
395 ni_log(NI_LOG_DEBUG, "hdr10+ application_version %u\n", hdrp->application_version);
396
397
398 // Num_windows u(2)
399 hdrp->num_windows = ni_bs_reader_get_bits(&br, 2);
400 ni_log(NI_LOG_DEBUG, "hdr10+ num_windows %u\n", hdrp->num_windows);
401 if (!(1 == hdrp->num_windows || 2 == hdrp->num_windows ||
402 3 == hdrp->num_windows))
403 {
404 // wrong format and skip this HDR10+ SEI
405 } else
406 {
407 // the following block will be skipped for hdrp->num_windows ==
408 // 1
409 for (w = 1; w < hdrp->num_windows; w++)
410 {
412 ni_make_q((int)ni_bs_reader_get_bits(&br, 16), 1);
414 ni_make_q((int)ni_bs_reader_get_bits(&br, 16), 1);
416 ni_make_q((int)ni_bs_reader_get_bits(&br, 16), 1);
418 ni_make_q((int)ni_bs_reader_get_bits(&br, 16), 1);
419 hdrp->params[w - 1].center_of_ellipse_x =
420 ni_bs_reader_get_bits(&br, 16);
421 hdrp->params[w - 1].center_of_ellipse_y =
422 ni_bs_reader_get_bits(&br, 16);
423 hdrp->params[w - 1].rotation_angle =
424 ni_bs_reader_get_bits(&br, 8);
426 ni_bs_reader_get_bits(&br, 16);
428 ni_bs_reader_get_bits(&br, 16);
430 ni_bs_reader_get_bits(&br, 16);
431 hdrp->params[w - 1].overlap_process_option =
433 ni_bs_reader_get_bits(&br, 1);
434 }
435
436 // values are scaled down according to standard spec
438 (int)ni_bs_reader_get_bits(&br, 27);
440
442 ni_bs_reader_get_bits(&br, 1);
443
445 "hdr10+ targeted_system_display_maximum_luminance "
446 "%d\n",
449 "hdr10+ targeted_system_display_actual_peak_lumi"
450 "nance_flag %u\n",
452
454 {
455 i_limit =
457 ni_bs_reader_get_bits(&br, 5);
458
459 j_limit =
461 ni_bs_reader_get_bits(&br, 5);
462
464 "hdr10+ num_rows_targeted_system_display_actual"
465 "_peak_luminance x "
466 "num_cols_targeted_system_display_actual_"
467 "peak_luminance %d x %d\n",
468 i_limit, j_limit);
469
470 i_limit = i_limit > 25 ? 25 : i_limit;
471 j_limit = j_limit > 25 ? 25 : j_limit;
472 for (i = 0; i < i_limit; i++)
473 for (j = 0; j < j_limit; j++)
474 {
476 [i][j]
477 .num = (int)ni_bs_reader_get_bits(&br, 4);
479 [i][j]
480 .den = 15;
482 "hdr10+ targeted_system_display_actual_peak"
483 "_luminance[%d][%d] %d\n",
484 i, j,
486 [i][j]
487 .num);
488 }
489 }
490
491 for (w = 0; w < hdrp->num_windows; w++)
492 {
493 for (i = 0; i < 3; i++)
494 {
495 hdrp->params[w].maxscl[i].num =
496 (int)ni_bs_reader_get_bits(&br, 17);
497 hdrp->params[w].maxscl[i].den = 100000;
498 ni_log(NI_LOG_DEBUG, "hdr10+ maxscl[%d][%d] %d\n", w, i,
499 hdrp->params[w].maxscl[i].num);
500 }
501 hdrp->params[w].average_maxrgb.num =
502 (int)ni_bs_reader_get_bits(&br, 17);
503 hdrp->params[w].average_maxrgb.den = 100000;
504 ni_log(NI_LOG_DEBUG, "hdr10+ average_maxrgb[%d] %d\n", w,
505 hdrp->params[w].average_maxrgb.num);
506
507 i_limit =
509 ni_bs_reader_get_bits(&br, 4);
511 "hdr10+ num_distribution_maxrgb_percentiles[%d] %d\n",
513
514 i_limit = i_limit > 15 ? 15 : i_limit;
515 for (i = 0; i < i_limit; i++)
516 {
518 ni_bs_reader_get_bits(&br, 7);
520 (int)ni_bs_reader_get_bits(&br, 17);
522 100000;
524 "hdr10+ distribution_maxrgb_percentage[%d][%d] "
525 "%u\n",
526 w, i,
529 "hdr10+ distribution_maxrgb_percentile[%d][%d] "
530 "%d\n",
531 w, i,
532 hdrp->params[w]
534 .percentile.num);
535 }
536
538 (int)ni_bs_reader_get_bits(&br, 10);
539 hdrp->params[w].fraction_bright_pixels.den = 1000;
540 ni_log(NI_LOG_DEBUG, "hdr10+ fraction_bright_pixels[%d] %d\n", w,
542 }
543
545 ni_bs_reader_get_bits(&br, 1);
547 "hdr10+ mastering_display_actual_peak_luminance_flag %u\n",
550 {
551 i_limit =
553 ni_bs_reader_get_bits(&br, 5);
554 j_limit =
556 ni_bs_reader_get_bits(&br, 5);
558 "hdr10+ num_rows_mastering_display_actual_peak_"
559 "luminance x "
560 "num_cols_mastering_display_actual_peak_luminance "
561 "%d x %d\n",
562 i_limit, j_limit);
563
564 i_limit = i_limit > 25 ? 25 : i_limit;
565 j_limit = j_limit > 25 ? 25 : j_limit;
566 for (i = 0; i < i_limit; i++)
567 for (j = 0; j < j_limit; j++)
568 {
570 .num = (int)ni_bs_reader_get_bits(&br, 4);
572 .den = 15;
574 "hdr10+ mastering_display_actual_peak_lumi"
575 "nance[%d][%d] %d\n",
576 i, j,
577 hdrp
578 ->mastering_display_actual_peak_luminance[i]
579 [j]
580 .num);
581 }
582 }
583
584 for (w = 0; w < hdrp->num_windows; w++)
585 {
586 hdrp->params[w].tone_mapping_flag =
587 ni_bs_reader_get_bits(&br, 1);
588 ni_log(NI_LOG_DEBUG, "hdr10+ tone_mapping_flag[%d] %u\n", w,
589 hdrp->params[w].tone_mapping_flag);
590
591 if (hdrp->params[w].tone_mapping_flag)
592 {
593 hdrp->params[w].knee_point_x.num =
594 (int)ni_bs_reader_get_bits(&br, 12);
595 hdrp->params[w].knee_point_x.den = 4095;
596 hdrp->params[w].knee_point_y.num =
597 (int)ni_bs_reader_get_bits(&br, 12);
598 hdrp->params[w].knee_point_y.den = 4095;
599 ni_log(NI_LOG_DEBUG, "hdr10+ knee_point_x[%d] %d\n", w,
600 hdrp->params[w].knee_point_x.num);
601 ni_log(NI_LOG_DEBUG, "hdr10+ knee_point_y[%d] %d\n", w,
602 hdrp->params[w].knee_point_y.num);
603
605 ni_bs_reader_get_bits(&br, 4);
607 "hdr10+ num_bezier_curve_anchors[%d] %u\n", w,
609 for (i = 0;
610 i < hdrp->params[w].num_bezier_curve_anchors; i++)
611 {
612 hdrp->params[w].bezier_curve_anchors[i].num =
613 (int)ni_bs_reader_get_bits(&br, 10);
614 hdrp->params[w].bezier_curve_anchors[i].den = 1023;
616 "hdr10+ bezier_curve_anchors[%d][%d] %d\n", w,
617 i, hdrp->params[w].bezier_curve_anchors[i].num);
618 }
619 }
620
622 ni_bs_reader_get_bits(&br, 1);
624 "hdr10+ color_saturation_mapping_flag[%d] %u\n", w,
627 {
629 (int)ni_bs_reader_get_bits(&br, 6);
632 "hdr10+ color_saturation_weight[%d] %d\n", w,
634 }
635 } // num_windows
636
637 } // right number of windows
638 } // alloc memory
639 } // HDR10+ SEI
640
641 // init source stream info to default values (unspecified)
645 frame->video_full_range_flag = 0;
646 frame->aspect_ratio_idc = 0;
647 frame->sar_width = 0;
648 frame->sar_height = 0;
649 frame->vui_num_units_in_tick = 0;
650 frame->vui_time_scale = 0;
651
652 // VUI if retrieved
653 if (frame->vui_offset || frame->vui_len)
654 {
655 sei_buf = (uint8_t *)frame->p_data[start_offset] + frame->vui_offset;
656 ni_extended_dec_metadata_t *p_dec_ext_meta =
658 frame->vui_num_units_in_tick = p_dec_ext_meta->num_units_in_tick;
659 frame->vui_time_scale = p_dec_ext_meta->time_scale;
660 frame->color_primaries = p_dec_ext_meta->color_primaries;
661 frame->color_trc = p_dec_ext_meta->color_trc;
662 frame->color_space = p_dec_ext_meta->color_space;
663 frame->video_full_range_flag = p_dec_ext_meta->video_full_range_flag;
664
666 "ni_dec_retrieve_aux_data VUI "
667 "aspect_ratio_idc %u "
668 "sar_width %u sar_height %u "
669 "video_full_range_flag %d "
670 "color-pri %u color-trc %u color-space %u "
671 "vui_num_units_in_tick %u "
672 "vui_time_scale %u\n",
673 frame->aspect_ratio_idc, frame->sar_width, frame->sar_height,
675 frame->color_trc, frame->color_space,
677 }
678
679 // alternative transfer characteristics SEI if available
682 {
683 sei_buf = (uint8_t *)frame->p_data[start_offset] +
685
686 // and overwrite the color-trc in the VUI
687 ni_log(NI_LOG_DEBUG, "ni_dec_retrieve_aux_data alt trc SEI value %u over-"
688 "writting VUI color-trc value %u\n",
689 *sei_buf, frame->color_trc);
690 frame->color_trc = *sei_buf;
691 }
692}
693
694// Convert struct of ROIs to NetInt ROI map and store them inside the encoder
695// context passed in.
696// return 0 if successful, -1 otherwise
697static int set_roi_map(ni_session_context_t *p_enc_ctx,
698 ni_codec_format_t codec_format,
699 const ni_aux_data_t *aux_data, int nb_roi, int width,
700 int height, int intra_qp)
701{
702 (void)intra_qp;
703 int r;
704 uint32_t i, j, k, m;
705 const ni_region_of_interest_t *roi =
706 (const ni_region_of_interest_t *)aux_data->data;
707 uint32_t self_size = roi->self_size;
708 int32_t set_qp = 0;
709 uint32_t sumQp = 0;
710 uint8_t isAbsQp_flag = 0; // 0 for delta qp, 1 for absolute qp
711 ni_xcoder_params_t *api_params =
712 (ni_xcoder_params_t *)p_enc_ctx->p_session_config;
713
714 uint32_t max_cu_size = (codec_format == NI_CODEC_FORMAT_H264) ? 16 : 64;
715
716 // AV1 non-8x8-aligned resolution is implicitly cropped due to Quadra HW limitation
717 if (NI_CODEC_FORMAT_AV1 == codec_format)
718 {
719 width = (width / 8) * 8;
720 height = (height / 8) * 8;
721 }
722
723 // for H.264, select ROI Map Block Unit Size: 16x16
724 // for H.265, select ROI Map Block Unit Size: 64x64
725 uint32_t roiMapBlockUnitSize =
726 (codec_format == NI_CODEC_FORMAT_H264) ? 16 : 64;
727 uint32_t mbWidth = ((width + max_cu_size - 1) & (~(max_cu_size - 1))) /
728 roiMapBlockUnitSize;
729 uint32_t mbHeight = ((height + max_cu_size - 1) & (~(max_cu_size - 1))) /
730 roiMapBlockUnitSize;
731 uint32_t numMbs = mbWidth * mbHeight;
732 uint32_t subMbWidth = roiMapBlockUnitSize / 8;
733 uint32_t subMbHeight = subMbWidth;
734 uint32_t subNumMbs = subMbWidth * subMbHeight;
735
736 // (ROI map version >= 1) each QP info takes 8-bit, represent 8x8 pixel
737 // block
738 uint32_t block_size = ((width + max_cu_size - 1) & (~(max_cu_size - 1))) *
739 ((height + max_cu_size - 1) & (~(max_cu_size - 1))) / (8 * 8);
740
741 // need to align to 64 bytes
742 uint32_t customMapSize = ((block_size + 63) & (~63));
743 if (!p_enc_ctx->roi_map)
744 {
745 p_enc_ctx->roi_map =
746 (ni_enc_quad_roi_custom_map *)calloc(1, customMapSize);
747 if (!p_enc_ctx->roi_map)
748 {
749 return -1;
750 }
751 }
752
753 // init ipcm_flag to 0, roiAbsQp_falg to 0 (qp delta), and qp_info to 0
754 memset(p_enc_ctx->roi_map, 0, customMapSize);
755
756 // iterate ROI list from the last as regions are defined in order of
757 // decreasing importance.
758 for (r = nb_roi - 1; r >= 0; r--)
759 {
760 roi = (const ni_region_of_interest_t *)((uint8_t *)aux_data->data + (size_t)self_size * r);
761 if (!roi->qoffset.den)
762 {
763 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_region_of_interest_t.qoffset.den must not be "
764 "zero.\n");
765 continue;
766 }
768 // set_qp in range [1, 10] mean it need to reset qp after
769 // rate control in fw when customize_roi_qp_level is 1.
770 // set_qp is the level in customize qp map, it choose dst qp
771 // in customize qp map base on the rate control qp and set_qp
772 set_qp = (int32_t)((float)roi->qoffset.num * 1.0f /
773 (float)roi->qoffset.den * NI_CUSTOMIZE_ROI_QPOFFSET_LEVEL);
774 if (set_qp > 0 && set_qp <= NI_CUSTOMIZE_ROI_QPOFFSET_LEVEL) {
775 isAbsQp_flag = api_params->cfg_enc_params.customize_roi_qp_level;
776 } else {
777 continue;
778 }
779 } else {
780 set_qp = (int32_t)((float)roi->qoffset.num * 1.0f /
781 (float)roi->qoffset.den * NI_INTRA_QP_RANGE);
782 set_qp = clip3(NI_MIN_QP_DELTA, NI_MAX_QP_DELTA, set_qp);
783 // Adjust qp delta range (-25 to 25) to (0 to 63): 0 to 0, -1 to 1, -2 to
784 // 2 ... 1 to 63, 2 to 62 ...
785 // Theoretically the possible qp delta range is (-32 to 31)
786 set_qp = (NI_MAX_QP_INFO + 1 - set_qp) % (NI_MAX_QP_INFO + 1);
787 }
788 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
789 "set_roi_map: left %d right %d top %d bottom %d num %d den"
790 " %d set_qp %d\n",
791 roi->left, roi->right, roi->top, roi->bottom, roi->qoffset.num,
792 roi->qoffset.den, set_qp);
793
794 // copy ROI MBs QPs into custom map
795 for (j = 0; j < mbHeight; j++)
796 {
797 for (i = 0; i < mbWidth; i++)
798 {
799 k = j * (int)mbWidth + i;
800
801 for (m = 0; m < subNumMbs; m++)
802 {
803 if (((int)(i % mbWidth) >=
804 (int)((roi->left + roiMapBlockUnitSize - 1) /
805 roiMapBlockUnitSize) -
806 1) &&
807 ((int)(i % mbWidth) <=
808 (int)((roi->right + roiMapBlockUnitSize - 1) /
809 roiMapBlockUnitSize) -
810 1) &&
811 ((int)(j % mbHeight) >=
812 (int)((roi->top + roiMapBlockUnitSize - 1) /
813 roiMapBlockUnitSize) -
814 1) &&
815 ((int)(j % mbHeight) <=
816 (int)((roi->bottom + roiMapBlockUnitSize - 1) /
817 roiMapBlockUnitSize) -
818 1))
819 {
820 p_enc_ctx->roi_map[k * subNumMbs + m].field.ipcm_flag =
821 0; // don't force skip mode
822 p_enc_ctx->roi_map[k * subNumMbs + m]
823 .field.roiAbsQp_flag = isAbsQp_flag;
824 p_enc_ctx->roi_map[k * subNumMbs + m].field.qp_info =
825 set_qp;
826 // ni_log2(p_enc_ctx, NI_LOG_DEBUG, "## x %d y %d index %d\n", i,
827 // j, k*subNumMbs+m);
828 }
829 }
830 sumQp += p_enc_ctx->roi_map[(size_t)k * subNumMbs].field.qp_info;
831 }
832 }
833 }
834
835 p_enc_ctx->roi_len = customMapSize;
836 p_enc_ctx->roi_avg_qp = (numMbs != 0 ? (sumQp + (numMbs >> 1)) / numMbs : 0) + NI_DEFAULT_INTRA_QP;
837
838 return 0;
839}
840
841/*!*****************************************************************************
842 * \brief Prepare auxiliary data that should be sent together with this frame
843 * to encoder based on the auxiliary data of the decoded frame.
844 *
845 * Note: Some of the SEI (e.g. HDR) will be updated and stored in encoder
846 * context whenever received through decoded frame; they will be sent
847 * out with the encoded frame to encoder only when appropriate, i.e.
848 * should_send_sei_with_frame is true. When a type of aux data is to be
849 * sent, its associated length will be set in the encoder frame.
850 *
851 * \param[in/out] p_enc_ctx encoder session contextwhose various SEI type
852 * header can be updated as the result of this function
853 * \param[out] p_enc_frame frame to be sent to encoder
854 * \param[in] p_dec_frame frame that is returned by decoder
855 * \param[in] codec_format H.264 or H.265
856 * \param[in] should_send_sei_with_frame if need to send a certain type of
857 * SEI with this frame
858 * \param[out] mdcv_data SEI for HDR mastering display color volume info
859 * \param[out] cll_data SEI for HDR content light level info
860 * \param[out] cc_data SEI for close caption
861 * \param[out] udu_data SEI for User data unregistered
862 * \param[out] hdrp_data SEI for HDR10+
863 *
864 * \return NONE
865 ******************************************************************************/
867 ni_frame_t *p_enc_frame, ni_frame_t *p_dec_frame,
868 ni_codec_format_t codec_format,
869 int should_send_sei_with_frame, uint8_t *mdcv_data,
870 uint8_t *cll_data, uint8_t *cc_data,
871 uint8_t *udu_data, uint8_t *hdrp_data)
872{
873 uint8_t *dst = NULL;
874 ni_aux_data_t *aux_data = NULL;
875 ni_xcoder_params_t *api_params =
877
878 const int is_av1 = (NI_CODEC_FORMAT_AV1 == codec_format);
879 const int is_h264 = (NI_CODEC_FORMAT_H264 == codec_format);
880
881 // reset all auxiliary data flags and lengths of encode frame
883 p_enc_frame->use_cur_src_as_long_term_pic =
884 p_enc_frame->use_long_term_ref = 0;
885
886 p_enc_frame->sei_total_len = p_enc_frame->sei_cc_offset =
887 p_enc_frame->sei_cc_len =
892 p_enc_frame->sei_user_data_unreg_offset =
893 p_enc_frame->sei_user_data_unreg_len =
894 p_enc_frame->sei_hdr_plus_offset =
895 p_enc_frame->sei_hdr_plus_len = 0;
896
897 // prep for NetInt intra period reconfiguration support: when intra period
898 // setting has been requested by both frame and API, API takes priority
899 int intraprd = -1;
900 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_INTRAPRD);
901 if (aux_data)
902 {
903 intraprd = *((int32_t *)aux_data->data);
904 if (intraprd < 0 || intraprd > 1024)
905 {
906 ni_log(NI_LOG_ERROR, "ERROR: %s(): invalid intraperiod in aux data %d\n",
907 __func__, intraprd);
908 intraprd = -1;
909 }
910 }
911
912 if (p_enc_ctx->reconfig_intra_period >= 0)
913 {
914 intraprd = p_enc_ctx->reconfig_intra_period;
915 p_enc_ctx->reconfig_intra_period = -1;
916 ni_log(NI_LOG_DEBUG, "%s(): API set intraPeriod %d\n", __func__,
917 intraprd);
918 }
919
920 if (intraprd >= 0)
921 {
922 if (api_params->cfg_enc_params.intra_mb_refresh_mode ||
923 api_params->cfg_enc_params.gop_preset_index == 1)
924 {
925 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): NOT allowed to reconfig intraPeriod %d in intra_mb_refresh_mode %d or gop_preset_index %d\n",
926 __func__,
927 intraprd,
929 api_params->cfg_enc_params.gop_preset_index);
930 }
931 else
932 {
933 // FW forces IDR frame when reconfig intra period, so the following steps are required for repeating SEI (and required for ni_should_send_sei_with_frame)
934 should_send_sei_with_frame = 1;
935 api_params->cfg_enc_params.intra_period = intraprd;
936
937 if (intraprd)
938 {
939 p_enc_ctx->force_idr_intra_offset =
940 intraprd - (p_enc_ctx->frame_num % intraprd);
941 }
942 else
943 {
944 p_enc_ctx->force_idr_intra_offset = 0;
945 }
946
947 p_enc_ctx->enc_change_params->enable_option |=
949 p_enc_ctx->enc_change_params->intraPeriod = intraprd;
950 ni_log(NI_LOG_INFO, "%s(): set intraPeriod %d on frame %u, update intra offset %u\n", __func__,
951 intraprd, p_enc_ctx->frame_num, p_enc_ctx->force_idr_intra_offset);
952 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
953 }
954 }
955
956 // 1. Prep SEI for HDR (mastering display color volume)
957 aux_data = ni_frame_get_aux_data(
959 if (aux_data)
960 {
961 p_enc_ctx->mdcv_max_min_lum_data_len = 8;
962 // Payload is 24 bytes: 6*2 primaries + 2*2 white point + 2*4 luminance.
963 // AV1: type(3) + payload(24) + trailing(1).
964 // H.265: header(8) + payload(24) + trailing(1).
965 // H.264: header(7) + payload(24) + trailing(1) -> one byte less than H.265.
966 if (is_av1)
967 p_enc_ctx->sei_hdr_mastering_display_color_vol_len = 4 + 24;
968 else
970 (is_h264 ? 8 : 9) + 24;
971
974
975 // save a copy
976 if (!p_enc_ctx->p_master_display_meta_data)
977 {
979 }
980 if (!p_enc_ctx->p_master_display_meta_data)
981 {
982 ni_log2(p_enc_ctx, NI_LOG_ERROR, "Error mem alloc for mastering display color vol\n");
983 } else
984 {
985 memcpy(p_enc_ctx->p_master_display_meta_data, p_src,
987 const int luma_max_den = is_av1 ? AV1_MASTERING_DISP_LUMA_MAX_DEN
989 const int luma_min_den = is_av1 ? AV1_MASTERING_DISP_LUMA_MIN_DEN
991
992 uint32_t max_lum = htonl(
993 (uint32_t)lrint(luma_max_den * ni_q2d(p_src->max_luminance)));
994 uint32_t min_lum = htonl(
995 (uint32_t)lrint(luma_min_den * ni_q2d(p_src->min_luminance)));
996
997 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "### %s: luma_max_den %d luma_min_den %d\n", __func__, luma_max_den, luma_min_den);
998 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "### %s: max n %d d %d min n %d d %d\n", __func__,
999 p_src->max_luminance.num, p_src->max_luminance.den,
1000 p_src->min_luminance.num, p_src->min_luminance.den);
1001
1002 memcpy(p_enc_ctx->ui8_mdcv_max_min_lum_data, &max_lum, 4);
1003 memcpy(p_enc_ctx->ui8_mdcv_max_min_lum_data + 4, &min_lum, 4);
1004
1005 if (!is_av1)
1006 {
1007 // emulation prevention checking of luminance data
1008 int emu_bytes_inserted = ni_insert_emulation_prevent_bytes(
1009 p_enc_ctx->ui8_mdcv_max_min_lum_data, 2 * 4);
1010
1011 p_enc_ctx->mdcv_max_min_lum_data_len += emu_bytes_inserted;
1013 emu_bytes_inserted;
1014 }
1015 }
1016 }
1017
1018 // 2. Construct the Bitstream Payload
1020 p_enc_ctx->p_master_display_meta_data && should_send_sei_with_frame)
1021 {
1022 dst = mdcv_data;
1023 if (is_av1)
1024 {
1025 // AV1 Metadata OBU Header for obu_type: 5 (OBU_METADATA)
1026 dst[0] = 0x2a; // (5 << 3) + 2;
1027 dst[1] = 0x1a; // OBU length
1028 dst[2] = 0x2; // metadata_type METADATA_TYPE_HDR_MDCV // See 5.8 in spec
1029 dst += 3;
1030 }
1031 else if (is_h264)
1032 {
1033 dst[0] = dst[1] = dst[2] = 0; dst[3] = 1; // Annex B Start Code
1034 dst[4] = 0x6; // nal_unit_type = SEI
1035 dst[5] = 0x89; // payload type = 137 (mastering_display_colour_volume)
1036 dst[6] = 0x18; // payload size = 24
1037 dst += 7;
1038 }
1039 else // H.265
1040 {
1041 dst[0] = dst[1] = dst[2] = 0; dst[3] = 1; // Annex B Start Code
1042 dst[4] = 0x4e; // nal_unit_type = PREFIX_SEI_NUT
1043 dst[5] = 1; // nuh_layer_id = 0, nuh_temporal_id_plus1 = 1
1044 dst[6] = 0x89; // payload type = 137
1045 dst[7] = 0x18; // payload size = 24
1046 dst += 8;
1047 }
1048
1053 p_enc_ctx->p_master_display_meta_data;
1054
1055 const int chroma_den = is_av1 ? AV1_MASTERING_DISP_CHROMA_DEN
1057
1058 // Destination primary index (dst order) -> source index in p_src.
1059 // AV1 is native R,G,B -> {0,1,2}
1060 // H.264/H.265 need G,B,R -> G=src[1], B=src[2], R=src[0]
1061 static const int src_idx_av1[3] = {0, 1, 2};
1062 static const int src_idx_hevc[3] = {1, 2, 0};
1063 const int *src_idx = is_av1 ? src_idx_av1 : src_idx_hevc;
1064
1065 for (int d = 0; d < 3; d++)
1066 {
1067 int s = src_idx[d];
1068 p_mdcv->display_primaries[d][0] = htons(
1069 (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[s][0])));
1070 p_mdcv->display_primaries[d][1] = htons(
1071 (uint16_t)lrint(chroma_den * ni_q2d(p_src->display_primaries[s][1])));
1072 }
1073
1074 p_mdcv->white_point_x =
1075 htons((uint16_t)lrint(chroma_den * ni_q2d(p_src->white_point[0])));
1076 p_mdcv->white_point_y =
1077 htons((uint16_t)lrint(chroma_den * ni_q2d(p_src->white_point[1])));
1078
1079 dst += 6 * 2 + 2 * 2;
1080 memcpy(dst, p_enc_ctx->ui8_mdcv_max_min_lum_data,
1081 p_enc_ctx->mdcv_max_min_lum_data_len);
1082 dst += p_enc_ctx->mdcv_max_min_lum_data_len;
1083
1084 *dst = 0x80; // RBSP Trailing bit
1085
1088
1089 p_enc_frame->sei_total_len +=
1091 }
1092
1093 // prep HDR content light level info (MaxCLL / MaxFALL)
1094 aux_data = ni_frame_get_aux_data(p_dec_frame,
1096 if (aux_data)
1097 {
1098 // size of: start code + NAL unit header + payload type byte +
1099 // payload size byte + payload + rbsp trailing bits, default HEVC
1100 p_enc_ctx->light_level_data_len = 4;
1101 if (NI_CODEC_FORMAT_AV1 == codec_format)
1102 {
1103 p_enc_ctx->sei_hdr_content_light_level_info_len = 3 + 2 * 2 + 1;
1104 }
1105 else
1106 {
1107 p_enc_ctx->sei_hdr_content_light_level_info_len = 8 + 2 * 2 + 1;
1108 if (NI_CODEC_FORMAT_H264 == codec_format)
1109 {
1111 }
1112 }
1113
1114 uint16_t max_content_light_level =
1115 htons(((ni_content_light_level_t *)aux_data->data)->max_cll);
1116 uint16_t max_pic_average_light_level =
1117 htons(((ni_content_light_level_t *)aux_data->data)->max_fall);
1118
1119 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "content light level info, MaxCLL %u MaxFALL %u\n",
1120 ((ni_content_light_level_t *)aux_data->data)->max_cll,
1121 ((ni_content_light_level_t *)aux_data->data)->max_fall);
1122
1123 memcpy(p_enc_ctx->ui8_light_level_data, &max_content_light_level,
1124 sizeof(uint16_t));
1125 memcpy(&(p_enc_ctx->ui8_light_level_data[2]),
1126 &max_pic_average_light_level, sizeof(uint16_t));
1127
1128 // H.264 / H.265 require emulation-prevention
1129 if (codec_format == NI_CODEC_FORMAT_H264 ||
1130 codec_format == NI_CODEC_FORMAT_H265)
1131 {
1132 int emu_bytes_inserted = ni_insert_emulation_prevent_bytes(
1133 p_enc_ctx->ui8_light_level_data, p_enc_ctx->light_level_data_len);
1134
1135 p_enc_ctx->light_level_data_len += emu_bytes_inserted;
1136 p_enc_ctx->sei_hdr_content_light_level_info_len += emu_bytes_inserted;
1137 }
1138 }
1139
1140 if (p_enc_ctx->sei_hdr_content_light_level_info_len &&
1141 should_send_sei_with_frame)
1142 {
1143 dst = cll_data;
1144
1145 if (NI_CODEC_FORMAT_AV1 == codec_format)
1146 {
1147 // AV1 Metadata OBU Header for obu_type: 5 (OBU_METADATA)
1148 dst[0] = 0x2a; // (5 << 3) + 2;
1149 dst[1] = 0x6; // OBU length
1150 dst[2] = 0x1; // metadata_type METADATA_TYPE_HDR_CLL
1151 dst += 3;
1152 }
1153 else if (NI_CODEC_FORMAT_H264 == codec_format)
1154 {
1155 dst[0] = dst[1] = dst[2] = 0; dst[3] = 1; // Annex B Start Code
1156 dst[4] = 0x6;
1157 dst[5] = 0x90; // payload type=144
1158 dst[6] = 4; // payload size=4
1159 dst += 7;
1160 } else
1161 {
1162 dst[0] = dst[1] = dst[2] = 0; dst[3] = 1; // Annex B Start Code
1163 dst[4] = 0x4e;
1164 dst[5] = 1;
1165 dst[6] = 0x90; // payload type=144
1166 dst[7] = 4; // payload size=4
1167 dst += 8;
1168 }
1169
1170 memcpy(dst, p_enc_ctx->ui8_light_level_data,
1171 p_enc_ctx->light_level_data_len);
1172 dst += p_enc_ctx->light_level_data_len;
1173 *dst = 0x80;
1174
1177
1178 p_enc_frame->sei_total_len +=
1180 }
1181
1182 // prep SEI for close caption
1183 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_A53_CC);
1184 if (aux_data)
1185 {
1186 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_cc_len %d\n", aux_data->size);
1187
1188 uint8_t cc_data_emu_prevent[NI_MAX_SEI_DATA];
1189 int cc_size = aux_data->size;
1190 if (cc_size > NI_MAX_SEI_DATA)
1191 {
1192 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_cc_len %d > MAX %d !\n",
1193 aux_data->size, (int)NI_MAX_SEI_DATA);
1194 cc_size = NI_MAX_SEI_DATA;
1195 }
1196 memcpy(cc_data_emu_prevent, aux_data->data, cc_size);
1197
1198 int cc_size_emu_prevent = cc_size;
1199 // H.264 / H.265 require emulation-prevention
1200 if (codec_format == NI_CODEC_FORMAT_H264 ||
1201 codec_format == NI_CODEC_FORMAT_H265)
1202 {
1203 cc_size_emu_prevent = cc_size + ni_insert_emulation_prevent_bytes(cc_data_emu_prevent, cc_size);
1204 if (cc_size_emu_prevent != cc_size)
1205 {
1206 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data: close caption "
1207 "emulation prevention bytes added: %d\n",
1208 cc_size_emu_prevent - cc_size);
1209 }
1210 }
1211 dst = cc_data;
1212 // set header info fields and extra size based on codec
1213 if (NI_CODEC_FORMAT_H265 == codec_format)
1214 {
1215 p_enc_frame->sei_cc_len = NI_CC_SEI_HDR_HEVC_LEN +
1216 cc_size_emu_prevent + NI_CC_SEI_TRAILER_LEN;
1217 p_enc_frame->sei_total_len += p_enc_frame->sei_cc_len;
1218
1219 p_enc_ctx->itu_t_t35_cc_sei_hdr_hevc[7] = cc_size + 11;
1220 p_enc_ctx->itu_t_t35_cc_sei_hdr_hevc[16] = (cc_size / 3) | 0xc0;
1221
1222 memcpy(dst, p_enc_ctx->itu_t_t35_cc_sei_hdr_hevc,
1225 memcpy(dst, cc_data_emu_prevent, cc_size_emu_prevent);
1226 dst += cc_size_emu_prevent;
1227 memcpy(dst, p_enc_ctx->sei_trailer, NI_CC_SEI_TRAILER_LEN);
1228 } else if (NI_CODEC_FORMAT_H264 == codec_format)
1229 {
1230 p_enc_frame->sei_cc_len = NI_CC_SEI_HDR_H264_LEN +
1231 cc_size_emu_prevent + NI_CC_SEI_TRAILER_LEN;
1232 p_enc_frame->sei_total_len += p_enc_frame->sei_cc_len;
1233
1234 p_enc_ctx->itu_t_t35_cc_sei_hdr_h264[6] = cc_size + 11;
1235 p_enc_ctx->itu_t_t35_cc_sei_hdr_h264[15] = (cc_size / 3) | 0xc0;
1236
1237 memcpy(dst, p_enc_ctx->itu_t_t35_cc_sei_hdr_h264,
1240 memcpy(dst, cc_data_emu_prevent, cc_size_emu_prevent);
1241 dst += cc_size_emu_prevent;
1242 memcpy(dst, p_enc_ctx->sei_trailer, NI_CC_SEI_TRAILER_LEN);
1243 }
1244 else if (NI_CODEC_FORMAT_AV1 == codec_format)
1245 {
1248
1249 // 1. OBU Header: Type 5 (Metadata), Has Size = 1
1250 // Byte: 0x2a (00101 0 1 0)
1251 ni_bs_writer_put(&pb, 0x2a, 8);
1252
1253 // 2. OBU Size using LEB128
1254 // Size = Metadata_type(1) + T.35_header(10) + cc_data(cc_size)
1255 // Note: We use raw cc_size as AV1 doesn't use emulation prevention
1256 uint32_t obu_payload_size = 1 + 10 + cc_size + NI_CC_SEI_TRAILER_LEN;
1257 ni_bs_writer_leb128(&pb, obu_payload_size);
1258
1259 // 3. Metadata Type: METADATA_TYPE_ITUT_T35 (4)
1260 ni_bs_writer_put(&pb, 0x04, 8);
1261
1262 // 4. ITU-T T.35 Payload Header (First 9 bytes of your template)
1263 // This covers country_code, provider_code, and "GA94" identifier
1264 // We skip index 0 (OBU Hdr), 1 (Old Size), and 2 (Meta Type)
1265 for (int i = 3; i < 11; i++)
1266 {
1267 ni_bs_writer_put(&pb, p_enc_ctx->itu_t_t35_cc_sei_hdr_av1[i], 8);
1268 }
1269
1270 // 5. Set CC count (Standard ATSC T.35 logic)
1271 uint8_t cc_count_byte = (uint8_t)((cc_size / 3) | 0xc0);
1272 ni_bs_writer_put(&pb, cc_count_byte, 8);
1273
1274 // 6. Marker bits / em_data (Index 12 of g_itu_t_t35_cc_sei_hdr_av1)
1275 ni_bs_writer_put(&pb, p_enc_ctx->itu_t_t35_cc_sei_hdr_av1[12], 8);
1276
1277 // 7. Calculate total length and copy to destination
1278 // The writer now contains the full dynamic header
1279 uint32_t header_len = (uint32_t)(ni_bs_writer_tell(&pb) / 8);
1280 p_enc_frame->sei_cc_len = header_len + cc_size + NI_CC_SEI_TRAILER_LEN;
1281 p_enc_frame->sei_total_len += p_enc_frame->sei_cc_len;
1282
1283 ni_bs_writer_copy(dst, &pb);
1284 dst += header_len;
1285
1286 // 8. Copy raw CC data
1287 memcpy(dst, aux_data->data, cc_size);
1288 dst += cc_size;
1289 memcpy(dst, p_enc_ctx->sei_trailer, NI_CC_SEI_TRAILER_LEN);
1290 ni_bs_writer_clear(&pb);
1291 }
1292 }
1293
1294 // prep SEI for HDR+
1295 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_HDR_PLUS);
1296 if (aux_data)
1297 {
1299 int w, i, j;
1301 uint32_t ui_tmp;
1302
1304
1305 // HDR10+ SEI header bytes
1306
1307 // itu_t_t35_provider_code and itu_t_t35_provider_oriented_code are
1308 // contained in the first 4 bytes of payload; pb has all the data until
1309 // start of trailer
1310 ni_bs_writer_put(&pb, 0, 8);
1311 ni_bs_writer_put(&pb, 0x3c,
1312 8); // u16 itu_t_t35_provider_code = 0x003c
1313 ni_bs_writer_put(&pb, 0, 8);
1314 // u16 itu_t_t35_provider_oriented_code = 0x0001
1315 ni_bs_writer_put(&pb, 0x01, 8);
1316 ni_bs_writer_put(&pb, 4, 8); // u8 application_identifier = 0x04
1318 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ application_version %u\n", hdrp->application_version);
1319
1320 ni_bs_writer_put(&pb, hdrp->num_windows, 2);
1321 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ num_windows %u\n", hdrp->num_windows);
1322 for (w = 1; w < hdrp->num_windows; w++)
1323 {
1325 &pb, hdrp->params[w - 1].window_upper_left_corner_x.num, 16);
1327 &pb, hdrp->params[w - 1].window_upper_left_corner_y.num, 16);
1329 &pb, hdrp->params[w - 1].window_lower_right_corner_x.num, 16);
1331 &pb, hdrp->params[w - 1].window_lower_right_corner_y.num, 16);
1332 ni_bs_writer_put(&pb, hdrp->params[w - 1].center_of_ellipse_x, 16);
1333 ni_bs_writer_put(&pb, hdrp->params[w - 1].center_of_ellipse_y, 16);
1334 ni_bs_writer_put(&pb, hdrp->params[w - 1].rotation_angle, 8);
1336 &pb, hdrp->params[w - 1].semimajor_axis_internal_ellipse, 16);
1338 &pb, hdrp->params[w - 1].semimajor_axis_external_ellipse, 16);
1340 &pb, hdrp->params[w - 1].semiminor_axis_external_ellipse, 16);
1342 1);
1343 }
1344
1345 // values are scaled up according to standard spec
1346 ui_tmp = lrint(10000 *
1348 ni_bs_writer_put(&pb, ui_tmp, 27);
1351 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ targeted_system_display_maximum_luminance "
1352 "%u\n",
1353 ui_tmp);
1354 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1355 "hdr10+ targeted_system_display_actual_peak_luminance_"
1356 "flag %u\n",
1358
1360 {
1362 &pb,
1364 5);
1366 &pb,
1368 5);
1369 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1370 "hdr10+ num_rows_targeted_system_display_actual_peak_luminance "
1371 "x num_cols_targeted_system_display_actual_peak_luminance %u x "
1372 "%u\n",
1375
1376 for (i = 0; i <
1378 i++)
1379 for (
1380 j = 0; j <
1382 j++)
1383 {
1384 ui_tmp = lrint(
1385 15 *
1386 ni_q2d(
1388 [i][j]));
1389 ni_bs_writer_put(&pb, ui_tmp, 4);
1390 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ targeted_system_display_actual_peak_"
1391 "luminance[%d][%d] %u\n",
1392 i, j, ui_tmp);
1393 }
1394 }
1395
1396 for (w = 0; w < hdrp->num_windows; w++)
1397 {
1398 for (i = 0; i < 3; i++)
1399 {
1400 ui_tmp = lrint(100000 * ni_q2d(hdrp->params[w].maxscl[i]));
1401 ni_bs_writer_put(&pb, ui_tmp, 17);
1402 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ maxscl[%d][%d] %u\n", w, i, ui_tmp);
1403 }
1404 ui_tmp = lrint(100000 * ni_q2d(hdrp->params[w].average_maxrgb));
1405 ni_bs_writer_put(&pb, ui_tmp, 17);
1406 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ average_maxrgb[%d] %u\n", w, ui_tmp);
1407
1410 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1411 "hdr10+ num_distribution_maxrgb_percentiles[%d] %d\n", w,
1413
1414 for (i = 0; i < hdrp->params[w].num_distribution_maxrgb_percentiles;
1415 i++)
1416 {
1418 &pb, hdrp->params[w].distribution_maxrgb[i].percentage, 7);
1419 ui_tmp = lrint(
1420 100000 *
1421 ni_q2d(hdrp->params[w].distribution_maxrgb[i].percentile));
1422 ni_bs_writer_put(&pb, ui_tmp, 17);
1423 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1424 "hdr10+ distribution_maxrgb_percentage[%d][%d] %u\n", w, i,
1426 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1427 "hdr10+ distribution_maxrgb_percentile[%d][%d] %u\n", w, i,
1428 ui_tmp);
1429 }
1430
1431 ui_tmp =
1432 lrint(1000 * ni_q2d(hdrp->params[w].fraction_bright_pixels));
1433 ni_bs_writer_put(&pb, ui_tmp, 10);
1434 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ fraction_bright_pixels[%d] %u\n", w, ui_tmp);
1435 }
1436
1437 ni_bs_writer_put(&pb,
1439 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1440 "hdr10+ mastering_display_actual_peak_luminance_flag %u\n",
1443 {
1448 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1449 "hdr10+ num_rows_mastering_display_actual_peak_luminance x "
1450 "num_cols_mastering_display_actual_peak_luminance %u x %u\n",
1453
1454 for (i = 0;
1456 i++)
1457 for (j = 0;
1459 j++)
1460 {
1461 ui_tmp = lrint(
1462 15 *
1463 ni_q2d(
1465 [j]));
1466 ni_bs_writer_put(&pb, ui_tmp, 4);
1467 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1468 "hdr10+ "
1469 "mastering_display_actual_peak_luminance[%d][%d] %u\n",
1470 i, j, ui_tmp);
1471 }
1472 }
1473
1474 for (w = 0; w < hdrp->num_windows; w++)
1475 {
1476 ni_bs_writer_put(&pb, hdrp->params[w].tone_mapping_flag, 1);
1477 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ tone_mapping_flag[%d] %u\n", w,
1478 hdrp->params[w].tone_mapping_flag);
1479
1480 if (hdrp->params[w].tone_mapping_flag)
1481 {
1482 ui_tmp = lrint(4095 * ni_q2d(hdrp->params[w].knee_point_x));
1483 ni_bs_writer_put(&pb, ui_tmp, 12);
1484 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ knee_point_x[%d] %u\n", w, ui_tmp);
1485
1486 ui_tmp = lrint(4095 * ni_q2d(hdrp->params[w].knee_point_y));
1487 ni_bs_writer_put(&pb, ui_tmp, 12);
1488 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ knee_point_y[%d] %u\n", w, ui_tmp);
1489
1491 4);
1492 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ num_bezier_curve_anchors[%d] %u\n", w,
1494 for (i = 0; i < hdrp->params[w].num_bezier_curve_anchors; i++)
1495 {
1496 ui_tmp = lrint(
1497 1023 * ni_q2d(hdrp->params[w].bezier_curve_anchors[i]));
1498 ni_bs_writer_put(&pb, ui_tmp, 10);
1499 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ bezier_curve_anchors[%d][%d] %u\n",
1500 w, i, ui_tmp);
1501 }
1502 }
1503
1505 1);
1506 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ color_saturation_mapping_flag[%d] %u\n", w,
1509 {
1510 ui_tmp =
1511 lrint(8 * ni_q2d(hdrp->params[w].color_saturation_weight));
1512 ni_bs_writer_put(&pb, ui_tmp, 6);
1513 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ color_saturation_weight[%d] %u\n", w,
1514 ui_tmp);
1515 }
1516 } // num_windows
1517
1518 uint64_t hdr10p_num_bytes = (ni_bs_writer_tell(&pb) + 7) / 8;
1519 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "hdr10+ total bits: %d -> bytes %" PRIu64 "\n",
1520 (int)ni_bs_writer_tell(&pb), hdr10p_num_bytes);
1522
1523 dst = hdrp_data;
1524
1525 // emulation prevention checking of payload
1526 int emu_bytes_inserted;
1527
1528 // set header info fields and extra size based on codec
1529 if (NI_CODEC_FORMAT_H265 == codec_format)
1530 {
1531 p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_hevc[7] =
1532 (uint8_t)hdr10p_num_bytes + NI_RBSP_TRAILING_BITS_LEN;
1533
1534 memcpy(dst, p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_hevc,
1537 ni_bs_writer_copy(dst, &pb);
1538
1539 emu_bytes_inserted =
1540 ni_insert_emulation_prevent_bytes(dst, (int)hdr10p_num_bytes);
1541 dst += hdr10p_num_bytes + emu_bytes_inserted;
1542 *dst = p_enc_ctx->sei_trailer[1];
1543 //dst += NI_RBSP_TRAILING_BITS_LEN;
1544
1546 (uint32_t)hdr10p_num_bytes + emu_bytes_inserted +
1548 p_enc_frame->sei_total_len += p_enc_frame->sei_hdr_plus_len;
1549 } else if (NI_CODEC_FORMAT_H264 == codec_format)
1550 {
1551 p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_h264[6] =
1552 (uint8_t)hdr10p_num_bytes + NI_RBSP_TRAILING_BITS_LEN;
1553
1554 memcpy(dst, p_enc_ctx->itu_t_t35_hdr10p_sei_hdr_h264,
1557 ni_bs_writer_copy(dst, &pb);
1558
1559 emu_bytes_inserted =
1560 ni_insert_emulation_prevent_bytes(dst, (int)hdr10p_num_bytes);
1561 dst += hdr10p_num_bytes + emu_bytes_inserted;
1562 *dst = p_enc_ctx->sei_trailer[1];
1563 //dst += NI_RBSP_TRAILING_BITS_LEN;
1564
1566 (uint8_t)hdr10p_num_bytes + emu_bytes_inserted +
1568 p_enc_frame->sei_total_len += p_enc_frame->sei_hdr_plus_len;
1569 } else if (NI_CODEC_FORMAT_AV1 == codec_format)
1570 {
1571 ni_bitstream_writer_t header_pb;
1572 ni_bitstream_writer_init(&header_pb);
1573
1574 // OBU Header: Type 5 (Metadata), Has Size = 1 (0x2a)
1575 ni_bs_writer_put(&header_pb, 0x2a, 8);
1576
1577 // Calculate OBU Size
1578 // Metadata_type(1) + country_code(1) + payload + trailing_byte(1)
1579 uint32_t obu_payload_size = 1 + 1 + (uint32_t)hdr10p_num_bytes +
1581 ni_bs_writer_leb128(&header_pb, obu_payload_size);
1582
1583 // Metadata Type (4) and Country Code (0xb5)
1584 ni_bs_writer_put(&header_pb, 0x04, 8);
1585 ni_bs_writer_put(&header_pb, 0xb5, 8);
1586
1587 uint32_t header_len = (uint32_t)(ni_bs_writer_tell(&header_pb) / 8);
1588
1589 // Update frame tracking lengths
1590 p_enc_frame->sei_hdr_plus_len = header_len + (uint32_t)hdr10p_num_bytes +
1592 p_enc_frame->sei_total_len += p_enc_frame->sei_hdr_plus_len;
1593
1594 // Copy Header (OBU Header + LEB128 Size + Metadata Type + Country Code)
1595 ni_bs_writer_copy(dst, &header_pb);
1596 dst += header_len;
1597
1598 // Copy HDR10+ Payload
1599 ni_bs_writer_copy(dst, &pb);
1600 dst += hdr10p_num_bytes;
1601 *dst = p_enc_ctx->sei_trailer[1];
1602 ni_bs_writer_clear(&header_pb);
1603
1604 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "AV1 HDR10+ with Trailer: Total %u bytes\n",
1605 p_enc_frame->sei_hdr_plus_len);
1606 } else
1607 {
1608 ni_log2(p_enc_ctx, NI_LOG_ERROR,
1609 "ni_enc_prep_aux_data: codec %d not supported for HDR10+ "
1610 "SEI !\n",
1611 codec_format);
1612 p_enc_frame->sei_hdr_plus_len = 0;
1613 }
1614
1615 ni_bs_writer_clear(&pb);
1616 } // hdr10+
1617
1618 // prep SEI for User Data Unregistered
1619 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_UDU_SEI);
1620 if (aux_data)
1621 {
1622 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data sei_user_data_unreg_len %d\n",
1623 aux_data->size);
1624
1625 // emulation prevention checking: a working buffer of size in worst case
1626 // that each two bytes comes with 1B emulation prevention byte
1627 int udu_sei_size = aux_data->size;
1628 int ext_udu_sei_size, sei_len;
1629
1630 uint8_t *sei_data = malloc(udu_sei_size * 3 / 2);
1631 if (sei_data)
1632 {
1633 memcpy(sei_data, (uint8_t *)aux_data->data, udu_sei_size);
1634 int emu_bytes_inserted =
1635 ni_insert_emulation_prevent_bytes(sei_data, udu_sei_size);
1636
1637 ext_udu_sei_size = udu_sei_size + emu_bytes_inserted;
1638
1639 if (NI_CODEC_FORMAT_H264 == codec_format)
1640 {
1641 /* 4B long start code + 1B nal header + 1B SEI type + Bytes of
1642 payload length + Bytes of SEI payload + 1B trailing */
1643 sei_len =
1644 6 + ((udu_sei_size + 0xFE) / 0xFF) + ext_udu_sei_size + 1;
1645 } else
1646 {
1647 /* 4B long start code + 2B nal header + 1B SEI type + Bytes of
1648 payload length + Bytes of SEI payload + 1B trailing */
1649 sei_len =
1650 7 + ((udu_sei_size + 0xFE) / 0xFF) + ext_udu_sei_size + 1;
1651 }
1652
1653 // discard this UDU SEI if the total SEI size exceeds the max size
1654 if (p_enc_frame->sei_total_len + sei_len > NI_ENC_MAX_SEI_BUF_SIZE)
1655 {
1656 ni_log2(p_enc_ctx, NI_LOG_ERROR,
1657 "ni_enc_prep_aux_data sei total length %u + sei_len %d "
1658 "exceeds maximum sei size %u, discarding it !\n",
1659 p_enc_frame->sei_total_len, sei_len,
1661 } else
1662 {
1663 int payload_size = udu_sei_size;
1664
1665 dst = udu_data;
1666 *dst++ = 0x00; // long start code
1667 *dst++ = 0x00;
1668 *dst++ = 0x00;
1669 *dst++ = 0x01;
1670
1671 if (NI_CODEC_FORMAT_H264 == codec_format)
1672 {
1673 *dst++ = 0x06; // nal type: SEI
1674 } else
1675 {
1676 *dst++ = 0x4e; // nal type: SEI
1677 *dst++ = 0x01;
1678 }
1679 *dst++ = 0x05; // SEI type: user data unregistered
1680
1681 // original payload size
1682 while (payload_size > 0)
1683 {
1684 *dst++ =
1685 (payload_size > 0xFF ? 0xFF : (uint8_t)payload_size);
1686 payload_size -= 0xFF;
1687 }
1688
1689 // payload data after emulation prevention checking
1690 memcpy(dst, sei_data, ext_udu_sei_size);
1691 dst += ext_udu_sei_size;
1692
1693 // trailing byte
1694 *dst = 0x80;
1695 dst++;
1696
1697 // save UDU data length
1698 p_enc_frame->sei_user_data_unreg_len = sei_len;
1699 p_enc_frame->sei_total_len += sei_len;
1700 }
1701
1702 free(sei_data);
1703 sei_data = NULL;
1704 }
1705 }
1706
1707 // supply QP map if ROI enabled and if ROIs passed in as aux data
1708 aux_data = ni_frame_get_aux_data(p_dec_frame,
1710 if (api_params->cfg_enc_params.roi_enable && aux_data)
1711 {
1712 int is_new_rois = 1;
1713 const ni_region_of_interest_t *roi = NULL;
1714 uint32_t self_size = 0;
1715
1716 roi = (const ni_region_of_interest_t *)aux_data->data;
1717 self_size = roi->self_size;
1718 if (!self_size || aux_data->size % self_size)
1719 {
1720 ni_log2(p_enc_ctx, NI_LOG_ERROR, "Invalid ni_region_of_interest_t.self_size, "
1721 "aux_data size %d self_size %u\n",
1722 aux_data->size, self_size);
1723 } else
1724 {
1725 int nb_roi = aux_data->size / (int)self_size;
1726
1727 // update ROI(s) if new/different from last one
1728 if (0 == p_enc_ctx->nb_rois || 0 == p_enc_ctx->roi_side_data_size ||
1729 !p_enc_ctx->av_rois || p_enc_ctx->nb_rois != nb_roi ||
1730 p_enc_ctx->roi_side_data_size != aux_data->size ||
1731 memcmp(p_enc_ctx->av_rois, aux_data->data, aux_data->size) != 0)
1732 {
1733 p_enc_ctx->roi_side_data_size = aux_data->size;
1734 p_enc_ctx->nb_rois = nb_roi;
1735
1736 free(p_enc_ctx->av_rois);
1737 p_enc_ctx->av_rois = malloc(aux_data->size);
1738 if (!p_enc_ctx->av_rois)
1739 {
1740 ni_log2(p_enc_ctx, NI_LOG_ERROR, "malloc ROI aux_data failed.\n");
1741 is_new_rois = 0;
1742 } else
1743 {
1744 memcpy(p_enc_ctx->av_rois, aux_data->data, aux_data->size);
1745 }
1746 } else
1747 {
1748 is_new_rois = 0;
1749 }
1750
1751 if (is_new_rois)
1752 {
1753 if (set_roi_map(p_enc_ctx, codec_format, aux_data, nb_roi,
1754 api_params->source_width,
1755 api_params->source_height,
1756 api_params->cfg_enc_params.rc.intra_qp))
1757 {
1758 ni_log2(p_enc_ctx, NI_LOG_ERROR, "set_roi_map failed\n");
1759 }
1760 }
1761 }
1762
1763 // ROI data in the frame
1764 p_enc_frame->roi_len = p_enc_ctx->roi_len;
1765 }
1766
1767 // when ROI is enabled, a QP map is always supplied with each frame, and
1768 // we use frame->roi_len value to: when 0, supply a zeroed map; when non-0,
1769 // supply the map stored in p_enc_ctx->roi_map.
1770 // - if ROI aux data is present, use it, otherwise:
1771 // - if cacheRoi, use map if exists, use 0 map otherwise
1772 // - if !cacheRoi, use 0 map
1773 // Note: the above excludes the demo modes which is handled separately in
1774 // application (e.g. nienc, xcoder)
1775 if (api_params->cfg_enc_params.roi_enable && !api_params->roi_demo_mode)
1776 {
1777 if (aux_data && p_enc_ctx->roi_map)
1778 {
1779 p_enc_frame->roi_len = p_enc_ctx->roi_len;
1780 } else
1781 {
1782 if (api_params->cacheRoi)
1783 {
1784 p_enc_frame->roi_len =
1785 (p_enc_ctx->roi_map ? p_enc_ctx->roi_len : 0);
1786 } else
1787 {
1788 p_enc_frame->roi_len = 0;
1789 }
1790 }
1791
1792 p_enc_frame->extra_data_len += p_enc_ctx->roi_len;
1793
1794 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_prep_aux_data: supply QP map, cacheRoi %d "
1795 "aux_data %d ctx->roi_map %d frame->roi_len %u ctx->roi_len %u\n",
1796 api_params->cacheRoi, aux_data != NULL,
1797 p_enc_ctx->roi_map != NULL, p_enc_frame->roi_len, p_enc_ctx->roi_len);
1798 }
1799
1800 // prep for NetInt long term reference frame support setting: when this has
1801 // been requested by both frame and API, API takes priority
1802 ni_long_term_ref_t ltr = {0};
1803 aux_data =
1805 if (aux_data)
1806 {
1807 ltr = *((ni_long_term_ref_t *)aux_data->data);
1808 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1809 "%s(): frame aux data LTR use_cur_src_as_ltr %u "
1810 "use_ltr %u\n",
1811 __func__, ltr.use_cur_src_as_long_term_pic,
1812 ltr.use_long_term_ref);
1813 }
1814
1815 if (p_enc_ctx->ltr_to_set.use_cur_src_as_long_term_pic > 0 ||
1816 p_enc_ctx->ltr_to_set.use_long_term_ref > 0)
1817 {
1818 ltr = p_enc_ctx->ltr_to_set;
1820 p_enc_ctx->ltr_to_set.use_long_term_ref = 0;
1821
1822 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1823 "%s(): frame API set LTR use_cur_src_as_ltr %u "
1824 "use_ltr %u\n",
1825 __func__, ltr.use_cur_src_as_long_term_pic,
1826 ltr.use_long_term_ref);
1827 }
1828
1829 if (ltr.use_cur_src_as_long_term_pic > 0 || ltr.use_long_term_ref > 0)
1830 {
1831 p_enc_frame->use_cur_src_as_long_term_pic =
1833 p_enc_frame->use_long_term_ref = ltr.use_long_term_ref;
1834 }
1835
1836 // prep for NetInt target max/min QP reconfiguration support: when max/min QP
1837 // setting has been requested by both frame and API, API takes priority
1838 ni_rc_min_max_qp qp_info = {0};
1839 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_MAX_MIN_QP);
1840 if (aux_data)
1841 {
1842 qp_info = *(ni_rc_min_max_qp *)aux_data->data;
1843 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
1844 "%s(): frame aux data qp info max/min I qp <%d %d> maxDeltaQp <%d> max/min PB qp <%d %d>",
1845 __func__, qp_info.maxQpI, qp_info.minQpI, qp_info.maxDeltaQp, qp_info.maxQpPB, qp_info.minQpPB);
1846 }
1847 if (qp_info.maxQpI > 0)
1848 {
1849 p_enc_ctx->enc_change_params->minQpI = qp_info.minQpI;
1850 p_enc_ctx->enc_change_params->maxQpI = qp_info.maxQpI;
1851 p_enc_ctx->enc_change_params->maxDeltaQp = qp_info.maxDeltaQp;
1852 p_enc_ctx->enc_change_params->minQpPB = qp_info.minQpPB;
1853 p_enc_ctx->enc_change_params->maxQpPB = qp_info.maxQpPB;
1854 p_enc_ctx->enc_change_params->enable_option |=
1856 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
1857 }
1858
1859 // prep for NetInt target bitrate reconfiguration support: when bitrate
1860 // setting has been requested by both frame and API, API takes priority
1861 int32_t bitrate = -1;
1862 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_BITRATE);
1863 if (aux_data)
1864 {
1865 bitrate = *((int32_t *)aux_data->data);
1866 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data bitrate %d\n", __func__,
1867 bitrate);
1868 }
1869
1870 if (p_enc_ctx->target_bitrate > 0)
1871 {
1872 bitrate = p_enc_ctx->target_bitrate;
1873 p_enc_ctx->target_bitrate = -1;
1874 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set bitrate %d\n", __func__, bitrate);
1875 }
1876
1877 if (bitrate > 0)
1878 {
1879 p_enc_ctx->enc_change_params->enable_option |=
1881
1882 p_enc_ctx->enc_change_params->bitRate = bitrate;
1883 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
1884
1885 // update last bitrate with reconfigured bitrate
1886 p_enc_ctx->last_bitrate = bitrate;
1887 ni_log2(p_enc_ctx, NI_LOG_INFO, "%s: bitrate %d updated for reconfig\n", __func__, bitrate);
1888 }
1889
1890 // prep for NetInt API force frame type
1891 if (p_enc_ctx->force_idr_frame)
1892 {
1893 p_enc_frame->force_key_frame = 1;
1894 p_enc_frame->ni_pict_type = PIC_TYPE_IDR;
1895
1896 p_enc_ctx->force_idr_frame = 0;
1897 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API force IDR frame\n", __func__);
1898 }
1899
1900 // prep for NetInt VUI reconfiguration support: when VUI HRD
1901 // setting has been requested by both frame and API, API takes priority
1902 ni_vui_hrd_t vui = {0};
1903 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_VUI);
1904 if (aux_data)
1905 {
1906 ni_vui_hrd_t *aux_vui_ptr = (ni_vui_hrd_t *)aux_data->data;
1907
1908 if (aux_vui_ptr->colorDescPresent < 0 || aux_vui_ptr->colorDescPresent > 1)
1909 {
1910 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid colorDescPresent in aux data %d\n",
1911 __func__, aux_vui_ptr->colorDescPresent);
1912 }
1913 else
1914 {
1915 vui.colorDescPresent = aux_vui_ptr->colorDescPresent;
1916 }
1917
1918 if((aux_vui_ptr->aspectRatioWidth > NI_MAX_ASPECTRATIO) || (aux_vui_ptr->aspectRatioHeight > NI_MAX_ASPECTRATIO))
1919 {
1920 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid aspect ratio in aux data %dx%d\n",
1921 __func__, aux_vui_ptr->aspectRatioWidth, aux_vui_ptr->aspectRatioHeight);
1922 }
1923 else
1924 {
1925 vui.colorDescPresent = aux_vui_ptr->colorDescPresent;
1926 vui.colorPrimaries = aux_vui_ptr->colorPrimaries;
1927 vui.colorTrc = aux_vui_ptr->colorTrc;
1928 vui.colorSpace = aux_vui_ptr->colorSpace;
1929 vui.aspectRatioWidth = aux_vui_ptr->aspectRatioWidth;
1930 vui.aspectRatioHeight = aux_vui_ptr->aspectRatioHeight;
1931 }
1932
1933 if (aux_vui_ptr->videoFullRange < 0 || aux_vui_ptr->videoFullRange > 1)
1934 {
1935 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): invalid videoFullRange in aux data %d\n",
1936 __func__, aux_vui_ptr->videoFullRange);
1937 }
1938 else
1939 {
1940 vui.videoFullRange = aux_vui_ptr->videoFullRange;
1941 }
1942 }
1943
1944 if (p_enc_ctx->vui.aspectRatioWidth > 0)
1945 {
1946 vui = p_enc_ctx->vui;
1947 p_enc_ctx->vui.colorDescPresent =
1948 p_enc_ctx->vui.colorPrimaries =
1949 p_enc_ctx->vui.colorTrc =
1950 p_enc_ctx->vui.colorSpace =
1951 p_enc_ctx->vui.aspectRatioWidth =
1952 p_enc_ctx->vui.aspectRatioHeight =
1953 p_enc_ctx->vui.videoFullRange = 0;
1954 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set VUI "
1955 "colorDescPresent %d colorPrimaries %d "
1956 "colorTrc %d colorSpace %d aspectRatioWidth %d "
1957 "aspectRatioHeight %d videoFullRange %d\n",
1958 __func__, vui.colorDescPresent,
1959 vui.colorPrimaries, vui.colorTrc,
1962 }
1963
1964 if (vui.aspectRatioWidth > 0)
1965 {
1966 p_enc_ctx->enc_change_params->enable_option |=
1968
1971 p_enc_ctx->enc_change_params->colorTrc = vui.colorTrc;
1972 p_enc_ctx->enc_change_params->colorSpace = vui.colorSpace;
1976 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
1977 }
1978
1979 // prep for NetInt long term reference interval reconfiguration support:
1980 // when LTR has been requested by both frame and API, API takes priority
1981 int32_t ltr_interval = -1;
1982 aux_data =
1984 if (aux_data)
1985 {
1986 ltr_interval = *((int32_t *)aux_data->data);
1987 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data LTR interval %d\n", __func__,
1988 ltr_interval);
1989 }
1990
1991 if (p_enc_ctx->ltr_interval > 0)
1992 {
1993 ltr_interval = p_enc_ctx->ltr_interval;
1994 p_enc_ctx->ltr_interval = -1;
1995 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set LTR interval %d\n", __func__,
1996 ltr_interval);
1997 }
1998
1999 if (ltr_interval > 0)
2000 {
2001 p_enc_ctx->enc_change_params->enable_option |=
2003
2004 p_enc_ctx->enc_change_params->ltrInterval = ltr_interval;
2005 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2006 }
2007
2008 // prep for NetInt target framerate reconfiguration support: when framerate
2009 // setting has been requested by both frame aux data and API, API takes priority
2010 ni_framerate_t framerate = {0};
2011 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_FRAMERATE);
2012 if (aux_data)
2013 {
2014 ni_framerate_t *aux_framerate_ptr = (ni_framerate_t *)aux_data->data;
2015 int32_t framerate_num = aux_framerate_ptr->framerate_num;
2016 int32_t framerate_denom = aux_framerate_ptr->framerate_denom;
2017 if ((framerate_num <= 0) || (framerate_denom <= 0))
2018 {
2019 ni_log2(p_enc_ctx, NI_LOG_ERROR,
2020 "ERROR: %s(): invalid framerate in aux data (%d/%d)\n",
2021 __func__, framerate_num, framerate_denom);
2022 } else
2023 {
2024 if ((framerate_num % framerate_denom) != 0)
2025 {
2026 uint32_t numUnitsInTick = 1000;
2027 framerate_num = framerate_num / framerate_denom;
2028 framerate_denom = (int32_t)(numUnitsInTick + 1);
2029 framerate_num += 1;
2030 framerate_num = (int32_t)(framerate_num * numUnitsInTick);
2031 } else
2032 {
2033 framerate_num = framerate_num / framerate_denom;
2034 framerate_denom = 1;
2035 }
2036 if (((framerate_num + framerate_denom - 1) / framerate_denom) >
2038 {
2039 ni_log2(p_enc_ctx, NI_LOG_ERROR,
2040 "ERROR: %s(): invalid framerate in aux data (%d/%d)\n",
2041 __func__, aux_framerate_ptr->framerate_num,
2042 aux_framerate_ptr->framerate_denom);
2043 } else
2044 {
2045 framerate.framerate_num = framerate_num;
2046 framerate.framerate_denom = framerate_denom;
2047 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data framerate (%d/%d)\n",
2048 __func__, framerate_num, framerate_denom);
2049 }
2050 }
2051 }
2052
2053 if (p_enc_ctx->framerate.framerate_num > 0)
2054 {
2055 framerate = p_enc_ctx->framerate;
2056 p_enc_ctx->framerate.framerate_num =
2057 p_enc_ctx->framerate.framerate_denom = 0;
2058 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set framerate (%d/%d)\n", __func__,
2059 framerate.framerate_num, framerate.framerate_denom);
2060 }
2061
2062 if (framerate.framerate_num > 0)
2063 {
2064 p_enc_ctx->enc_change_params->enable_option |=
2066
2067 p_enc_ctx->enc_change_params->frameRateNum = framerate.framerate_num;
2068 p_enc_ctx->enc_change_params->frameRateDenom =
2069 framerate.framerate_denom;
2070 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2071
2072 // update last framerate with reconfigured framerate
2073 p_enc_ctx->last_framerate.framerate_num = framerate.framerate_num;
2074 p_enc_ctx->last_framerate.framerate_denom = framerate.framerate_denom;
2075 ni_log2(p_enc_ctx, NI_LOG_INFO, "%s: framerate num %d denom %d updated for reconfig\n",
2076 __func__, framerate.framerate_num, framerate.framerate_denom);
2077 }
2078
2079 // prep for NetInt frame reference invalidation support: when this setting
2080 // has been requested by both frame and API, API takes priority
2081 int32_t frame_num = -1;
2082 aux_data =
2084 if (aux_data)
2085 {
2086 frame_num = *((int32_t *)aux_data->data);
2087 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data frame ref invalid %d\n",
2088 __func__, frame_num);
2089 }
2090
2091 if (p_enc_ctx->ltr_frame_ref_invalid > 0)
2092 {
2093 frame_num = p_enc_ctx->ltr_frame_ref_invalid;
2094 p_enc_ctx->ltr_frame_ref_invalid = -1;
2095 ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s(): API set frame ref invalid %d\n", __func__,
2096 frame_num);
2097 }
2098
2099 if (frame_num >= 0)
2100 {
2101 p_enc_ctx->enc_change_params->enable_option |=
2103
2104 p_enc_ctx->enc_change_params->invalidFrameNum = frame_num;
2105 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2106 }
2107
2108 // prep for alternative preferred transfer characteristics SEI
2110 should_send_sei_with_frame)
2111 {
2112 if (NI_CODEC_FORMAT_H264 == codec_format)
2113 {
2114 p_enc_frame->preferred_characteristics_data_len = 9;
2115 } else
2116 {
2117 p_enc_frame->preferred_characteristics_data_len = 10;
2118 }
2119
2121 (uint8_t)
2123 p_enc_frame->sei_total_len +=
2125 }
2126
2127 // prep for NetInt maxFrameSize reconfiguration support: when maxFrameSize
2128 // setting has been requested by both frame aux data and API, API takes priority
2129 int32_t max_frame_size = 0;
2131 if (aux_data)
2132 {
2133 max_frame_size = *((int32_t *)aux_data->data);
2134 uint32_t maxFrameSize = (uint32_t)max_frame_size / 2000;
2135 uint32_t min_maxFrameSize;
2136 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data max_frame_size %d\n", __func__,
2137 max_frame_size);
2138
2139 if (!api_params->low_delay_mode)
2140 {
2141 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): max_frame_size %d is valid only when lowDelay mode is enabled\n",
2142 __func__, max_frame_size);
2143 max_frame_size = 0;
2144 }
2145 else
2146 {
2147 int32_t tmp_bitrate, tmp_framerate_num, tmp_framerate_denom;
2148 tmp_bitrate = (p_enc_ctx->enc_change_params->bitRate > 0) ? p_enc_ctx->enc_change_params->bitRate : api_params->bitrate;
2149
2150 if ((p_enc_ctx->enc_change_params->frameRateNum > 0) && (p_enc_ctx->enc_change_params->frameRateDenom > 0))
2151 {
2152 tmp_framerate_num = p_enc_ctx->enc_change_params->frameRateNum;
2153 tmp_framerate_denom = p_enc_ctx->enc_change_params->frameRateDenom;
2154 }
2155 else
2156 {
2157 tmp_framerate_num = (int32_t)api_params->fps_number;
2158 tmp_framerate_denom = (int32_t)api_params->fps_denominator;
2159 }
2160
2161 min_maxFrameSize = (((uint32_t)tmp_bitrate / tmp_framerate_num * tmp_framerate_denom) / 8) / 2000;
2162
2163 if (maxFrameSize < min_maxFrameSize)
2164 {
2165 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): max_frame_size %d is too small (invalid)\n",
2166 __func__, max_frame_size);
2167 max_frame_size = 0;
2168 }
2169
2170 if (max_frame_size > NI_MAX_FRAME_SIZE) {
2171 max_frame_size = NI_MAX_FRAME_SIZE;
2172 }
2173 }
2174 }
2175
2176 if (p_enc_ctx->max_frame_size > 0)
2177 {
2178 max_frame_size = p_enc_ctx->max_frame_size;
2179 p_enc_ctx->max_frame_size = 0;
2180 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set max_frame_size %d\n", __func__, max_frame_size);
2181 }
2182
2183 if (max_frame_size > 0)
2184 {
2185 p_enc_ctx->enc_change_params->enable_option |=
2187
2188 p_enc_ctx->enc_change_params->maxFrameSize = (uint16_t)(max_frame_size / 2000);
2189 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2190 }
2191
2192 // prep for NetInt crf reconfiguration support: when crf
2193 // setting has been requested by both frame aux data and API, API takes priority
2194 float crf = -1.0f;
2195 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_CRF);
2196 if (aux_data)
2197 {
2198 crf = (float)(*((int32_t *)aux_data->data));
2199 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data crf %d\n", __func__,
2200 crf);
2201
2202 if (api_params->cfg_enc_params.crf < 0)
2203 {
2204 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): reconfigure crf value %d is valid only in CRF mode\n",
2205 __func__, crf);
2206 crf = -1;
2207 }
2208 else
2209 {
2210 if (crf < 0 || crf > 51)
2211 {
2212 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): crf value %d is invalid (valid range in [0..51])\n",
2213 __func__, crf);
2214 crf = -1;
2215 }
2216 }
2217 }
2218 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_CRF_FLOAT);
2219 if (aux_data)
2220 {
2221 crf = *((float *)aux_data->data);
2222 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data crf %f\n", __func__,
2223 crf);
2224
2225 if (api_params->cfg_enc_params.crfFloat < 0)
2226 {
2227 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): reconfigure crf value %f is valid only in CRF mode\n",
2228 __func__, crf);
2229 crf = -1;
2230 }
2231 else
2232 {
2233 if (crf < 0 || crf > 51)
2234 {
2235 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s(): crf value %f is invalid (valid range in [0..51])\n",
2236 __func__, crf);
2237 crf = -1;
2238 }
2239 }
2240 }
2241
2242 if (p_enc_ctx->reconfig_crf >= 0 || p_enc_ctx->reconfig_crf_decimal > 0)
2243 {
2244 crf = (float)(p_enc_ctx->reconfig_crf +
2245 (float)p_enc_ctx->reconfig_crf_decimal / 100.0);
2246 p_enc_ctx->reconfig_crf = -1;
2247 p_enc_ctx->reconfig_crf_decimal = 0;
2248 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_crf %f\n", __func__, crf);
2249 }
2250
2251 if (crf >= 0)
2252 {
2253 p_enc_ctx->enc_change_params->enable_option |=
2255
2256 p_enc_ctx->enc_change_params->crf = (uint8_t)crf;
2257 p_enc_ctx->enc_change_params->crfDecimal =
2258 (uint8_t)((crf - (float)p_enc_ctx->enc_change_params->crf) * 100);
2259 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2260 }
2261
2262 int32_t vbvMaxRate = 0;
2264 if (aux_data)
2265 {
2266 vbvMaxRate = *((int32_t *)aux_data->data);
2267 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data vbvMaxRate %d\n", __func__,
2268 vbvMaxRate);
2269 }
2270
2271 if (p_enc_ctx->reconfig_vbv_max_rate > 0)
2272 {
2273 vbvMaxRate = p_enc_ctx->reconfig_vbv_max_rate;
2274 p_enc_ctx->reconfig_vbv_max_rate = 0;
2275 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_vbv_max_rate %d\n", __func__, vbvMaxRate);
2276 }
2277
2278 if (vbvMaxRate)
2279 {
2280 p_enc_ctx->enc_change_params->enable_option |=
2282
2283 p_enc_ctx->enc_change_params->vbvMaxRate = vbvMaxRate;
2284 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2285 }
2286
2287 int32_t vbvBufferSize = 0;
2289 if (aux_data)
2290 {
2291 vbvBufferSize = *((int32_t *)aux_data->data);
2292 if ((vbvBufferSize < 10 && vbvBufferSize != 0) || vbvBufferSize > 3000)
2293 {
2294 ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s(): invalid frame aux data vbvBufferSize %d\n", __func__,
2295 vbvBufferSize);
2296 vbvBufferSize = 0;
2297 }
2298 else
2299 {
2300 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data vbvBufferSize %d\n", __func__,
2301 vbvBufferSize);
2302 }
2303 }
2304
2305 if (p_enc_ctx->reconfig_vbv_buffer_size > 0)
2306 {
2307 vbvBufferSize = p_enc_ctx->reconfig_vbv_buffer_size;
2308 p_enc_ctx->reconfig_vbv_buffer_size = 0;
2309 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_vbv_max_rate %d\n", __func__, vbvBufferSize);
2310 }
2311
2312 if (vbvBufferSize)
2313 {
2314 p_enc_ctx->enc_change_params->enable_option |=
2316
2317 p_enc_ctx->enc_change_params->vbvBufferSize = vbvBufferSize;
2318 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2319 }
2320
2321 int16_t sliceArg = 0;
2322 aux_data = ni_frame_get_aux_data(p_dec_frame, NI_FRAME_AUX_DATA_SLICE_ARG);
2323 if (aux_data)
2324 {
2325 sliceArg = *((int16_t *)aux_data->data);
2326 ni_encoder_cfg_params_t *p_enc = &api_params->cfg_enc_params;
2327 if (p_enc->slice_mode == 0)
2328 {
2329 ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s():not support to reconfig slice_arg when slice_mode disable.\n",
2330 __func__);
2331 sliceArg = 0;
2332 }
2333 if (NI_CODEC_FORMAT_JPEG == p_enc_ctx->codec_format || NI_CODEC_FORMAT_AV1 == p_enc_ctx->codec_format)
2334 {
2335 ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s():sliceArg is only supported for H.264 or H.265.\n",
2336 __func__);
2337 sliceArg = 0;
2338 }
2339 int ctu_mb_size = (NI_CODEC_FORMAT_H264 == p_enc_ctx->codec_format) ? 16 : 64;
2340 int max_num_ctu_mb_row = (api_params->source_height + ctu_mb_size - 1) / ctu_mb_size;
2341 if (sliceArg < 1 || sliceArg > max_num_ctu_mb_row)
2342 {
2343 ni_log2(p_enc_ctx, NI_LOG_ERROR, "%s(): invalid frame aux data sliceArg %d\n", __func__,
2344 sliceArg);
2345 sliceArg = 0;
2346 }
2347 else
2348 {
2349 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): frame aux data sliceArg %d\n", __func__,
2350 sliceArg);
2351 }
2352 }
2353
2354 if (p_enc_ctx->reconfig_slice_arg > 0)
2355 {
2356 sliceArg = p_enc_ctx->reconfig_slice_arg;
2357 p_enc_ctx->reconfig_slice_arg = 0;
2358 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "%s(): API set reconfig_slice_arg %d\n", __func__, sliceArg);
2359 }
2360
2361 if (sliceArg)
2362 {
2363 if (sliceArg > NI_MAX_SLICE_SIZE) {
2364 ni_log2(p_enc_ctx, NI_LOG_INFO, "%s(): slice arg > NI_MAX_SLICE_SIZE, change from %d to %d\n",
2365 __func__, sliceArg, NI_MAX_SLICE_SIZE);
2366 sliceArg = NI_MAX_SLICE_SIZE;
2367 }
2368 p_enc_ctx->enc_change_params->enable_option |=
2370
2371 p_enc_ctx->enc_change_params->sliceArg = sliceArg;
2372 p_enc_frame->reconf_len = sizeof(ni_encoder_change_params_t);
2373 }
2374}
2375
2376/*!*****************************************************************************
2377 * \brief Copy auxiliary data that should be sent together with this frame
2378 * to encoder.
2379 *
2380 * \param[in] p_enc_ctx encoder session context
2381 * \param[out] p_enc_frame frame to be sent to encoder
2382 * \param[in] p_dec_frame frame returned by decoder
2383 * \param[in] mdcv_data SEI for HDR mastering display color volume info
2384 * \param[in] cll_data SEI for HDR content light level info
2385 * \param[in] cc_data SEI for close caption
2386 * \param[in] udu_data SEI for User data unregistered
2387 * \param[in] hdrp_data SEI for HDR10+
2388 * \param[in] is_hwframe, must be 0 (sw frame) or 1 (hw frame)
2389 * \param[in] is_semiplanar, must be 1 (semiplanar frame) or 0 (not)
2390 *
2391 * \return NONE
2392 ******************************************************************************/
2394 ni_frame_t *p_enc_frame, ni_frame_t *p_dec_frame,
2395 ni_codec_format_t codec_format,
2396 const uint8_t *mdcv_data, const uint8_t *cll_data,
2397 const uint8_t *cc_data, const uint8_t *udu_data,
2398 const uint8_t *hdrp_data, int is_hwframe,
2399 int is_semiplanar)
2400{
2401 (void)p_dec_frame;
2402 ni_xcoder_params_t *api_params =
2404
2405 // fill in extra data (skipping meta data header)
2406 if (is_hwframe != 0 && is_hwframe != 1 && is_semiplanar != 0 &&
2407 is_semiplanar != 1)
2408 {
2409 ni_log2(p_enc_ctx, NI_LOG_ERROR,
2410 "ni_enc_copy_aux_data: error, illegal hwframe or nv12frame\n");
2411 return;
2412 }
2413
2414 uint32_t frame_metadata_size = NI_APP_ENC_FRAME_META_DATA_SIZE;
2416 "6Q") < 0)
2417 {
2419 }
2421 "6rc") < 0)
2422 {
2424 }
2425
2426
2427 uint8_t *dst = (uint8_t *)p_enc_frame->p_data[2 + is_hwframe] +
2428 p_enc_frame->data_len[2 + is_hwframe] + frame_metadata_size;
2429
2430 if (!is_hwframe)
2431 {
2432 dst = (uint8_t *)p_enc_frame->p_data[2 - is_semiplanar] +
2433 p_enc_frame->data_len[2 - is_semiplanar] +
2434 frame_metadata_size;
2435 }
2436
2437 // Separate metadata buffer (not contiguous with YUV buffer)
2438 if (p_enc_frame->separate_metadata)
2439 {
2440 dst = p_enc_frame->p_metadata_buffer + frame_metadata_size;
2441 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: p_metadata_buffer %p frame_metadata_size %u dst %p\n",
2442 p_enc_frame->p_metadata_buffer, frame_metadata_size, dst);
2443 }
2444
2445 // fill in reconfig data if enabled; even if it's disabled, keep the space
2446 // for it if SEI or ROI is present;
2447 if (p_enc_frame->reconf_len || api_params->cfg_enc_params.roi_enable ||
2448 p_enc_frame->sei_total_len)
2449 {
2450 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: keep reconfig space: %"
2451 PRId64 " to %p\n", sizeof(ni_encoder_change_params_t), dst);
2452
2453 memset(dst, 0, sizeof(ni_encoder_change_params_t));
2454
2455 if (p_enc_frame->reconf_len && p_enc_ctx->enc_change_params)
2456 {
2457 memcpy(dst, p_enc_ctx->enc_change_params, p_enc_frame->reconf_len);
2458 }
2459
2460 dst += sizeof(ni_encoder_change_params_t);
2461 }
2462
2463 // fill in ROI map, if ROI is enabled; the ROI map could be:
2464 // - a zeroed one, e.g. in the case of no any ROI specified yet at session
2465 // start, or
2466 // - one generated by ROI auxiliary data coming with the frame, or
2467 // - a hardcoded one created in nienc/xcoder by ROI demo modes
2468 if (api_params->cfg_enc_params.roi_enable)
2469 {
2470 if (p_enc_frame->roi_len && p_enc_ctx->roi_map)
2471 {
2472 memcpy(dst, p_enc_ctx->roi_map, p_enc_frame->roi_len);
2473 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: ROI size: %u to %p\n",
2474 p_enc_frame->roi_len, dst);
2475
2476 } else
2477 {
2478 memset(dst, 0, p_enc_ctx->roi_len);
2479 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: zeroed ROI size: %u to %p\n",
2480 p_enc_ctx->roi_len, dst);
2481 }
2482 // for QUADRA, when ROI enabled, requires ROI map included in input buffer and data transferred for every frame
2483 dst += p_enc_ctx->roi_len;
2484 // reset frame ROI len to the actual map size
2485 p_enc_frame->roi_len = p_enc_ctx->roi_len;
2486 }
2487
2488 // HDR SEI: mastering display color volume
2490 {
2491 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: HDR SEI mdcv size: %u to %p\n",
2492 p_enc_frame->sei_hdr_mastering_display_color_vol_len, dst);
2493 memcpy(dst, mdcv_data,
2495 dst += p_enc_frame->sei_hdr_mastering_display_color_vol_len;
2496 }
2497
2498 // HDR SEI: content light level info
2499 if (p_enc_frame->sei_hdr_content_light_level_info_len)
2500 {
2501 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: HDR SEI cll size: %u to %p\n",
2502 p_enc_frame->sei_hdr_content_light_level_info_len, dst);
2503
2504 memcpy(dst, cll_data,
2506 dst += p_enc_frame->sei_hdr_content_light_level_info_len;
2507 }
2508
2509 // HLG SEI: preferred characteristics
2510 if (p_enc_frame->preferred_characteristics_data_len)
2511 {
2512 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: preferred characteristics size: %u to %p\n",
2513 p_enc_frame->preferred_characteristics_data_len, dst);
2514
2515 dst[0] = dst[1] = dst[2] = 0;
2516 dst[3] = 1;
2517 if (NI_CODEC_FORMAT_H265 == codec_format)
2518 {
2519 dst[4] = 0x4e;
2520 dst[5] = 1;
2521 dst[6] = 0x93; // payload type=147
2522 dst[7] = 1; // payload size=1
2523 dst += 8;
2524 } else
2525 {
2526 dst[4] = 0x6;
2527 dst[5] = 0x93; // payload type=147
2528 dst[6] = 1; // payload size=1
2529 dst += 7;
2530 }
2531 *dst = p_enc_ctx->preferred_characteristics_data;
2532 dst++;
2533 *dst = 0x80;
2534 dst++;
2535 }
2536
2537 // close caption
2538 if (p_enc_frame->sei_cc_len)
2539 {
2540 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: close caption size: %u to %p\n",
2541 p_enc_frame->sei_cc_len, dst);
2542
2543 memcpy(dst, cc_data, p_enc_frame->sei_cc_len);
2544 dst += p_enc_frame->sei_cc_len;
2545 }
2546
2547 // HDR10+
2548 if (p_enc_frame->sei_hdr_plus_len)
2549 {
2550 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: HDR10+ size: %u to %p\n",
2551 p_enc_frame->sei_hdr_plus_len, dst);
2552
2553 memcpy(dst, hdrp_data, p_enc_frame->sei_hdr_plus_len);
2554 dst += p_enc_frame->sei_hdr_plus_len;
2555 }
2556
2557 // User data unregistered SEI
2558 if (p_enc_frame->sei_user_data_unreg_len)
2559 {
2560 ni_log2(p_enc_ctx, NI_LOG_DEBUG, "ni_enc_copy_aux_data: UDU size: %u to %p\n",
2561 p_enc_frame->sei_user_data_unreg_len, dst);
2562 memcpy(dst, udu_data, p_enc_frame->sei_user_data_unreg_len);
2563 //dst += p_enc_frame->sei_user_data_unreg_len;
2564 }
2565}
2566
2567/*!*****************************************************************************
2568 * \brief Insert timecode data into picture timing SEI (H264) or time code SEI (H265)
2569 *
2570 * \note This function must be callled after all other aux data has been processed by
2571 * ni_enc_prep_aux_data and ni_enc_copy_aux_data. Otherwise the timecode SEI data
2572 * might be overwritten
2573 *
2574 * \param[in] p_enc_ctx encoder session context
2575 * \param[out] p_enc_frame frame to be sent to encoder
2576 * \param[in] p_timecode the timecode data to be written along with the frame
2577 *
2578 * \return NI_RETCODE_SUCCESS on success, NI_RETCODE_FAILURE on failure
2579 ******************************************************************************/
2581 ni_timecode_t *p_timecode)
2582{
2583 uint8_t timecode_data[NI_MAX_SEI_DATA];
2584 uint8_t *dst = timecode_data;
2585 uint8_t *extradata_dst;
2587 uint32_t header_len, payload_len, total_len;
2588 int emu_bytes_inserted, is_hwframe, is_semiplanar;
2589
2590 if (!p_enc_ctx || !p_enc_frame || !p_timecode) {
2591 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s received NULL parameter\n", __func__);
2592 return NI_RETCODE_FAILURE;
2593 }
2594
2595 if (p_enc_ctx->codec_format != NI_CODEC_FORMAT_H264 && p_enc_ctx->codec_format != NI_CODEC_FORMAT_H265) {
2596 ni_log2(p_enc_ctx, NI_LOG_ERROR, "ERROR: %s insertion of timecode in SEI is only supported on H264 and H265 encoder\n", __func__);
2597 return NI_RETCODE_FAILURE;
2598 }
2599
2600 is_hwframe = p_enc_ctx->hw_action != NI_CODEC_HW_NONE;
2601 is_semiplanar = p_enc_ctx->pixel_format == NI_PIX_FMT_NV12 ||
2602 p_enc_ctx->pixel_format == NI_PIX_FMT_P010LE;
2603 extradata_dst = (uint8_t *)p_enc_frame->p_data[2 + is_hwframe] +
2604 p_enc_frame->data_len[2 + is_hwframe] + p_enc_frame->extra_data_len;
2605 if (!is_hwframe)
2606 {
2607 extradata_dst = (uint8_t *)p_enc_frame->p_data[2 - is_semiplanar] +
2608 p_enc_frame->data_len[2 - is_semiplanar] + p_enc_frame->extra_data_len;
2609 }
2610
2611 // separate metadata buffer (not contiguous with YUV buffer)
2612 if (p_enc_frame->separate_metadata)
2613 {
2614 extradata_dst = p_enc_frame->p_metadata_buffer + p_enc_frame->extra_data_len;
2615 }
2616
2617 // H264 + hrdEnable=1 path: FW generates its own H264 picture timing SEI
2618 // that includes timecode. Instead of formatting a second (conflicting) SEI
2619 // NAL unit on the host side, append the raw timecode struct to the end of
2620 // the frame's auxiliary data buffer so the FW can read it and override the
2621 // timecode it writes into its picture timing SEI.
2622 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264 &&
2623 p_enc_ctx->p_session_config &&
2624 ((ni_xcoder_params_t *)p_enc_ctx->p_session_config)->cfg_enc_params.hrdEnable)
2625 {
2626 ni_timecode_raw_t raw_tc;
2627
2628 // Reject the request if old FW is used to avoid sending the raw timecode
2629 // data to old FW which it doesn't know how to interpret
2631 (char *)&p_enc_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX],
2632 "6t9") < 0)
2633 {
2634 ni_log2(p_enc_ctx, NI_LOG_ERROR,
2635 "ERROR: %s timecode injection for H264 hrdEnable=1 case is not "
2636 "supported on FW API version < 6t9\n", __func__);
2637 return NI_RETCODE_FAILURE;
2638 }
2639
2640 // Fail if extra timecode data will make total SEI length exceed limit
2641 if (p_enc_frame->sei_total_len + sizeof(ni_timecode_raw_t) > NI_ENC_MAX_SEI_BUF_SIZE)
2642 {
2643 ni_log2(p_enc_ctx, NI_LOG_ERROR,
2644 "ERROR: %s cannot insert timecode data because current sei total "
2645 "length %u + timecode data len %u exceeds maximum sei size %u\n",
2646 __func__, p_enc_frame->sei_total_len, sizeof(ni_timecode_raw_t),
2648 return NI_RETCODE_FAILURE;
2649 }
2650
2651 // fill the raw struct from ni_timecode_t fields
2652 raw_tc.nuit_field_based_flag = p_timecode->nuit_field_based_flag;
2653 raw_tc.counting_type = p_timecode->counting_type;
2654 raw_tc.full_timestamp_flag = p_timecode->full_timestamp_flag;
2655 raw_tc.discontinuity_flag = p_timecode->discontinuity_flag;
2656 raw_tc.cnt_dropped_flag = p_timecode->cnt_dropped_flag;
2657 raw_tc.n_frames = p_timecode->n_frames;
2658 raw_tc.seconds_flag = p_timecode->seconds_flag;
2659 raw_tc.seconds_value = p_timecode->seconds_value;
2660 raw_tc.minutes_flag = p_timecode->minutes_flag;
2661 raw_tc.minutes_value = p_timecode->minutes_value;
2662 raw_tc.hours_flag = p_timecode->hours_flag;
2663 raw_tc.hours_value = p_timecode->hours_value;
2664 raw_tc.time_offset_length = p_timecode->time_offset_length;
2665 raw_tc.time_offset_value = p_timecode->time_offset_value;
2666
2667 memcpy(extradata_dst, &raw_tc, sizeof(raw_tc));
2668
2669 // Set the flag to indicate that raw timecode is present,
2670 // ni_encoder_session_write will write this to the metadata header
2671 p_enc_frame->timecode_present = 1;
2672
2673 // Only advance extra_data_len (not sei_total_len) so the raw timecode is not
2674 // treated as part of the external SEI that's directly written to the output stream
2675 p_enc_frame->extra_data_len += sizeof(ni_timecode_raw_t);
2676
2677 ni_log2(p_enc_ctx, NI_LOG_DEBUG,
2678 "%s: H264 hrdEnable=1 path - appended %zu-byte raw timecode struct "
2679 "to frame buffer (extra_data_len=%u)\n",
2680 __func__, sizeof(ni_timecode_raw_t), p_enc_frame->extra_data_len);
2681
2682 return NI_RETCODE_SUCCESS;
2683 }
2684
2686
2687 // NAL start code
2688 ni_bs_writer_put(&pb, 0x00, 8);
2689 ni_bs_writer_put(&pb, 0x00, 8);
2690 ni_bs_writer_put(&pb, 0x00, 8);
2691 ni_bs_writer_put(&pb, 0x01, 8);
2692
2693 // NAL type: SEI
2694 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2695 ni_bs_writer_put(&pb, 0x06, 8);
2696 } else {
2697 ni_bs_writer_put(&pb, 0x4e, 8);
2698 ni_bs_writer_put(&pb, 0x01, 8);
2699 }
2700
2701 // SEI type: picture timing (1) for H264, time code (136) for H265
2702 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2703 ni_bs_writer_put(&pb, 0x01, 8);
2704 header_len = 7;
2705 } else {
2706 ni_bs_writer_put(&pb, 0x88, 8);
2707 header_len = 8;
2708 }
2709
2710 // SEI payload size, to be set later
2711 ni_bs_writer_put(&pb, 0x00, 8);
2712
2713 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2714 ni_bs_writer_put(&pb, 0x0, 4); // pic_struct, always 0 (progressive)
2715 } else {
2716 ni_bs_writer_put(&pb, 0x1, 2); // num_clock_ts, only support inserting 1
2717 }
2718
2719 // actual timestamp data below, retrieve the values from ni_timecode_t passed in
2720 ni_bs_writer_put(&pb, 0x1, 1); // clock_timestamp_flag = 1
2721 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2722 ni_bs_writer_put(&pb, 0x0, 2); // ct_type, always 0 (progressive)
2723 }
2724 ni_bs_writer_put(&pb, p_timecode->nuit_field_based_flag, 1);
2725 ni_bs_writer_put(&pb, p_timecode->counting_type, 5);
2726 ni_bs_writer_put(&pb, p_timecode->full_timestamp_flag, 1);
2727 ni_bs_writer_put(&pb, p_timecode->discontinuity_flag, 1);
2728 ni_bs_writer_put(&pb, p_timecode->cnt_dropped_flag, 1);
2729 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2730 ni_bs_writer_put(&pb, p_timecode->n_frames, 8);
2731 } else {
2732 ni_bs_writer_put(&pb, p_timecode->n_frames, 9);
2733 }
2734 if (p_timecode->full_timestamp_flag) {
2735 ni_bs_writer_put(&pb, p_timecode->seconds_value, 6);
2736 ni_bs_writer_put(&pb, p_timecode->minutes_value, 6);
2737 ni_bs_writer_put(&pb, p_timecode->hours_value, 5);
2738 } else {
2739 ni_bs_writer_put(&pb, p_timecode->seconds_flag, 1);
2740 if (p_timecode->seconds_flag) {
2741 ni_bs_writer_put(&pb, p_timecode->seconds_value, 6);
2742 ni_bs_writer_put(&pb, p_timecode->minutes_flag, 1);
2743 if (p_timecode->minutes_flag) {
2744 ni_bs_writer_put(&pb, p_timecode->minutes_value, 6);
2745 ni_bs_writer_put(&pb, p_timecode->hours_flag, 1);
2746 if (p_timecode->hours_flag) {
2747 ni_bs_writer_put(&pb, p_timecode->hours_value, 5);
2748 }
2749 }
2750 }
2751 }
2752 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H265) {
2753 ni_bs_writer_put(&pb, p_timecode->time_offset_length, 5);
2754 if (p_timecode->time_offset_length) {
2755 ni_bs_writer_put(&pb, p_timecode->time_offset_value, p_timecode->time_offset_length);
2756 }
2757 } else {
2758 // for H264, time_offset_length is stored in HRD parameters in VUI, which can only be set
2759 // in the FW when HRD is enabled, so we assume that it is not present, in which case it
2760 // should be intepreted as 24 by default
2761 ni_bs_writer_put(&pb, p_timecode->time_offset_value, 24);
2762 }
2763
2764 ni_bs_writer_put(&pb, 1, 1);
2766 payload_len = (uint32_t)((ni_bs_writer_tell(&pb) + 7) / 8) - header_len;
2767 ni_bs_writer_copy(dst, &pb);
2768 ni_bs_writer_clear(&pb);
2769
2770 // set the SEI payload size
2771 if (p_enc_ctx->codec_format == NI_CODEC_FORMAT_H264) {
2772 dst[6] = payload_len;
2773 } else {
2774 dst[7] = payload_len;
2775 }
2776 dst += header_len;
2777
2778 // insert emulation prevention bytes to the SEI payload data and write trailing bits
2779 emu_bytes_inserted = ni_insert_emulation_prevent_bytes(dst, (int)payload_len);
2780 dst += payload_len + emu_bytes_inserted;
2781 *dst = 0x80;
2782
2783 // total size of the timecode_data buffer to be copied
2784 total_len = header_len + payload_len + emu_bytes_inserted + 1;
2785
2786 // Fail if extra SEI data will make total SEI length exceed limit
2787 if (p_enc_frame->sei_total_len + total_len > NI_ENC_MAX_SEI_BUF_SIZE)
2788 {
2789 ni_log2(p_enc_ctx, NI_LOG_ERROR,
2790 "ERROR: %s cannot insert timecode data because current sei total length %u "
2791 "+ pic_timing/timecode SEI length %u exceeds maximum sei size %u\n",
2792 __func__, p_enc_frame->sei_total_len, total_len, NI_ENC_MAX_SEI_BUF_SIZE);
2793 return NI_RETCODE_FAILURE;
2794 }
2795
2796 // copy formatted SEI NAL unit data to the proper buffer
2797 memcpy(extradata_dst, timecode_data, total_len);
2798
2799 // finally, update the relevant data size counters in ni_frame_t
2800 p_enc_frame->sei_total_len += total_len;
2801 p_enc_frame->extra_data_len += total_len;
2802
2803 return NI_RETCODE_SUCCESS;
2804}
2805
2806/*!*****************************************************************************
2807 * \brief Send an input data frame to the encoder with YUV data given in
2808 * the inputs.
2809 *
2810 * For ideal performance memory should be 4k aligned. If it is not 4K aligned
2811 * then a temporary 4k aligned memory will be used to copy data to and from
2812 * when writing and reading. This will negatively impact performance.
2813 *
2814 * Any metadata to be sent with the frame should be attached to p_enc_frame
2815 * as aux data (e.g. using ni_frame_new_aux_data()).
2816 *
2817 * \param[in] p_ctx Encoder session context
2818 * \param[in] p_enc_frame Struct holding information about the frame
2819 * to be sent to the encoder
2820 * \param[in] p_yuv_buffer Caller allocated buffer holding YUV data
2821 * for the frame
2822 *
2823 * \return On success
2824 * Total number of bytes written
2825 * On failure
2826 * NI_RETCODE_INVALID_PARAM
2827 * NI_RETCODE_ERROR_MEM_ALOC
2828 * NI_RETCODE_ERROR_NVME_CMD_FAILED
2829 * NI_RETCODE_ERROR_INVALID_SESSION
2830 *****************************************************************************/
2832 ni_frame_t *p_enc_frame, uint8_t *p_yuv_buffer)
2833{
2834 int frame_width;
2835 int frame_height;
2836 bool need_copy = true;
2837 ni_xcoder_params_t *p_param;
2839 bool alignment_2pass_wa = false;
2840 int is_hwframe;
2841
2842 if (!p_ctx || !p_enc_frame)
2843 {
2844 ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s passed parameters are null, return\n",
2845 __func__);
2847 }
2848
2849 if (!p_yuv_buffer)
2850 {
2851 // send EOS
2852 p_enc_frame->end_of_stream = 1;
2853 goto send_frame;
2854 }
2855
2856 if (((uintptr_t)p_yuv_buffer) % NI_MEM_PAGE_ALIGNMENT)
2857 {
2858 ni_log2(p_ctx, NI_LOG_INFO, "WARNING: %s passed buffer ptr %p is not 4k aligned\n",
2859 __func__, p_yuv_buffer);
2860
2861 }
2862
2863 is_hwframe = p_ctx->hw_action != NI_CODEC_HW_NONE;
2864 frame_width = (int)p_enc_frame->video_width;
2865 frame_height = (int)p_enc_frame->video_height;
2866 p_param = (ni_xcoder_params_t *)p_ctx->p_session_config;
2867
2868 // extra data starts with metadata header
2870
2871 if (!p_enc_frame->start_of_stream &&
2872 (p_enc_frame->video_width != p_ctx->actual_video_width ||
2873 p_enc_frame->video_height != p_ctx->active_video_height ||
2874 p_enc_frame->pixel_format != p_ctx->pixel_format))
2875 {
2876 ni_log2(p_ctx, NI_LOG_INFO,
2877 "%s: resolution change %dx%d -> %dx%d "
2878 "or pixel format change %d -> %d\n",
2879 __func__, p_ctx->actual_video_width, p_ctx->active_video_height,
2880 p_enc_frame->video_width, p_enc_frame->video_height,
2881 p_ctx->pixel_format, p_enc_frame->pixel_format);
2882
2883 // change run state
2885
2886 ni_log2(p_ctx, NI_LOG_DEBUG, "%s: session_run_state change to %d \n", __func__,
2887 p_ctx->session_run_state);
2888
2889 // send EOS
2890 p_enc_frame->end_of_stream = 1;
2891 goto send_frame;
2892 }
2893
2894 // ROI demo mode takes higher priority over aux data
2895 // Note: when ROI demo modes enabled, supply ROI map for the specified range
2896 // frames, and 0 map for others
2897 if (p_param->roi_demo_mode && p_param->cfg_enc_params.roi_enable)
2898 {
2899 if (p_ctx->frame_num > 90 && p_ctx->frame_num < 300)
2900 {
2901 p_enc_frame->roi_len = p_ctx->roi_len;
2902 } else
2903 {
2904 p_enc_frame->roi_len = 0;
2905 }
2906 // when ROI enabled, always have a data buffer for ROI
2907 // Note: this is handled separately from ROI through side/aux data
2908 p_enc_frame->extra_data_len += p_ctx->roi_len;
2909 }
2910
2911 int should_send_sei_with_frame =
2913
2914 uint8_t mdcv_data[NI_MAX_SEI_DATA];
2915 uint8_t cll_data[NI_MAX_SEI_DATA];
2916 uint8_t cc_data[NI_MAX_SEI_DATA];
2917 uint8_t udu_data[NI_MAX_SEI_DATA];
2918 uint8_t hdrp_data[NI_MAX_SEI_DATA];
2919
2920 // Convert aux data attached to input frame into required format,
2921 // and store in local arrays
2922 ni_enc_prep_aux_data(p_ctx, p_enc_frame, p_enc_frame, p_ctx->codec_format,
2923 should_send_sei_with_frame, mdcv_data, cll_data,
2924 cc_data, udu_data, hdrp_data);
2925
2926 p_enc_frame->extra_data_len += p_enc_frame->sei_total_len;
2927
2928 // data layout requirement: leave space for reconfig data if at least one of
2929 // reconfig, SEI or ROI is present
2930 // Note: ROI is present when enabled, so use encode config flag instead of
2931 // frame's roi_len as it can be 0 indicating a 0'd ROI map setting !
2932 if (p_enc_frame->reconf_len || p_enc_frame->sei_total_len ||
2933 (p_param->roi_demo_mode && p_param->cfg_enc_params.roi_enable))
2934 {
2935 p_enc_frame->extra_data_len += sizeof(ni_encoder_change_params_t);
2936 }
2937
2938 // Check whether line-by-line copy is needed
2939 int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0};
2940 int dst_height_aligned[NI_MAX_NUM_DATA_POINTERS] = {0};
2941 int is_semiplanar = !ni_get_planar_from_pixfmt(p_ctx->pixel_format);
2942 ni_get_hw_yuv420p_dim(frame_width, frame_height, p_ctx->bit_depth_factor,
2943 is_semiplanar, dst_stride, dst_height_aligned);
2944
2945 int src_stride[NI_MAX_NUM_DATA_POINTERS];
2946 int src_height[NI_MAX_NUM_DATA_POINTERS];
2947 uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS];
2948
2949 bool isrgba = (p_ctx->pixel_format == NI_PIX_FMT_ABGR || p_ctx->pixel_format == NI_PIX_FMT_ARGB
2950 || p_ctx->pixel_format == NI_PIX_FMT_RGBA || p_ctx->pixel_format == NI_PIX_FMT_BGRA);
2951
2952 // NOTE - FFmpeg / Gstreamer users should use linesize array in frame structure instead of src_stride in the following sample code
2953 src_stride[0] = frame_width * p_ctx->bit_depth_factor;
2954 src_height[0] = frame_height;
2955 p_src[0] = p_yuv_buffer;
2956
2957 if (isrgba)
2958 {
2959 src_stride[1] = 0;
2960 src_stride[2] = 0;
2961
2962 src_height[1] = 0;
2963 src_height[2] = 0;
2964
2965 p_src[1] = NULL;
2966 p_src[2] = NULL;
2967 }
2968 else
2969 {
2970 src_stride[1] = is_semiplanar ? src_stride[0] : src_stride[0] / 2;
2971 src_stride[2] = is_semiplanar ? 0 : src_stride[0] / 2;
2972
2973 src_height[1] = src_height[0] / 2;
2974 src_height[2] = is_semiplanar ? 0 : src_height[1];
2975
2976 p_src[1] = p_src[0] + (ptrdiff_t)src_stride[0] * src_height[0];
2977 p_src[2] = p_src[1] + (ptrdiff_t)src_stride[1] * src_height[1];
2978 }
2979
2980 alignment_2pass_wa = (
2981 (p_param->cfg_enc_params.lookAheadDepth ||
2982 p_param->cfg_enc_params.crf >= 0 ||
2983 p_param->cfg_enc_params.crfFloat >= 0) &&
2986
2987 if (alignment_2pass_wa && !is_hwframe) {
2988 if (is_semiplanar) {
2989 // for 2-pass encode output mismatch WA, need to extend (and
2990 // pad) CbCr plane height, because 1st pass assume input 32
2991 // align
2992 dst_height_aligned[1] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2;
2993 } else {
2994 // for 2-pass encode output mismatch WA, need to extend (and
2995 // pad) Cr plane height, because 1st pass assume input 32 align
2996 dst_height_aligned[2] = (((dst_height_aligned[0] + 31) / 32) * 32) / 2;
2997 }
2998 }
2999
3000 // check input resolution zero copy compatible or not
3002 p_param, frame_width, frame_height,
3003 (const int *)src_stride, false) == NI_RETCODE_SUCCESS)
3004 {
3005 need_copy = false;
3006 //alloc metadata buffer etc. (if needed)
3008 p_enc_frame, frame_width,
3009 frame_height, (const int *)src_stride, (const uint8_t **)p_src,
3010 (int)(p_enc_frame->extra_data_len));
3011 if (retval != NI_RETCODE_SUCCESS)
3012 goto end;
3013 }
3014 else
3015 {
3016 // if linesize changes (while resolution remains the same), copy to previously configured linesizes
3017 if (p_param->luma_linesize && p_param->chroma_linesize)
3018 {
3019 dst_stride[0] = p_param->luma_linesize;
3020 dst_stride[1] = p_param->chroma_linesize;
3021 dst_stride[2] = is_semiplanar ? 0 : p_param->chroma_linesize;
3022 }
3024 p_param->cfg_enc_params.planar, p_enc_frame, frame_width,
3025 dst_height_aligned[0], dst_stride,
3027 (int)(p_enc_frame->extra_data_len), alignment_2pass_wa);
3028 if (retval != NI_RETCODE_SUCCESS)
3029 {
3030 return retval;
3031 }
3032 }
3033
3034 ni_log2(p_ctx, NI_LOG_TRACE,
3035 "%s: src_stride %d dst_stride "
3036 "%d dst_height_aligned %d src_height %d need_copy %d\n",
3037 __func__, src_stride[0],
3038 dst_stride[0], dst_height_aligned[0],
3039 src_height[0], need_copy);
3040
3041 if (need_copy)
3042 {
3043 ni_copy_hw_yuv420p((uint8_t **)(p_enc_frame->p_data), p_src,
3044 frame_width, frame_height, p_ctx->bit_depth_factor,
3045 is_semiplanar,
3046 p_param->cfg_enc_params.conf_win_right, dst_stride,
3047 dst_height_aligned, src_stride, src_height);
3048 p_enc_frame->separate_metadata = 0;
3049 }
3050
3051 ni_log2(p_ctx, NI_LOG_DEBUG,
3052 "p_dst alloc linesize = %d/%d/%d src height=%d "
3053 "dst height aligned = %d/%d/%d force_key_frame=%d, "
3054 "extra_data_len=%u"
3055 " sei_size=%u (hdr_content_light_level %u hdr_mastering_display_"
3056 "color_vol %u hdr10+ %u hrd %d) reconf_size=%u roi_size=%u "
3057 "force_pic_qp=%u udu_sei_size=%u "
3058 "use_cur_src_as_long_term_pic %u use_long_term_ref %u\n",
3059 dst_stride[0], dst_stride[1], dst_stride[2], frame_height,
3060 dst_height_aligned[0], dst_height_aligned[1], dst_height_aligned[2],
3061 p_enc_frame->force_key_frame, p_enc_frame->extra_data_len,
3062 p_enc_frame->sei_total_len,
3065 p_enc_frame->sei_hdr_plus_len, 0, /* hrd is 0 size for now */
3066 p_enc_frame->reconf_len, p_enc_frame->roi_len,
3067 p_enc_frame->force_pic_qp, p_enc_frame->sei_user_data_unreg_len,
3068 p_enc_frame->use_cur_src_as_long_term_pic,
3069 p_enc_frame->use_long_term_ref);
3070
3071 ni_enc_copy_aux_data(p_ctx, p_enc_frame, p_enc_frame, p_ctx->codec_format,
3072 mdcv_data, cll_data, cc_data, udu_data, hdrp_data,
3073 0 /*swframe*/, is_semiplanar);
3074
3075send_frame:
3076 retval = ni_device_session_write(p_ctx, (ni_session_data_io_t *)p_enc_frame,
3078end:
3079 if (!need_copy)
3080 {
3081 // Don't want to accidentally free or reuse user-allocated YUV buffer, so remove from frame
3082 p_enc_frame->p_buffer = NULL;
3083 p_enc_frame->buffer_size = 0;
3084 for (int i = 0; i < NI_MAX_NUM_DATA_POINTERS; i++)
3085 {
3086 p_enc_frame->data_len[i] = 0;
3087 p_enc_frame->p_data[i] = NULL;
3088 }
3089 }
3090
3091 return retval;
3092}
3093
3094/*!*****************************************************************************
3095 * \brief Find the next start code
3096 *
3097 * \param[in] p pointer to buffer start address.
3098 * \param[in] end pointer to buffer end address.
3099 * \param[state] state pointer to nalu type address
3100 *
3101 * \return search end address
3102 ******************************************************************************/
3103const uint8_t *ni_find_start_code (const uint8_t *p, const uint8_t *end, uint32_t *state)
3104{
3105 int i;
3106
3107 if (p >= end)
3108 return end;
3109
3110 for (i = 0; i < 3; i++) {
3111 uint32_t tmp = *state << 8;
3112 *state = tmp + *(p++);
3113 if (tmp == 0x100 || p == end)
3114 return p;
3115 }
3116
3117 while (p < end) {
3118 if (p[-1] > 1)
3119 p += 3;
3120 else if (p[-2])
3121 p += 2;
3122 else if (p[-3] | (p[-1] - 1))
3123 p++;
3124 else {
3125 p++;
3126 break;
3127 }
3128 }
3129
3130 p = ((p) < (end) ? (p - 4) : (end - 4)); // min
3131 *state =
3132 (((uint32_t) (p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3]);
3133
3134 return p + 4;
3135}
3136
3137/*!******************************************************************************
3138 * \brief Extract custom sei payload data from pkt_data,
3139 * and save it to ni_packet_t
3140 *
3141 * \param uint8_t *pkt_data - FFmpeg AVPacket data
3142 * \param int pkt_size - packet size
3143 * \param long index - pkt data index of custom sei first byte after SEI type
3144 * \param ni_packet_t *p_packet - libxcoder internal packet
3145 * \param uint8_t sei_type - type of SEI
3146 * \param int vcl_found - whether got vcl in the pkt data, 1 means got
3147 *
3148 * \return - 0 on success, non-0 on failure
3149 ********************************************************************************/
3150int ni_extract_custom_sei(uint8_t *pkt_data, int pkt_size, long index,
3151 ni_packet_t *p_packet, uint8_t sei_type, int vcl_found)
3152{
3153 int i, len;
3154 uint8_t *udata;
3155 uint8_t *sei_data;
3156 int sei_size;
3157 int sei_index;
3158 ni_custom_sei_t *p_custom_sei;
3159
3160 ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
3161
3162 if (p_packet->p_custom_sei_set == NULL)
3163 {
3164 /* max size */
3165 p_packet->p_custom_sei_set = (ni_custom_sei_set_t *)malloc(sizeof(ni_custom_sei_set_t));
3166 if (p_packet->p_custom_sei_set == NULL)
3167 {
3168 ni_log(NI_LOG_ERROR, "failed to allocate all custom sei buffer.\n");
3170 }
3171 memset(p_packet->p_custom_sei_set, 0, sizeof(ni_custom_sei_set_t));
3172 }
3173
3174 sei_index = p_packet->p_custom_sei_set->count;
3175 p_custom_sei = &p_packet->p_custom_sei_set->custom_sei[sei_index];
3176 if (sei_index >= NI_MAX_CUSTOM_SEI_CNT)
3177 {
3178 ni_log(NI_LOG_INFO, "number of custom sei in current frame is out of limit(%d).\n",
3180 return 0;
3181 }
3182 sei_data = &p_custom_sei->data[0];
3183
3191 sei_size = 0;
3192 while (index < pkt_size && pkt_data[index] == 0xff)
3193 {
3194 sei_size += pkt_data[index++];
3195 }
3196
3197 if (index >= pkt_size)
3198 {
3199 ni_log(NI_LOG_INFO, "custom sei corrupted: length truncated.\n");
3200 return NI_RETCODE_FAILURE;
3201 }
3202 sei_size += pkt_data[index++];
3203
3204 if (sei_size > NI_MAX_CUSTOM_SEI_DATA)
3205 {
3206 ni_log(NI_LOG_INFO, "custom sei corrupted: size(%d) out of limit(%d).\n",
3207 sei_size, NI_MAX_CUSTOM_SEI_DATA);
3208 return 0;
3209 }
3210
3211 udata = &pkt_data[index];
3212
3213 /* set SEI payload type at the first byte */
3214 sei_data[0] = sei_type;
3215
3216 /* extract SEI payload data
3217 * SEI payload data in NAL is EBSP(Encapsulated Byte Sequence Payload),
3218 * need change EBSP to RBSP(Raw Byte Sequence Payload) for exact size
3219 */
3220 for (i = 0, len = 0; (i < pkt_size - index) && len < sei_size; i++, len++)
3221 {
3222 /* if the latest 3-byte data pattern matchs '00 00 03' which means udata[i] is an escaping byte,
3223 * discard udata[i]. */
3224 if (i >= 2 && udata[i - 2] == 0 && udata[i - 1] == 0 && udata[i] == 3)
3225 {
3226 len--;
3227 continue;
3228 }
3229 sei_data[len] = udata[i];
3230 }
3231
3232 if (len != sei_size)
3233 {
3234 ni_log(NI_LOG_INFO, "custom sei corrupted: data truncated, "
3235 "required size:%d, actual size:%d.\n", sei_size, len);
3236 return NI_RETCODE_FAILURE;
3237 }
3238
3239 p_custom_sei->type = sei_type;
3240 p_custom_sei->size = sei_size;
3242
3243 p_packet->p_custom_sei_set->count++;
3244
3245 ni_log(NI_LOG_TRACE, "%s() exit, custom sei size=%d type=%d\n",
3246 __FUNCTION__, sei_size, sei_type);
3247
3248 return 0;
3249}
3250
3251/*!******************************************************************************
3252 * \brief Decode parse packet
3253 *
3254 * \param[in] p_session_ctx Pointer to a caller allocated
3255 * ni_session_context_t struct
3256 * \param[in] p_param Pointer to a caller allocated
3257 * ni_xcoder_params_t struct
3258 * \param[in] *data FFmpeg AVPacket data
3259 * \param[in] size packet size
3260 * \param[in] p_packet Pointer to a caller allocated
3261 * ni_packet_t struct
3262 * \param[in] low_delay FFmpeg lowdelay
3263 * \param[in] codec_format enum ni_codec_format_t
3264 * \param[in] pkt_nal_bitmap pkt_nal_bitmap
3265 * \param[in] custom_sei_type custom_sei_type
3266 * \param[in] *svct_skip_next_packet svct_skip_next_packet int*
3267 * \param[in] *is_lone_sei_pkt is_lone_sei_pkt int*
3268 *
3269 * \return - 0 on success, non-0 on failure
3270 ********************************************************************************/
3272 uint8_t *data, int size, ni_packet_t *p_packet, int low_delay,
3273 int codec_format, int pkt_nal_bitmap, int custom_sei_type,
3274 int *svct_skip_next_packet, int *is_lone_sei_pkt)
3275{
3276 int pkt_sei_alone = 1;
3277 int vcl_found = 0;
3278 int tmp_low_delay =
3279 (p_session_ctx->decoder_low_delay == -1) ? 0 : low_delay;
3280 int svct_layer = (codec_format == NI_CODEC_FORMAT_H264) ?
3283 // int pkt_nal_bitmap = ni_dec_ctx->pkt_nal_bitmap;
3284 const uint8_t *ptr = data;
3285 const uint8_t *end = data + size;
3286 uint32_t stc;
3287 int nalu_type;
3288 uint8_t sei_type = 0;
3289 int ret = 0;
3290 int nalu_count = 0;
3292 int temporal_id;
3293 const uint8_t *next = NULL;
3294 int sei_size = 0, i = 0;
3295
3296 if (pkt_nal_bitmap & NI_GENERATE_ALL_NAL_HEADER_BIT)
3297 {
3298 ni_log2(p_session_ctx, NI_LOG_TRACE,
3299 "ni_dec_packet_parse(): already find the header of streams.\n");
3300 low_delay = 0;
3301 }
3302
3303 while (
3304 (custom_sei_type != NI_INVALID_SEI_TYPE ||
3306 svct_layer != NI_INVALID_SVCT_DECODING_LAYER || tmp_low_delay ||
3308 ptr < end)
3309 {
3310 stc = -1;
3311 ptr = ni_find_start_code(ptr, end, &stc);
3312 if (ptr == end)
3313 {
3314 if (0 == nalu_count)
3315 {
3316 pkt_sei_alone = 0;
3317 ni_log2(p_session_ctx, NI_LOG_TRACE, "%s(): no NAL found in pkt.\n",
3318 __FUNCTION__);
3319 }
3320 break;
3321 }
3322 nalu_count++;
3323
3324 if (NI_CODEC_FORMAT_H264 == codec_format)
3325 {
3326 nalu_type = (int)stc & 0x1f;
3327
3328 //check whether the packet is sei alone
3329 pkt_sei_alone = (pkt_sei_alone && 6 /*H264_NAL_SEI */ == nalu_type);
3330
3331 // Enable decoder low delay mode on sequence change
3332 if (low_delay)
3333 {
3334 switch (nalu_type)
3335 {
3336 case 7 /*H264_NAL_SPS */:
3337 pkt_nal_bitmap |= NI_NAL_SPS_BIT;
3338 break;
3339 case 8 /*H264_NAL_PPS */:
3340 pkt_nal_bitmap |= NI_NAL_PPS_BIT;
3341 break;
3342 default:
3343 break;
3344 }
3345
3346 if (pkt_nal_bitmap == (NI_NAL_SPS_BIT | NI_NAL_PPS_BIT))
3347 {
3348 ni_log2(p_session_ctx, NI_LOG_TRACE,
3349 "ni_dec_packet_parse(): Detect SPS, PPS and IDR, "
3350 "enable decoder low delay mode.\n");
3351 p_session_ctx->decoder_low_delay = low_delay;
3352 pkt_nal_bitmap |= NI_GENERATE_ALL_NAL_HEADER_BIT;
3353 low_delay = 0;
3354 }
3355 }
3356 // check whether the packet contains SEI NAL after VCL units
3357 if (6 /*H264_NAL_SEI */ == nalu_type)
3358 {
3359 // Find the end of the SEI NAL unit
3360 next = ni_find_start_code(ptr, end, &stc);
3361 if (next >= data + 5 && *(next - 5) == 0)
3362 next -= 5; // long start code
3363 else
3364 next -= 4; // short start code
3365
3366 // More SEI messages in the NAL unit if remaining data larger than 1 byte
3367 while (next - ptr > 1)
3368 {
3369 sei_type = *ptr;
3370 if (vcl_found ||
3371 custom_sei_type == sei_type ||
3372 p_param->dec_input_params.custom_sei_passthru == sei_type ||
3374 {
3375 // SEI after VCL found or SEI type indicated then extract
3376 // the SEI unit;
3377 // ret = ni_quadra_extract_custom_sei(ni_dec_ctx, data, size,
3378 // ptr + 1 - data, p_packet,
3379 // sei_type, vcl_found);
3380 ret = ni_extract_custom_sei(data, size,
3381 (long)(ptr + 1 - data), p_packet,
3382 sei_type, vcl_found);
3383 if (ret != 0)
3384 {
3385 return ret;
3386 }
3387 }
3388
3389 // Skip the current SEI message including any emulation prevention bytes
3390 ptr++;
3391 sei_size = 0;
3392 while (ptr + 1 < next && *ptr == 0xff)
3393 {
3394 sei_size += *ptr++;
3395 }
3396 sei_size += *ptr++;
3397 for (i = 0; i < sei_size && next - ptr > 1; i++)
3398 {
3399 if (i >= 2 && *(ptr - 2) == 0 && *(ptr - 1) == 0 && *ptr == 3)
3400 sei_size++;
3401 ptr++;
3402 }
3403 }
3404 } else if (nalu_type >= 1 /* H264_NAL_SLICE */ &&
3405 nalu_type <= 5 /* H264_NAL_IDR_SLICE */)
3406 {
3407 vcl_found = 1;
3408 } else if (14 /*H264_NAL_PREFIX */ == nalu_type)
3409 {
3410 ni_bitstream_reader_init(&br, ptr,
3411 48); // 3 * 2 bytes * 8 = 48 bits
3412 // skip some header
3413 ni_bs_reader_skip_bits(&br, 16);
3414 temporal_id = (int)ni_bs_reader_get_bits(&br, 3);
3415 if (temporal_id > svct_layer)
3416 {
3417 // H264_NAL_PREFIX UNIT will be sent with the last packet.
3418 // So, the H264_NAL_PREFIX here is used for the next packet.
3419 *svct_skip_next_packet = 1;
3420 ni_log2(p_session_ctx, NI_LOG_TRACE,
3421 "ni_dec_packet_parse(): temporal_id %d"
3422 " is bigger than decoded layer %d, skip the next "
3423 "packet\n",
3424 temporal_id, svct_layer);
3425 }
3426 }
3427 } else if (NI_CODEC_FORMAT_H265 == codec_format)
3428 {
3429 nalu_type = (int)(stc >> 1) & 0x3F;
3430
3431 //check whether the packet is sei alone
3432 pkt_sei_alone = (pkt_sei_alone &&
3433 (39 /* HEVC_NAL_SEI_PREFIX */ == nalu_type ||
3434 40 /* HEVC_NAL_SEI_SUFFIX */ == nalu_type));
3435
3436 // Enable decoder low delay mode on sequence change
3437 if (low_delay)
3438 {
3439 switch (nalu_type)
3440 {
3441 case 32 /* HEVC_NAL_VPS */:
3442 pkt_nal_bitmap |= NI_NAL_VPS_BIT;
3443 break;
3444 case 33 /* HEVC_NAL_SPS */:
3445 pkt_nal_bitmap |= NI_NAL_SPS_BIT;
3446 break;
3447 case 34 /* HEVC_NAL_PPS */:
3448 pkt_nal_bitmap |= NI_NAL_PPS_BIT;
3449 break;
3450 default:
3451 break;
3452 }
3453
3454 if (pkt_nal_bitmap ==
3456 {
3457 // Packets before the header is sent cannot be decoded.
3458 // So set packet num to zero here.
3459 ni_log2(p_session_ctx, NI_LOG_TRACE,
3460 "ni_dec_packet_parse(): Detect VPS, SPS, PPS and "
3461 "IDR enable decoder low delay mode.\n");
3462 p_session_ctx->decoder_low_delay = low_delay;
3463 pkt_nal_bitmap |= NI_GENERATE_ALL_NAL_HEADER_BIT;
3464 low_delay = 0;
3465 }
3466 }
3467 // check whether the packet contains SEI NAL after VCL units
3468 if (39 /* HEVC_NAL_SEI_PREFIX */ == nalu_type ||
3469 40 /* HEVC_NAL_SEI_SUFFIX */ == nalu_type)
3470 {
3471 // Find the end of the SEI NAL unit
3472 next = ni_find_start_code(ptr, end, &stc);
3473 if (next >= data + 5 && *(next - 5) == 0)
3474 next -= 5; // long start code
3475 else
3476 next -= 4; // short start code
3477
3478 // Skip NAL unit header
3479 ptr++;
3480
3481 // More SEI messages in the NAL unit if remaining data larger than 1 byte
3482 while (next - ptr > 1)
3483 {
3484 sei_type = *ptr;
3485 if (vcl_found ||
3486 custom_sei_type == sei_type ||
3487 p_param->dec_input_params.custom_sei_passthru == sei_type ||
3489 {
3490 // SEI after VCL found or SEI type indicated then extract
3491 // the SEI unit;
3492 // ret = ni_quadra_extract_custom_sei(ni_dec_ctx, data, size,
3493 // ptr + 2 - data, p_packet,
3494 // sei_type, vcl_found);
3495 ret = ni_extract_custom_sei(data, size, (long)(ptr + 1 - data), p_packet,
3496 sei_type, vcl_found);
3497 if (ret != 0)
3498 {
3499 return ret;
3500 }
3501 }
3502
3503 // Skip the current SEI message including any emulation prevention bytes
3504 ptr++;
3505 sei_size = 0;
3506 while (ptr + 1 < next && *ptr == 0xff)
3507 {
3508 sei_size += *ptr++;
3509 }
3510 sei_size += *ptr++;
3511 for (i = 0; i < sei_size && next - ptr > 1; i++)
3512 {
3513 if (i >= 2 && *(ptr - 2) == 0 && *(ptr - 1) == 0 && *ptr == 3)
3514 sei_size++;
3515 ptr++;
3516 }
3517 }
3518 } else if (nalu_type >= 0 /* HEVC_NAL_TRAIL_N */ &&
3519 nalu_type <= 31 /* HEVC_NAL_RSV_VCL31 */)
3520 {
3521 vcl_found = 1;
3522 }
3523 } else
3524 {
3525 ni_log2(p_session_ctx,NI_LOG_DEBUG, "%s() wrong codec %d !\n", __FUNCTION__, codec_format);
3526 pkt_sei_alone = 0;
3527 break;
3528 }
3529 }
3530
3531 if (nalu_count > 0)
3532 {
3533 *is_lone_sei_pkt = pkt_sei_alone;
3534 }
3535
3536 return 0;
3537}
3538
3539
3540/*!******************************************************************************
3541 * \brief Decode parse packet
3542 *
3543 * \param[in] p_session_ctx Pointer to a caller allocated
3544 * ni_session_context_t struct
3545 * \param[in] p_param Pointer to a caller allocated
3546 * ni_xcoder_params_t struct
3547 * \param[in] *data FFmpeg AVPacket data
3548 * \param[in] size packet size
3549 * \param[in] p_packet Pointer to a caller allocated
3550 * ni_packet_t struct
3551 * \param[in] low_delay FFmpeg lowdelay
3552 * \param[in] codec_format enum ni_codec_format_t
3553 * \param[in] *p_pkt_nal_bitmap p_pkt_nal_bitmap int*
3554 * \param[in] custom_sei_type custom_sei_type
3555 * \param[in] *svct_skip_next_packet svct_skip_next_packet int*
3556 * \param[in] *is_lone_sei_pkt is_lone_sei_pkt int*
3557 *
3558 * \return - 0 on success, non-0 on failure
3559 ********************************************************************************/
3561 uint8_t *data, int size, ni_packet_t *p_packet, int low_delay,
3562 int codec_format, int *p_pkt_nal_bitmap, int custom_sei_type,
3563 int *svct_skip_next_packet, int *is_lone_sei_pkt)
3564{
3565 int pkt_sei_alone = 1;
3566 int vcl_found = 0;
3567 int tmp_low_delay = 0;
3568
3569 int svct_layer = NI_INVALID_SVCT_DECODING_LAYER;
3570 int pkt_nal_bitmap = 0;
3571 const uint8_t *ptr;
3572 const uint8_t *end;
3573 uint32_t stc;
3574 int nalu_type;
3575 uint8_t sei_type = 0;
3576 int ret = 0;
3577 int nalu_count = 0;
3579 int temporal_id;
3580 const uint8_t *next = NULL;
3581 int sei_size = 0, i = 0;
3582
3583 if (!data)
3584 {
3585 ni_log2(p_ctx, NI_LOG_TRACE, "%s(): null packet data, return 0\n",
3586 __func__);
3587 return 0;
3588 }
3589
3590 if (!p_ctx || !p_param || !p_packet || !p_pkt_nal_bitmap || !svct_skip_next_packet || !is_lone_sei_pkt)
3591 {
3592 ni_log2(p_ctx, NI_LOG_ERROR, "ERROR: %s() passed parameters are null!, return\n",
3593 __func__);
3594 return -1;
3595 }
3596
3597 tmp_low_delay = (p_ctx->decoder_low_delay == -1) ? 0 : low_delay;
3598 svct_layer = (codec_format == NI_CODEC_FORMAT_H264) ?
3601 pkt_nal_bitmap = *p_pkt_nal_bitmap;
3602 ptr = data;
3603 end = data + size;
3604
3605 if (pkt_nal_bitmap & NI_GENERATE_ALL_NAL_HEADER_BIT)
3606 {
3607 ni_log2(p_ctx, NI_LOG_TRACE,
3608 "%s(): already find the header of streams.\n",
3609 __func__);
3610 low_delay = 0;
3611 }
3612
3613 while (
3614 (custom_sei_type != NI_INVALID_SEI_TYPE ||
3616 svct_layer != NI_INVALID_SVCT_DECODING_LAYER || tmp_low_delay ||
3618 ptr < end)
3619 {
3620 stc = -1;
3621 ptr = ni_find_start_code(ptr, end, &stc);
3622 if (ptr == end)
3623 {
3624 if (0 == nalu_count)
3625 {
3626 pkt_sei_alone = 0;
3627 ni_log2(p_ctx, NI_LOG_TRACE, "%s(): no NAL found in pkt.\n",
3628 __func__);
3629 }
3630 break;
3631 }
3632 nalu_count++;
3633
3634 if (NI_CODEC_FORMAT_H264 == codec_format)
3635 {
3636 nalu_type = (int)stc & 0x1f;
3637
3638 //check whether the packet is sei alone
3639 pkt_sei_alone = (pkt_sei_alone && 6 /*H264_NAL_SEI */ == nalu_type);
3640
3641 // Enable decoder low delay mode on sequence change
3642 if (low_delay)
3643 {
3644 switch (nalu_type)
3645 {
3646 case 7 /*H264_NAL_SPS */:
3647 pkt_nal_bitmap |= NI_NAL_SPS_BIT;
3648 break;
3649 case 8 /*H264_NAL_PPS */:
3650 pkt_nal_bitmap |= NI_NAL_PPS_BIT;
3651 break;
3652 default:
3653 break;
3654 }
3655
3656 if (pkt_nal_bitmap == (NI_NAL_SPS_BIT | NI_NAL_PPS_BIT))
3657 {
3658 ni_log2(p_ctx, NI_LOG_TRACE,
3659 "%s(): Detect SPS, PPS and IDR, "
3660 "enable decoder low delay mode.\n",
3661 __func__);
3662 p_ctx->decoder_low_delay = low_delay;
3663 pkt_nal_bitmap |= NI_GENERATE_ALL_NAL_HEADER_BIT;
3664 low_delay = 0;
3665 }
3666 }
3667 // check whether the packet contains SEI NAL after VCL units
3668 if (6 /*H264_NAL_SEI */ == nalu_type)
3669 {
3670 // Find the end of the SEI NAL unit
3671 next = ni_find_start_code(ptr, end, &stc);
3672 if (next >= data + 5 && *(next - 5) == 0)
3673 next -= 5; // long start code
3674 else
3675 next -= 4; // short start code
3676
3677 // More SEI messages in the NAL unit if remaining data larger than 1 byte
3678 while (next - ptr > 1)
3679 {
3680 sei_type = *ptr;
3681 if (vcl_found ||
3682 custom_sei_type == sei_type ||
3683 p_param->dec_input_params.custom_sei_passthru == sei_type ||
3685 {
3686 // SEI after VCL found or SEI type indicated then extract
3687 // the SEI unit;
3688 // ret = ni_quadra_extract_custom_sei(ni_dec_ctx, data, size,
3689 // ptr + 1 - data, p_packet,
3690 // sei_type, vcl_found);
3691 ret = ni_extract_custom_sei(data, size,
3692 (long)(ptr + 1 - data), p_packet,
3693 sei_type, vcl_found);
3694 if (ret != 0)
3695 {
3696 return ret;
3697 }
3698 }
3699
3700 // Skip the current SEI message including any emulation prevention bytes
3701 ptr++;
3702 sei_size = 0;
3703 while (ptr + 1 < next && *ptr == 0xff)
3704 {
3705 sei_size += *ptr++;
3706 }
3707 sei_size += *ptr++;
3708 for (i = 0; i < sei_size && next - ptr > 1; i++)
3709 {
3710 if (i >= 2 && *(ptr - 2) == 0 && *(ptr - 1) == 0 && *ptr == 3)
3711 sei_size++;
3712 ptr++;
3713 }
3714 }
3715 } else if (nalu_type >= 1 /* H264_NAL_SLICE */ &&
3716 nalu_type <= 5 /* H264_NAL_IDR_SLICE */)
3717 {
3718 vcl_found = 1;
3719 } else if (14 /*H264_NAL_PREFIX */ == nalu_type)
3720 {
3721 ni_bitstream_reader_init(&br, ptr,
3722 48); // 3 * 2 bytes * 8 = 48 bits
3723 // skip some header
3724 ni_bs_reader_skip_bits(&br, 16);
3725 temporal_id = (int)ni_bs_reader_get_bits(&br, 3);
3726 if (temporal_id > svct_layer)
3727 {
3728 // H264_NAL_PREFIX UNIT will be sent with the last packet.
3729 // So, the H264_NAL_PREFIX here is used for the next packet.
3730 *svct_skip_next_packet = 1;
3731 ni_log2(p_ctx, NI_LOG_TRACE,
3732 "%s(): temporal_id %d"
3733 " is bigger than decoded layer %d, skip the next "
3734 "packet\n",
3735 __func__, temporal_id, svct_layer);
3736 }
3737 }
3738 } else if (NI_CODEC_FORMAT_H265 == codec_format)
3739 {
3740 nalu_type = (int)(stc >> 1) & 0x3F;
3741
3742 //check whether the packet is sei alone
3743 pkt_sei_alone = (pkt_sei_alone &&
3744 (39 /* HEVC_NAL_SEI_PREFIX */ == nalu_type ||
3745 40 /* HEVC_NAL_SEI_SUFFIX */ == nalu_type));
3746
3747 // Enable decoder low delay mode on sequence change
3748 if (low_delay)
3749 {
3750 switch (nalu_type)
3751 {
3752 case 32 /* HEVC_NAL_VPS */:
3753 pkt_nal_bitmap |= NI_NAL_VPS_BIT;
3754 break;
3755 case 33 /* HEVC_NAL_SPS */:
3756 pkt_nal_bitmap |= NI_NAL_SPS_BIT;
3757 break;
3758 case 34 /* HEVC_NAL_PPS */:
3759 pkt_nal_bitmap |= NI_NAL_PPS_BIT;
3760 break;
3761 default:
3762 break;
3763 }
3764
3765 if (pkt_nal_bitmap ==
3767 {
3768 // Packets before the header is sent cannot be decoded.
3769 // So set packet num to zero here.
3770 ni_log2(p_ctx, NI_LOG_TRACE,
3771 "%s(): Detect VPS, SPS, PPS and "
3772 "IDR enable decoder low delay mode.\n", __func__);
3773 p_ctx->decoder_low_delay = low_delay;
3774 pkt_nal_bitmap |= NI_GENERATE_ALL_NAL_HEADER_BIT;
3775 low_delay = 0;
3776 }
3777 }
3778 // check whether the packet contains SEI NAL after VCL units
3779 if (39 /* HEVC_NAL_SEI_PREFIX */ == nalu_type ||
3780 40 /* HEVC_NAL_SEI_SUFFIX */ == nalu_type)
3781 {
3782 // Find the end of the SEI NAL unit
3783 next = ni_find_start_code(ptr, end, &stc);
3784 if (next >= data + 5 && *(next - 5) == 0)
3785 next -= 5; // long start code
3786 else
3787 next -= 4; // short start code
3788
3789 // Skip NAL unit header
3790 ptr++;
3791
3792 // More SEI messages in the NAL unit if remaining data larger than 1 byte
3793 while (next - ptr > 1)
3794 {
3795 sei_type = *ptr;
3796 if (vcl_found ||
3797 custom_sei_type == sei_type ||
3798 p_param->dec_input_params.custom_sei_passthru == sei_type ||
3800 {
3801 // SEI after VCL found or SEI type indicated then extract
3802 // the SEI unit;
3803 // ret = ni_quadra_extract_custom_sei(ni_dec_ctx, data, size,
3804 // ptr + 2 - data, p_packet,
3805 // sei_type, vcl_found);
3806 ret = ni_extract_custom_sei(data, size, (long)(ptr + 1 - data), p_packet,
3807 sei_type, vcl_found);
3808 if (ret != 0)
3809 {
3810 return ret;
3811 }
3812 }
3813
3814 // Skip the current SEI message including any emulation prevention bytes
3815 ptr++;
3816 sei_size = 0;
3817 while (ptr + 1 < next && *ptr == 0xff)
3818 {
3819 sei_size += *ptr++;
3820 }
3821 sei_size += *ptr++;
3822 for (i = 0; i < sei_size && next - ptr > 1; i++)
3823 {
3824 if (i >= 2 && *(ptr - 2) == 0 && *(ptr - 1) == 0 && *ptr == 3)
3825 sei_size++;
3826 ptr++;
3827 }
3828 }
3829 } else if (nalu_type >= 0 /* HEVC_NAL_TRAIL_N */ &&
3830 nalu_type <= 31 /* HEVC_NAL_RSV_VCL31 */)
3831 {
3832 vcl_found = 1;
3833 }
3834 } else
3835 {
3836 ni_log2(p_ctx,NI_LOG_DEBUG, "%s() wrong codec %d !\n", __func__, codec_format);
3837 pkt_sei_alone = 0;
3838 break;
3839 }
3840 }
3841
3842 if (nalu_count > 0)
3843 {
3844 *is_lone_sei_pkt = pkt_sei_alone;
3845 }
3846
3847 *p_pkt_nal_bitmap = pkt_nal_bitmap;
3848
3849 return 0;
3850}
3851
3852/*!******************************************************************************
3853 * \brief Expand frame form src frame
3854 *
3855 * \param[in] dst Pointer to a caller allocated ni_frame_t struct
3856 * \param[in] src Pointer to a caller allocated ni_frame_t struct
3857 * \param[in] dst_stride int dst_stride[]
3858 * \param[in] raw_width frame width
3859 * \param[in] raw_height frame height
3860 * \param[in] ni_fmt ni_pix_fmt_t type for ni pix_fmt
3861 * \param[in] nb_planes int nb_planes
3862 *
3863 * \return - 0 on success, NI_RETCODE_FAILURE on failure
3864 ********************************************************************************/
3865int ni_expand_frame(ni_frame_t *dst, ni_frame_t *src, int dst_stride[],
3866 int raw_width, int raw_height, int ni_fmt, int nb_planes)
3867{
3868 int i, j, h, tenBit = 0;
3869 int vpad[3], hpad[3], src_height[3], src_width[3], src_stride[3];
3870 uint8_t *src_line, *dst_line, *sample, *dest, YUVsample;
3871 uint16_t lastidx;
3872
3873 switch (ni_fmt)
3874 {
3875 case NI_PIX_FMT_YUV420P:
3876 /* width of source frame for each plane in pixels */
3877 src_width[0] = NIALIGN(raw_width, 2);
3878 src_width[1] = NIALIGN(raw_width, 2) / 2;
3879 src_width[2] = NIALIGN(raw_width, 2) / 2;
3880
3881 /* height of source frame for each plane in pixels */
3882 src_height[0] = NIALIGN(raw_height, 2);
3883 src_height[1] = NIALIGN(raw_height, 2) / 2;
3884 src_height[2] = NIALIGN(raw_height, 2) / 2;
3885
3886 /* stride of source frame for each plane in bytes */
3887 src_stride[0] = NIALIGN(src_width[0], 128);
3888 src_stride[1] = NIALIGN(src_width[1], 128);
3889 src_stride[2] = NIALIGN(src_width[2], 128);
3890
3891 tenBit = 0;
3892
3893 /* horizontal padding needed for each plane in bytes */
3894 hpad[0] = dst_stride[0] - src_width[0];
3895 hpad[1] = dst_stride[1] - src_width[1];
3896 hpad[2] = dst_stride[2] - src_width[2];
3897
3898 /* vertical padding needed for each plane in pixels */
3899 vpad[0] = NI_MIN_HEIGHT - src_height[0];
3900 vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1];
3901 vpad[2] = NI_MIN_HEIGHT / 2 - src_height[2];
3902
3903 break;
3904
3906 /* width of source frame for each plane in pixels */
3907 src_width[0] = NIALIGN(raw_width, 2);
3908 src_width[1] = NIALIGN(raw_width, 2) / 2;
3909 src_width[2] = NIALIGN(raw_width, 2) / 2;
3910
3911 /* height of source frame for each plane in pixels */
3912 src_height[0] = NIALIGN(raw_height, 2);
3913 src_height[1] = NIALIGN(raw_height, 2) / 2;
3914 src_height[2] = NIALIGN(raw_height, 2) / 2;
3915
3916 /* stride of source frame for each plane in bytes */
3917 src_stride[0] = NIALIGN(src_width[0] * 2, 128);
3918 src_stride[1] = NIALIGN(src_width[1] * 2, 128);
3919 src_stride[2] = NIALIGN(src_width[2] * 2, 128);
3920
3921 tenBit = 1;
3922
3923 /* horizontal padding needed for each plane in bytes */
3924 hpad[0] = dst_stride[0] - src_width[0] * 2;
3925 hpad[1] = dst_stride[1] - src_width[1] * 2;
3926 hpad[2] = dst_stride[2] - src_width[2] * 2;
3927
3928 /* vertical padding needed for each plane in pixels */
3929 vpad[0] = NI_MIN_HEIGHT - src_height[0];
3930 vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1];
3931 vpad[2] = NI_MIN_HEIGHT / 2 - src_height[2];
3932
3933 break;
3934
3935 case NI_PIX_FMT_NV12:
3936 /* width of source frame for each plane in pixels */
3937 src_width[0] = NIALIGN(raw_width, 2);
3938 src_width[1] = NIALIGN(raw_width, 2);
3939 src_width[2] = 0;
3940
3941 /* height of source frame for each plane in pixels */
3942 src_height[0] = NIALIGN(raw_height, 2);
3943 src_height[1] = NIALIGN(raw_height, 2) / 2;
3944 src_height[2] = 0;
3945
3946 /* stride of source frame for each plane in bytes */
3947 src_stride[0] = NIALIGN(src_width[0], 128);
3948 src_stride[1] = NIALIGN(src_width[1], 128);
3949 src_stride[2] = 0;
3950
3951 tenBit = 0;
3952
3953 /* horizontal padding needed for each plane in bytes */
3954 hpad[0] = dst_stride[0] - src_width[0];
3955 hpad[1] = dst_stride[1] - src_width[1];
3956 hpad[2] = 0;
3957
3958 /* vertical padding for each plane in pixels */
3959 vpad[0] = NI_MIN_HEIGHT - src_height[0];
3960 vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1];
3961 vpad[2] = 0;
3962
3963 break;
3964
3965 case NI_PIX_FMT_P010LE:
3966 /* width of source frame for each plane in pixels */
3967 src_width[0] = NIALIGN(raw_width, 2);
3968 src_width[1] = NIALIGN(raw_width, 2);
3969 src_width[2] = 0;
3970
3971 /* height of source frame for each plane in pixels */
3972 src_height[0] = NIALIGN(raw_height, 2);
3973 src_height[1] = NIALIGN(raw_height, 2) / 2;
3974 src_height[2] = 0;
3975
3976 /* stride of source frame for each plane in bytes */
3977 src_stride[0] = NIALIGN(src_width[0] * 2, 128);
3978 src_stride[1] = NIALIGN(src_width[1] * 2, 128);
3979 src_stride[2] = 0;
3980
3981 tenBit = 1;
3982
3983 /* horizontal padding needed for each plane in bytes */
3984 hpad[0] = dst_stride[0] - src_width[0] * 2;
3985 hpad[1] = dst_stride[1] - src_width[1] * 2;
3986 hpad[2] = 0;
3987
3988 /* vertical padding for each plane in pixels */
3989 vpad[0] = NI_MIN_HEIGHT - src_height[0];
3990 vpad[1] = NI_MIN_HEIGHT / 2 - src_height[1];
3991 vpad[2] = 0;
3992
3993 break;
3994
3995 default:
3996 ni_log(NI_LOG_ERROR, "Invalid pixel format %d\n",ni_fmt);
3997 return NI_RETCODE_FAILURE;
3998 }
3999
4000 for (i = 0; i < nb_planes && nb_planes < NI_MAX_NUM_DATA_POINTERS; i++)
4001 {
4002 dst_line = dst->p_data[i];
4003 src_line = src->p_data[i];
4004
4005 for (h = 0; i < 3 && h < src_height[i]; h++)
4006 {
4007 memcpy(dst_line, src_line, (size_t)src_width[i] * (tenBit + 1));
4008
4009 /* Add horizontal padding */
4010 if (hpad[i])
4011 {
4012 lastidx = src_width[i];
4013
4014 if (tenBit)
4015 {
4016 sample = &src_line[(ptrdiff_t)(lastidx - 1) * 2];
4017 dest = &dst_line[(ptrdiff_t)lastidx * 2];
4018
4019 /* two bytes per sample */
4020 for (j = 0; j < hpad[i] / 2; j++)
4021 {
4022 memcpy(dest, sample, 2);
4023 dest += 2;
4024 }
4025 } else
4026 {
4027 YUVsample = dst_line[lastidx - 1];
4028 memset(&dst_line[lastidx], YUVsample, hpad[i]);
4029 }
4030 }
4031
4032 src_line += src_stride[i];
4033 dst_line += dst_stride[i];
4034 }
4035
4036 /* Pad the height by duplicating the last line */
4037 src_line = dst_line - dst_stride[i];
4038
4039 for (h = 0; h < vpad[i]; h++)
4040 {
4041 memcpy(dst_line, src_line, dst_stride[i]);
4042 dst_line += dst_stride[i];
4043 }
4044 }
4045
4046 return 0;
4047}
4048
4049/*!******************************************************************************
4050 * \brief Reset decoder ppu resolution
4051 *
4052 * \param[in] p_session_ctx Pointer to a caller allocated
4053 * ni_session_context_t struct
4054 * \param[in] p_param Pointer to a caller allocated
4055 * ni_xcoder_params_t struct
4056 * \param[in] ppu_config Pointer to a caller allocated
4057 * ni_ppu_config_t struct
4058 *
4059 * \return - 0 on success, NI_RETCODE_FAILURE on failure
4060 ********************************************************************************/
4062 ni_xcoder_params_t *p_param, ni_ppu_config_t *ppu_config)
4063{
4064 int sei_size, size, len;
4065 int ret = 0, i = 0, j = 0;
4066 uint8_t *p_src_sei_data, *p_dst_sei_data;
4067 ni_custom_sei_t *p_dst_custom_sei;
4068
4069 if (!p_session_ctx || !p_param || !ppu_config)
4070 {
4072 return ret;
4073 }
4074
4075 // check fw revision
4077 (char*) &p_session_ctx->fw_rev[NI_XCODER_REVISION_API_MAJOR_VER_IDX],
4078 "6rx") < 0)
4079 {
4080 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s: not supported on device with FW API version < 6rx\n", __func__);
4082 }
4083
4084 if (NI_CODEC_FORMAT_H264 != p_session_ctx->codec_format &&
4085 NI_CODEC_FORMAT_H265 != p_session_ctx->codec_format)
4086 {
4087 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): Ppu reconfig only support "
4088 "h264 and h265 decoder\n", __func__);
4090 }
4091
4092 ni_decoder_input_params_t *p_dec_input_param = &(p_param->dec_input_params);
4093 if (p_dec_input_param->hwframes != 1)
4094 {
4095 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): Not hw mode, "
4096 "So can't reconfig ppu\n", __func__);
4098 }
4099 if (p_dec_input_param->enable_out1 == 0 &&
4100 ppu_config->ppu_set_enable & (0x01 << 1))
4101 {
4102 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): Warning Not enable ppu1, "
4103 "So can't reconfig ppu1\n", __func__);
4105 }
4106 if (p_dec_input_param->enable_out2 == 0 &&
4107 ppu_config->ppu_set_enable & (0x01 << 2))
4108 {
4109 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): Warning Not enable ppu2, "
4110 "So can't reconfig ppu2\n", __func__);
4112 }
4113 for (i = 0; i < NI_MAX_NUM_OF_DECODER_OUTPUTS; i++)
4114 {
4115 if (ppu_config->ppu_set_enable & (0x01 << i))
4116 {
4117 if (ppu_config->ppu_w[i] > NI_MAX_RESOLUTION_WIDTH ||
4118 ppu_config->ppu_h[i] > NI_MAX_RESOLUTION_HEIGHT ||
4119 ppu_config->ppu_w[i] < NI_MIN_RESOLUTION_WIDTH_SCALER ||
4120 ppu_config->ppu_h[i] < NI_MIN_RESOLUTION_WIDTH_SCALER)
4121 {
4122 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): ppu width x height %dx%d "
4123 "out of range\n", __func__, ppu_config->ppu_w[i], ppu_config->ppu_h[i]);
4125 return ret;
4126 }
4127 if ((ppu_config->ppu_w[i] & 1) || (ppu_config->ppu_h[i] & 1))
4128 {
4129 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): ppu wxh %dx%d not align to 2!\n",
4130 __func__, ppu_config->ppu_w[i], ppu_config->ppu_h[i]);
4132 return ret;
4133 }
4134 }
4135 }
4136 p_dst_custom_sei = malloc(sizeof(ni_custom_sei_t));
4137 if (p_dst_custom_sei == NULL)
4138 {
4139 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): failed "
4140 "to allocate memory for custom sei data\n", __func__);
4142 return ret;
4143 }
4144 memset(p_dst_custom_sei, 0, sizeof(ni_custom_sei_t));
4145
4146
4147 sei_size = sizeof(ni_ppu_config_t);
4148
4149 p_src_sei_data = (uint8_t *)ppu_config;
4150 p_dst_sei_data = &p_dst_custom_sei->data[0];
4151 size = 0;
4152
4153 // long start code
4154 p_dst_sei_data[size++] = 0x00;
4155 p_dst_sei_data[size++] = 0x00;
4156 p_dst_sei_data[size++] = 0x00;
4157 p_dst_sei_data[size++] = 0x01;
4158
4159 if (NI_CODEC_FORMAT_H264 == p_session_ctx->codec_format)
4160 {
4161 p_dst_sei_data[size++] = 0x06; //nal type: SEI
4162 }
4163 else
4164 {
4165 p_dst_sei_data[size++] = 0x4e; //nal type: SEI
4166 p_dst_sei_data[size++] = 0x01;
4167 }
4168
4169 // SEI type
4170 p_dst_sei_data[size++] = NI_SEI_TYPE_PPU_RECONFIG;
4171
4172 // original payload size
4173 len = sei_size;
4174 while (len >= 0)
4175 {
4176 p_dst_sei_data[size++] = len > 0xff ? 0xff : len;
4177 len -= 0xff;
4178 }
4179
4180 // payload data
4181 for (j = 0; j < sei_size && size < NI_MAX_CUSTOM_SEI_DATA - 1; j++)
4182 {
4183 if (j >= 2 && !p_dst_sei_data[size - 2] && !p_dst_sei_data[size - 1] && p_src_sei_data[j] <= 0x03)
4184 {
4185 /* insert 0x3 as emulation_prevention_three_byte */
4186 p_dst_sei_data[size++] = 0x03;
4187 }
4188 p_dst_sei_data[size++] = p_src_sei_data[j];
4189 }
4190
4191 if (j != sei_size)
4192 {
4193 ni_log2(p_session_ctx, NI_LOG_ERROR, "%s(): sei RBSP size out of limit(%d), "
4194 "idx=%u, size=%d\n", __func__,
4195 NI_MAX_CUSTOM_SEI_DATA, i, sei_size);
4196 free(p_dst_custom_sei);
4197 return NI_RETCODE_FAILURE;
4198 }
4199
4200 // trailing byte
4201 p_dst_sei_data[size++] = 0x80;
4202
4203 memcpy(p_session_ctx->p_leftover + p_session_ctx->prev_size,
4204 p_dst_sei_data, size);
4205 p_session_ctx->prev_size += size;
4206 free(p_dst_custom_sei);
4207
4208 return ret;
4209}
void ni_dec_retrieve_aux_data(ni_frame_t *frame)
Retrieve auxiliary data (close caption, various SEI) associated with this frame that is returned by d...
int ni_extract_custom_sei(uint8_t *pkt_data, int pkt_size, long index, ni_packet_t *p_packet, uint8_t sei_type, int vcl_found)
Extract custom sei payload data from pkt_data, and save it to ni_packet_t.
int ni_should_send_sei_with_frame(ni_session_context_t *p_enc_ctx, ni_pic_type_t pic_type, ni_xcoder_params_t *p_param)
Whether SEI (HDR) should be sent together with this frame to encoder.
void ni_enc_prep_aux_data(ni_session_context_t *p_enc_ctx, ni_frame_t *p_enc_frame, ni_frame_t *p_dec_frame, ni_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...
const uint8_t * ni_find_start_code(const uint8_t *p, const uint8_t *end, uint32_t *state)
Find the next start code.
int ni_expand_frame(ni_frame_t *dst, ni_frame_t *src, int dst_stride[], int raw_width, int raw_height, int ni_fmt, int nb_planes)
Expand frame form src frame.
int ni_reconfig_ppu_output(ni_session_context_t *p_session_ctx, ni_xcoder_params_t *p_param, ni_ppu_config_t *ppu_config)
Reset decoder ppu resolution.
gop_preset_t
Definition ni_av_codec.c:58
@ GOP_PRESET_BSP_2
Definition ni_av_codec.c:70
@ GOP_PRESET_BBSP_3
Definition ni_av_codec.c:76
@ NUM_GOP_PRESET_NUM
Definition ni_av_codec.c:79
@ GOP_PRESET_BBP_3
Definition ni_av_codec.c:75
@ GOP_PRESET_LP_4
Definition ni_av_codec.c:65
@ GOP_PRESET_SP_1
Definition ni_av_codec.c:69
@ GOP_PRESET_BBBP_3
Definition ni_av_codec.c:64
@ GOP_PRESET_CUSTOM
Definition ni_av_codec.c:59
@ GOP_PRESET_BP_2
Definition ni_av_codec.c:63
@ GOP_PRESET_B_1
Definition ni_av_codec.c:62
@ GOP_PRESET_P_1
Definition ni_av_codec.c:61
@ GOP_PRESET_BBBSP_3
Definition ni_av_codec.c:71
@ GOP_PRESET_BBBBBBBP_8
Definition ni_av_codec.c:77
@ GOP_PRESET_BBBBBBBSP_8
Definition ni_av_codec.c:78
@ GOP_PRESET_RA_8
Definition ni_av_codec.c:67
@ GOP_PRESET_LD_4
Definition ni_av_codec.c:66
@ GOP_PRESET_LSP_4
Definition ni_av_codec.c:72
@ GOP_PRESET_I_1
Definition ni_av_codec.c:60
int ni_dec_packet_parse2(ni_session_context_t *p_ctx, ni_xcoder_params_t *p_param, uint8_t *data, int size, ni_packet_t *p_packet, int low_delay, int codec_format, int *p_pkt_nal_bitmap, int custom_sei_type, int *svct_skip_next_packet, int *is_lone_sei_pkt)
Decode parse packet.
LIB_API int ni_enc_insert_timecode(ni_session_context_t *p_enc_ctx, ni_frame_t *p_enc_frame, ni_timecode_t *p_timecode)
Insert timecode data into picture timing SEI (H264) or time code SEI (H265)
int ni_enc_write_from_yuv_buffer(ni_session_context_t *p_ctx, ni_frame_t *p_enc_frame, uint8_t *p_yuv_buffer)
Send an input data frame to the encoder with YUV data given in the inputs.
slice_type_t
Definition ni_av_codec.c:50
@ SLICE_TYPE_I
Definition ni_av_codec.c:53
@ SLICE_TYPE_P
Definition ni_av_codec.c:52
@ SLICE_TYPE_MP
Definition ni_av_codec.c:54
@ SLICE_TYPE_B
Definition ni_av_codec.c:51
NI_DEPRECATED int ni_dec_packet_parse(ni_session_context_t *p_session_ctx, ni_xcoder_params_t *p_param, uint8_t *data, int size, ni_packet_t *p_packet, int low_delay, int codec_format, int pkt_nal_bitmap, int custom_sei_type, int *svct_skip_next_packet, int *is_lone_sei_pkt)
Decode parse packet.
void ni_enc_copy_aux_data(ni_session_context_t *p_enc_ctx, ni_frame_t *p_enc_frame, ni_frame_t *p_dec_frame, ni_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, int is_hwframe, int is_semiplanar)
Copy auxiliary data that should be sent together with this frame to encoder.
Audio/video related utility definitions.
@ NI_COL_TRC_UNSPECIFIED
#define AV1_MASTERING_DISP_LUMA_MAX_DEN
@ NI_COL_SPC_UNSPECIFIED
#define AV1_MASTERING_DISP_LUMA_MIN_DEN
#define NI_NAL_VPS_BIT
Definition ni_av_codec.h:39
@ NI_COL_PRI_UNSPECIFIED
Definition ni_av_codec.h:99
#define NI_SEI_TYPE_PPU_RECONFIG
Definition ni_av_codec.h:50
enum _ni_hdr_plus_overlap_process_option ni_hdr_plus_overlap_process_option_t
#define MASTERING_DISP_LUMA_DEN
#define AV1_MASTERING_DISP_CHROMA_DEN
#define MASTERING_DISP_CHROMA_DEN
#define NI_NAL_SPS_BIT
Definition ni_av_codec.h:40
#define NI_NAL_PPS_BIT
Definition ni_av_codec.h:41
#define NI_GENERATE_ALL_NAL_HEADER_BIT
Definition ni_av_codec.h:42
int ni_bs_writer_leb128(ni_bitstream_writer_t *stream, uint32_t data)
write unsigned LEB128 bit string to bitstream and return bytes written. Commonly used for OBU sizes i...
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 definitions to operate on bits in a bitstream.
Common NETINT definitions used by all modules.
#define NI_INVALID_SEI_TYPE
Definition ni_defs.h:314
#define NI_DEPRECATED
Definition ni_defs.h:80
#define NI_XCODER_REVISION_API_MAJOR_VER_IDX
Definition ni_defs.h:99
#define NI_MAX_NUM_DATA_POINTERS
Definition ni_defs.h:244
#define NI_APP_ENC_FRAME_META_DATA_SIZE_UNDER_MAJOR_6_MINOR_rc
Definition ni_defs.h:325
#define NI_APP_ENC_FRAME_META_DATA_SIZE
Definition ni_defs.h:322
#define NI_MAX_CUSTOM_SEI_CNT
Definition ni_defs.h:317
#define NI_MAX_NUM_OF_DECODER_OUTPUTS
Definition ni_defs.h:255
@ NI_DEVICE_TYPE_ENCODER
Definition ni_defs.h:361
#define NI_APP_ENC_FRAME_META_DATA_SIZE_UNDER_MAJOR_6_MINOR_Q
Definition ni_defs.h:324
#define NI_MEM_PAGE_ALIGNMENT
Definition ni_defs.h:263
ni_retcode_t
Definition ni_defs.h:447
@ NI_RETCODE_FAILURE
Definition ni_defs.h:449
@ NI_RETCODE_ERROR_UNSUPPORTED_FW_VERSION
Definition ni_defs.h:542
@ NI_RETCODE_SUCCESS
Definition ni_defs.h:448
@ NI_RETCODE_PARAM_INVALID_VALUE
Definition ni_defs.h:458
@ NI_RETCODE_ERROR_MEM_ALOC
Definition ni_defs.h:452
@ NI_RETCODE_INVALID_PARAM
Definition ni_defs.h:450
#define NI_UNUSED
Definition ni_defs.h:67
ni_aux_data_t * ni_frame_new_aux_data(ni_frame_t *frame, ni_aux_data_type_t type, int data_size)
Add a new auxiliary data to a frame.
ni_retcode_t ni_encoder_frame_zerocopy_buffer_alloc(ni_frame_t *p_frame, int video_width, int video_height, const int linesize[], const uint8_t *data[], int extra_len)
Allocate memory for encoder zero copy (metadata, etc.) for encoding based on given parameters,...
ni_retcode_t ni_encoder_frame_zerocopy_check(ni_session_context_t *p_enc_ctx, ni_xcoder_params_t *p_enc_params, int width, int height, const int linesize[], bool set_linesize)
Check if incoming frame is encoder zero copy compatible or not.
ni_aux_data_t * ni_frame_get_aux_data(const ni_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_frame_new_aux_data_from_raw_data(ni_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.
ni_retcode_t ni_encoder_sw_frame_buffer_alloc(bool planar, ni_frame_t *p_frame, int video_width, int video_height, int linesize[], int alignment, int extra_len, bool alignment_2pass_wa)
This API is a wrapper for ni_encoder_frame_buffer_alloc(), used for planar pixel formats,...
int ni_device_session_write(ni_session_context_t *p_ctx, ni_session_data_io_t *p_data, ni_device_type_t device_type)
Sends data to the device If device_type is NI_DEVICE_TYPE_DECODER sends data packet to decoder If dev...
Public definitions for operating NETINT video processing devices for video processing.
#define NI_MIN_HEIGHT
@ SESSION_RUN_STATE_SEQ_CHANGE_DRAINING
@ NI_CUSTOM_SEI_LOC_AFTER_VCL
@ NI_CUSTOM_SEI_LOC_BEFORE_VCL
#define NI_CC_SEI_TRAILER_LEN
#define NI_MAX_SEI_DATA
#define NI_CC_SEI_HDR_H264_LEN
#define NI_MAX_CUSTOM_SEI_DATA
#define NI_MAX_FRAME_SIZE
struct _ni_encoder_change_params_t ni_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_SLICE_ARG
@ NI_FRAME_AUX_DATA_CRF_FLOAT
@ NI_FRAME_AUX_DATA_UDU_SEI
@ NI_FRAME_AUX_DATA_MAX_MIN_QP
@ NI_FRAME_AUX_DATA_FRAMERATE
@ NI_FRAME_AUX_DATA_LTR_INTERVAL
@ NI_FRAME_AUX_DATA_HDR_PLUS
@ NI_FRAME_AUX_DATA_VBV_MAX_RATE
@ NI_FRAME_AUX_DATA_INTRAPRD
@ NI_FRAME_AUX_DATA_CRF
@ NI_FRAME_AUX_DATA_MAX_FRAME_SIZE
@ NI_FRAME_AUX_DATA_VUI
@ NI_FRAME_AUX_DATA_INVALID_REF_FRAME
@ 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
@ NI_FRAME_AUX_DATA_VBV_BUFFER_SIZE
#define NI_MAX_RESOLUTION_WIDTH
#define NI_MAX_SLICE_SIZE
#define NI_ENC_MAX_SEI_BUF_SIZE
struct _ni_ppu_config ni_ppu_config_t
#define NI_HDR10P_SEI_HDR_H264_LEN
#define NI_DEFAULT_INTRA_QP
#define NI_MAX_QP_DELTA
#define NI_MIN_QP_DELTA
#define NI_CUSTOMIZE_ROI_QPOFFSET_LEVEL
Max number of lines supported for qpoffset level.
enum _ni_codec_format ni_codec_format_t
This is an enumeration for supported codec formats.
#define NI_MAX_QP_INFO
#define NI_MIN_RESOLUTION_WIDTH_SCALER
#define NI_MAX_FRAMERATE
#define NI_HDR10P_SEI_HDR_HEVC_LEN
@ NI_CODEC_HW_NONE
@ NI_CODEC_FORMAT_H265
@ NI_CODEC_FORMAT_AV1
@ NI_CODEC_FORMAT_H264
@ NI_CODEC_FORMAT_JPEG
@ NI_PIX_FMT_ARGB
@ NI_PIX_FMT_P010LE
@ NI_PIX_FMT_YUV420P
@ NI_PIX_FMT_ABGR
@ NI_PIX_FMT_RGBA
@ NI_PIX_FMT_NV12
@ NI_PIX_FMT_BGRA
@ NI_PIX_FMT_YUV420P10LE
#define NI_MAX_ASPECTRATIO
ni_pic_type_t
@ PIC_TYPE_IDR
@ PIC_TYPE_P
@ NI_CUS_ROI_MAPFILE
#define NI_MAX_RESOLUTION_HEIGHT
#define NI_INTRA_QP_RANGE
@ NI_SET_CHANGE_PARAM_INVALID_REF_FRAME
@ NI_SET_CHANGE_PARAM_RC_TARGET_RATE
@ NI_SET_CHANGE_PARAM_RC_FRAMERATE
@ NI_SET_CHANGE_PARAM_CRF
@ NI_SET_CHANGE_PARAM_LTR_INTERVAL
@ NI_SET_CHANGE_PARAM_VBV
@ NI_SET_CHANGE_PARAM_VUI_HRD_PARAM
@ NI_SET_CHANGE_PARAM_RC_MIN_MAX_QP
@ NI_SET_CHANGE_PARAM_SLICE_ARG
@ NI_SET_CHANGE_PARAM_INTRA_PERIOD
@ NI_SET_CHANGE_PARAM_MAX_FRAME_SIZE
#define NI_INVALID_SVCT_DECODING_LAYER
#define NI_CC_SEI_HDR_HEVC_LEN
#define NI_RBSP_TRAILING_BITS_LEN
int ni_get_planar_from_pixfmt(int pix_fmt)
Grab planar info from NI_PIX_FMT.
Private definitions used by ni_device_api.c for video processing tasks.
struct _ni_enc_timecode_raw ni_timecode_raw_t
void ni_log2(const void *p_context, ni_log_level_t level, const char *fmt,...)
print log message and additional information using ni_log_callback,
Definition ni_log.c:337
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition ni_log.c:183
Logging definitions.
@ NI_LOG_DEBUG
Definition ni_log.h:64
@ NI_LOG_TRACE
Definition ni_log.h:65
@ NI_LOG_ERROR
Definition ni_log.h:62
@ NI_LOG_INFO
Definition ni_log.h:63
void ni_get_hw_yuv420p_dim(int width, int height, int factor, int is_semiplanar, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS])
Get dimension information of Netint HW YUV420p frame to be sent to encoder for encoding....
Definition ni_util.c:2747
int ni_insert_emulation_prevent_bytes(uint8_t *buf, int size)
Insert emulation prevention byte(s) as needed into the data buffer.
Definition ni_util.c:3299
void ni_copy_hw_yuv420p(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int frame_width, int frame_height, int factor, int is_semiplanar, int conf_win_right, int dst_stride[NI_MAX_NUM_DATA_POINTERS], int dst_height[NI_MAX_NUM_DATA_POINTERS], int src_stride[NI_MAX_NUM_DATA_POINTERS], int src_height[NI_MAX_NUM_DATA_POINTERS])
Copy YUV data to Netint HW YUV420p frame layout to be sent to encoder for encoding....
Definition ni_util.c:3060
int ni_cmp_fw_api_ver(const char ver1[], const char ver2[])
Compare two 3 character strings containing a FW API version. Handle comparision when FW API version f...
Definition ni_util.c:4387
Utility definitions.
#define NIALIGN(x, a)
Definition ni_util.h:100
payload format of HDR SEI content light level info
ni_custom_sei_t custom_sei[NI_MAX_CUSTOM_SEI_CNT]
custom sei payload passthrough
uint8_t data[NI_MAX_CUSTOM_SEI_DATA]
ni_custom_sei_location_t location
decoded payload format of HDR SEI mastering display colour volume
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 itu_t_t35_country_code
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]
encoded payload format of HDR SEI mastering display colour volume
struct _ni_encoder_cfg_params::@16 rc
This is a data structure for encoding parameters that have changed.
uint16_t force_pic_qp
uint8_t color_trc
uint32_t data_len[NI_MAX_NUM_DATA_POINTERS]
unsigned int sei_hdr_mastering_display_color_vol_offset
uint8_t * p_buffer
uint32_t vui_time_scale
uint32_t start_of_stream
unsigned int sei_hdr_content_light_level_info_offset
uint16_t sar_width
ni_codec_format_t src_codec
uint8_t color_primaries
unsigned int vui_len
unsigned int reconf_len
uint8_t preferred_characteristics_data_len
uint32_t vui_num_units_in_tick
uint8_t aspect_ratio_idc
uint32_t end_of_stream
uint16_t sar_height
uint8_t separate_metadata
unsigned int sei_hdr_plus_len
unsigned int vui_offset
uint32_t video_width
unsigned int sei_hdr_plus_offset
uint8_t timecode_present
uint8_t * p_data[NI_MAX_NUM_DATA_POINTERS]
uint8_t color_space
unsigned int extra_data_len
uint32_t buffer_size
unsigned int sei_total_len
unsigned int sei_cc_len
unsigned int sei_cc_offset
unsigned int sei_user_data_unreg_len
ni_pic_type_t ni_pict_type
uint8_t use_cur_src_as_long_term_pic
unsigned int sei_hdr_content_light_level_info_len
uint8_t * p_metadata_buffer
unsigned int sei_hdr_mastering_display_color_vol_len
int video_full_range_flag
unsigned int sei_user_data_unreg_offset
uint8_t use_long_term_ref
uint32_t video_height
unsigned int roi_len
unsigned int sei_alt_transfer_characteristics_len
unsigned int sei_alt_transfer_characteristics_offset
int32_t framerate_denom
int32_t framerate_num
ni_hdr_plus_percentile_t distribution_maxrgb[15]
ni_hdr_plus_overlap_process_option_t overlap_process_option
ni_rational_t percentile
uint8_t use_cur_src_as_long_term_pic
ni_rational_t display_primaries[3][2]
ni_custom_sei_set_t * p_custom_sei_set
uint16_t ppu_h[NI_MAX_NUM_OF_DECODER_OUTPUTS]
uint16_t ppu_w[NI_MAX_NUM_OF_DECODER_OUTPUTS]
uint8_t itu_t_t35_hdr10p_sei_hdr_hevc[NI_HDR10P_SEI_HDR_HEVC_LEN]
uint8_t preferred_characteristics_data
uint8_t ui8_light_level_data[5]
uint8_t itu_t_t35_cc_sei_hdr_av1[NI_CC_SEI_HDR_AV1_LEN]
int sei_hdr_mastering_display_color_vol_len
uint8_t sei_trailer[NI_CC_SEI_TRAILER_LEN]
ni_framerate_t framerate
uint8_t ui8_mdcv_max_min_lum_data[9]
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_framerate_t last_framerate
uint32_t force_idr_intra_offset
ni_long_term_ref_t ltr_to_set
ni_session_run_state_t session_run_state
ni_encoder_change_params_t * enc_change_params
uint8_t itu_t_t35_hdr10p_sei_hdr_h264[NI_HDR10P_SEI_HDR_H264_LEN]
ni_enc_quad_roi_custom_map * roi_map
ni_region_of_interest_t * av_rois
uint8_t minutes_value
uint32_t time_offset_value
uint8_t counting_type
uint8_t hours_flag
uint16_t n_frames
uint8_t minutes_flag
uint8_t hours_value
uint8_t full_timestamp_flag
uint8_t nuit_field_based_flag
uint8_t time_offset_length
uint8_t seconds_flag
uint8_t discontinuity_flag
uint8_t seconds_value
uint8_t cnt_dropped_flag
int32_t videoFullRange
int32_t colorDescPresent
int32_t colorPrimaries
int32_t aspectRatioHeight
int32_t colorSpace
int32_t colorTrc
int32_t aspectRatioWidth
ni_encoder_cfg_params_t cfg_enc_params
ni_decoder_input_params_t dec_input_params
encoder AVC ROI custom map (1 MB = 8bits)