libxcoder  3.5.1
ni_enc_api_logan.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_enc_api_logan.c
24 *
25 * \brief NETINT encoder API file
26 *
27 *******************************************************************************/
28 
29 #include "ni_enc_api_logan.h"
30 
31 static uint8_t g_itu_t_t35_cc_sei_hdr_hevc[NI_CC_SEI_HDR_HEVC_LEN] =
32 {
33  0x00, 0x00, 0x00, 0x01, // NAL start code 00 00 00 01
34  0x4e,
35  0x01, // nal_unit_header() {forbidden bit=0 nal_unit_type=39,
36  // nuh_layer_id=0 nuh_temporal_id_plus1=1)
37  0x04, // payloadType= 4 (user_data_registered_itu_t_t35)
38  0 + 11, // payLoadSize= ui16Len + 11; to be set (index 7)
39  0xb5, // itu_t_t35_country_code =181 (North America)
40  0x00,
41  0x31, // itu_t_t35_provider_code = 49
42  0x47, 0x41, 0x39,
43  0x34, // ATSC_user_identifier = "GA94"
44  0x03, // ATSC1_data_user_data_type_code=3
45  0 | 0xc0, // (ui16Len/3) | 0xc0 (to be set; index 16) (each CC character
46  //is 3 bytes)
47  0xFF // em_data = 255
48 };
49 
50 static uint8_t g_itu_t_t35_hdr10p_sei_hdr_hevc[NI_HDR10P_SEI_HDR_HEVC_LEN] =
51 {
52  0x00, 0x00, 0x00, 0x01, // NAL start code 00 00 00 01
53  0x4e,
54  0x01, // nal_unit_header() {forbidden bit=0 nal_unit_type=39,
55  // nuh_layer_id=0 nuh_temporal_id_plus1=1)
56  0x04, // payloadType= 4 (user_data_registered_itu_t_t35)
57  0x00, // payLoadSize; to be set (index 7)
58  0xb5, // u8 itu_t_t35_country_code =181 (North America)
59  //0x00,
60  //0x3c, // u16 itu_t_t35_provider_code = 0x003c
61  //0x00,
62  //0x01, // u16 itu_t_t35_provider_oriented_code = 0x0001
63  // payLoadSize count starts from itu_t_t35_provider_code and goes until
64  // and including trailer
65 };
66 
67 static uint8_t g_itu_t_t35_cc_sei_hdr_h264[NI_CC_SEI_HDR_H264_LEN] =
68 {
69  0x00, 0x00, 0x00, 0x01, // NAL start code 00 00 00 01
70  0x06, // nal_unit_header() {forbidden bit=0 nal_ref_idc=0, nal_unit_type=6
71  0x04, // payloadType= 4 (user_data_registered_itu_t_t35)
72  0 + 11, // payLoadSize= ui16Len + 11; to be set (index 6)
73  0xb5, // itu_t_t35_country_code =181 (North America)
74  0x00,
75  0x31, // itu_t_t35_provider_code = 49
76  0x47, 0x41, 0x39,
77  0x34, // ATSC_user_identifier = "GA94"
78  0x03, // ATSC1_data_user_data_type_code=3
79  0 | 0xc0, // (ui16Len/3) | 0xc0 (to be set; index 15) (each CC character
80  //is 3 bytes)
81  0xFF // em_data = 255
82 };
83 
84 static uint8_t g_itu_t_t35_hdr10p_sei_hdr_h264[NI_HDR10P_SEI_HDR_H264_LEN] =
85 {
86  0x00, 0x00, 0x00, 0x01, // NAL start code 00 00 00 01
87  0x06, // nal_unit_header() {forbidden bit=0 nal_ref_idc=0, nal_unit_type=6
88  0x04, // payloadType= 4 (user_data_registered_itu_t_t35)
89  0x00, // payLoadSize; to be set (index 6)
90  0xb5, // itu_t_t35_country_code =181 (North America)
91  //0x00,
92  //0x3c, // u16 itu_t_t35_provider_code = 0x003c
93  //0x00,
94  //0x01, // u16 itu_t_t35_provider_oriented_code = 0x0001
95  // payLoadSize count starts from itu_t_t35_provider_code and goes until
96  // and including trailer
97 };
98 
99 static uint8_t g_sei_trailer[NI_CC_SEI_TRAILER_LEN] =
100 {
101  0xFF, // marker_bits = 255
102  0x80 // RBSP trailing bits - rbsp_stop_one_bit and 7 rbsp_alignment_zero_bit
103 };
104 
105 /*!*****************************************************************************
106  * \brief Initialize ni_logan_enc_context_t
107  *
108  * \param[in/out] p_enc_ctx Pointer to ni_logan_enc_context_t
109  *
110  * \return
111  ******************************************************************************/
112 static void ni_logan_enc_context_init(ni_logan_enc_context_t* p_enc_ctx)
113 {
114  if (!p_enc_ctx)
115  {
116  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter\n",
117  __FUNCTION__, __LINE__);
118  return;
119  }
120 
121  /* Variables that need to be initialized */
122  p_enc_ctx->started = 0;
123  p_enc_ctx->p_spsPpsHdr = NULL;
124  p_enc_ctx->spsPpsAttach = 0;
125  p_enc_ctx->spsPpsArrived = 0;
126  p_enc_ctx->spsPpsHdrLen = 0;
127  p_enc_ctx->firstPktArrived = 0;
128  p_enc_ctx->dts_offset = 0;
129  p_enc_ctx->reconfigCount = 0;
130  p_enc_ctx->total_frames_received = 0;
131  p_enc_ctx->first_frame_pts = 0;
132  p_enc_ctx->latest_dts = 0;
133 
134  p_enc_ctx->orig_conf_win_top = 0;
135  p_enc_ctx->orig_conf_win_bottom = 0;
136  p_enc_ctx->orig_conf_win_left = 0;
137  p_enc_ctx->orig_conf_win_left = 0;
138 
139  p_enc_ctx->extradata = NULL;
140  p_enc_ctx->extradata_size = 0;
141 
142  p_enc_ctx->gotPacket = 0;
143  p_enc_ctx->sentFrame = 0;
144 
145  p_enc_ctx->fps_number = 0;
146  p_enc_ctx->fps_denominator = 0;
147 
148  p_enc_ctx->actual_dev_enc_idx = NI_INVALID_DEVICE_HANDLE;
149  p_enc_ctx->actual_dev_name = NULL;
150 
151  p_enc_ctx->encoder_flushing = 0;
152  p_enc_ctx->encoder_eof = 0;
153  p_enc_ctx->eos_fme_received = 0;
154 
155  memset(&(p_enc_ctx->output_pkt), 0, sizeof(ni_logan_session_data_io_t));
156  return;
157 }
158 
159 /*!*****************************************************************************
160  * \brief Initialize encode parameters, including ni_logan_enc_context_t,
161  * ni_logan_session_context_t and ni_logan_encoder_params_t
162  *
163  * \param[in/out] p_enc_ctx Pointer to ni_logan_enc_context_t
164  *
165  * \return On success
166  * NI_LOGAN_RETCODE_SUCCESS
167  * On failure
168  * NI_LOGAN_RETCODE_FAILURE
169  * NI_LOGAN_RETCODE_INVALID_PARAM,
170  * NI_LOGAN_RETCODE_ERROR_MEM_ALOC, etc
171  ******************************************************************************/
173 {
175  ni_logan_session_context_t *p_session_ctx = NULL;
176  ni_logan_encoder_params_t *p_encoder_params = NULL;
177 
178  if (!p_enc_ctx)
179  {
180  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter\n",
181  __FUNCTION__, __LINE__);
183  }
184 
186 
187  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
188 
189  // resource management request
190  if (0 == strcmp(p_enc_ctx->dev_xcoder, LIST_DEVICES_STR))
191  {
192  ni_log(NI_LOG_DEBUG, "XCoder: printing out all xcoder devices and "
193  "their load, and exit ...\n");
196  }
197 
198  // Encoder Context init
199  ni_logan_enc_context_init(p_enc_ctx);
200 
201  // Xcoder Session Context
202  p_session_ctx = malloc(sizeof(ni_logan_session_context_t));
203  if (!p_session_ctx)
204  {
205  ni_log(NI_LOG_ERROR, "ERROR %d:%s() line %d, alloc session context failed\n",
206  NI_ERRNO, __FUNCTION__, __LINE__);
208  LRETURN;
209  }
210  else
211  {
212  p_enc_ctx->p_session_ctx = p_session_ctx;
214 
215  /* this will be init again in ni_logan_encoder_session_open()
216  * can be modified in the future */
217  // init close caption SEI header and trailer
218  memcpy(p_session_ctx->itu_t_t35_cc_sei_hdr_hevc, g_itu_t_t35_cc_sei_hdr_hevc,
220  memcpy(p_session_ctx->itu_t_t35_cc_sei_hdr_h264, g_itu_t_t35_cc_sei_hdr_h264,
222  memcpy(p_session_ctx->sei_trailer, g_sei_trailer, NI_CC_SEI_TRAILER_LEN);
223  // init hdr10+ SEI header
224  memcpy(p_session_ctx->itu_t_t35_hdr10p_sei_hdr_hevc, g_itu_t_t35_hdr10p_sei_hdr_hevc,
226  memcpy(p_session_ctx->itu_t_t35_hdr10p_sei_hdr_h264, g_itu_t_t35_hdr10p_sei_hdr_h264,
228  }
229 
230  // Xcoder User Configuration
231  p_encoder_params = malloc(sizeof(ni_logan_encoder_params_t));
232  if (!p_encoder_params)
233  {
234  ni_log(NI_LOG_ERROR, "ERROR %d:%s() line %d, alloc encoder params failed\n",
235  NI_ERRNO, __FUNCTION__, __LINE__);
237  LRETURN;
238  }
239  else
240  {
241  p_enc_ctx->p_encoder_params = p_encoder_params;
242  retval = ni_logan_encoder_init_default_params(p_encoder_params,
243  p_enc_ctx->timebase_den,
244  p_enc_ctx->timebase_num * p_enc_ctx->ticks_per_frame,
245  p_enc_ctx->bit_rate,
246  NI_LOGAN_ODD2EVEN(p_enc_ctx->width),
247  NI_LOGAN_ODD2EVEN(p_enc_ctx->height));
248  if (retval < 0)
249  {
250  switch (retval)
251  {
253  ni_log(NI_LOG_ERROR, "Invalid Picture Width: too big\n");
254  break;
256  ni_log(NI_LOG_ERROR, "Invalid Picture Width: too small\n");
257  break;
259  ni_log(NI_LOG_ERROR, "Invalid Picture Height: too big\n");
260  break;
262  ni_log(NI_LOG_ERROR, "Invalid Picture Height: too small\n");
263  break;
265  ni_log(NI_LOG_ERROR, "Invalid Picture Width x Height: exceeds %d\n",
267  break;
268  default:
269  break;
270  }
271  ni_log(NI_LOG_ERROR, "%s(): line %d, %s\n",
272  __FUNCTION__, __LINE__, ni_logan_err2str(retval));
273  LRETURN;
274  }
275  }
276 
277  // Init input fifo
280  if (!p_enc_ctx->input_data_fifo)
281  {
282  ni_log(NI_LOG_ERROR, "%s(): line %d initialize enc frame buffer pool failed\n",
283  __FUNCTION__, __LINE__);
285  LRETURN;
286  }
287 
288  END:
289 
290  if (retval != NI_LOGAN_RETCODE_SUCCESS)
291  {
292  free(p_enc_ctx->p_session_ctx);
293  p_enc_ctx->p_session_ctx = NULL;
294  free(p_encoder_params);
295  p_enc_ctx->p_encoder_params = NULL;
297  }
298  return retval;
299 }
300 
301 /*!*****************************************************************************
302  * \brief Parse encoder parameters
303  * Check whether the parameters are reasonable
304  *
305  * \param[in/out] p_enc_ctx Pointer to ni_logan_enc_context_t
306  *
307  * \return On success
308  * NI_LOGAN_RETCODE_SUCCESS
309  * On failure
310  * NI_LOGAN_RETCODE_FAILURE,
311  * NI_LOGAN_RETCODE_INVALID_PARAM, etc.
312  ******************************************************************************/
314 {
316  ni_logan_session_context_t *p_session_ctx = NULL;
317  ni_logan_encoder_params_t *p_encoder_params = NULL;
318 
319  if (!p_enc_ctx)
320  {
321  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter\n",
322  __FUNCTION__, __LINE__);
324  }
325  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
326 
327  p_session_ctx = p_enc_ctx->p_session_ctx;
328  p_encoder_params = p_enc_ctx->p_encoder_params;
329  if (!p_session_ctx || !p_encoder_params)
330  {
331  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter, %p, %p\n",
332  __FUNCTION__, __LINE__, p_session_ctx, p_encoder_params);
334  }
335 
336  // ni_session_context_t sync up ni_logan_enc_context_t
337  p_session_ctx->codec_format = p_enc_ctx->codec_format;
338  p_session_ctx->p_session_config = p_enc_ctx->p_encoder_params;
339  p_session_ctx->hw_id = p_enc_ctx->dev_enc_idx;
340  p_session_ctx->hw_name = p_enc_ctx->dev_enc_name;
341  strcpy(p_session_ctx->dev_xcoder, p_enc_ctx->dev_xcoder);
342 
343  //overwrite keep alive timeout value here with a custom value if it was provided
344  // provided
345  // if xcoder option is set then overwrite the (legacy) decoder option
346  uint32_t xcoder_timeout = p_encoder_params->enc_input_params.keep_alive_timeout;
347  if (xcoder_timeout != NI_LOGAN_DEFAULT_KEEP_ALIVE_TIMEOUT)
348  {
349  p_session_ctx->keep_alive_timeout = xcoder_timeout;
350  }
351  else
352  {
353  p_session_ctx->keep_alive_timeout = p_enc_ctx->keep_alive_timeout;
354  }
355 
356  //overwrite set_high_priority value here with a custom value if it was provided
357  uint32_t xcoder_high_priority = p_encoder_params->enc_input_params.set_high_priority;
358  if(xcoder_high_priority != 0)
359  {
360  p_session_ctx->set_high_priority = xcoder_high_priority;
361  }
362  else
363  {
364  p_session_ctx->set_high_priority = p_enc_ctx->set_high_priority;
365  }
366 
367  // GOP PARSE
368  switch (p_encoder_params->enc_input_params.gop_preset_index)
369  {
370  /* dts_offset is the max number of non-reference frames in a GOP
371  * (derived from x264/5 algo) In case of IBBBP the first dts of the I frame should be input_pts-(3*ticks_per_frame)
372  * In case of IBP the first dts of the I frame should be input_pts-(1*ticks_per_frame)
373  * thus we ensure pts>dts in all cases
374  * */
375  case 1 /*PRESET_IDX_ALL_I*/:
376  case 2 /*PRESET_IDX_IPP*/:
377  case 6 /*PRESET_IDX_IPPPP*/:
378  case 9 /*PRESET_IDX_SP*/:
379  p_enc_ctx->dts_offset = 0;
380  break;
381  /* ts requires dts/pts of I frame not same when there are B frames in streams */
382  case 3 /*PRESET_IDX_IBBB*/:
383  case 4 /*PRESET_IDX_IBPBP*/:
384  case 7 /*PRESET_IDX_IBBBB*/:
385  p_enc_ctx->dts_offset = 1;
386  break;
387  case 5 /*PRESET_IDX_IBBBP*/:
388  p_enc_ctx->dts_offset = 2;
389  break;
390  case 8 /*PRESET_IDX_RA_IB*/:
391  p_enc_ctx->dts_offset = 3;
392  break;
393  default:
394  // TBD need user to specify offset
395  p_enc_ctx->dts_offset = 7;
396  ni_log(NI_LOG_DEBUG, "dts offset default to 7, TBD\n");
397  break;
398  }
399  if (1 == p_encoder_params->force_frame_type)
400  {
401  p_enc_ctx->dts_offset = 7;
402  }
403 
404  p_session_ctx->src_bit_depth = 8;
405  p_session_ctx->src_endian = NI_LOGAN_FRAME_LITTLE_ENDIAN;
406  p_session_ctx->roi_len = 0;
407  p_session_ctx->roi_avg_qp = 0;
408  p_session_ctx->bit_depth_factor = 1;
409 
410  if (NI_LOGAN_PIX_FMT_YUV420P10BE == p_enc_ctx->pix_fmt ||
412  {
413  p_session_ctx->bit_depth_factor = 2;
414  p_session_ctx->src_bit_depth = 10;
415  if (NI_LOGAN_PIX_FMT_YUV420P10BE == p_enc_ctx->pix_fmt)
416  {
417  p_session_ctx->src_endian = NI_LOGAN_FRAME_BIG_ENDIAN;
418  }
419  }
420 
421  // init HDR SEI stuff
422  p_session_ctx->sei_hdr_content_light_level_info_len =
423  p_session_ctx->light_level_data_len =
425  p_session_ctx->mdcv_max_min_lum_data_len = 0;
426  p_session_ctx->p_master_display_meta_data = NULL;
427 
428  // init HRD SEI stuff (TBD: value after recovery ?)
429  p_session_ctx->hrd_params.au_cpb_removal_delay_minus1 = 0;
430 
431  // DolbyVision, HRD and AUD settings
432  if (NI_LOGAN_CODEC_FORMAT_H265 == p_enc_ctx->codec_format)
433  {
434  if (5 == p_encoder_params->dolby_vision_profile)
435  {
436  p_encoder_params->hrd_enable = 1;
437  p_encoder_params->enable_aud = 1;
439  p_encoder_params->enc_input_params.decoding_refresh_type = 2;
440  }
441  if (p_encoder_params->hrd_enable)
442  {
443  p_encoder_params->enc_input_params.rc.enable_rate_control = 1;
444  }
445  }
446 
447  if (ni_logan_encoder_params_check(p_encoder_params, p_enc_ctx->codec_format) !=
449  {
450  ni_log(NI_LOG_ERROR, "Validate encode parameters failed\n");
452  }
453 
454  /* Update parameters that may be changed through xcoder parameters */
455  p_enc_ctx->fps_number = p_encoder_params->fps_number;
456  p_enc_ctx->fps_denominator = p_encoder_params->fps_denominator;
457  p_enc_ctx->bit_rate = p_encoder_params->bitrate;
458 
459  if (p_encoder_params->enable_vfr)
460  {
461  //in the vfr mode, Customer WangSu may reset time base to a very large value, such as 1000.
462  //At this time, the calculated framerate depends on timebase and ticket_per_frame is incorrect.
463  //So we choose to set the default framerate 30.
464  //If the calucluated framerate is correct, we will keep the original calculated framerate value
465  //Assume the frame between 5-120 is correct.
466  //using the time_base to initial timing info
467  if (p_encoder_params->enc_input_params.frame_rate < 5 ||
468  p_encoder_params->enc_input_params.frame_rate > 120)
469  {
470  p_encoder_params->enc_input_params.frame_rate = 30;
471  }
472  p_session_ctx->ui32timing_scale = p_enc_ctx->timebase_den;
473  p_session_ctx->ui32num_unit_in_tick = p_enc_ctx->timebase_num;
474  p_session_ctx->prev_bitrate = p_enc_ctx->bit_rate;
475  p_session_ctx->init_bitrate = p_enc_ctx->bit_rate;
476  p_session_ctx->last_change_framenum = 0;
477  p_session_ctx->fps_change_detect_count = 0;
478  }
479 
480  // generate encoded bitstream headers in advance if configured to do so
481  if (p_encoder_params->generate_enc_hdrs)
482  {
483  retval = ni_logan_encode_header(p_enc_ctx);
484  }
485 
486  ni_log(NI_LOG_TRACE, "XCoder Encoder Session Context:\n");
487 
488  ni_log(NI_LOG_TRACE, "hw_id=%d\n", p_session_ctx->hw_id);
489  ni_log(NI_LOG_TRACE, "hw_name=%s\n", p_session_ctx->hw_name);
490  ni_log(NI_LOG_TRACE, "codec_format=%u\n", p_session_ctx->codec_format);
491  ni_log(NI_LOG_TRACE, "src_bit_depth=%d\n", p_session_ctx->src_bit_depth);
492  ni_log(NI_LOG_TRACE, "src_endian=%d\n", p_session_ctx->src_endian);
493  ni_log(NI_LOG_TRACE, "bit_depth_factor=%d\n", p_session_ctx->bit_depth_factor);
494  ni_log(NI_LOG_TRACE, "keep_alive_timeout=%u\n", p_session_ctx->keep_alive_timeout);
495  ni_log(NI_LOG_TRACE, "set_high_priority=%u\n", p_session_ctx->set_high_priority);
496 
497  ni_log(NI_LOG_TRACE, "timebase_num=%d\n", p_enc_ctx->timebase_num);
498  ni_log(NI_LOG_TRACE, "timebase_den=%d\n", p_enc_ctx->timebase_den);
499  ni_log(NI_LOG_TRACE, "ticks_per_frame=%d\n", p_enc_ctx->ticks_per_frame);
500  ni_log(NI_LOG_TRACE, "bit_rate=%d\n", p_enc_ctx->bit_rate);
501  ni_log(NI_LOG_TRACE, "width=%d\n", p_enc_ctx->width);
502  ni_log(NI_LOG_TRACE, "height=%d\n", p_enc_ctx->height);
503  ni_log(NI_LOG_TRACE, "pix_fmt=%d\n", p_enc_ctx->pix_fmt);
504 
505  ni_log(NI_LOG_TRACE, "color_primaries=%d\n", p_enc_ctx->color_primaries);
506  ni_log(NI_LOG_TRACE, "color_trc=%d\n", p_enc_ctx->color_trc);
507  ni_log(NI_LOG_TRACE, "color_space=%d\n", p_enc_ctx->color_space);
508  ni_log(NI_LOG_TRACE, "color_range=%d\n", p_enc_ctx->color_range);
509 
510  ni_log(NI_LOG_TRACE, "sar_num=%d\n", p_enc_ctx->sar_num);
511  ni_log(NI_LOG_TRACE, "sar_den=%d\n", p_enc_ctx->sar_den);
512 
513  return retval;
514 }
515 
516 /*!*****************************************************************************
517  * \brief Get encoder headers from the hardware
518  *
519  * \param[in/out] p_enc_ctx Pointer to ni_logan_enc_context_t
520  *
521  * \return On success
522  * NI_LOGAN_RETCODE_SUCCESS
523  * On failure
524  * NI_LOGAN_RETCODE_FAILURE,
525  * NI_LOGAN_RETCODE_ERROR_MEM_ALOC, etc
526  ******************************************************************************/
528 {
529  int ret = NI_LOGAN_RETCODE_SUCCESS;
530  int recv = 0;
531  ni_logan_session_context_t session_ctx = {0};
532  ni_logan_encoder_params_t *p_encoder_param = p_enc_ctx->p_encoder_params;
533  ni_logan_session_data_io_t session_data_pkt = {0};
534 
535  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
536 
537  // use a copy of encoder context, take care to restore original config
538  // cropping setting
539  memcpy(&session_ctx, p_enc_ctx->p_session_ctx, sizeof(ni_logan_session_context_t));
540 
541  int orig_conf_win_right = p_encoder_param->enc_input_params.conf_win_right;
542  int orig_conf_win_bottom = p_encoder_param->enc_input_params.conf_win_bottom;
543  ni_logan_session_context_t *p_orig_session_ctx = p_enc_ctx->p_session_ctx;
544  p_enc_ctx->p_session_ctx = &session_ctx;
545 
546  // set to null when to generate encoder header
547  p_enc_ctx->p_input_fme = NULL;
548  ret = ni_logan_encode_open(p_enc_ctx);
549  if (ret != NI_LOGAN_RETCODE_SUCCESS)
550  {
551  ni_log(NI_LOG_ERROR, "ERROR %d:%s() line %d, failed to open encoder, ret=%d\n",
552  __FUNCTION__, __LINE__, ret);
553  return ret;
554  }
555 
556  ni_logan_packet_t *p_ni_pkt = &session_data_pkt.data.packet;
558 
559  for (; ;)
560  {
561  recv = ni_logan_device_session_read(&session_ctx, &session_data_pkt,
563 
564  if (recv > 0)
565  {
567  p_enc_ctx->extradata = malloc(p_enc_ctx->extradata_size);
568  if (!p_enc_ctx->extradata)
569  {
570  ni_log(NI_LOG_ERROR, "ERROR %d:%s() line %d, alloc extradata failed\n",
571  NI_ERRNO, __FUNCTION__, __LINE__);
572  p_enc_ctx->extradata_size = 0;
574  }
575  else
576  {
577  memset(p_enc_ctx->extradata, 0, p_enc_ctx->extradata_size);
578  memcpy(p_enc_ctx->extradata,
580  p_enc_ctx->extradata_size);
581  }
582 
583  ni_log(NI_LOG_TRACE, "%s extradata_size: %d\n", __FUNCTION__,
584  p_enc_ctx->extradata_size);
585  break;
586  }
587  else if (recv == NI_LOGAN_RETCODE_SUCCESS)
588  {
589  continue;
590  }
591  else
592  {
593  ni_log(NI_LOG_ERROR, "%s session read error: %d", __FUNCTION__, recv);
594  break;
595  }
596  }
597 
598  // close and clean up the temporary session
600 
601 #ifdef _WIN32
603 #elif __linux__
606 #endif
607  session_ctx.device_handle = NI_INVALID_DEVICE_HANDLE;
608  session_ctx.blk_io_handle = NI_INVALID_DEVICE_HANDLE;
609 
610  ni_logan_packet_buffer_free(p_ni_pkt);
611 
612  p_encoder_param->enc_input_params.conf_win_right = orig_conf_win_right;
613  p_encoder_param->enc_input_params.conf_win_bottom = orig_conf_win_bottom;
614  p_enc_ctx->actual_dev_enc_idx = NI_INVALID_DEVICE_HANDLE;
615  p_enc_ctx->actual_dev_name = NULL;
616  p_enc_ctx->p_session_ctx = p_orig_session_ctx;
617 
618  return (recv < 0 ? recv : ret);
619 
620 }
621 
622 /*!*****************************************************************************
623  * \brief Open encoder
624  *
625  * \param[in/out] p_enc_ctx Pointer to ni_logan_enc_context_t
626  *
627  * \return On success
628  * NI_LOGAN_RETCODE_SUCCESS
629  * On failure
630  * NI_LOGAN_RETCODE_FAILURE
631  * NI_LOGAN_RETCODE_INVALID_PARAM, etc.
632  ******************************************************************************/
634 {
635  int ret = 0;
636  ni_logan_session_context_t *p_session_ctx = NULL;
637  ni_logan_encoder_params_t *p_encoder_param = NULL;
638  ni_logan_frame_t *p_in_frame = NULL;
639  int frame_width;
640  int frame_height;
641  int linesize_aligned = 0;
642  int height_aligned = 0;
643  int video_full_range_flag = 0;
644  // color metrics
645  ni_color_primaries_t color_primaries;
647  ni_color_space_t color_space;
648 
649  if (!p_enc_ctx || !p_enc_ctx->p_session_ctx || !p_enc_ctx->p_encoder_params)
650  {
651  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter, %p, %p, %p\n",
652  __FUNCTION__, __LINE__, p_enc_ctx, p_enc_ctx->p_session_ctx,
653  p_enc_ctx->p_encoder_params);
655  }
656 
657  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
658 
659  p_session_ctx = p_enc_ctx->p_session_ctx;
660  p_encoder_param = p_enc_ctx->p_encoder_params;
661  p_in_frame = p_enc_ctx->p_input_fme;
662  color_primaries = p_enc_ctx->color_primaries;
663  color_trc = p_enc_ctx->color_trc;
664  color_space = p_enc_ctx->color_space;
665 
666  if (p_in_frame && p_in_frame->video_orig_width > 0 && p_in_frame->video_orig_height > 0)
667  {
668  frame_width = NI_LOGAN_ODD2EVEN(p_in_frame->video_orig_width);
669  frame_height = NI_LOGAN_ODD2EVEN(p_in_frame->video_orig_height);
670  color_primaries = p_in_frame->color_primaries;
671  color_trc = p_in_frame->color_trc;
672  color_space = p_in_frame->color_space;
673  // Force frame color metrics if specified in command line
674  if (p_in_frame->color_primaries != p_enc_ctx->color_primaries &&
676  {
677  color_primaries = p_enc_ctx->color_primaries;
678  }
679  if (p_in_frame->color_trc != p_enc_ctx->color_trc &&
680  p_enc_ctx->color_trc != NI_COL_TRC_UNSPECIFIED)
681  {
682  color_trc = p_enc_ctx->color_trc;
683  }
684  if (p_in_frame->color_space != p_enc_ctx->color_space &&
685  p_enc_ctx->color_space != NI_COL_SPC_UNSPECIFIED)
686  {
687  color_space = p_enc_ctx->color_space;
688  }
689  }
690  else
691  {
692  frame_width = NI_LOGAN_ODD2EVEN(p_enc_ctx->width);
693  frame_height = NI_LOGAN_ODD2EVEN(p_enc_ctx->height);
694  color_primaries = p_enc_ctx->color_primaries;
695  color_trc = p_enc_ctx->color_trc;
696  color_space = p_enc_ctx->color_space;
697  }
698 
699  linesize_aligned = ((frame_width + 7) / 8) * 8;
700  if (p_enc_ctx->codec_format == NI_LOGAN_CODEC_FORMAT_H264)
701  {
702  linesize_aligned = ((frame_width + 15) / 16) * 16;
703  }
704 
705  // save the original ConformanceWindowOffsets before changed
706  p_enc_ctx->orig_conf_win_right = p_encoder_param->enc_input_params.conf_win_right;
707  p_enc_ctx->orig_conf_win_bottom = p_encoder_param->enc_input_params.conf_win_bottom;
708  if (linesize_aligned < NI_LOGAN_MIN_WIDTH)
709  {
710  p_encoder_param->enc_input_params.conf_win_right += NI_LOGAN_MIN_WIDTH - frame_width;
711  linesize_aligned = NI_LOGAN_MIN_WIDTH;
712  }
713  else if (linesize_aligned > frame_width)
714  {
715  p_encoder_param->enc_input_params.conf_win_right += linesize_aligned - frame_width;
716  }
717  p_encoder_param->source_width = linesize_aligned;
718 
719  height_aligned = ((frame_height + 7) / 8) * 8;
720  if (p_enc_ctx->codec_format== NI_LOGAN_CODEC_FORMAT_H264) {
721  height_aligned = ((frame_height + 15) / 16) * 16;
722  }
723 
724  if (height_aligned < NI_LOGAN_MIN_HEIGHT)
725  {
726  p_encoder_param->enc_input_params.conf_win_bottom += NI_LOGAN_MIN_HEIGHT - frame_height;
727  p_encoder_param->source_height = NI_LOGAN_MIN_HEIGHT;
728  height_aligned = NI_LOGAN_MIN_HEIGHT;
729  }
730  else if (height_aligned > frame_height)
731  {
732  p_encoder_param->enc_input_params.conf_win_bottom += height_aligned - frame_height;
733  p_encoder_param->source_height = height_aligned;
734  }
735 
736  // DolbyVision support
737  if (5 == p_encoder_param->dolby_vision_profile &&
739  {
740  color_primaries = color_trc = color_space = 2;
741  video_full_range_flag = 1;
742  }
743 
744  // According to the pixel format or color range from the incoming video
745  if (p_enc_ctx->color_range == NI_COL_RANGE_JPEG ||
746  p_enc_ctx->pix_fmt == NI_LOGAN_PIX_FMT_YUVJ420P)
747  {
748  ni_log(NI_LOG_TRACE, "%s set video_full_range_flag\n", __FUNCTION__);
749  video_full_range_flag = 1;
750  }
751 
752  if (p_encoder_param->enable_vui_info_passthru == 1)
753  {
754  // The vui info should flow decoder, so skip ni_logan_set_vui
755  ;
756  }
757  else if ((5 == p_encoder_param->dolby_vision_profile &&
759  color_primaries == NI_COL_PRI_BT2020 ||
760  color_trc == NI_COL_TRC_SMPTE2084 ||
761  color_trc == NI_COL_TRC_ARIB_STD_B67 ||
762  color_space == NI_COL_SPC_BT2020_NCL ||
763  color_space == NI_COL_SPC_BT2020_CL)
764  {
765  p_encoder_param->hdrEnableVUI = 1;
766  ni_logan_set_vui(p_encoder_param,p_session_ctx,
767  color_primaries, color_trc, color_space,
768  video_full_range_flag, p_enc_ctx->sar_num,
769  p_enc_ctx->sar_den, p_enc_ctx->codec_format);
770  ni_log(NI_LOG_TRACE, "XCoder HDR color info color_primaries: %d "
771  "color_trc: %d color_space %d sar %d/%d\n",
772  color_primaries, color_trc, color_space,
773  p_enc_ctx->sar_num, p_enc_ctx->sar_den);
774  }
775  else
776  {
777  p_encoder_param->hdrEnableVUI = 0;
778  ni_logan_set_vui(p_encoder_param, p_session_ctx,
779  color_primaries, color_trc, color_space,
780  video_full_range_flag, p_enc_ctx->sar_num,
781  p_enc_ctx->sar_den, p_enc_ctx->codec_format);
782  }
783 
785 
786  p_enc_ctx->actual_dev_name = p_session_ctx->dev_xcoder_name;
787  p_enc_ctx->actual_dev_enc_idx = p_session_ctx->hw_id;
788 
789  if (ret != NI_LOGAN_RETCODE_SUCCESS)
790  {
791  ni_log(NI_LOG_ERROR, "%s(): error line %d, failed to open encoder, ret=%d\n",
792  __FUNCTION__, __LINE__, ret);
793  return ret;
794  }
795  else
796  {
797  ni_log(NI_LOG_TRACE, "%s(): encoder %s Index %d (inst: %d) opened successfully\n",
798  __FUNCTION__, p_enc_ctx->actual_dev_name, p_enc_ctx->actual_dev_enc_idx,
799  p_session_ctx->session_id);
800  }
801  return ret;
802 }
803 
804 /*!*****************************************************************************
805  * \brief Close encoder
806  *
807  * \param[in/out] p_enc_ctx Pointer to ni_logan_enc_context_t
808  *
809  * \return On success
810  * NI_LOGAN_RETCODE_SUCCESS
811  * On failure
812  * NI_LOGAN_RETCODE_FAILURE
813  * NI_LOGAN_RETCODE_INVALID_PARAM,
814  * NI_LOGAN_RETCODE_ERROR_MEM_ALOC,
815  * NI_LOGAN_RETCODE_ERROR_NVME_CMD_FAILED, etc
816  ******************************************************************************/
818 {
819  int ret = NI_LOGAN_RETCODE_SUCCESS;
820  ni_logan_session_context_t *p_session_ctx = NULL;
821  ni_logan_session_data_io_t *p_ni_frame = NULL;
822 
823  if (!p_enc_ctx || !p_enc_ctx->p_session_ctx)
824  {
825  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter, %p, %p\n",
826  __FUNCTION__, __LINE__, p_enc_ctx, p_enc_ctx->p_session_ctx);
828  }
829  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
830 
831  p_session_ctx = p_enc_ctx->p_session_ctx;
832  ret = ni_logan_device_session_close(p_session_ctx,
833  p_enc_ctx->encoder_eof,
835  if (NI_LOGAN_RETCODE_SUCCESS != ret)
836  {
837  ni_log(NI_LOG_ERROR, "%s(): error line %d, failed to close encoder, ret=%d\n",
838  __FUNCTION__, __LINE__, ret);
839  }
840 
841 #ifdef _WIN32
842  ni_logan_device_close(p_session_ctx->device_handle);
843 #elif __linux__
844  ni_logan_device_close(p_session_ctx->device_handle);
845  ni_logan_device_close(p_session_ctx->blk_io_handle);
846 #endif
847  p_session_ctx->device_handle = NI_INVALID_DEVICE_HANDLE;
848  p_session_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE;
849 
851 
854  {
855  if (p_enc_ctx->input_data_fifo)
856  {
857  // push back
858  do{
859  p_ni_frame = ni_logan_fifo_generic_write(p_enc_ctx->input_data_fifo);
860  }while(p_ni_frame);
861  // free all
862  do{
863  p_ni_frame = ni_logan_fifo_generic_read(p_enc_ctx->input_data_fifo);
864  if (p_ni_frame)
865  {
866  ni_logan_frame_buffer_free(&(p_ni_frame->data.frame));
867  }
868  }while(p_ni_frame);
869  }
871  ni_log(NI_LOG_TRACE, "%s(): encoder frame fifo freed.\n", __FUNCTION__);
872 
874  free(p_enc_ctx->p_session_ctx);
875  p_enc_ctx->p_session_ctx = NULL;
876 
877  free(p_enc_ctx->p_encoder_params);
878  p_enc_ctx->p_encoder_params = NULL;
879  }
880  else
881  {
883  ni_log(NI_LOG_TRACE, "%s(): encoder reset flow or sequence change flow.\n", __FUNCTION__);
884  }
885 
886  free(p_enc_ctx->extradata);
887  p_enc_ctx->extradata = NULL;
888  p_enc_ctx->extradata_size = 0;
889 
890  free(p_enc_ctx->p_spsPpsHdr);
891  p_enc_ctx->p_spsPpsHdr = NULL;
892  p_enc_ctx->spsPpsHdrLen = 0;
893 
894  return ret;
895 }
896 
897 /*!*****************************************************************************
898  * \brief Reinit encoder in some situation
899  *
900  * \param[in/out] p_enc_ctx Pointer to ni_logan_enc_context_t
901  *
902  * \return On success
903  * NI_LOGAN_RETCODE_SUCCESS
904  * On failure
905  * NI_LOGAN_RETCODE_FAILURE,
906  * NI_LOGAN_RETCODE_INVALID_PARAM, etc.
907  ******************************************************************************/
908 static int ni_logan_encode_reinit(ni_logan_enc_context_t *p_enc_ctx)
909 {
910  int ret = NI_LOGAN_RETCODE_SUCCESS;
911  ni_logan_session_context_t *p_session_ctx = p_enc_ctx->p_session_ctx;
912  ni_logan_session_data_io_t *p_input_fme = NULL;
913  ni_logan_encoder_params_t* p_encoder_params = p_enc_ctx->p_encoder_params;
914  int orig_conf_win_bottom = p_enc_ctx->orig_conf_win_bottom;
915  int orig_conf_win_right = p_enc_ctx->orig_conf_win_right;
916  ni_logan_session_run_state_t orig_run_state = p_session_ctx->session_run_state;
917 
918  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
919 
920  ni_logan_encode_close(p_enc_ctx);
921 
922  ni_logan_enc_context_init(p_enc_ctx);
923 
925 
926  // for sequence change, re-init avctx's resolution to the changed one
927  // that is stored in the first frame of the fifo
928  if (orig_run_state == LOGAN_SESSION_RUN_STATE_SEQ_CHANGE_DRAINING)
929  {
930  p_input_fme = ni_logan_fifo_generic_read(p_enc_ctx->input_data_fifo);
931  if (!p_input_fme)
932  {
933  ni_log(NI_LOG_ERROR, "%s(): fifo is empty when reinit\n", __FUNCTION__);
935  return ret;
936  }
937  ni_log(NI_LOG_TRACE, "%s(): resolution changing %dx%d -> %dx%d\n",
938  __FUNCTION__, p_enc_ctx->width, p_enc_ctx->height,
939  p_input_fme->data.frame.video_width,
940  p_input_fme->data.frame.video_height);
941  p_enc_ctx->width = p_input_fme->data.frame.video_orig_width;
942  p_enc_ctx->height = p_input_fme->data.frame.video_orig_height;
943  ret = ni_logan_fifo_return_read(p_enc_ctx->input_data_fifo);
944  if (ret < 0)
945  {
946  ni_log(NI_LOG_INFO, "%s(): Drop 1 frame because of fifo full, "
947  "when encode reinit\n", __FUNCTION__);
948  }
949 
950  // refill the encoder params
951  p_encoder_params->source_width = NI_LOGAN_ODD2EVEN(p_enc_ctx->width);
952  p_encoder_params->source_height = NI_LOGAN_ODD2EVEN(p_enc_ctx->height);
953  if (p_encoder_params->source_width > NI_LOGAN_PARAM_MAX_WIDTH)
954  {
956  return ret;
957  }
958  if (p_encoder_params->source_width < NI_LOGAN_PARAM_MIN_WIDTH)
959  {
961  return ret;
962  }
963  if (p_encoder_params->source_height > NI_LOGAN_PARAM_MAX_HEIGHT)
964  {
966  return ret;
967  }
968  if (p_encoder_params->source_height < NI_LOGAN_PARAM_MIN_HEIGHT)
969  {
971  return ret;
972  }
973  if (p_encoder_params->source_height*p_encoder_params->source_width > NI_LOGAN_MAX_RESOLUTION_AREA)
974  {
976  return ret;
977  }
978  }
979 
980  // these may be updated in ni_logan_encode_open()
981  p_encoder_params->enc_input_params.conf_win_bottom = orig_conf_win_bottom;
982  p_encoder_params->enc_input_params.conf_win_right = orig_conf_win_right;
983 
984  ret = ni_logan_encode_params_parse(p_enc_ctx);
985  if (ret < 0)
986  {
987  ni_log(NI_LOG_ERROR, "%s(): line %d, %s\n",
988  __FUNCTION__, __LINE__, ni_logan_err2str(ret));
990  return ret;
991  }
992 
993  while (!ni_logan_fifo_is_empty(p_enc_ctx->input_data_fifo))
994  {
996  ret = ni_logan_encode_send(p_enc_ctx);
997  if (ret < 0)
998  {
999  ni_log(NI_LOG_ERROR, "%s(): line %d, encode send failed, %s\n",
1000  __FUNCTION__, __LINE__, ni_logan_err2str(ret));
1001  break;
1002  }
1004  {
1005  ni_log(NI_LOG_INFO, "%s(): break flush queued frames because of "
1006  "resolution changes again, left cnt=%d\n",
1007  __FUNCTION__, p_enc_ctx->input_data_fifo->number_of_buffers_used);
1008  break;
1009  }
1010  else if (p_session_ctx->status == NI_LOGAN_RETCODE_NVME_SC_WRITE_BUFFER_FULL)
1011  {
1012  ni_log(NI_LOG_INFO, "%s(): break flush queued frames because of "
1013  "buffer full, left cnt=%d\n",
1014  __FUNCTION__, p_enc_ctx->input_data_fifo->number_of_buffers_used);
1015  break;
1016  }
1017  else
1018  {
1019  ni_log(NI_LOG_TRACE, "%s(): continue to flush queued frames, cnt=%d\n",
1020  __FUNCTION__, p_enc_ctx->input_data_fifo->number_of_buffers_used);
1021  }
1022  }
1023 
1024  return ret;
1025 }
1026 
1027 /*!*****************************************************************************
1028  * \brief Get allocated ni_frame from fifo pool
1029  *
1030  * \param[in] p_enc_ctx Pointer to ni_logan_enc_context_t
1031  *
1032  * \return On success
1033  * NI_LOGAN_RETCODE_SUCCESS
1034  * On failure
1035  * NI_LOGAN_RETCODE_FAILURE
1036  ******************************************************************************/
1038 {
1039  int ret = NI_LOGAN_RETCODE_SUCCESS;
1040  ni_logan_session_context_t *p_session_ctx = NULL;
1041  ni_logan_encoder_params_t *p_encoder_params = NULL;
1042 
1043  if (!p_enc_ctx || !p_enc_ctx->p_session_ctx || !p_enc_ctx->p_encoder_params)
1044  {
1045  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter, %p, %p, %p\n",
1046  __FUNCTION__, __LINE__, p_enc_ctx, p_enc_ctx->p_session_ctx,
1047  p_enc_ctx->p_encoder_params);
1049  }
1050  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
1051 
1052  p_session_ctx = p_enc_ctx->p_session_ctx;
1053  p_encoder_params = p_enc_ctx->p_encoder_params;
1054 
1056  if (p_enc_ctx->p_input_fme)
1057  {
1059 
1060  // force pic qp demo mode: initial QP (200 frames) -> QP value specified by
1061  // ForcePicQpDemoMode (100 frames) -> initial QP (remaining frames)
1062  if (p_encoder_params->force_pic_qp_demo_mode)
1063  {
1064  if (p_session_ctx->frame_num >= 300)
1065  {
1066  p_enc_ctx->p_input_fme->data.frame.force_pic_qp = p_encoder_params->enc_input_params.rc.intra_qp;
1067  }
1068  else if (p_session_ctx->frame_num >= 200)
1069  {
1070  p_enc_ctx->p_input_fme->data.frame.force_pic_qp = p_encoder_params->force_pic_qp_demo_mode;
1071  }
1072  }
1073  }
1074  else
1075  {
1076  ni_log(NI_LOG_ERROR, "%s(): Error fifo is full or opinter is null:%p\n",
1077  __FUNCTION__, p_enc_ctx->input_data_fifo);
1079  }
1080  return ret;
1081 }
1082 
1083 /*!*****************************************************************************
1084  * \brief Fill reconfig vfr
1085  *
1086  * \param[in] p_ctx Pointer to ni_logan_enc_context_t
1087  * \param[in/out] ni_frame aux_data may be updated
1088  * \param[in] pts frame pts
1089  *
1090  * \return
1091  ******************************************************************************/
1093  ni_logan_frame_t *ni_frame,
1094  int64_t pts)
1095 {
1096  uint32_t timebase = p_enc_ctx->timebase_num / p_enc_ctx->timebase_den;
1097  ni_logan_enc_reconfig_vfr(p_enc_ctx->p_session_ctx, p_enc_ctx->p_encoder_params, ni_frame, pts, timebase);
1098  return;
1099 }
1100 
1101 /*!*****************************************************************************
1102  * \brief Copy frame data to NI frame
1103  *
1104  * \param[in/out] p_enc_ctx Pointer to ni_logan_enc_context_t
1105  * \param[in] p_dec_frame Pointer to ni_logan_frame_t,
1106  * contains aux data from NI decoder
1107  * \param[in] p_data Pointer to input frame data
1108  * \param[in] linesize Pointer to linesize of input frame
1109  *
1110  * \return On success
1111  * NI_LOGAN_RETCODE_SUCCESS
1112  * On failure
1113  * NI_LOGAN_RETCODE_FAILURE,
1114  * NI_LOGAN_RETCODE_ERROR_MEM_ALOC, etc
1115  ******************************************************************************/
1117  ni_logan_frame_t *p_dec_frame,
1118  uint8_t *p_data[NI_LOGAN_MAX_NUM_DATA_POINTERS],
1119  int linesize[NI_LOGAN_MAX_NUM_DATA_POINTERS])
1120 {
1121  int ret = NI_LOGAN_RETCODE_SUCCESS;
1122  ni_logan_session_context_t *p_session_ctx = NULL;
1123  ni_logan_encoder_params_t *p_encoder_params = NULL;
1124  ni_logan_frame_t *p_ni_frame = NULL;
1125  int send_sei_with_idr = 0;
1126 
1127  if (!p_enc_ctx || !p_enc_ctx->p_session_ctx || !p_enc_ctx->p_encoder_params ||
1128  !p_enc_ctx->p_input_fme)
1129  {
1130  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter, %p, %p, %p, %p\n",
1131  __FUNCTION__, __LINE__, p_enc_ctx, p_enc_ctx->p_session_ctx,
1132  p_enc_ctx->p_encoder_params, p_enc_ctx->p_input_fme);
1134  }
1135  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
1136  p_session_ctx = p_enc_ctx->p_session_ctx;
1137  p_encoder_params = p_enc_ctx->p_encoder_params;
1138  p_ni_frame = p_enc_ctx->p_input_fme;
1139  p_ni_frame->video_width = NI_LOGAN_ODD2EVEN(p_ni_frame->video_orig_width);
1140  p_ni_frame->video_height = NI_LOGAN_ODD2EVEN(p_ni_frame->video_orig_height);
1141 
1142  // data buffer for various SEI: HDR mastering display color volume, HDR
1143  // content light level, close caption, User data unregistered, HDR10+ etc.
1144  uint8_t mdcv_data[NI_LOGAN_MAX_SEI_DATA];
1145  uint8_t cll_data[NI_LOGAN_MAX_SEI_DATA];
1146  uint8_t cc_data[NI_LOGAN_MAX_SEI_DATA];
1147  uint8_t udu_data[NI_LOGAN_MAX_SEI_DATA];
1148  uint8_t hdrp_data[NI_LOGAN_MAX_SEI_DATA];
1149 
1150  int dst_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS] = {0};
1151  int dst_height_aligned[NI_LOGAN_MAX_NUM_DATA_POINTERS] = {0};
1152  int src_height[NI_LOGAN_MAX_NUM_DATA_POINTERS] = {0};
1153 
1154  // whether should send SEI with this frame
1155  send_sei_with_idr = ni_logan_should_send_sei_with_frame(p_session_ctx,
1156  p_ni_frame->ni_logan_pict_type,
1157  p_encoder_params);
1158 
1159  // prep for auxiliary data (various SEI, ROI) in encode frame, based on the
1160  // data returned in decoded frame
1161  ni_logan_enc_prep_aux_data(p_session_ctx, p_ni_frame, p_dec_frame,
1162  p_enc_ctx->codec_format, send_sei_with_idr,
1163  mdcv_data, cll_data, cc_data, udu_data, hdrp_data);
1164 
1165  if (p_ni_frame->sei_total_len > NI_LOGAN_ENC_MAX_SEI_BUF_SIZE)
1166  {
1167  ni_log(NI_LOG_ERROR, "%s: sei total length %u exceeds maximum sei "
1168  "size %u.\n", __FUNCTION__, p_ni_frame->sei_total_len,
1171  return ret;
1172  }
1173 
1174  p_ni_frame->extra_data_len += p_ni_frame->sei_total_len;
1175  // FW layout requirement: leave space for reconfig data if SEI and/or ROI
1176  // is present
1177  if ((p_ni_frame->sei_total_len || p_ni_frame->roi_len)
1178  && !p_ni_frame->reconf_len)
1179  {
1180  p_ni_frame->extra_data_len += sizeof(ni_logan_encoder_change_params_t);
1181  }
1182 
1183  src_height[0] = p_ni_frame->video_orig_height;
1184  src_height[1] = src_height[2] = src_height[0] / 2;
1185 
1187  p_ni_frame->video_height,
1188  p_session_ctx->bit_depth_factor,
1190  dst_stride, dst_height_aligned);
1191 
1192  // alignment(16) extra padding for H.264 encoding
1194  p_ni_frame->video_width,
1195  p_ni_frame->video_height,
1196  dst_stride,
1197  (p_enc_ctx->codec_format == NI_LOGAN_CODEC_FORMAT_H264),
1198  p_ni_frame->extra_data_len,
1199  p_session_ctx->bit_depth_factor);
1200  if (!p_ni_frame->p_data[0])
1201  {
1202  ni_log(NI_LOG_ERROR, "%s: alloc frame buffer failed\n", __FUNCTION__);
1204  return ret;
1205  }
1206 
1207  ni_log(NI_LOG_TRACE, "%s: api_fme.data_len[0]=%d, "
1208  "buffered_fme.linesize=%d/%d/%d, dst alloc linesize = %d/%d/%d, "
1209  "src height = %d/%d%d, dst height aligned = %d/%d/%d, "
1210  "ctx->api_fme.force_key_frame=%d, extra_data_len=%d sei_size=%u "
1211  "(hdr_content_light_level %u hdr_mastering_display_color_vol %u "
1212  "hdr10+ %u cc %u udu %u prefC %u) "
1213  "reconf_size=%u roi_size=%u force_pic_qp=%u "
1214  "use_cur_src_as_long_term_pic %u use_long_term_ref %u\n",
1215  __FUNCTION__, p_ni_frame->data_len[0], linesize[0], linesize[1],
1216  linesize[2], dst_stride[0], dst_stride[1], dst_stride[2],
1217  src_height[0], src_height[1], src_height[2],
1218  dst_height_aligned[0], dst_height_aligned[1], dst_height_aligned[2],
1219  p_ni_frame->force_key_frame,
1220  p_ni_frame->extra_data_len,
1221  p_ni_frame->sei_total_len,
1224  p_ni_frame->sei_hdr_plus_len,
1225  p_ni_frame->sei_cc_len,
1226  p_ni_frame->sei_user_data_unreg_len,
1228  p_ni_frame->reconf_len,
1229  p_ni_frame->roi_len,
1230  p_ni_frame->force_pic_qp,
1231  p_ni_frame->use_cur_src_as_long_term_pic,
1232  p_ni_frame->use_long_term_ref);
1233 
1234  // YUV part of the encoder input data layout
1235  ni_logan_copy_hw_yuv420p(p_ni_frame->p_data, p_data,
1236  p_ni_frame->video_orig_width,
1237  p_ni_frame->video_orig_height,
1238  p_session_ctx->bit_depth_factor,
1239  dst_stride, dst_height_aligned,
1240  linesize, src_height);
1241 
1242  ni_log(NI_LOG_TRACE, "%s: After memcpy p_data 0:0x%p 1:0x%p 2:0x%p "
1243  "len:0:%d 1:%d 2:%d\n",
1244  p_ni_frame->p_data,
1245  p_ni_frame->p_data,
1246  p_ni_frame->p_data,
1247  p_ni_frame->data_len[0],
1248  p_ni_frame->data_len[1],
1249  p_ni_frame->data_len[2]);
1250 
1251  // auxiliary data part of the encoder input data layout
1252  ni_logan_enc_copy_aux_data(p_session_ctx, p_ni_frame, p_dec_frame,
1253  p_session_ctx->codec_format, mdcv_data, cll_data,
1254  cc_data, udu_data, hdrp_data);
1255  return ret;
1256 }
1257 
1258 /*!*****************************************************************************
1259  * \brief Send encode data to NI device
1260  *
1261  * \param[in] p_enc_ctx Pointer to ni_logan_enc_context_t
1262  *
1263  * \return On success
1264  * NI_LOGAN_RETCODE_SUCCESS
1265  * On failure
1266  * NI_LOGAN_RETCODE_FAILURE,
1267  * NI_LOGAN_RETCODE_INVALID_PARAM, etc.
1268  ******************************************************************************/
1270 {
1271  int ret = NI_LOGAN_RETCODE_SUCCESS;
1272  int sent;
1273  ni_logan_session_context_t *p_session_ctx = NULL;
1274  ni_logan_encoder_params_t *p_encoder_params = NULL;
1275  ni_logan_session_data_io_t *p_input_fme = NULL;
1276 
1277  if (!p_enc_ctx || !p_enc_ctx->p_session_ctx || !p_enc_ctx->p_encoder_params)
1278  {
1279  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter, %p, %p, %p\n",
1280  __FUNCTION__, __LINE__, p_enc_ctx, p_enc_ctx->p_session_ctx,
1281  p_enc_ctx->p_encoder_params);
1283  }
1284  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
1285 
1286  p_session_ctx = p_enc_ctx->p_session_ctx;
1287  p_encoder_params = p_enc_ctx->p_encoder_params;
1288 
1289  if (p_enc_ctx->encoder_flushing)
1290  {
1291  if (ni_logan_fifo_is_empty(p_enc_ctx->input_data_fifo))
1292  {
1293  ni_log(NI_LOG_DEBUG, "XCoder EOF: null frame && fifo empty\n");
1294  return ret;
1295  }
1296  }
1297 
1299  {
1300  ni_log(NI_LOG_DEBUG, "%s(): sequence change draining state\n", __FUNCTION__);
1301  return ret;
1302  }
1303 
1304  p_input_fme = ni_logan_fifo_generic_read(p_enc_ctx->input_data_fifo);
1305 
1306  if (!p_input_fme && p_enc_ctx->eos_fme_received)
1307  {
1308  p_enc_ctx->encoder_flushing = 1;
1309  ni_log(NI_LOG_DEBUG, "null frame, eos_fme_received = 1\n");
1310  if (p_enc_ctx->started)
1311  {
1313  }
1314  return ret;
1315  }
1316  else
1317  {
1318  p_enc_ctx->p_input_fme = p_input_fme;
1319 
1320  // check whether sequence changed
1321  if (p_input_fme->data.frame.video_orig_width != p_enc_ctx->width ||
1322  p_input_fme->data.frame.video_orig_height != p_enc_ctx->height)
1323  {
1325  ret = ni_logan_fifo_return_read(p_enc_ctx->input_data_fifo);
1326  if (ret < 0)
1327  {
1328  ni_log(NI_LOG_INFO, "%s(): Drop 1 frame because of buffer full, "
1329  "when sequence changed\n", __FUNCTION__);
1330  }
1331 
1333  ni_log(NI_LOG_TRACE, "%s(): frame_num=%d, encoder sequence changed, "
1334  "%dx%d to %dx%d\n", __FUNCTION__, p_session_ctx->frame_num,
1335  p_enc_ctx->width, p_enc_ctx->height,
1336  p_input_fme->data.frame.video_orig_width,
1337  p_input_fme->data.frame.video_orig_height);
1338  return ret;
1339  }
1340 
1341  ni_log(NI_LOG_TRACE, "%s(): ni_frame num=%d, pts=%d, dts=%d, WxH=%dx%d, "
1342  "orig WxH=%dx%d, crop=%d,%d,%d,%d, pict_type=%d, key_frame=%d, "
1343  "buffer_size=%d, data_len=%d,%d,%d,%d\n", __FUNCTION__,
1344  p_session_ctx->frame_num,
1345  p_input_fme->data.frame.pts,
1346  p_input_fme->data.frame.dts,
1347  p_input_fme->data.frame.video_width,
1348  p_input_fme->data.frame.video_height,
1349  p_input_fme->data.frame.video_orig_width,
1350  p_input_fme->data.frame.video_orig_height,
1351  p_input_fme->data.frame.crop_top,
1352  p_input_fme->data.frame.crop_bottom,
1353  p_input_fme->data.frame.crop_left,
1354  p_input_fme->data.frame.crop_right,
1355  p_input_fme->data.frame.ni_logan_pict_type,
1356  p_input_fme->data.frame.force_key_frame,
1357  p_input_fme->data.frame.buffer_size,
1358  p_input_fme->data.frame.data_len[0],
1359  p_input_fme->data.frame.data_len[1],
1360  p_input_fme->data.frame.data_len[2],
1361  p_input_fme->data.frame.data_len[3]);
1362  ni_log(NI_LOG_TRACE, "%s(): ni_frame sei_total_len=%d, sei_cc=%d-%d, "
1363  "sei_hdr_mastering_display_color_vol=%d-%d, sei_hdr_plus=%d-%d, "
1364  "sei_hdr_content_light_level_info=%d-%d, sei_user_data_unreg=%d-%d, "
1365  "sei_alt_transfer_characteristics=%d-%d, vui=%d-%d, roi_len=%d, "
1366  "reconf_len=%d, extra_data_len=%d\n", __FUNCTION__,
1367  p_input_fme->data.frame.sei_total_len,
1368  p_input_fme->data.frame.sei_cc_offset,
1369  p_input_fme->data.frame.sei_cc_len,
1372  p_input_fme->data.frame.sei_hdr_plus_offset,
1373  p_input_fme->data.frame.sei_hdr_plus_len,
1376  p_input_fme->data.frame.sei_user_data_unreg_offset,
1377  p_input_fme->data.frame.sei_user_data_unreg_len,
1380  p_input_fme->data.frame.vui_offset,
1381  p_input_fme->data.frame.vui_len,
1382  p_input_fme->data.frame.roi_len,
1383  p_input_fme->data.frame.reconf_len,
1384  p_input_fme->data.frame.extra_data_len);
1385 
1386  if (p_enc_ctx->started == 0)
1387  {
1388  ret = ni_logan_encode_open(p_enc_ctx);
1389  if (ret < 0)
1390  {
1391  ni_log(NI_LOG_ERROR, "ni_logan_encode_open failed:%d\n", ret);
1392  return ret;
1393  }
1394  p_enc_ctx->started = 1;
1395  p_input_fme->data.frame.start_of_stream = 1;
1396  }
1397  else
1398  {
1399  p_input_fme->data.frame.start_of_stream = 0;
1400  }
1401 
1402  sent = ni_logan_device_session_write(p_session_ctx, p_input_fme, NI_LOGAN_DEVICE_TYPE_ENCODER);
1403  ni_log(NI_LOG_TRACE, "%s: pts %lld dts %lld size %d sent to xcoder\n",
1404  __FUNCTION__, p_input_fme->data.frame.pts, p_input_fme->data.frame.dts, sent);
1405  // return EIO at error
1407  {
1408  ni_log(NI_LOG_TRACE, "%s(): vpu recovery1, push back frame %d\n",
1409  __FUNCTION__, p_session_ctx->frame_num);
1411  ret = ni_logan_fifo_return_read(p_enc_ctx->input_data_fifo);
1412  if (ret < 0)
1413  {
1414  ni_log(NI_LOG_INFO, "%s(): Drop 1 frame because of buffer full, "
1415  "when vpu recovery happened\n", __FUNCTION__);
1416  }
1417  ret = ni_logan_encode_reinit(p_enc_ctx);
1418  if (ret < 0)
1419  {
1420  ni_log(NI_LOG_ERROR, "%s(): VPU recovery failed:%d, returning "
1421  "EIO\n", __FUNCTION__, sent);
1423  }
1424  return ret;
1425  }
1426  else if (sent < 0)
1427  {
1428  ni_log(NI_LOG_ERROR, "%s(): failure sent (%d), returning EIO\n",
1429  __FUNCTION__, sent);
1430  return ret;
1431  }
1432  else if (sent == 0)
1433  {
1434  // when buffer_full, drop the frame and return EAGAIN if in strict timeout
1435  // mode, otherwise buffer the frame and it is to be sent out using encode2
1436  // API: queue the frame only if not done so yet, i.e. queue is empty
1437  // *and* it's a valid frame. ToWatch: what are other rc cases ?
1438  if (p_session_ctx->status == NI_LOGAN_RETCODE_NVME_SC_WRITE_BUFFER_FULL)
1439  {
1440  if (p_encoder_params->strict_timeout_mode)
1441  {
1442  ni_log(NI_LOG_ERROR, "%s(): Error Strict timeout period exceeded"
1443  " returning EAGAIN\n", __FUNCTION__);
1445  }
1446  else
1447  {
1448  ni_log(NI_LOG_TRACE, "%s(): Write buffer full, push back frame %d\n",
1449  __FUNCTION__, p_session_ctx->frame_num);
1450  ret = ni_logan_fifo_return_read(p_enc_ctx->input_data_fifo);
1451  if (ret < 0)
1452  {
1453  ni_log(NI_LOG_INFO, "%s(): Drop 1 frame because of fifo full, "
1454  "when wirte buffer full\n", __FUNCTION__);
1455  }
1456  }
1457  return ret;
1458  }
1459  }
1460  else
1461  {
1462  p_enc_ctx->sentFrame = 1;
1463  //pushing input pts in circular FIFO
1464  p_session_ctx->enc_pts_list[p_session_ctx->enc_pts_w_idx % NI_LOGAN_FIFO_SZ] = p_input_fme->data.frame.pts;
1465  p_session_ctx->enc_pts_w_idx++;
1467  }
1468  }
1469 
1470  return ret;
1471 }
1472 
1473 /*!*****************************************************************************
1474  * \brief Copy NI packet to packet data buffer
1475  *
1476  * \param[in] p_enc_ctx Pointer to ni_logan_enc_context_t
1477  * \param[out] p_data Pointer to output packet data buffer,
1478  * \param[in] first_packet flag of first packet
1479  * \param[in] sps_pps_attach flag of attached SPS/PPS
1480  *
1481  * \return On success
1482  * NI_LOGAN_RETCODE_SUCCESS
1483  * On failure
1484  * NI_LOGAN_RETCODE_FAILURE,
1485  * NI_LOGAN_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG, etc
1486  ******************************************************************************/
1488  uint8_t *p_data,
1489  int first_packet,
1490  int sps_pps_attach)
1491 {
1492  int ret = 0;
1493  ni_logan_session_context_t *p_session_ctx = NULL;
1494  ni_logan_encoder_params_t *p_encoder_params = NULL;
1495  ni_logan_packet_t *p_output_pkt = NULL;
1496 
1497  if (!p_enc_ctx || !p_enc_ctx->p_session_ctx || !p_enc_ctx->p_encoder_params)
1498  {
1499  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter, %p, %p, %p\n",
1500  __FUNCTION__, __LINE__, p_enc_ctx, p_enc_ctx->p_session_ctx,
1501  p_enc_ctx->p_encoder_params);
1503  }
1504  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
1505 
1506  p_session_ctx = p_enc_ctx->p_session_ctx;
1507  p_encoder_params = p_enc_ctx->p_encoder_params;
1508  p_output_pkt = &p_enc_ctx->output_pkt;
1509 
1511  int nalu_type = 0;
1512  const uint8_t *p_start_code;
1513  uint32_t stc = -1;
1514  uint32_t copy_len = 0;
1515  uint8_t *p_src = (uint8_t*)p_output_pkt->p_data + meta_size;
1516  uint8_t *p_end = p_src + (p_output_pkt->data_len - meta_size);
1517  int64_t local_pts = p_output_pkt->pts;
1518  int custom_sei_cnt = 0;
1519  int sei_idx = 0;
1520  ni_logan_all_custom_sei_t *ni_logan_all_custom_sei;
1521  ni_logan_custom_sei_t *ni_logan_custom_sei;
1522  if (p_session_ctx->pkt_custom_sei[local_pts % NI_LOGAN_FIFO_SZ])
1523  {
1524  ni_logan_all_custom_sei = p_session_ctx->pkt_custom_sei[local_pts % NI_LOGAN_FIFO_SZ];
1525  custom_sei_cnt = ni_logan_all_custom_sei->custom_sei_cnt;
1526  }
1527 
1528  if (custom_sei_cnt)
1529  {
1530  // if HRD or custom sei enabled, search for pic_timing or custom SEI insertion point by
1531  // skipping non-VCL until video data is found.
1532  p_start_code = p_src;
1533  if(NI_LOGAN_CODEC_FORMAT_H265 == p_enc_ctx->codec_format)
1534  {
1535  do
1536  {
1537  stc = -1;
1538  p_start_code = ni_logan_find_start_code(p_start_code, p_end, &stc);
1539  nalu_type = (stc >> 1) & 0x3F;
1540  } while (nalu_type > 21/*NAL_CRA_NUT*/);
1541 
1542  // calc. length to copy
1543  copy_len = p_start_code - 5 - p_src;
1544  }
1545  else if(NI_LOGAN_CODEC_FORMAT_H264 == p_enc_ctx->codec_format)
1546  {
1547  do
1548  {
1549  stc = -1;
1550  p_start_code = ni_logan_find_start_code(p_start_code, p_end, &stc);
1551  nalu_type = stc & 0x1F;
1552  } while (nalu_type > 5/*NAL_IDR_SLICE*/);
1553 
1554  // calc. length to copy
1555  copy_len = p_start_code - 5 - p_src;
1556  }
1557  else
1558  {
1559  ni_log(NI_LOG_ERROR, "%s: codec %d not supported for SEI !\n",
1560  __FUNCTION__, p_enc_ctx->codec_format);
1561  }
1562  }
1563 
1564  uint8_t *p_dst = p_data;
1565  if (sps_pps_attach)
1566  {
1567  memcpy(p_dst, p_enc_ctx->p_spsPpsHdr, p_enc_ctx->spsPpsHdrLen);
1568  p_dst += p_enc_ctx->spsPpsHdrLen;
1569  }
1570  if (custom_sei_cnt)
1571  {
1572  // copy buf_period
1573  memcpy(p_dst, p_src, copy_len);
1574  p_dst += copy_len;
1575 
1576  // copy custom sei before slice
1577  sei_idx = 0;
1578  while (sei_idx < custom_sei_cnt)
1579  {
1580  ni_logan_custom_sei = &ni_logan_all_custom_sei->ni_custom_sei[sei_idx];
1581  if (ni_logan_custom_sei->custom_sei_loc == NI_LOGAN_CUSTOM_SEI_LOC_AFTER_VCL)
1582  {
1583  break;
1584  }
1585  memcpy(p_dst, ni_logan_custom_sei->custom_sei_data, ni_logan_custom_sei->custom_sei_size);
1586  p_dst += ni_logan_custom_sei->custom_sei_size;
1587  sei_idx ++;
1588  }
1589 
1590  // copy the IDR data
1591  memcpy(p_dst, p_src + copy_len,
1592  p_output_pkt->data_len - meta_size - copy_len);
1593  p_dst += (p_output_pkt->data_len - meta_size - copy_len);
1594 
1595  // copy custom sei after slice
1596  while (sei_idx < custom_sei_cnt)
1597  {
1598  ni_logan_custom_sei = &ni_logan_all_custom_sei->ni_custom_sei[sei_idx];
1599  memcpy(p_dst, ni_logan_custom_sei->custom_sei_data, ni_logan_custom_sei->custom_sei_size);
1600  p_dst += ni_logan_custom_sei->custom_sei_size;
1601  sei_idx ++;
1602  }
1603  }
1604  else
1605  {
1606  memcpy(p_dst, (uint8_t*)p_output_pkt->p_data + meta_size,
1607  p_output_pkt->data_len - meta_size);
1608  }
1609 
1610  // free buffer
1611  if (custom_sei_cnt)
1612  {
1613  free(p_session_ctx->pkt_custom_sei[local_pts % NI_LOGAN_FIFO_SZ]);
1614  p_session_ctx->pkt_custom_sei[local_pts % NI_LOGAN_FIFO_SZ] = NULL;
1615  }
1616 
1617  int pts, dts;
1618  pts = p_output_pkt->pts;
1619  /* to ensure pts>dts for all frames, we assign a guess pts for the first 'dts_offset' frames and then the pts from input stream
1620  * is extracted from input pts FIFO.
1621  * if GOP = IBBBP and PTSs = 0 1 2 3 4 5 .. then out DTSs = -3 -2 -1 0 1 ... and -3 -2 -1 are the guessed values
1622  * if GOP = IBPBP and PTSs = 0 1 2 3 4 5 .. then out DTSs = -1 0 1 2 3 ... and -1 is the guessed value
1623  * the number of guessed values is equal to dts_offset
1624  */
1625  if (p_enc_ctx->total_frames_received < p_enc_ctx->dts_offset)
1626  {
1627  // guess dts
1628  dts = p_enc_ctx->first_frame_pts + (p_enc_ctx->total_frames_received - p_enc_ctx->dts_offset) * p_enc_ctx->ticks_per_frame;
1629  }
1630  else
1631  {
1632  // get dts from pts FIFO
1633  dts = p_session_ctx->enc_pts_list[p_session_ctx->enc_pts_r_idx % NI_LOGAN_FIFO_SZ];
1634  p_session_ctx->enc_pts_r_idx++;
1635  }
1636 
1637  if (p_enc_ctx->total_frames_received >= 1)
1638  {
1639  if (dts < p_enc_ctx->latest_dts)
1640  {
1641  ni_log(NI_LOG_INFO, "dts: %ld < latest_dts: %ld.\n",
1642  dts, p_enc_ctx->latest_dts);
1643  }
1644  }
1645 
1646  if (dts > pts)
1647  {
1648  ni_log(NI_LOG_INFO, "dts: %ld, pts: %ld. Forcing dts=pts\n",
1649  dts, pts);
1650  dts = pts;
1651  }
1652  p_enc_ctx->total_frames_received++;
1653  p_enc_ctx->latest_dts = dts;
1654 
1655  p_output_pkt->pts = pts;
1656  p_output_pkt->dts = dts;
1657  ni_log(NI_LOG_DEBUG, "%s pkt %" PRId64 " pts %" PRId64 " "
1658  "dts %" PRId64 " \n", __FUNCTION__,
1659  p_session_ctx->pkt_num - 1, pts, dts);
1660 
1661  p_enc_ctx->encoder_eof = p_output_pkt->end_of_stream;
1662 
1663  if (p_enc_ctx->encoder_eof &&
1665  {
1666  // after sequence change completes, reset codec state
1667  ni_log(NI_LOG_TRACE, "%s(): sequence change2 completed, return 0 "
1668  "and will reopen codec !\n", __FUNCTION__);
1669  ret = ni_logan_encode_reinit(p_enc_ctx);
1670  }
1671  else if(!ni_logan_fifo_is_empty(p_enc_ctx->input_data_fifo) &&
1672  (LOGAN_SESSION_RUN_STATE_NORMAL == p_session_ctx->session_run_state) &&
1674  {
1676  ret = ni_logan_encode_send(p_enc_ctx);
1677  // if session_run_state is changed in xcoder_send_frame, keep it
1679  {
1681  }
1682  if (ret < 0)
1683  {
1684  ni_log(NI_LOG_ERROR, "ni_logan_encode_send flush send failed ret = %d\n",
1685  ret);
1686  return ret;
1687  }
1688  }
1689  return ret;
1690 }
1691 
1692 /*!*****************************************************************************
1693  * \brief Receive encoded data from NI device
1694  *
1695  * \param[in] p_enc_ctx Pointer to ni_logan_enc_context_t
1696  *
1697  * \return 0 when no packets received
1698  * > 0 when new packet received, means the size of packet
1699  * < 0 when failed, NI_LOGAN_RETCODE_FAILURE,
1700  * NI_LOGAN_RETCODE_INVALID_PARAM, etc.
1701  ******************************************************************************/
1703 {
1704  int ret = 0;
1705  int recv;
1706  int i;
1707  ni_logan_session_context_t *p_session_ctx = NULL;
1708  ni_logan_encoder_params_t *p_encoder_params = NULL;
1709  ni_logan_packet_t *p_output_pkt = NULL;
1710 
1711  if (!p_enc_ctx || !p_enc_ctx->p_session_ctx || !p_enc_ctx->p_encoder_params)
1712  {
1713  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter, %p, %p, %p\n",
1714  __FUNCTION__, __LINE__, p_enc_ctx, p_enc_ctx->p_session_ctx,
1715  p_enc_ctx->p_encoder_params);
1717  }
1718  ni_log(NI_LOG_TRACE, "%s() enter\n", __FUNCTION__);
1719 
1720  p_session_ctx = p_enc_ctx->p_session_ctx;
1721  p_encoder_params = p_enc_ctx->p_encoder_params;
1722  p_output_pkt = &p_enc_ctx->output_pkt;
1723 
1725 
1726  for (; ;)
1727  {
1728  recv = ni_logan_device_session_read(p_session_ctx, p_output_pkt, NI_LOGAN_DEVICE_TYPE_ENCODER);
1729 
1730  ni_log(NI_LOG_TRACE, "%s(): pkt_num=%d, end_of_stream=%d, data_len=%d, "
1731  "recv=%d, encoder_flushing=%d, encoder_eof=%d\n",
1732  __FUNCTION__, p_session_ctx->pkt_num, p_output_pkt->end_of_stream,
1733  p_output_pkt->data_len, recv, p_enc_ctx->encoder_flushing,
1734  p_enc_ctx->encoder_eof);
1735 
1736  if (recv <= 0)
1737  {
1738  p_enc_ctx->encoder_eof = p_output_pkt->end_of_stream;
1739  /* not ready ?? */
1740  if (p_enc_ctx->encoder_eof || p_output_pkt->end_of_stream)
1741  {
1743  {
1744  // after sequence change completes, reset codec state
1745  ni_log(NI_LOG_TRACE, "%s(): sequence change1 completed, return "
1746  "AVERROR(EAGAIN) and will reopen codec!\n", __FUNCTION__);
1747  ret = ni_logan_encode_reinit(p_enc_ctx);
1748  if (ret >= 0)
1749  {
1750  // when reopen encoder success, try to recive packet
1752  continue;
1753  // ret = 0;
1754  }
1755  break;
1756  }
1757 
1758  ret = 0;
1759  ni_log(NI_LOG_TRACE, "%s: got encoder_eof return AVERROR_EOF\n",
1760  __FUNCTION__);
1761  break;
1762  }
1763  else
1764  {
1766  {
1767  ni_log(NI_LOG_DEBUG, "%s(): vpu recovery2\n", __FUNCTION__);
1769  ret = ni_logan_encode_reinit(p_enc_ctx);
1770  if (ret < 0)
1771  {
1772  ni_log(NI_LOG_ERROR, "%s(): VPU recovery failed:%d, "
1773  "returning EIO\n", __FUNCTION__, ret);
1775  }
1776  return ret;
1777  }
1778  else if (recv < 0)
1779  {
1780  if ((NI_LOGAN_RETCODE_ERROR_INVALID_SESSION == recv) && !p_enc_ctx->started)
1781  {
1782  // session may be in recovery state, return EAGAIN
1783  ni_log(NI_LOG_INFO, "%s: VPU might be reset, "
1784  "invalid session id\n", __FUNCTION__);
1785  ret = 0;
1786  }
1787  else
1788  {
1789  ni_log(NI_LOG_ERROR, "%s: Persistent failure, "
1790  "returning EIO,ret=%d\n", __FUNCTION__, recv);
1792  }
1793  p_enc_ctx->gotPacket = 0;
1794  p_enc_ctx->sentFrame = 0;
1795  break;
1796  }
1797  else if (p_encoder_params->low_delay_mode == 1 && p_enc_ctx->sentFrame && !p_enc_ctx->gotPacket)
1798  {
1799  ni_log(NI_LOG_TRACE, "%s: low delay mode, keep reading until "
1800  "pkt arrives\n", __FUNCTION__);
1801  continue;
1802  }
1803  else if (p_encoder_params->low_delay_mode == 2 &&
1804  p_session_ctx->frame_num - p_session_ctx->pkt_num >
1805  (p_encoder_params->enc_input_params.gop_preset_index == 0 ?
1807  g_map_preset_to_gopsize[p_encoder_params->enc_input_params.gop_preset_index]))
1808  {
1809  ni_log(NI_LOG_TRACE, "%s: low delay mode 2, keep reading send frame %d receive pkt %d gop %d\n",
1810  __FUNCTION__, p_session_ctx->frame_num, p_session_ctx->pkt_num,
1811  p_encoder_params->enc_input_params.gop_preset_index);
1812  continue;
1813  }
1814  p_enc_ctx->gotPacket = 0;
1815  p_enc_ctx->sentFrame = 0;
1816 
1817  if (!ni_logan_fifo_is_empty(p_enc_ctx->input_data_fifo) &&
1818  (LOGAN_SESSION_RUN_STATE_NORMAL == p_session_ctx->session_run_state) &&
1820  {
1821  // flush the fifo
1823  ret = ni_logan_encode_send(p_enc_ctx);
1824  // if session_run_state is changed in xcoder_send_frame, keep it
1826  {
1828  }
1829 
1830  if (ret < 0)
1831  {
1832  ni_log(NI_LOG_ERROR, "ni_logan_encode_send flush send failed ret = %d\n",
1833  ret);
1834  return ret;
1835  }
1836  continue;
1837  }
1838  ret = 0;
1839  if (!p_enc_ctx->encoder_flushing && !p_enc_ctx->eos_fme_received)
1840  {
1841  ni_log(NI_LOG_TRACE, "%s: NOT encoder_flushing, return "
1842  "AVERROR(EAGAIN)\n", __FUNCTION__);
1843  break;
1844  }
1845  }
1846  }
1847  else
1848  {
1849  /* got encoded data back */
1851  if (! p_enc_ctx->spsPpsArrived)
1852  {
1853  ret = 0;
1854  p_enc_ctx->spsPpsArrived = 1;
1855  p_enc_ctx->spsPpsHdrLen = recv - meta_size;
1856  p_enc_ctx->p_spsPpsHdr = malloc(p_enc_ctx->spsPpsHdrLen);
1857  if (! p_enc_ctx->p_spsPpsHdr)
1858  {
1860  break;
1861  }
1862 
1863  memcpy(p_enc_ctx->p_spsPpsHdr, (uint8_t*)p_output_pkt->p_data + meta_size,
1864  p_output_pkt->data_len - meta_size);
1865 
1866  // start pkt_num counter from 1 to get the real first frame
1867  p_session_ctx->pkt_num = 1;
1868  // for low-latency mode, keep reading until the first frame is back
1869  if (p_encoder_params->low_delay_mode == 1)
1870  {
1871  ni_log(NI_LOG_TRACE, "%s: low delay mode, keep reading until "
1872  "1ast pkt arrives\n", __FUNCTION__);
1873  continue;
1874  }
1875  // when recive sps, should try to recive the first packet
1876  continue;
1877  }
1878  p_enc_ctx->gotPacket = 1;
1879  p_enc_ctx->sentFrame = 0;
1880 
1881  int nalu_type = 0;
1882  const uint8_t *p_start_code;
1883  uint32_t stc = -1;
1884  uint32_t copy_len = 0;
1885  uint8_t *p_src = (uint8_t*)p_output_pkt->p_data + meta_size;
1886  uint8_t *p_end = p_src + (p_output_pkt->data_len - meta_size);
1887  int64_t local_pts = p_output_pkt->pts;
1888  int custom_sei_cnt = 0;
1889  int total_custom_sei_len = 0;
1890  int sei_idx = 0;
1891  ni_logan_all_custom_sei_t *ni_logan_all_custom_sei;
1892  if (p_session_ctx->pkt_custom_sei[local_pts % NI_LOGAN_FIFO_SZ])
1893  {
1894  ni_logan_all_custom_sei = p_session_ctx->pkt_custom_sei[local_pts % NI_LOGAN_FIFO_SZ];
1895  custom_sei_cnt = ni_logan_all_custom_sei->custom_sei_cnt;
1896  for (sei_idx = 0; sei_idx < custom_sei_cnt; sei_idx ++)
1897  {
1898  total_custom_sei_len += ni_logan_all_custom_sei->ni_custom_sei[sei_idx].custom_sei_size;
1899  }
1900  }
1901 
1902  if (!p_enc_ctx->firstPktArrived)
1903  {
1904  p_enc_ctx->spsPpsAttach = 0;
1905  // if enable forced repeat header, add a SPS/PPS header in the first packat
1908  {
1909  p_enc_ctx->spsPpsAttach = 1;
1910  }
1911  }
1912  else
1913  {
1914  p_enc_ctx->spsPpsAttach = 0;
1915  // insert header when intraRefresh is enabled and forced header mode is 1 (all key frames)
1916  // for every intraRefreshMinPeriod key frames, pkt counting starts from 1, e.g. for
1917  // cycle of 100, the header is forced on frame 102, 202, ...;
1918  // note that api_ctx.pkt_num returned is the actual index + 1
1919  if (p_enc_ctx->p_spsPpsHdr && p_enc_ctx->spsPpsHdrLen &&
1921  (1 == p_encoder_params->enc_input_params.intra_mb_refresh_mode ||
1922  2 == p_encoder_params->enc_input_params.intra_mb_refresh_mode ||
1923  3 == p_encoder_params->enc_input_params.intra_mb_refresh_mode))
1924  {
1925  if (p_encoder_params->intra_refresh_reset)
1926  {
1927  if (p_session_ctx->pkt_num - p_session_ctx->force_frame_pkt_num == p_encoder_params->ui32minIntraRefreshCycle)
1928  {
1929  p_enc_ctx->spsPpsAttach = 1;
1930  p_session_ctx->force_frame_pkt_num = p_session_ctx->pkt_num;
1931  }
1932  else
1933  {
1934  for (i = 0; i < NI_LOGAN_MAX_FORCE_FRAME_TABLE_SIZE; i++)
1935  {
1936  if (p_output_pkt->pts == p_session_ctx->force_frame_pts_table[i])
1937  {
1938  p_enc_ctx->spsPpsAttach = 1;
1939  p_session_ctx->force_frame_pkt_num = p_session_ctx->pkt_num;
1940  break;
1941  }
1942  }
1943  }
1944  }
1945  else if (p_encoder_params->ui32minIntraRefreshCycle > 0 && p_session_ctx->pkt_num > 3 &&
1946  0 == ((p_session_ctx->pkt_num - 3) % p_encoder_params->ui32minIntraRefreshCycle))
1947  {
1948  p_enc_ctx->spsPpsAttach = 1;
1949  ni_log(NI_LOG_TRACE, "%s pkt %" PRId64 " force header on "
1950  "intraRefreshMinPeriod %u\n", __FUNCTION__,
1951  p_session_ctx->pkt_num - 1, p_encoder_params->ui32minIntraRefreshCycle);
1952  }
1953  }
1954  }
1955 
1956  ret = p_output_pkt->data_len - meta_size + total_custom_sei_len;
1957  break;
1958  }
1959  }
1960  return ret;
1961 }
void ni_logan_enc_reconfig_vfr(ni_logan_session_context_t *p_session_ctx, ni_logan_encoder_params_t *p_encoder_params, ni_logan_frame_t *ni_frame, int64_t pts, uint32_t timebase)
Fill reconfig vfr.
void ni_logan_enc_init_aux_params(ni_logan_session_data_io_t *p_api_fme)
Initialize auxiliary data that should be sent together with this frame to encoder based on the auxili...
const uint8_t * ni_logan_find_start_code(const uint8_t *p, const uint8_t *end, uint32_t *state)
Find the next start code.
void ni_logan_enc_copy_aux_data(ni_logan_session_context_t *p_enc_ctx, ni_logan_frame_t *p_enc_frame, ni_logan_frame_t *p_dec_frame, ni_logan_codec_format_t codec_format, const uint8_t *mdcv_data, const uint8_t *cll_data, const uint8_t *cc_data, const uint8_t *udu_data, const uint8_t *hdrp_data)
Copy auxiliary data that should be sent together with this frame to encoder.
void ni_logan_set_vui(ni_logan_encoder_params_t *p_param, ni_logan_session_context_t *p_ctx, ni_color_primaries_t color_primaries, ni_color_transfer_characteristic_t color_trc, ni_color_space_t color_space, int video_full_range_flag, int sar_num, int sar_den, ni_logan_codec_format_t codec_format)
Set SPS VUI part of encoded stream header.
int ni_logan_should_send_sei_with_frame(ni_logan_session_context_t *p_enc_ctx, ni_logan_pic_type_t pic_type, ni_logan_encoder_params_t *p_param)
Whether SEI (HDR) should be sent together with this frame to encoder.
void ni_logan_enc_prep_aux_data(ni_logan_session_context_t *p_enc_ctx, ni_logan_frame_t *p_enc_frame, ni_logan_frame_t *p_dec_frame, ni_logan_codec_format_t codec_format, int should_send_sei_with_frame, uint8_t *mdcv_data, uint8_t *cll_data, uint8_t *cc_data, uint8_t *udu_data, uint8_t *hdrp_data)
Prepare auxiliary data that should be sent together with this frame to encoder based on the auxiliary...
@ NI_COL_TRC_UNSPECIFIED
@ NI_COL_TRC_SMPTE2084
@ NI_COL_TRC_ARIB_STD_B67
enum _ni_color_primaries ni_color_primaries_t
@ NI_COL_SPC_BT2020_NCL
@ NI_COL_SPC_UNSPECIFIED
@ NI_COL_SPC_BT2020_CL
@ NI_COL_PRI_UNSPECIFIED
@ NI_COL_PRI_BT2020
enum _ni_color_transfer_characteristic ni_color_transfer_characteristic_t
enum _ni_color_space ni_color_space_t
@ NI_COL_RANGE_JPEG
the normal 2^n-1 "JPEG" YUV ranges
ni_logan_retcode_t
@ NI_LOGAN_RETCODE_PARAM_ERROR_HEIGHT_TOO_SMALL
@ NI_LOGAN_RETCODE_ERROR_INVALID_SESSION
@ NI_LOGAN_RETCODE_PARAM_ERROR_AREA_TOO_BIG
@ NI_LOGAN_RETCODE_PARAM_ERROR_WIDTH_TOO_SMALL
@ NI_LOGAN_RETCODE_INVALID_PARAM
@ NI_LOGAN_RETCODE_ERROR_MEM_ALOC
@ NI_LOGAN_RETCODE_ERROR_VPU_RECOVERY
@ NI_LOGAN_RETCODE_PARAM_ERROR_HEIGHT_TOO_BIG
@ NI_LOGAN_RETCODE_SUCCESS
@ NI_LOGAN_RETCODE_NVME_SC_WRITE_BUFFER_FULL
@ NI_LOGAN_RETCODE_FAILURE
@ NI_LOGAN_RETCODE_PARAM_ERROR_WIDTH_TOO_BIG
#define END
#define NI_LOGAN_FW_ENC_BITSTREAM_META_DATA_SIZE
#define NI_LOGAN_MAX_NUM_DATA_POINTERS
#define NI_ERRNO
#define NI_LOGAN_FIFO_SZ
#define NI_LOGAN_MAX_FORCE_FRAME_TABLE_SIZE
@ NI_LOGAN_DEVICE_TYPE_ENCODER
#define LRETURN
#define NI_LOGAN_MAX_TX_SZ
ni_logan_retcode_t ni_logan_packet_buffer_alloc(ni_logan_packet_t *p_packet, int packet_size)
Allocate memory for the packet buffer based on provided packet size.
ni_logan_retcode_t ni_logan_encoder_params_check(ni_logan_encoder_params_t *p_params, ni_logan_codec_format_t codec)
Validate relationship of some params in encoder parameters structure.
ni_logan_retcode_t ni_logan_device_session_flush(ni_logan_session_context_t *p_ctx, ni_logan_device_type_t device_type)
Sends a flush command to the device ni_logan_device_session_open() If device_type is NI_LOGAN_DEVICE_...
ni_logan_retcode_t ni_logan_device_session_close(ni_logan_session_context_t *p_ctx, int eos_recieved, ni_logan_device_type_t device_type)
Closes device session that was previously opened by calling ni_logan_device_session_open() If device_...
ni_logan_retcode_t ni_logan_packet_buffer_free(ni_logan_packet_t *p_packet)
Free packet buffer that was previously allocated with either ni_logan_packet_buffer_alloc.
void ni_logan_device_session_context_init(ni_logan_session_context_t *p_ctx)
Initialize already allocated session context to a known state.
ni_logan_retcode_t ni_logan_frame_buffer_free(ni_logan_frame_t *p_frame)
Free frame buffer that was previously allocated with either ni_logan_frame_buffer_alloc or ni_logan_e...
ni_logan_retcode_t ni_logan_encoder_frame_buffer_alloc(ni_logan_frame_t *p_frame, int video_width, int video_height, int linesize[], int alignment, int extra_len, int factor)
Allocate memory for the frame buffer for encoding based on given parameters, taking into account pic ...
int ni_logan_device_session_read(ni_logan_session_context_t *p_ctx, ni_logan_session_data_io_t *p_data, ni_logan_device_type_t device_type)
Reads data the device If device_type is NI_LOGAN_DEVICE_TYPE_DECODER reads data packet from decoder I...
void ni_logan_device_session_context_clear(ni_logan_session_context_t *p_ctx)
Clear already allocated session context to all zeros.
const char * ni_logan_err2str(int err)
Convert error numver into error messages.
ni_logan_retcode_t ni_logan_encoder_init_default_params(ni_logan_encoder_params_t *p_param, int fps_num, int fps_denom, long bit_rate, int width, int height)
Initialize default encoder parameters.
ni_logan_retcode_t ni_logan_device_session_open(ni_logan_session_context_t *p_ctx, ni_logan_device_type_t device_type)
Opens a new device session depending on the device_type parameter If device_type is NI_LOGAN_DEVICE_T...
int ni_logan_device_session_write(ni_logan_session_context_t *p_ctx, ni_logan_session_data_io_t *p_data, ni_logan_device_type_t device_type)
Sends data the device If device_type is NI_LOGAN_DEVICE_TYPE_DECODER sends data packet to decoder If ...
void ni_logan_device_close(ni_device_handle_t device_handle)
Closes device and releases resources.
enum _ni_logan_session_run_state ni_logan_session_run_state_t
Session running state type.
struct _ni_logan_encoder_change_params_t ni_logan_encoder_change_params_t
This is a data structure for encoding parameters that have changed.
#define NI_CC_SEI_TRAILER_LEN
#define NI_LOGAN_PARAM_MAX_HEIGHT
#define NI_CC_SEI_HDR_H264_LEN
#define NI_LOGAN_PARAM_MAX_WIDTH
@ NI_LOGAN_CUSTOM_SEI_LOC_AFTER_VCL
#define NI_LOGAN_MIN_WIDTH
#define NI_HDR10P_SEI_HDR_H264_LEN
#define NI_LOGAN_ENC_REPEAT_HEADERS_ALL_I_FRAMES
#define NI_LOGAN_PARAM_MIN_WIDTH
#define NI_LOGAN_MAX_SEI_DATA
#define NI_LOGAN_MIN_HEIGHT
#define LIST_DEVICES_STR
#define NI_LOGAN_DEFAULT_KEEP_ALIVE_TIMEOUT
#define NI_HDR10P_SEI_HDR_HEVC_LEN
#define NI_LOGAN_ENC_MAX_SEI_BUF_SIZE
@ LOGAN_SESSION_RUN_STATE_RESETTING
@ LOGAN_SESSION_RUN_STATE_QUEUED_FRAME_DRAINING
@ LOGAN_SESSION_RUN_STATE_SEQ_CHANGE_DRAINING
@ LOGAN_SESSION_RUN_STATE_NORMAL
#define NI_LOGAN_FRAME_LITTLE_ENDIAN
#define NI_LOGAN_ENC_REPEAT_HEADERS_ALL_KEY_FRAMES
@ NI_LOGAN_CODEC_FORMAT_H265
@ NI_LOGAN_CODEC_FORMAT_H264
#define NI_LOGAN_MAX_RESOLUTION_AREA
@ NI_LOGAN_PIX_FMT_YUV420P10BE
@ NI_LOGAN_PIX_FMT_YUV420P10LE
@ NI_LOGAN_PIX_FMT_YUVJ420P
#define NI_LOGAN_PARAM_MIN_HEIGHT
#define NI_CC_SEI_HDR_HEVC_LEN
#define NI_LOGAN_FRAME_BIG_ENDIAN
int ni_logan_encode_params_parse(ni_logan_enc_context_t *p_enc_ctx)
Parse encoder parameters Check whether the parameters are reasonable.
int ni_logan_encode_send(ni_logan_enc_context_t *p_enc_ctx)
Send encode data to NI device.
int ni_logan_encode_header(ni_logan_enc_context_t *p_enc_ctx)
Get encoder headers from the hardware.
int ni_logan_encode_copy_frame_data(ni_logan_enc_context_t *p_enc_ctx, ni_logan_frame_t *p_dec_frame, uint8_t *p_data[NI_LOGAN_MAX_NUM_DATA_POINTERS], int linesize[NI_LOGAN_MAX_NUM_DATA_POINTERS])
Copy frame data to NI frame.
int ni_logan_encode_receive(ni_logan_enc_context_t *p_enc_ctx)
Receive encoded data from NI device.
int ni_logan_encode_init(ni_logan_enc_context_t *p_enc_ctx)
Initialize encode parameters, including ni_logan_enc_context_t, ni_logan_session_context_t and ni_log...
int ni_logan_encode_get_frame(ni_logan_enc_context_t *p_enc_ctx)
Get allocated ni_frame from fifo pool.
void ni_logan_encode_reconfig_vfr(ni_logan_enc_context_t *p_enc_ctx, ni_logan_frame_t *ni_frame, int64_t pts)
Fill reconfig vfr.
int ni_logan_encode_open(ni_logan_enc_context_t *p_enc_ctx)
Open encoder.
int ni_logan_encode_close(ni_logan_enc_context_t *p_enc_ctx)
Close encoder.
int ni_logan_encode_copy_packet_data(ni_logan_enc_context_t *p_enc_ctx, uint8_t *p_data, int first_packet, int sps_pps_attach)
Copy NI packet to packet data buffer.
NETINT encoder API header file.
ni_log_level_t ff_to_ni_log_level(int fflog_level)
Convert ffmpeg log level integer to appropriate ni_log_level_t.
Definition: ni_log_logan.c:160
void ni_log_set_level(ni_log_level_t level)
Set ni_log_level.
Definition: ni_log_logan.c:138
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition: ni_log_logan.c:120
@ NI_LOG_DEBUG
Definition: ni_log_logan.h:66
@ NI_LOG_TRACE
Definition: ni_log_logan.h:67
@ NI_LOG_ERROR
Definition: ni_log_logan.h:64
@ NI_LOG_INFO
Definition: ni_log_logan.h:65
LIB_API void ni_logan_rsrc_print_all_devices_capability(void)
Print detailed capability information of all devices on the system.
uint8_t * ni_logan_fifo_generic_read(ni_logan_fifo_buffer_t *p_fifo)
Get first filled buffer to read in the fifo.
uint8_t * ni_logan_fifo_generic_write(ni_logan_fifo_buffer_t *p_fifo)
Get free buffer to write in the fifo.
void ni_logan_copy_hw_yuv420p(uint8_t *p_dst[NI_LOGAN_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_LOGAN_MAX_NUM_DATA_POINTERS], int frame_width, int frame_height, int bit_depth_factor, int dst_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS], int dst_height[NI_LOGAN_MAX_NUM_DATA_POINTERS], int src_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS], int src_height[NI_LOGAN_MAX_NUM_DATA_POINTERS])
Copy YUV data to Netint HW YUV420p frame layout to be sent to encoder for encoding....
int ni_logan_fifo_return_read(ni_logan_fifo_buffer_t *p_fifo)
Push back the last read buffer to the fifo.
int ni_logan_fifo_is_empty(ni_logan_fifo_buffer_t *p_fifo)
Check if a fifo is empty.
void ni_logan_get_hw_yuv420p_dim(int width, int height, int bit_depth_factor, int is_h264, int plane_stride[NI_LOGAN_MAX_NUM_DATA_POINTERS], int plane_height[NI_LOGAN_MAX_NUM_DATA_POINTERS])
Get dimension information of Netint HW YUV420p frame to be sent to encoder for encoding....
ni_logan_fifo_buffer_t * ni_logan_fifo_initialize(uint32_t number_of_buffers, uint32_t size)
Initialize a fifo buffer.
void ni_logan_fifo_free(ni_logan_fifo_buffer_t *p_fifo)
Free a fifo.
#define NI_LOGAN_ODD2EVEN(X)
Definition: ni_util_logan.h:80
#define NI_LOGAN_INPUT_DATA_BUF_CNT_INIT
Definition: ni_util_logan.h:74
uint32_t au_cpb_removal_delay_minus1
ni_logan_custom_sei_t ni_custom_sei[NI_LOGAN_MAX_CUSTOM_SEI_CNT]
custom sei payload passthrough
ni_logan_custom_sei_location_t custom_sei_loc
uint8_t custom_sei_data[NI_LOGAN_MAX_CUSTOM_SEI_SZ]
ni_logan_fifo_buffer_t * input_data_fifo
ni_logan_session_data_io_t * p_input_fme
ni_logan_session_data_io_t output_pkt
struct _ni_logan_encoder_input_params::@3 rc
ni_logan_custom_gop_params_t custom_gop_params
ni_logan_encoder_input_params_t enc_input_params
unsigned int sei_hdr_mastering_display_color_vol_offset
unsigned int sei_hdr_content_light_level_info_offset
uint8_t preferred_characteristics_data_len
unsigned int sei_hdr_plus_len
uint32_t data_len[NI_LOGAN_MAX_NUM_DATA_POINTERS]
unsigned int sei_hdr_plus_offset
unsigned int extra_data_len
unsigned int sei_total_len
unsigned int sei_cc_offset
unsigned int sei_user_data_unreg_len
ni_logan_pic_type_t ni_logan_pict_type
uint8_t use_cur_src_as_long_term_pic
unsigned int sei_hdr_content_light_level_info_len
void * p_data[NI_LOGAN_MAX_NUM_DATA_POINTERS]
unsigned int sei_hdr_mastering_display_color_vol_len
unsigned int sei_user_data_unreg_offset
unsigned int sei_alt_transfer_characteristics_len
unsigned int sei_alt_transfer_characteristics_offset
uint8_t itu_t_t35_hdr10p_sei_hdr_hevc[NI_HDR10P_SEI_HDR_HEVC_LEN]
ni_device_handle_t device_handle
uint8_t sei_trailer[NI_CC_SEI_TRAILER_LEN]
int64_t enc_pts_list[NI_LOGAN_FIFO_SZ]
uint8_t itu_t_t35_cc_sei_hdr_hevc[NI_CC_SEI_HDR_HEVC_LEN]
ni_logan_session_run_state_t session_run_state
uint8_t itu_t_t35_cc_sei_hdr_h264[NI_CC_SEI_HDR_H264_LEN]
ni_device_handle_t blk_io_handle
int64_t force_frame_pts_table[NI_LOGAN_MAX_FORCE_FRAME_TABLE_SIZE]
uint8_t itu_t_t35_hdr10p_sei_hdr_h264[NI_HDR10P_SEI_HDR_H264_LEN]
char dev_xcoder[LOGAN_MAX_CHAR_IN_DEVICE_NAME]
ni_logan_all_custom_sei_t * pkt_custom_sei[NI_LOGAN_FIFO_SZ]
char dev_xcoder_name[LOGAN_MAX_CHAR_IN_DEVICE_NAME]
union _ni_logan_session_data_io::@4 data