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