libxcoder  3.5.1
ni_dec_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_dec_api_logan.c
24 *
25 * \brief NETINT decoder API file
26 *
27 *******************************************************************************/
28 
29 #include "ni_dec_api_logan.h"
30 #define NI_LOGAN_DEC_PKT_BUF_NUM_MAX 300
31 
32 void ni_logan_buf_pool_free(void *opaque, uint8_t *data)
33 {
34  if (data)
35  {
36  ni_logan_buf_t *buf = (ni_logan_buf_t *) opaque;
38  }
39 }
41 {
43 
44  ni_logan_session_context_t *p_session_ctx = NULL;
45  ni_log(NI_LOG_DEBUG, "ni_logan_xcoder_dec_close enter\n");
46  if (!ni_dec_ctx)
47  {
48  ni_log(NI_LOG_ERROR, "ni_dec_ctx is null\n");
50  }
51  p_session_ctx = ni_dec_ctx->p_session_ctx;
52  if (!p_session_ctx)
53  {
54  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter, %p\n",
55  __FUNCTION__, __LINE__, p_session_ctx);
57  }
58 
59  ret = ni_logan_device_session_close(p_session_ctx, ni_dec_ctx->eos, NI_LOGAN_DEVICE_TYPE_DECODER);
60  if (NI_LOGAN_RETCODE_SUCCESS != ret)
61  {
62  ni_log(NI_LOG_ERROR, "Failed to close Decode Session (status = %d)\n", ret);
63  }
64 #ifdef _WIN32
65  ni_logan_device_close(p_session_ctx->device_handle);
66 #elif __linux__
67  ni_logan_device_close(p_session_ctx->device_handle);
68  ni_logan_device_close(p_session_ctx->blk_io_handle);
69 #endif
70  p_session_ctx->device_handle = NI_INVALID_DEVICE_HANDLE;
71  p_session_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE;
72 
73  return 0;
74 }
75 
77 {
78  ni_logan_session_context_t *p_session_ctx = ni_dec_ctx->p_session_ctx;
79  ni_logan_decoder_params_t *p_param = ni_dec_ctx->p_param;
80  ni_logan_session_data_io_t *p_ni_packet = NULL;
81  ni_log(NI_LOG_DEBUG, "ni_logan_dec_close enter\n");
82 
83  /* this call shall release resource based on ni_logan_dec_context_t*/
84  ni_logan_xcoder_dec_close(ni_dec_ctx);
85 
86  free(ni_dec_ctx->extradata);
87  ni_dec_ctx->extradata = NULL;
88  ni_dec_ctx->extradata_size = 0;
89  ni_dec_ctx->got_first_key_frame = 0;
90  ni_dec_ctx->dev_xcoder = NULL; //Set to Null
92 
93  if (ni_dec_ctx->input_data_fifo)
94  {
95  // push back
96  do{
97  p_ni_packet = ni_logan_fifo_generic_write(ni_dec_ctx->input_data_fifo);
98  }while(p_ni_packet);
99  // free all
100  do{
101  p_ni_packet = ni_logan_fifo_generic_read(ni_dec_ctx->input_data_fifo);
102  if (p_ni_packet)
103  {
104  ni_logan_packet_buffer_free(&(p_ni_packet->data.packet));
105  }
106  }while(p_ni_packet);
107  }
108 
109  ni_logan_fifo_free(ni_dec_ctx->input_data_fifo);
110  ni_log(NI_LOG_DEBUG, "%s(): decoder frame fifo freed.\n", __FUNCTION__);
111  // no releaseResource for decoder for now
113  if (p_session_ctx)
114  {
115  free(p_session_ctx);
116  }
117  if (p_param)
118  {
119  free(p_param);
120  }
121 }
122 
124 {
126  ni_logan_decoder_params_t *p_param = NULL;
127  ni_logan_session_context_t *p_session_ctx = NULL;
129  ni_log(NI_LOG_DEBUG, "ni_logan_setup_decoder enter\n");
130 
131  if (!ni_dec_ctx)
132  {
133  ni_log(NI_LOG_ERROR, "ni_dec_ctx is null\n");
135  }
136  // Xcoder Session Context
137  p_session_ctx = malloc(sizeof(ni_logan_session_context_t));
138  if (!p_session_ctx)
139  {
140  ni_log(NI_LOG_ERROR, "ERROR %d:%s() line %d, alloc session context failed\n",
141  NI_ERRNO, __FUNCTION__, __LINE__);
143  LRETURN;
144  }
145  else
146  {
147  ni_dec_ctx->p_session_ctx = p_session_ctx;
149  }
150 
151  if (0 == strcmp(ni_dec_ctx->dev_xcoder, LIST_DEVICES_STR))
152  {
153  ni_log(NI_LOG_DEBUG, "XCoder: printing out all xcoder devices and "
154  "their load, and exit ...\n");
157  }
158  else if (ni_dec_ctx->width > NI_LOGAN_MAX_RESOLUTION_WIDTH ||
159  ni_dec_ctx->height > NI_LOGAN_MAX_RESOLUTION_HEIGHT ||
160  ni_dec_ctx->width * ni_dec_ctx->height > NI_LOGAN_MAX_RESOLUTION_AREA)
161  {
162  ni_log(NI_LOG_ERROR, "Error XCoder resolution %dx%d not supported\n",
163  ni_dec_ctx->width, ni_dec_ctx->height);
164  ni_log(NI_LOG_ERROR, "Max Supported Width: %d Height %d Area %d\n",
166  retval = NI_LOGAN_RETCODE_FAILURE;
167  LRETURN;
168  }
169  ni_log(NI_LOG_DEBUG, "XCoder setup device decoder\n");
170  if(ni_dec_ctx->dev_dec_idx < 0)
171  {
172  // the user did not specify which device to use.
173  // we need to auto select the device,
174  // we need to know which selection method to use.
175  // if the slection method is not in place, we use best model by default
176  //
177  if (strlen(ni_dec_ctx->dev_xcoder) <= 0)
178  {
179  strcpy(p_session_ctx->dev_xcoder, BEST_MODEL_LOAD_STR);
180  }
181  else
182  {
183  strcpy(p_session_ctx->dev_xcoder, ni_dec_ctx->dev_xcoder);
184  }
185  }
186  ni_dec_ctx->started = 0;
187  ni_dec_ctx->got_first_key_frame = 0;
188 
189  ni_dec_ctx->offset = 0LL;
190  ni_dec_ctx->draining = 0;
191 
192  //Xcoder User Configuration
193  p_param = malloc(sizeof(ni_logan_decoder_params_t));
194  if (!p_param)
195  {
196  ni_log(NI_LOG_ERROR, "ERROR %d:%s() line %d, alloc session context failed\n",
197  NI_ERRNO, __FUNCTION__, __LINE__);
199  LRETURN;
200  }
201  else
202  {
203  ni_dec_ctx->p_param = p_param;
204  if (ni_logan_decoder_init_default_params(ni_dec_ctx->p_param, ni_dec_ctx->fps_num,
205  ni_dec_ctx->fps_denom, ni_dec_ctx->bit_rate,
206  ni_dec_ctx->width, ni_dec_ctx->height) < 0)
207  {
208  ni_log(NI_LOG_INFO, "Error setting params\n");
209  retval = NI_LOGAN_RETCODE_FAILURE;
210  LRETURN;
211  }
212  }
213 
214  // Init input fifo
217  if (!ni_dec_ctx->input_data_fifo)
218  {
219  ni_log(NI_LOG_ERROR, "%s(): line %d initialize enc frame buffer pool failed\n",
220  __FUNCTION__, __LINE__);
222  LRETURN;
223  }
224 
225 END:
226 
227  if (retval != NI_LOGAN_RETCODE_SUCCESS)
228  {
229  free(p_session_ctx);
230  ni_dec_ctx->p_session_ctx = NULL;
231  free(p_param);
232  ni_dec_ctx->p_param = NULL;
233  ni_logan_fifo_free(ni_dec_ctx->input_data_fifo);
234  }
235 
236  return retval;
237 }
238 
240 {
241  /* ToDo: call xcode_dec_open to open a decoder instance */
242  int ret;
243  ni_logan_decoder_params_t *p_param = NULL;
244  ni_logan_session_context_t *p_session_ctx = NULL;
245  ni_log(NI_LOG_DEBUG, "ni_logan_dec_init enter\n");
246 
247  if (!ni_dec_ctx)
248  {
249  ni_log(NI_LOG_ERROR, "ni_dec_ctx is null\n");
251  }
252  p_param = ni_dec_ctx->p_param;
253  p_session_ctx = ni_dec_ctx->p_session_ctx;
254  if (!p_param || !p_session_ctx)
255  {
256  ni_log(NI_LOG_ERROR, "%s(): line %d, Invalid Parameter, %p, %p\n",
257  __FUNCTION__, __LINE__, p_param, p_session_ctx);
259  }
260 
261  p_session_ctx->codec_format = ni_dec_ctx->codec_format;
262  p_session_ctx->bit_depth_factor = ni_dec_ctx->bit_depth_factor;
263  p_session_ctx->pic_reorder_delay = ni_dec_ctx->pic_reorder_delay;
264 
265  // 1. overwrite keep_alive_timeout value here with a custom value if it was provided
266  uint32_t xcoder_timeout = p_param->dec_input_params.keep_alive_timeout;
267  if (xcoder_timeout != NI_LOGAN_DEFAULT_KEEP_ALIVE_TIMEOUT)
268  {
269  p_session_ctx->keep_alive_timeout = xcoder_timeout;
270  }
271  else
272  {
273  p_session_ctx->keep_alive_timeout = ni_dec_ctx->keep_alive_timeout;
274  }
275  ni_log(NI_LOG_DEBUG, "Custom NVME Keep Alive Timeout set to %d\n",
276  p_session_ctx->keep_alive_timeout);
277 
278  // 2.overwrite set_high_priority value here with a custom value if it was provided
279  uint32_t xcoder_high_priority = p_param->dec_input_params.set_high_priority;
280  if(xcoder_high_priority != 0)
281  {
282  p_session_ctx->set_high_priority = xcoder_high_priority;
283  }
284  else
285  {
286  p_session_ctx->set_high_priority = ni_dec_ctx->set_high_priority;
287  }
288  ni_log(NI_LOG_DEBUG, "Custom NVMe set_high_priority set to = %d\n",
289  p_session_ctx->set_high_priority);
290 
291  // 3. overwrite UDU passthru value here with a custom value if it was provided
293  {
295  }
296 
297  // 4. overwrite check_packet value here with a custom value if it was provided
298  if (p_param->dec_input_params.check_packet != 0)
299  {
300  ni_dec_ctx->enable_check_packet = p_param->dec_input_params.check_packet;
301  }
302  else
303  {
304  p_param->dec_input_params.check_packet = ni_dec_ctx->enable_check_packet;
305  }
306 
307  // 5. overwrite UDU passthru value here with a custom value if it was provided
309  {
310  ni_dec_ctx->custom_sei = p_param->dec_input_params.custom_sei_passthru;
311  }
312  else
313  {
314  p_param->dec_input_params.custom_sei_passthru = ni_dec_ctx->custom_sei;
315  }
316 
317  p_session_ctx->p_session_config = p_param;
318 
319  p_session_ctx->hw_id = ni_dec_ctx->dev_dec_idx;
320  p_session_ctx->hw_name = ni_dec_ctx->dev_dec_name;
321  if(p_param->dec_input_params.lowdelay != 0)
322  {
323  ni_dec_ctx->low_delay = p_param->dec_input_params.lowdelay;
324  }
325  else
326  {
327  p_param->dec_input_params.lowdelay = ni_dec_ctx->low_delay;
328  }
329  p_session_ctx->decoder_low_delay = ni_dec_ctx->low_delay;
330  strcpy(p_session_ctx->dev_xcoder, ni_dec_ctx->dev_xcoder);
331 
333  if (ret != 0)
334  {
335  ni_log(NI_LOG_ERROR, "Failed to open decoder (status = %d), "
336  "resource unavailable\n", ret);
338  ni_logan_dec_close(ni_dec_ctx);
339  ni_log(NI_LOG_ERROR, "Failed to open decoder (status = %d), "
340  "resource unavailable\n", ret);
341  }
342  else
343  {
344  ni_dec_ctx->dev_xcoder_name = p_session_ctx->dev_xcoder_name;
345  ni_dec_ctx->blk_xcoder_name = p_session_ctx->blk_xcoder_name;
346  ni_dec_ctx->dev_dec_idx = p_session_ctx->hw_id;
347  ni_log(NI_LOG_DEBUG, "XCoder %s Index %d (inst: %d) opened successfully\n",
348  ni_dec_ctx->dev_xcoder_name, ni_dec_ctx->dev_dec_idx, p_session_ctx->session_id);
349  }
350 
351  ni_dec_ctx->eos_pkt_received = 0;
352  ni_dec_ctx->dec_wait = NI_LOGAN_POLL_INTERVAL;
353  ni_dec_ctx->current_pts = 0;
354  return ret;
355 }
356 
358 {
359  int ret = 0;
360  ni_log(NI_LOG_INFO, "ni_logan_dec_reinit enter\n");
361  int64_t bcp_current_pts = ni_dec_ctx->current_pts;
362  if ((ret = ni_logan_setup_decoder(ni_dec_ctx)) < 0)
363  {
364  return ret;
365  }
366  ni_logan_session_context_t *p_session_ctx = ni_dec_ctx->p_session_ctx;
367  if ((ret = ni_logan_dec_init(ni_dec_ctx)) < 0)
368  {
369  goto done;
370  }
371  ni_dec_ctx->current_pts = bcp_current_pts;
372 done:
373  if (NI_INVALID_DEVICE_HANDLE == p_session_ctx->blk_io_handle ||
374  NI_INVALID_DEVICE_HANDLE == p_session_ctx->device_handle)
375  {
376  ni_logan_dec_close(ni_dec_ctx);
377  }
378 
379  return ret;
380 }
381 // return 1 if need to prepend saved header to pkt data, 0 otherwise
382 int ni_logan_xcoder_add_headers(ni_logan_dec_context_t *ni_dec_ctx, uint8_t *pkt_data, int pkt_size,
383  int pkt_flags, uint8_t *extradata, int extradata_size)
384 {
385  int ret = 0;
386  const uint8_t *ptr = pkt_data;
387  const uint8_t *end = pkt_data + pkt_size;
388  uint32_t stc = -1;
389  uint8_t nalu_type = 0;
390 
391  if (!pkt_data)
392  {
393  return ret;
394  }
395 
396  while (ptr < end)
397  {
398  stc = -1;
399  ptr = ni_logan_find_start_code(ptr, end, &stc);
400  if (ptr == end)
401  {
402  break;
403  }
404 
405  // NAL type constant names have conflicts between AVC and HEVC, so
406  // use numbers directly for AVC
407  if (NI_LOGAN_CODEC_FORMAT_H264 == ni_dec_ctx->codec_format)
408  {
409  nalu_type = stc & 0x1F;
410 
411  // update extra data on sequence change by resetting got_first_key_frame
412  if (ni_dec_ctx->got_first_key_frame && pkt_flags & 0x0001)
413  {
414  if (ni_dec_ctx->extradata_size != extradata_size ||
415  memcmp(ni_dec_ctx->extradata, extradata, ni_dec_ctx->extradata_size))
416  {
417  ni_dec_ctx->got_first_key_frame = 0;
418  }
419  }
420 
421  // Find the first packet containing key frame
422  if (!ni_dec_ctx->got_first_key_frame && pkt_flags & 0x0001)
423  {
424  free(ni_dec_ctx->extradata);
425  ni_dec_ctx->extradata = malloc(extradata_size);
426  if (!ni_dec_ctx->extradata)
427  {
428  ni_log(NI_LOG_ERROR, "%s memory allocation failed !\n", __FUNCTION__);
429  ret = 0;
430  break;
431  }
432  ni_log(NI_LOG_TRACE, "%s size %d\n", __FUNCTION__, extradata_size);
433  memcpy(ni_dec_ctx->extradata, extradata, extradata_size);
434  ni_dec_ctx->extradata_size = extradata_size;
435  ni_dec_ctx->got_first_key_frame = 1;
436  ret = 1;
437  break;
438  }
439 
440  // when header (SPS/PPS) already exists, no need to prepend it again;
441  // we use one of the header info to simplify the checking.
442  if (/*NAL_SPS*/7 == nalu_type || /*NAL_PPS*/8 == nalu_type)
443  {
444  // save the header if not done yet for subsequent comparison
445  if (! ni_dec_ctx->extradata_size || ! ni_dec_ctx->extradata)
446  {
447  ni_dec_ctx->extradata = malloc(extradata_size);
448  if (! ni_dec_ctx->extradata)
449  {
450  ni_log(NI_LOG_ERROR, "%s memory allocation failed!\n",
451  __FUNCTION__);
452  ret = 0;
453  break;
454  }
455  ni_log(NI_LOG_TRACE, "%s size %d\n",
456  __FUNCTION__, extradata_size);
457  memcpy(ni_dec_ctx->extradata, extradata, extradata_size);
458  ni_dec_ctx->extradata_size = extradata_size;
459  }
460  ni_dec_ctx->got_first_key_frame = 1;
461  ret = 0;
462  break;
463  }
464  else if (nalu_type >= 1/*NAL_SLICE*/ && nalu_type <= 5/*NAL_IDR_SLICE*/)
465  {
466  // VCL types results in no header inserted
467  ret = 0;
468  break;
469  }
470  }
471  else if (NI_LOGAN_CODEC_FORMAT_H265 == ni_dec_ctx->codec_format)
472  {
473  nalu_type = (stc >> 1) & 0x3F;
474 
475  // IRAP picture types include: BLA, CRA, IDR and IRAP reserve types,
476  // 16-23, and insert header in front of IRAP at start or if header changes
477  if (ni_dec_ctx->got_first_key_frame && pkt_flags & 0x0001)
478  {
479  if (ni_dec_ctx->extradata_size != extradata_size ||
480  memcmp(ni_dec_ctx->extradata, extradata, ni_dec_ctx->extradata_size))
481  {
482  ni_dec_ctx->got_first_key_frame = 0;
483  }
484  }
485 
486  if (! ni_dec_ctx->got_first_key_frame && pkt_flags & 0x0001)
487  {
488  free(ni_dec_ctx->extradata);
489  ni_dec_ctx->extradata = malloc(extradata_size);
490  if (! ni_dec_ctx->extradata)
491  {
492  ni_log(NI_LOG_ERROR, "%s memory allocation failed !\n",
493  __FUNCTION__);
494  ret = 0;
495  break;
496  }
497  ni_log(NI_LOG_TRACE, "%s size %d\n",
498  __FUNCTION__, extradata_size);
499  memcpy(ni_dec_ctx->extradata, extradata, extradata_size);
500  ni_dec_ctx->extradata_size = extradata_size;
501  ni_dec_ctx->got_first_key_frame = 1;
502  ret = 1;
503  break;
504  }
505 
506  // when header (VPS/SPS/PPS) already exists, no need to prepend it again;
507  // we use one of the header info to simplify the checking.
508  if (/*NI_NAL_VPS*/32 == nalu_type || /*NI_NAL_SPS*/33 == nalu_type || /*NI_NAL_PPS*/34 == nalu_type)
509  {
510  // save the header if not done yet for subsequent comparison
511  if (! ni_dec_ctx->extradata_size || ! ni_dec_ctx->extradata)
512  {
513  ni_dec_ctx->extradata = malloc(extradata_size);
514  if (! ni_dec_ctx->extradata)
515  {
516  ni_log(NI_LOG_ERROR, "%s memory allocation failed!\n",
517  __FUNCTION__);
518  ret = 0;
519  break;
520  }
521  ni_log(NI_LOG_TRACE, "%s size %d\n",
522  __FUNCTION__, extradata_size);
523  memcpy(ni_dec_ctx->extradata, extradata, extradata_size);
524  ni_dec_ctx->extradata_size = extradata_size;
525  }
526  ni_dec_ctx->got_first_key_frame = 1;
527  ret = 0;
528  break;
529  }
530  else if (nalu_type >= 0/*NI_NAL_TRAIL_N*/ && nalu_type <= 31)
531  {
532  // VCL types results in no header inserted
533  ret = 0;
534  break;
535  }
536  }
537  else
538  {
539  ni_log(NI_LOG_ERROR, "%s wrong codec %d !\n",
540  __FUNCTION__, ni_dec_ctx->codec_format);
541  break;
542  }
543  }
544 
545  return ret;
546 }
547 
548 
549 // check if the packet is SEI only, 1 yes, 0 otherwise
550 // check if getting the header of streams in decoder low delay mode, and update its value
551 // check the new sequence headers and cache them.
552 int ni_logan_packet_parse(ni_logan_dec_context_t *ni_dec_ctx, uint8_t *pkt_data,
553  int pkt_size, ni_logan_packet_t *p_packet)
554 {
555  ni_logan_session_context_t *p_session_ctx = ni_dec_ctx->p_session_ctx;
556  ni_logan_decoder_params_t *p_param = ni_dec_ctx->p_param;
557  int pkt_sei_alone = 0;
558  int got_slice = 0;
559  int low_delay = ni_dec_ctx->low_delay;
560  int pkt_nal_bitmap = 0;
561  int chk_pkt = ni_dec_ctx->enable_check_packet;
562  const uint8_t *ptr = pkt_data;
563  const uint8_t *end = pkt_data + pkt_size;
564  uint8_t nalu_type = 0;
565  int nalu_count = 0;
566  int stc;
567 
568  if (!pkt_data)
569  {
570  return pkt_sei_alone;
571  }
572 
574  {
575  ni_log(NI_LOG_TRACE, "%s(): already find the header of streams.\n",
576  __FUNCTION__);
577  low_delay = 0;
578  }
579  pkt_sei_alone = 1;
580  while ((pkt_sei_alone || low_delay || chk_pkt) && ptr < end)
581  {
582  stc = -1;
583  ptr = ni_logan_find_start_code(ptr, end, &stc);
584  if (ptr == end)
585  {
586  if (0 == nalu_count)
587  {
588  pkt_sei_alone = 0;
589  ni_log(NI_LOG_TRACE, "%s(): no NAL found in pkt\n", __FUNCTION__);
590  }
591  break;
592  }
593  nalu_count++;
594 
595  if (NI_LOGAN_CODEC_FORMAT_H264 == ni_dec_ctx->codec_format)
596  {
597  nalu_type = stc & 0x1F;
598 
599  //check whether the packet is sei alone
600  pkt_sei_alone = (pkt_sei_alone && 6/*NAL_SEI*/ == nalu_type);
601 
602  //check whether the packet contains SEI NAL after VCL NAL units
603  if (got_slice && (6/*NAL_SEI*/ == nalu_type))
604  {
605  chk_pkt = 0;
606  // 5 bytes = 3 bytes start code + 1 byte nal type(0x06) + 1 byte sei type
607  p_packet->len_of_sei_after_vcl = (end - ptr) + 5;
608  ni_log(NI_LOG_TRACE, "%s(): found SEI after VCL NAL, len=%d\n",
609  __FUNCTION__, p_packet->len_of_sei_after_vcl);
610  }
611  else if ((nalu_type >= 1/*NAL_SLICE*/) && (nalu_type <= 5/*NAL_IDR_SLICE*/)) //VCL
612  {
613  got_slice = 1;
614  }
615 
616  // FFmpeg stores a complete frame in each AVPacket. A complete frame
617  // includes headers, SEIs, video slices, and other NALs such as access
618  // unit delimiters, etc. The decoder expects a complete frame for each
619  // packet writing to the decoder. Otherwise it can cause all sorts of
620  // problems. However in some cases the first NALU could be unit delimiter
621  // so we need to force to check NALU split to collect all the headers in
622  // case of decoder VPU recovery.
623  switch (nalu_type)
624  {
625  case 7/*NAL_SPS*/:
626  chk_pkt = 1;
627  pkt_nal_bitmap |= NI_LOGAN_NAL_SPS_BIT;
628  break;
629  case 8/*NAL_PPS*/:
630  chk_pkt = 1;
631  pkt_nal_bitmap |= NI_LOGAN_NAL_PPS_BIT;
632  break;
633  case 6/*NAL_SEI*/:
634  case 9/*NAL_AUD*/:
635  chk_pkt = 1;
636  break;
637  default:
638  chk_pkt = ni_dec_ctx->enable_check_packet | p_param->dec_input_params.check_packet;
639  break;
640  }
641 
642  // Set decoder low delay mode one-time.
643  if (pkt_nal_bitmap & (NI_LOGAN_NAL_SPS_BIT | NI_LOGAN_NAL_PPS_BIT))
644  {
645  ni_log(NI_LOG_TRACE, "%s(): Detect SPS, PPS and IDR, enable "
646  "decoder low delay mode.\n", __FUNCTION__);
647  pkt_nal_bitmap |= NI_LOGAN_GENERATE_ALL_NAL_HEADER_BIT;
648  if (low_delay)
649  {
650  p_session_ctx->decoder_low_delay = low_delay;
651  low_delay = 0;
652  }
653 
654  // Update cached packet including SPS+PPS+IDR slice. A complete frame
655  // needs to be cached for stream with intraPeriod = 0
656  if(got_slice)
657  {
658  p_packet->frame_type = LOGAN_PIC_TYPE_IDR;
659  }
660  }
661  }
662  else if (NI_LOGAN_CODEC_FORMAT_H265 == ni_dec_ctx->codec_format)
663  {
664  nalu_type = (stc >> 1) & 0x3F;
665 
666  //check whether the packet is sei alone
667  pkt_sei_alone = (pkt_sei_alone && (39 == nalu_type || 40 == nalu_type));
668 
669  //check whether the packet contains SEI NAL after VCL NAL units
670  if (got_slice && (/*NI_NAL_SEI_PREFIX*/39 == nalu_type || /*NI_NAL_SEI_SUFFIX*/40 == nalu_type))
671  {
672  chk_pkt = 0;
673  // 5 bytes = 3 bytes start code + 2 bytes nal type(0x4e 0x01)
674  p_packet->len_of_sei_after_vcl = (end - ptr) + 5;
675  ni_log(NI_LOG_TRACE, "%s(): found SEI after VCL NAL, len=%d\n",
676  __FUNCTION__, p_packet->len_of_sei_after_vcl);
677  }
678  else if ((nalu_type >= 0/*NI_NAL_TRAIL_N*/) && (nalu_type <= 31)) //VCL
679  {
680  got_slice = 1;
681  }
682 
683  // FFmpeg stores a complete frame in each AVPacket. A complete frame
684  // includes headers, SEIs, video slices, and other NALs such as access
685  // unit delimiters, etc. The decoder expects a complete frame for each
686  // packet writing to the decoder. Otherwise it can cause all sorts of
687  // problems. However in some cases the first NALU could be unit delimiter
688  // so we need to force to check NALU split to collect all the headers in
689  // case of decoder VPU recovery.
690  switch (nalu_type)
691  {
692  case 32/*NI_NAL_VPS*/:
693  chk_pkt = 1;
694  pkt_nal_bitmap |= NI_LOGAN_NAL_VPS_BIT;
695  break;
696  case 33/*NI_NAL_SPS*/:
697  chk_pkt = 1;
698  pkt_nal_bitmap |= NI_LOGAN_NAL_SPS_BIT;
699  break;
700  case 34/*NI_NAL_PPS*/:
701  chk_pkt = 1;
702  pkt_nal_bitmap |= NI_LOGAN_NAL_PPS_BIT;
703  break;
704  case 35/*NI_NAL_AUD*/:
705  case 36/*NI_NAL_EOS_NUT*/:
706  case 37/*NI_NAL_EOB_NUT*/:
707  case 38/*NI_NAL_FD_NUT*/:
708  case 39/*NI_NAL_SEI_PREFIX*/:
709  case 40/*NI_NAL_SEI_SUFFIX*/:
710  chk_pkt = 1;
711  break;
712  default:
713  chk_pkt = ni_dec_ctx->enable_check_packet | p_param->dec_input_params.check_packet;
714  break;
715  }
716 
717  // Set decoder low delay mode one-time.
719  {
720  ni_log(NI_LOG_TRACE, "%s(): Detect VPS, SPS, PPS and IDR, "
721  "enable decoder low delay mode.\n", __FUNCTION__);
722  pkt_nal_bitmap |= NI_LOGAN_GENERATE_ALL_NAL_HEADER_BIT;
723  if (low_delay)
724  {
725  p_session_ctx->decoder_low_delay = low_delay;
726  low_delay = 0;
727  }
728 
729  // Update cached packet including VPS+SPS+PPS+IDR slice. A complete frame
730  // needs to be cached for stream with intraPeriod = 0
731  if(got_slice)
732  {
733  p_packet->frame_type = LOGAN_PIC_TYPE_IDR;
734  }
735  }
736  }
737  else
738  {
739  ni_log(NI_LOG_ERROR, "%s() wrong codec %d!\n",
740  __FUNCTION__, ni_dec_ctx->codec_format);
741  pkt_sei_alone = 0;
742  break;
743  }
744  }
745 
746  ni_dec_ctx->pkt_nal_bitmap |= pkt_nal_bitmap;
747  return pkt_sei_alone;
748 }
749 
751 {
752  ni_log(NI_LOG_ERROR,"ni_logan_packet_buffer_clone enter\n");
753 
754  dst_pkt->pts = src_pkt->pts;
755  dst_pkt->dts = src_pkt->dts;
756  dst_pkt->flags = src_pkt->flags;
757  dst_pkt->video_width = src_pkt->video_width;
758  dst_pkt->video_height = src_pkt->video_height;
759  dst_pkt->data_len = src_pkt->data_len;
760  dst_pkt->p_data = src_pkt->p_data;
761  src_pkt->p_data = NULL;
762  return 0;
763 }
764 
765 int ni_logan_dec_send(ni_logan_dec_context_t *ni_dec_ctx, uint8_t *pkt_data,
766  int pkt_size, int pkt_flags, long long pkt_pts,
767  long long pkt_dts, int avctx_width, int avctx_height,
768  uint8_t *extradata, int extradata_size)
769 {
770  /* call xcoder_dec_send to send compressed video packet to the decoder
771  instance */
772  ni_logan_session_context_t *p_session_ctx = ni_dec_ctx->p_session_ctx;
773  ni_logan_decoder_params_t *p_param = ni_dec_ctx->p_param;
774  ni_logan_session_data_io_t *p_ni_packet = NULL;
775  int need_draining = 0;
776  size_t size;
777  ni_logan_packet_t *xpkt = NULL;
778  int ret;
779  int sent;
780  int send_size = 0;
781  int new_packet = 0;
782  int extra_prev_size = 0;
783 
784  size = pkt_size;
785 
786  if (ni_dec_ctx->flushing)
787  {
788  ni_log(NI_LOG_ERROR, "Decoder is flushing and cannot accept new "
789  "buffer until all output buffers have been released\n");
791  }
792 
793  if (pkt_size == 0)
794  {
795  need_draining = 1;
796  // Once VPU recovery, the s->draining may be lost during session reset. And
797  // so is the EOS indicator which might be lost in decoder session read. Here
798  // we try to recover EOS indicator so as to return EOF in this calling.
799  ni_dec_ctx->eos |= (ni_dec_ctx->draining &&
801  ni_log(NI_LOG_DEBUG, "Decoder is need_draining= %d , draining=%d,session_run_state=%d,eos=%d\n",
802  need_draining,ni_dec_ctx->draining,p_session_ctx->session_run_state,ni_dec_ctx->eos);
803  }
804 
805  if (ni_dec_ctx->draining && ni_dec_ctx->eos)
806  {
807  ni_log(NI_LOG_DEBUG, "Decoder is draining, eos\n");
809  }
810  if (!ni_dec_ctx->eos_pkt_received)
811  {
812  if (ni_logan_fifo_is_full(ni_dec_ctx->input_data_fifo))
813  {
814  ni_log(NI_LOG_ERROR,"fifo full,need lost 1 frame....\n");
815  p_ni_packet = ni_logan_fifo_generic_read(ni_dec_ctx->input_data_fifo);
816  ni_logan_packet_buffer_free(&(p_ni_packet->data.packet));
817  }
818  p_ni_packet = ni_logan_fifo_generic_write(ni_dec_ctx->input_data_fifo);
819  xpkt = &p_ni_packet->data.packet;
820  {
821  memset(xpkt, 0, sizeof(ni_logan_packet_t));
822  xpkt->pts = pkt_pts;
823  xpkt->dts = pkt_dts;
824  xpkt->flags = pkt_flags;
825  xpkt->video_width = avctx_width;
826  xpkt->video_height = avctx_height;
827  xpkt->p_data = NULL;
828  xpkt->data_len = pkt_size;
829  xpkt->p_all_custom_sei = NULL;
830  xpkt->len_of_sei_after_vcl = 0;
831 
832 
833  if (extradata_size > 0 && extradata_size != ni_dec_ctx->extradata_size &&
834  ni_logan_xcoder_add_headers(ni_dec_ctx, pkt_data, pkt_size, pkt_flags, extradata, extradata_size))
835  {
836  if (extradata_size > p_session_ctx->max_nvme_io_size * 2)
837  {
838  ni_log(NI_LOG_ERROR, "%s extradata_size %d exceeding max size "
839  "supported: %d\n", __FUNCTION__, extradata_size,
840  p_session_ctx->max_nvme_io_size * 2);
841  }
842  else
843  {
844  ni_log(NI_LOG_DEBUG, "%s extradata_size %d copied to pkt start\n",
845  __FUNCTION__, extradata_size);
846  p_session_ctx->prev_size = extradata_size;
847  memcpy(p_session_ctx->p_leftover, extradata, extradata_size);
848  }
849  }
850 
851  if (ni_dec_ctx->low_delay && ni_dec_ctx->got_first_key_frame &&
853  {
854  p_session_ctx->decoder_low_delay = p_param->dec_input_params.lowdelay;
856  ni_log(NI_LOG_TRACE, "%s got first IDR in decoder low delay mode, "
857  "delay time %dms, pkt_nal_bitmap %d\n", __FUNCTION__,
858  p_session_ctx->decoder_low_delay, ni_dec_ctx->pkt_nal_bitmap);
859  }
860 
861  // check if the packet is SEI only, save it to be sent with the next data frame.
862  // check if getting the header of streams in decoder low delay mode, and update its value.
863  // check the new sequence headers and cache them.
864  ret = ni_logan_packet_parse(ni_dec_ctx, pkt_data, pkt_size, xpkt);
865  if (ret)
866  {
867  // skip the packet if it's corrupted and/or exceeding lone SEI buf size
868  if (pkt_size + p_session_ctx->lone_sei_size <= NI_LOGAN_MAX_SEI_DATA)
869  {
870  memcpy(p_session_ctx->buf_lone_sei + p_session_ctx->lone_sei_size,
871  pkt_data, pkt_size);
872  p_session_ctx->lone_sei_size += pkt_size;
873 
874  ni_log(NI_LOG_TRACE, "%s pkt lone SEI saved and return %d\n",
875  __FUNCTION__, pkt_size);
876  }
877  else
878  {
879  ni_log(NI_LOG_DEBUG, "lone SEI size %d > buf size %ld "
880  "corrupted? skipped ..\n", pkt_size, NI_LOGAN_MAX_SEI_DATA);
881  }
882 
883  xpkt->data_len = 0;
884  return pkt_size;
885  }
886 
887  if (ni_dec_ctx->custom_sei != NI_LOGAN_INVALID_SEI_TYPE)
888  {
889  ret = ni_logan_detect_custom_sei(pkt_data, pkt_size, p_session_ctx, p_param, xpkt);
890  if (ret != 0)
891  {
892  goto fail;
893  }
894  }
895 
896  // embed lone SEI saved previously (if any) to send to decoder
897  if (p_session_ctx->lone_sei_size)
898  {
899  ni_log(NI_LOG_TRACE, "%s copy over lone SEI data size: %d\n",
900  __FUNCTION__, p_session_ctx->lone_sei_size);
901  memcpy((uint8_t *)p_session_ctx->p_leftover + p_session_ctx->prev_size,
902  p_session_ctx->buf_lone_sei, p_session_ctx->lone_sei_size);
903  p_session_ctx->prev_size += p_session_ctx->lone_sei_size;
904  p_session_ctx->lone_sei_size = 0;
905  }
906 
907  if ((pkt_size + p_session_ctx->prev_size) > 0)
908  {
909  ni_logan_packet_buffer_alloc(xpkt, (pkt_size + p_session_ctx->prev_size - xpkt->len_of_sei_after_vcl));
910  if (!xpkt->p_data)
911  {
913  goto fail;
914  }
915  }
916  new_packet = 1;
917  }
918 
919  ni_log(NI_LOG_DEBUG, "%s: pkt size=%d\n", __FUNCTION__, pkt_size);
920 
921  if (ni_dec_ctx->started == 0)
922  {
923  xpkt->start_of_stream = 1;
924  ni_dec_ctx->started = 1;
925  }
926 
927  ni_log(NI_LOG_TRACE, "ni_logan_packet_copy before: size=%d s->prev_size=%d"
928  " send_size=%d len_of_sei_after_slice=%d (end of stream)\n",
929  pkt_size, p_session_ctx->prev_size, send_size, xpkt->len_of_sei_after_vcl);
930  if (new_packet)
931  {
932  extra_prev_size = p_session_ctx->prev_size;
933  send_size = ni_logan_packet_copy(xpkt->p_data, pkt_data, (pkt_size - xpkt->len_of_sei_after_vcl),
934  p_session_ctx->p_leftover, &p_session_ctx->prev_size);
935  // increment offset of data sent to decoder and save it
936  xpkt->pos = ni_dec_ctx->offset;
937  ni_dec_ctx->offset += pkt_size + extra_prev_size;
938  }
939  ni_log(NI_LOG_TRACE, "ni_logan_packet_copy after: size=%d, s->prev_size=%d"
940  " send_size=%d xpkt->data_len=%d, len_of_sei_after_slice=%d (end of "
941  "stream)\n", pkt_size, p_session_ctx->prev_size, send_size,
942  xpkt->data_len, xpkt->len_of_sei_after_vcl);
943 
944  if (send_size < 0)
945  {
946  ni_log(NI_LOG_ERROR, "Failed to copy pkt (status = %d)\n",
947  send_size);
949  goto fail;
950  }
951  xpkt->data_len += extra_prev_size;
952  if (need_draining && !ni_dec_ctx->draining)
953  {
954  ni_log(NI_LOG_DEBUG, "Sending End Of Stream signal\n");
955  xpkt->end_of_stream = 1;
956  xpkt->data_len = 0;
957  ni_dec_ctx->eos_pkt_received = 1;
958  }
959  }
960 
962  ni_dec_ctx->dec_fifo_num == 0)
963  {
966  return 0;
967  }
968  else if (ni_dec_ctx->flush_buffer == NI_LOGAN_DECODE_FLUSH_STATUS_FLUSHING)
969  {
970  if (p_session_ctx->ready_to_flush == NI_LOGAN_DECODE_FLUSH_BUFFER_OFF)
972  else
973  return 0;
974  }
975 
976  if ((ni_dec_ctx->eos_pkt_received && !ni_dec_ctx->draining) ||
978  {
979  sent = 1;
980  while (!ni_logan_fifo_is_empty(ni_dec_ctx->input_data_fifo))
981  {
982  p_ni_packet = ni_logan_fifo_generic_read(ni_dec_ctx->input_data_fifo);
983  ni_log(NI_LOG_TRACE, "%s pts=%" PRIi64 ", dts=%" PRIi64"\n", __FUNCTION__,
984  p_ni_packet->data.packet.pts, p_ni_packet->data.packet.dts);
985 
986  sent = ni_logan_device_session_write(p_session_ctx, &(p_ni_packet->data.packet), NI_LOGAN_DEVICE_TYPE_DECODER);
987 
988  if (sent == 0 && !ni_logan_fifo_is_empty(ni_dec_ctx->input_data_fifo))
989  {
990  ni_log(NI_LOG_DEBUG, "dec_send EAGAIN this better not happen "
991  "sleep %d us !\n",
992  ni_dec_ctx->dec_wait);
993  usleep(ni_dec_ctx->dec_wait);
994  ni_dec_ctx->dec_wait += NI_LOGAN_POLL_INTERVAL;
996  break;
997  }
998  else if (sent < 0)
999  {
1000  ni_log(NI_LOG_ERROR, "Failed to send eos signal (status = %d)\n",sent);
1002  {
1003  ni_log(NI_LOG_INFO, "%s VPU recovery, need to reset\n",
1004  __FUNCTION__);
1006 
1007  if (ni_logan_decode_reset(ni_dec_ctx) < 0)
1008  {
1009  return NI_LOGAN_RETCODE_FAILURE;
1010  }
1011  if (ni_dec_ctx->seq_hdr_pkt.data_len > 0)
1012  {
1013  if (ni_logan_device_session_write(p_session_ctx, &ni_dec_ctx->seq_hdr_pkt, NI_LOGAN_DEVICE_TYPE_DECODER) < 0)
1014  {
1016  return NI_LOGAN_RETCODE_FAILURE;
1017  }
1018  }
1019  return 0;
1020  }
1022  goto fail;
1023  }
1024  else
1025  {
1026  if (&(p_ni_packet->data.packet).frame_type == LOGAN_PIC_TYPE_IDR)
1027  {
1028  if (ni_dec_ctx->seq_hdr_pkt.data_len > 0)
1029  {
1030  ni_logan_packet_buffer_free(&(p_ni_packet->data.packet));
1031  }
1032  ni_logan_packet_buffer_clone(&ni_dec_ctx->seq_hdr_pkt, &(p_ni_packet->data.packet));
1033  }
1034  ni_logan_packet_buffer_free(&(p_ni_packet->data.packet));
1035  if (&(p_ni_packet->data.packet).data_len == 0)
1036  {
1037  free(&(p_ni_packet->data.packet).p_all_custom_sei);
1038  (p_ni_packet->data.packet).p_all_custom_sei = NULL;
1039  }
1040  // wait time is incremental, and reset after a successful send
1041  ni_dec_ctx->dec_wait = NI_LOGAN_POLL_INTERVAL;
1043  {
1044  ni_dec_ctx->dec_fifo_num --;
1045  if (ni_dec_ctx->dec_fifo_num == 0)
1046  {
1049  return 0;
1050  }
1051  }
1052  }
1053  }
1054  if (ni_logan_fifo_is_empty(ni_dec_ctx->input_data_fifo))
1055  {
1057  ni_dec_ctx->draining = 1;
1059  ni_dec_ctx->eos_pkt_received = 0;
1060  }
1061  }
1062  else
1063  {
1064  sent = 0;
1065 
1066  p_ni_packet = ni_logan_fifo_generic_read(ni_dec_ctx->input_data_fifo);
1067  ni_log(NI_LOG_DEBUG, "%s pts=%" PRIi64 ", dts=%" PRIi64 " \n", __FUNCTION__, p_ni_packet->data.packet.pts, p_ni_packet->data.packet.dts);
1068 
1069  sent = ni_logan_device_session_write(p_session_ctx, &(p_ni_packet->data.packet), NI_LOGAN_DEVICE_TYPE_DECODER);
1070  if (sent < 0)
1071  {
1072  ni_log(NI_LOG_ERROR, "Failed to send compressed pkt (status=%d)\n", sent);
1074  {
1075  ni_log(NI_LOG_INFO, "%s VPU recovery, need to reset\n",
1076  __FUNCTION__);
1078 
1079  if (ni_logan_decode_reset(ni_dec_ctx) < 0)
1080  {
1081  return NI_LOGAN_RETCODE_FAILURE;
1082  }
1083  if (ni_dec_ctx->seq_hdr_pkt.data_len > 0)
1084  {
1085  if (ni_logan_device_session_write(p_session_ctx, &ni_dec_ctx->seq_hdr_pkt, NI_LOGAN_DEVICE_TYPE_DECODER) < 0)
1086  {
1088  return NI_LOGAN_RETCODE_FAILURE;
1089  }
1090  }
1091  return 0;
1092  }
1094  goto fail;
1095  }
1096  else if (sent == 0)
1097  {
1099  sent = size;
1100  }
1101  else
1102  {
1103  if (&(p_ni_packet->data.packet).frame_type == LOGAN_PIC_TYPE_IDR)
1104  {
1105  if (ni_dec_ctx->seq_hdr_pkt.data_len > 0)
1106  {
1107  ni_logan_packet_buffer_free(&(p_ni_packet->data.packet));
1108  }
1109  ni_logan_packet_buffer_clone(&ni_dec_ctx->seq_hdr_pkt, &(p_ni_packet->data.packet));
1110  }
1111  ni_logan_packet_buffer_free(&(p_ni_packet->data.packet));
1112  if (&(p_ni_packet->data.packet).data_len == 0)
1113  {
1114  free(&(p_ni_packet->data.packet).p_all_custom_sei);
1115  (p_ni_packet->data.packet).p_all_custom_sei = NULL;
1116  }
1117  }
1118  }
1119 
1120  return sent;
1121 
1122 fail:
1123  ni_logan_packet_buffer_free(&(p_ni_packet->data.packet));
1124  free(&(p_ni_packet->data.packet).p_all_custom_sei);
1125  (p_ni_packet->data.packet).p_all_custom_sei = NULL;
1126  ni_dec_ctx->draining = 1;
1127  ni_dec_ctx->eos = 1;
1128 
1129  return ret;
1130 }
1131 
1133 {
1134  ni_dec_ctx->draining = 0;
1135  ni_dec_ctx->flushing = 0;
1136  ni_dec_ctx->eos = 0;
1137  /* Future: for now, always return 1 to indicate the codec has been flushed
1138  and it leaves the flushing state and can process again ! will consider
1139  case of user retaining frames in HW "surface" usage */
1140  return 1;
1141 }
1142 
1144 {
1145  int ret = 1;
1146  if (ni_dec_ctx->flushing)
1147  {
1148  if (!ni_logan_dec_flush(ni_dec_ctx))
1149  {
1150  ni_log(NI_LOG_DEBUG, "IS flushing and NOT dec_flush, AGAIN!!!\n");
1151  ret = 0;
1152  }
1153  }
1154  return ret;
1155 }
1156 
1158  ni_logan_session_data_io_t *p_session_data,
1159  int avctx_width,
1160  int avctx_height)
1161 {
1162  ni_logan_session_context_t *p_session_ctx = ni_dec_ctx->p_session_ctx;
1163  int ret, width, height, alloc_mem;
1164 
1165  // If active video resolution has been obtained we just use it as it's the
1166  // exact size of frame to be returned, otherwise we use what we are told by
1167  // upper stream as the initial setting and it will be adjusted.
1168  width = p_session_ctx->active_video_width > 0 ? p_session_ctx->active_video_width : avctx_width;
1169  height = p_session_ctx->active_video_height > 0 ? p_session_ctx->active_video_height : avctx_height;
1170 
1171  // allocate memory only after resolution is known (buffer pool set up)
1172  alloc_mem = (p_session_ctx->active_video_width > 0) &&
1173  (p_session_ctx->active_video_height > 0 ? 1 : 0);
1174 
1176  &p_session_data->data.frame,
1177  alloc_mem,
1178  width,
1179  height,
1181  p_session_ctx->bit_depth_factor);
1182 
1183  return ret;
1184 }
1185 
1187  ni_logan_session_data_io_t *p_session_data,
1188  int avctx_width,
1189  int avctx_height)
1190 {
1191  ni_logan_session_context_t *p_session_ctx = ni_dec_ctx->p_session_ctx;
1192  int ret;
1193  ret = ni_logan_decoder_frame_alloc(ni_dec_ctx, p_session_data, avctx_width, avctx_height);
1194  if (NI_LOGAN_RETCODE_SUCCESS != ret)
1195  {
1196  return ret;
1197  }
1198 
1199  ret = ni_logan_device_session_read(p_session_ctx, p_session_data, NI_LOGAN_DEVICE_TYPE_DECODER);
1200  if (ret == 0)
1201  {
1202  ni_dec_ctx->eos = p_session_data->data.frame.end_of_stream;
1203  ni_logan_decoder_frame_free(p_session_data);
1204  return ret;
1205  }
1206  else if (ret > 0) //This is where to handle the frame change and all reinit i guess in revB
1207  {
1209  {
1210  // On decoder VPU recovery the first received frame corresponding to the
1211  // cached seq_hdr_pkt should be dropped since the data is outdated.
1213  ni_logan_decoder_frame_free(p_session_data);
1214  return 0;
1215  }
1216  }
1217  else
1218  {
1219  ni_log(NI_LOG_ERROR, "Failed to get output buffer (status=%d)\n", ret);
1221  {
1222  ni_log(NI_LOG_INFO, "%s VPU recovery, need to reset\n",
1223  __FUNCTION__);
1225  ni_logan_decoder_frame_free(p_session_data);
1226 
1227  if (ni_logan_decode_reset(ni_dec_ctx) < 0)
1228  {
1229  return NI_LOGAN_RETCODE_FAILURE;
1230  }
1231  if (ni_dec_ctx->seq_hdr_pkt.data_len > 0)
1232  {
1233  if (ni_logan_device_session_write(p_session_ctx, &ni_dec_ctx->seq_hdr_pkt, NI_LOGAN_DEVICE_TYPE_DECODER) < 0)
1234  {
1236  return NI_LOGAN_RETCODE_FAILURE;
1237  }
1238  }
1239  return 0;
1240  }
1241  }
1242  return ret;
1243 }
1244 
1246 {
1247  ni_logan_session_context_t *p_session_ctx = ni_dec_ctx->p_session_ctx;
1248  ni_logan_session_data_io_t *p_ni_packet = NULL;
1250  ni_log(NI_LOG_TRACE, "NI XCoder decode reset\n");
1251 
1252  int ori_run_state = p_session_ctx->session_run_state;
1253  ret = ni_logan_device_session_close(p_session_ctx, ni_dec_ctx->eos, NI_LOGAN_DEVICE_TYPE_DECODER);
1254 
1255 #ifdef _WIN32
1256  ni_logan_device_close(p_session_ctx->device_handle);
1257 #elif __linux__
1258  ni_logan_device_close(p_session_ctx->device_handle);
1259  ni_logan_device_close(p_session_ctx->blk_io_handle);
1260 #endif
1261  p_session_ctx->device_handle = NI_INVALID_DEVICE_HANDLE;
1262  p_session_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE;
1263 
1264  if (ni_dec_ctx->input_data_fifo)
1265  {
1266  // push back
1267  do{
1268  p_ni_packet = ni_logan_fifo_generic_write(ni_dec_ctx->input_data_fifo);
1269  }while(p_ni_packet);
1270  // free all
1271  do{
1272  p_ni_packet = ni_logan_fifo_generic_read(ni_dec_ctx->input_data_fifo);
1273  if (p_ni_packet)
1274  {
1275  ni_logan_packet_buffer_free(&(p_ni_packet->data.packet));
1276  }
1277  }while(p_ni_packet);
1278  }
1279  ni_logan_fifo_free(ni_dec_ctx->input_data_fifo);
1280  ni_log(NI_LOG_DEBUG, "%s(): decoder frame fifo freed.\n", __FUNCTION__);
1281 
1283  if (ni_logan_dec_reinit(ni_dec_ctx) < 0)
1284  {
1285  ni_log(NI_LOG_ERROR, "%s(): ni_logan_dec_reinit fail\n", __FUNCTION__);
1286  return NI_LOGAN_RETCODE_FAILURE;
1287  }
1288  p_session_ctx->session_run_state = ori_run_state;
1289  return 0;
1290 }
1291 
1293 {
1294  ni_logan_decoder_frame_buffer_free(&p_session_data->data.frame);
1295 }
1296 
1298 {
1299  ni_logan_session_context_t *p_session_ctx = ni_dec_ctx->p_session_ctx;
1300  ni_log(NI_LOG_DEBUG, "%s enter\n",__func__);
1301  ni_dec_ctx->dec_fifo_num = ni_dec_ctx->input_data_fifo->number_of_buffers_used;
1303 }
const uint8_t * ni_logan_find_start_code(const uint8_t *p, const uint8_t *end, uint32_t *state)
Find the next start code.
int ni_logan_detect_custom_sei(const uint8_t *data, int size, ni_logan_session_context_t *p_api_ctx, ni_logan_decoder_params_t *p_api_param, ni_logan_packet_t *p_packet)
detect custom SEI payload data in Packet data, custom SEI has two meanings: a. the SEI type is not in...
#define NI_LOGAN_NAL_PPS_BIT
#define NI_LOGAN_NAL_SPS_BIT
#define NI_LOGAN_NAL_VPS_BIT
#define NI_LOGAN_GENERATE_ALL_NAL_HEADER_BIT
#define NI_LOGAN_DEC_PKT_BUF_NUM_MAX
void ni_logan_decode_flush_buffers(ni_logan_dec_context_t *ni_dec_ctx)
decoder flush buffers
int ni_logan_xcoder_add_headers(ni_logan_dec_context_t *ni_dec_ctx, uint8_t *pkt_data, int pkt_size, int pkt_flags, uint8_t *extradata, int extradata_size)
int ni_logan_dec_receive(ni_logan_dec_context_t *ni_dec_ctx, ni_logan_session_data_io_t *p_session_data, int avctx_width, int avctx_height)
Receive decoded data from decoder, including ni_logan_dec_context_t,.
int ni_logan_dec_flush(ni_logan_dec_context_t *ni_dec_ctx)
void ni_logan_decoder_frame_free(ni_logan_session_data_io_t *p_session_data)
void ni_logan_buf_pool_free(void *opaque, uint8_t *data)
decoder frame buffer pool free, including void*
int ni_logan_dec_is_flushing(ni_logan_dec_context_t *ni_dec_ctx)
Decode is flushing or not, including ni_logan_dec_context_t,.
void ni_logan_dec_close(ni_logan_dec_context_t *ni_dec_ctx)
Decode close, including ni_logan_dec_context_t,.
int ni_logan_setup_decoder(ni_logan_dec_context_t *ni_dec_ctx)
Initialize init device session_context and init default params including ni_logan_dec_context_t,...
int ni_logan_dec_reinit(ni_logan_dec_context_t *ni_dec_ctx)
int ni_logan_decode_reset(ni_logan_dec_context_t *ni_dec_ctx)
int ni_logan_decoder_frame_alloc(ni_logan_dec_context_t *ni_dec_ctx, ni_logan_session_data_io_t *p_session_data, int avctx_width, int avctx_height)
int ni_logan_packet_buffer_clone(ni_logan_packet_t *dst_pkt, ni_logan_packet_t *src_pkt)
int ni_logan_packet_parse(ni_logan_dec_context_t *ni_dec_ctx, uint8_t *pkt_data, int pkt_size, ni_logan_packet_t *p_packet)
int ni_logan_dec_init(ni_logan_dec_context_t *ni_dec_ctx)
Initialize decode parameters and open decoder device including ni_logan_dec_context_t,...
int ni_logan_dec_send(ni_logan_dec_context_t *ni_dec_ctx, uint8_t *pkt_data, int pkt_size, int pkt_flags, long long pkt_pts, long long pkt_dts, int avctx_width, int avctx_height, uint8_t *extradata, int extradata_size)
Parse the packet and send the packet to decode device.
int ni_logan_xcoder_dec_close(ni_logan_dec_context_t *ni_dec_ctx)
@ NI_LOGAN_DECODE_FLUSH_STATUS_FLUSHING
@ NI_LOGAN_DECODE_FLUSH_STATUS_START
@ NI_LOGAN_DECODE_FLUSH_STATUS_OFF
ni_logan_retcode_t
@ NI_LOGAN_RETCODE_INVALID_PARAM
@ NI_LOGAN_RETCODE_ERROR_MEM_ALOC
@ NI_LOGAN_RETCODE_ERROR_VPU_RECOVERY
@ NI_LOGAN_RETCODE_SUCCESS
@ NI_LOGAN_RETCODE_FAILURE
#define END
#define NI_LOGAN_INVALID_SEI_TYPE
#define NI_LOGAN_POLL_INTERVAL
#define NI_ERRNO
@ NI_LOGAN_DEVICE_TYPE_DECODER
#define LRETURN
@ NI_LOGAN_DECODE_FLUSH_BUFFER_OFF
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_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.
ni_logan_retcode_t ni_logan_decoder_frame_buffer_alloc(ni_logan_buf_pool_t *p_pool, ni_logan_frame_t *p_frame, int alloc_mem, int video_width, int video_height, int alignment, int factor)
Allocate memory for decoder frame buffer based on provided parameters; the memory is retrieved from a...
ni_logan_retcode_t ni_logan_decoder_frame_buffer_free(ni_logan_frame_t *p_frame)
Free decoder frame buffer that was previously allocated with ni_logan_decoder_frame_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.
int ni_logan_packet_copy(void *p_destination, const void *const p_source, int cur_size, void *p_leftover, int *p_prev_size)
Copy video packet accounting for allighment.
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.
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.
ni_logan_retcode_t ni_logan_decoder_init_default_params(ni_logan_decoder_params_t *p_param, int fps_num, int fps_denom, long bit_rate, int width, int height)
Initialize default decoder parameters.
void ni_logan_decoder_frame_buffer_pool_return_buf(ni_logan_buf_t *buf, ni_logan_buf_pool_t *p_buffer_pool)
Return a memory buffer to memory buffer pool.
#define BEST_MODEL_LOAD_STR
#define NI_LOGAN_MAX_RESOLUTION_HEIGHT
@ LOGAN_PIC_TYPE_IDR
#define NI_LOGAN_MAX_SEI_DATA
#define LIST_DEVICES_STR
#define NI_LOGAN_DEFAULT_KEEP_ALIVE_TIMEOUT
@ LOGAN_SESSION_RUN_STATE_RESETTING
@ LOGAN_SESSION_RUN_STATE_NORMAL
@ NI_LOGAN_CODEC_FORMAT_H265
@ NI_LOGAN_CODEC_FORMAT_H264
#define NI_LOGAN_MAX_RESOLUTION_AREA
#define NI_LOGAN_MAX_RESOLUTION_WIDTH
ni_logan_retcode_t ni_logan_decoder_session_flush_buffers(ni_logan_session_context_t *p_ctx)
Flush decoder output.
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.
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.
int ni_logan_fifo_is_full(ni_logan_fifo_buffer_t *p_fifo)
Check if a fifo is full.
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.
struct _ni_logan_buf_pool_t * pool
ni_logan_fifo_buffer_t * input_data_fifo
unsigned long long offset
ni_logan_packet_t seq_hdr_pkt
ni_logan_decoder_input_params_t dec_input_params
ni_logan_all_custom_sei_t * p_all_custom_sei
uint8_t buf_lone_sei[NI_LOGAN_MAX_SEI_DATA]
ni_device_handle_t device_handle
ni_logan_session_run_state_t session_run_state
char blk_xcoder_name[LOGAN_MAX_CHAR_IN_DEVICE_NAME]
ni_device_handle_t blk_io_handle
ni_logan_buf_pool_t * dec_fme_buf_pool
char dev_xcoder[LOGAN_MAX_CHAR_IN_DEVICE_NAME]
char dev_xcoder_name[LOGAN_MAX_CHAR_IN_DEVICE_NAME]
union _ni_logan_session_data_io::@4 data