libxcoder  5.2.0
ni_p2p_read_test.c
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * Copyright (C) 2024 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_p2p_read_test.c
24  *
25  * \brief Application for performing video processing using libxcoder API and
26  * P2P DMA. Its code provides examples on how to programatically use
27  * libxcoder API in conjunction with P2P DMA.
28  *
29  * This test program requires TWO Quadra devices. One Quadra device
30  * acts as a proxy for the GPU card. The other Quadra device reads
31  * frames from the proxy GPU Quadra device via peer-to-peer then
32  * encodes the frame.
33  ******************************************************************************/
34 
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdint.h>
39 
40 #define _POSIX_C_SOURCE 200809L
41 #include <getopt.h>
42 #include <unistd.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <sys/time.h>
47 #include <time.h>
48 
49 #include <sys/mman.h>
50 
51 #include "ni_device_api.h"
52 #include "ni_util.h"
53 
54 #include <sys/ioctl.h>
55 #include "ni_p2p_ioctl.h"
56 
57 #define MAX_YUV_FRAME_SIZE (7680 * 4320 * 3 / 2)
58 #define MAX_ABGR_FRAME_SIZE (7680 * 4320 * 4)
59 
60 #if MAX_ABGR_FRAME_SIZE > MAX_YUV_FRAME_SIZE
61 #define MAX_FRAME_SIZE MAX_ABGR_FRAME_SIZE
62 #else
63 #define MAX_FRAME_SIZE MAX_YUV_FRAME_SIZE
64 #endif
65 
66 #define FILE_NAME_LEN 256
67 #define MAX_SWAP_SIZE 3
68 
69 int send_fin_flag = 0;
71 int enc_eos_sent = 0;
72 
73 uint32_t number_of_frames = 0;
74 uint32_t number_of_packets = 0;
75 uint64_t data_left_size = 0;
76 int g_repeat = 1;
77 
78 struct timeval start_time;
79 struct timeval previous_time;
80 struct timeval current_time;
81 
82 time_t start_timestamp = 0;
83 time_t previous_timestamp = 0;
84 time_t current_timestamp = 0;
85 
86 unsigned long total_file_size = 0;
87 
88 uint8_t *g_curr_cache_pos = NULL;
89 uint8_t *g_raw_frame = NULL;
90 
91 uint8_t g_rgb2yuv_csc = 0;
92 
94 
95 typedef struct {
97 } swapchain_t;
98 
99 /*!****************************************************************************
100  * \brief Exit on argument error
101  *
102  * \param[in] arg_name pointer to argument name
103  * [in] param pointer to provided parameter
104  *
105  * \return None program exit
106  ******************************************************************************/
107 void arg_error_exit(char *arg_name, char *param)
108 {
109  fprintf(stderr, "Error: unrecognized argument for %s, \"%s\"\n", arg_name,
110  param);
111  exit(-1);
112 }
113 
114 /*!****************************************************************************
115  * \brief Read the next frame
116  *
117  * \param[in] fd file descriptor of input file
118  * \param[out] p_dst pointer to place the frame
119  * \param[in] to_read number of bytes to copy to the pointer
120  *
121  * \return bytes copied
122  ******************************************************************************/
123 int read_next_chunk_from_file(int fd, uint8_t *p_dst, uint32_t to_read)
124 {
125  uint8_t *tmp_dst = p_dst;
127  "read_next_chunk_from_file:p_dst %p len %u totalSize %llu left %llu\n",
128  tmp_dst, to_read, (unsigned long long)total_file_size, (unsigned long long)data_left_size);
129  int to_copy = to_read;
130  unsigned long tmpFileSize = to_read;
131  if (data_left_size == 0)
132  {
133  if (g_repeat > 1)
134  {
136  g_repeat--;
137  ni_log(NI_LOG_DEBUG, "input processed %d left\n", g_repeat);
138  lseek(fd, 0, SEEK_SET); //back to beginning
139  } else
140  {
141  return 0;
142  }
143  } else if (data_left_size < to_read)
144  {
145  tmpFileSize = data_left_size;
146  to_copy = data_left_size;
147  }
148 
149  int one_read_size = read(fd, tmp_dst, to_copy);
150  if (one_read_size == -1)
151  {
152  fprintf(stderr, "Error: reading file, quit! left-to-read %lu\n",
153  tmpFileSize);
154  fprintf(stderr, "Error: input file read error\n");
155  return -1;
156  }
157  data_left_size -= one_read_size;
158 
159  return to_copy;
160 }
161 
162 /*!****************************************************************************
163  * \brief Get file size
164  *
165  * \param [in] filename name of input file
166  * [out] bytes_read number of bytes in file
167  *
168  * \return 0 on success
169  * < 0 on error
170  ******************************************************************************/
171 int get_file_size(const char *filename, unsigned long *bytes_read)
172 {
173  struct stat info;
174 
175  /* Get information on the file */
176  if (stat(filename, &info) < 0)
177  {
178  fprintf(stderr, "Can't stat %s\n", filename);
179  return -1;
180  }
181 
182  /* Check the file size */
183  if (info.st_size <= 0)
184  {
185  fprintf(stderr, "File %s is empty\n", filename);
186  return -1;
187  }
188 
189  *bytes_read = info.st_size;
190 
191  return 0;
192 }
193 
194 /*!****************************************************************************
195 * \brief Recycle hw frame back to Quadra
196 *
197 * \param [in] p2p_frame - hw frame to recycle
198 *
199 * \return Returns NI_RETCODE_SUCCESS or error
200 *******************************************************************************/
201 int recycle_frame(ni_frame_t *p2p_frame)
202 {
203  ni_retcode_t rc;
204 
205  rc = ni_hwframe_p2p_buffer_recycle(p2p_frame);
206 
207  if (rc != NI_RETCODE_SUCCESS)
208  {
209  fprintf(stderr, "Recycle failed\n");
210  }
211 
212  return rc;
213 }
214 
215 /*!****************************************************************************
216  * \brief Import a dma buf to a Quadra device
217  *
218  * \param [in] p_session - upload session to the Quadra device
219  * [in] frame - frame of the proxy GPU card containing the dma buf fd
220  * [in] frame_size - frame size in bytes
221  * [out] dma_addrs - DMA addresses of the GPU frame
222  *
223  * \return Returns 0 on success, -1 otherwise
224  ******************************************************************************/
225 static int import_dma_buf(
226  ni_session_context_t *p_session,
227  ni_frame_t *frame,
228  unsigned long frame_size,
229  ni_p2p_sgl_t *dma_addr)
230 {
231  niFrameSurface1_t *frame_surface;
232  struct netint_iocmd_import_dmabuf uimp;
233  int ret,i;
234 
235  frame_surface = (niFrameSurface1_t *) frame->p_data[3];
236 
237  uimp.fd = frame_surface->dma_buf_fd;
238  uimp.flags = 0; // import
239  uimp.domain = p_session->domain;
240  uimp.bus = p_session->bus;
241  uimp.dev = p_session->dev;
242  uimp.fn = p_session->fn;
243 
244  // Pass frame size to kernel driver. Only used for dma-buf compiled in A1 mode
245  uimp.dma_len[0] = frame_size;
246 
247  ret = ioctl(p_session->netint_fd, NETINT_IOCTL_IMPORT_DMABUF, &uimp);
248 
249  if (ret == 0)
250  {
251  for (i = 0; i < uimp.nents; i++)
252  {
253  dma_addr->ui32DMALen[i] = uimp.dma_len[i];
254  dma_addr->ui64DMAAddr[i] = uimp.dma_addr[i];
255  }
256  dma_addr->ui32NumEntries = uimp.nents;
257  }
258 
259  return ret;
260 }
261 
262 /*!****************************************************************************
263  * \brief Unimport a dma buf to a Quadra device
264  *
265  * \param [in] p_session - upload session to the Quadra device
266  * [in] frame - frame of the GPU card containing the dma buf fd
267  *
268  * \return Returns 0 on success, -1 otherwise
269  ******************************************************************************/
270 static int unimport_dma_buf(
271  ni_session_context_t *p_session,
272  ni_frame_t *frame)
273 {
274  niFrameSurface1_t *frame_surface;
275  struct netint_iocmd_import_dmabuf uimp;
276  int ret;
277 
278  frame_surface = (niFrameSurface1_t *) frame->p_data[3];
279 
280  uimp.fd = frame_surface->dma_buf_fd;
281  uimp.flags = 1; // unimport
282  uimp.domain = p_session->domain;
283  uimp.bus = p_session->bus;
284  uimp.dev = p_session->dev,
285  uimp.fn = p_session->fn;
286 
287  ret = ioctl(p_session->netint_fd, NETINT_IOCTL_IMPORT_DMABUF, &uimp);
288 
289  return ret;
290 }
291 
292 /*!****************************************************************************
293  * \brief Reads video data from input file then calls a special libxcoder API
294  * function to transfer the video data into the hardware frame on
295  * the proxy GPU Quadra device.
296  *
297  * \param [in] p_ctx pointer to upload session context
298  * [in] fd file descriptor of input file
299  * [in] pp_data address of pointer to frame data
300  * [in] p_in_frame pointer to hardware frame
301  * [in] input_video_width video width
302  * [in] input_video_height video height
303  * [out] bytes_sent updated byte count of total data read
304  * [out] input_exhausted set to 1 when we reach end-of-file
305  *
306  * \return 0 on success
307  * -1 on error
308  ******************************************************************************/
310  ni_session_context_t *p_ctx,
311  int fd,
312  uint8_t **pp_data,
313  ni_frame_t *p_in_frame,
314  int input_video_width,
315  int input_video_height,
316  unsigned long *bytes_sent,
317  int *input_exhausted)
318 {
319  static uint8_t tmp_buf[MAX_FRAME_SIZE];
320  void *p_buffer;
321  uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS];
322  uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS];
323  int src_stride[NI_MAX_NUM_DATA_POINTERS];
324  int src_height[NI_MAX_NUM_DATA_POINTERS];
325  int dst_stride[NI_MAX_NUM_DATA_POINTERS] = {0, 0, 0, 0};
326  int dst_height[NI_MAX_NUM_DATA_POINTERS] = {0, 0, 0, 0};
327  int frame_size;
328  int chunk_size;
329  int alignedh;
330  int Ysize;
331  int Usize;
332  int Vsize;
333  int linewidth;
334  int row;
335  uint8_t *pSrc,*pDst;
336  int total_size;
337 
338  ni_log2(p_ctx, NI_LOG_DEBUG, "===> gpu render frame <===\n");
339 
340  if (g_rgb2yuv_csc)
341  {
342  /* An 8-bit RGBA frame is in a packed format */
343  /* and occupies width * height * 4 bytes */
344  frame_size = input_video_width * input_video_height * 4;
345  }
346  else
347  {
348  /* An 8-bit YUV420 planar frame occupies */
349  /* [(width x height x 3)/2] bytes */
350  frame_size = input_video_height * input_video_width * 3 / 2;
351  }
352 
353  chunk_size = read_next_chunk_from_file(fd, tmp_buf, frame_size);
354 
355  if (chunk_size == 0)
356  {
357  ni_log2(p_ctx, NI_LOG_DEBUG, "%s: read chunk size 0, eos!\n", __func__);
358  *input_exhausted = 1;
359  }
360 
361  p_in_frame->video_width = input_video_width;
362  p_in_frame->video_height = input_video_height;
363  p_in_frame->extra_data_len = 0;
364 
365  ni_get_frame_dim(input_video_width, input_video_height,
367  dst_stride, dst_height);
368 
369  ni_log2(p_ctx, NI_LOG_DEBUG, "p_dst alloc linesize = %d/%d/%d src height=%d "
370  "dst height aligned = %d/%d/%d \n",
371  dst_stride[0], dst_stride[1], dst_stride[2],
372  input_video_height, dst_height[0], dst_height[1],
373  dst_height[2]);
374 
375  if (g_rgb2yuv_csc)
376  {
377  linewidth = NI_VPU_ALIGN16(input_video_width) * 4;
378  total_size = linewidth * input_video_height;
379 
380  // Round to nearest 4K
381  total_size = NI_VPU_ALIGN4096(total_size);
382 
383  if (*pp_data == NULL)
384  {
385  if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), total_size))
386  {
387  fprintf(stderr, "Can't alloc memory\n");
388  return -1;
389  }
390 
391  *pp_data = p_buffer;
392  }
393 
394  pSrc = tmp_buf;
395  pDst = *pp_data;
396 
397  for (row = 0; row < input_video_height; row++)
398  {
399  memcpy(pDst, pSrc, linewidth);
400  pSrc += linewidth;
401  pDst += linewidth;
402  }
403  }
404  else
405  {
406  src_stride[0] = input_video_width * p_ctx->bit_depth_factor;
407  src_stride[1] = src_stride[2] = src_stride[0] / 2;
408 
409  src_height[0] = input_video_height;
410  src_height[1] = src_height[0] / 2;
411  src_height[2] = src_height[1];
412 
413  p_src[0] = tmp_buf;
414  p_src[1] = tmp_buf + src_stride[0] * src_height[0];
415  p_src[2] = p_src[1] + src_stride[1] * src_height[1];
416 
417  alignedh = (input_video_height + 1) & ~1;
418 
419  Ysize = dst_stride[0] * alignedh;
420  Usize = dst_stride[1] * alignedh / 2;
421  Vsize = dst_stride[2] * alignedh / 2;
422 
423  total_size = Ysize + Usize + Vsize;
424  total_size = NI_VPU_ALIGN4096(total_size);
425 
426  if (*pp_data == NULL)
427  {
428  if (ni_posix_memalign(&p_buffer, sysconf(_SC_PAGESIZE), total_size))
429  {
430  fprintf(stderr, "Can't alloc memory\n");
431  return -1;
432  }
433 
434  *pp_data = p_buffer;
435  }
436 
437  p_dst[0] = *pp_data;
438  p_dst[1] = *pp_data + Ysize;
439  p_dst[2] = *pp_data + Ysize + Usize;
440  p_dst[3] = NULL;
441 
442  ni_copy_hw_yuv420p(p_dst, p_src, input_video_width, input_video_height, 1,
443  0, 0, dst_stride, dst_height, src_stride, src_height);
444  }
445 
446  *bytes_sent = total_size;
447 
448  /* Write a frame of video data to our proxy GPU Quadra device */
449  ni_uploader_p2p_test_load(p_ctx, *pp_data, total_size, p_in_frame);
450 
451  return 0;
452 }
453 
454 
455 /*!****************************************************************************
456  * \brief Prepare frame on the proxy GPU Quadra device
457  *
458  * \param [in] p_gpu_ctx pointer to caller allocated gpu
459  * session context
460  * [in] input_video_width video width
461  * [in] input_video_height video height
462  * [out] gpu_frame gpu frame
463  *
464  * \return 0 on success
465  * -1 on error
466  ******************************************************************************/
467 int gpu_prepare_frame(ni_session_context_t *p_gpu_ctx, int input_video_width,
468  int input_video_height, ni_frame_t *gpu_frame)
469 {
470  int ret = 0;
471 
472  // Allocate memory for a hardware frame
473  gpu_frame->start_of_stream = 0;
474  gpu_frame->end_of_stream = 0;
475  gpu_frame->force_key_frame = 0;
476  gpu_frame->extra_data_len = 0;
477 
478  // Allocate a hardware ni_frame structure for the encoder
480  gpu_frame, input_video_width, input_video_height,
481  (int)gpu_frame->extra_data_len) != NI_RETCODE_SUCCESS)
482  {
483  fprintf(stderr, "Error: could not allocate hw frame buffer!");
484  ret = -1;
485  goto fail_out;
486  }
487 
488 #ifndef _WIN32
489  // Acquire a hw frame from the proxy GPU session. This obtains a handle
490  // to Quadra memory from the previously created frame pool.
491  if (ni_device_session_acquire(p_gpu_ctx, gpu_frame))
492  {
493  fprintf(stderr, "Error: failed ni_device_session_acquire()\n");
494  ret = -1;
495  goto fail_out;
496  }
497 #endif
498 
499  return ret;
500 
501 fail_out:
502  ni_frame_buffer_free(gpu_frame);
503  return ret;
504 }
505 
506 /*!****************************************************************************
507  * \brief Prepare frame on the encoding Quadra device
508  *
509  * \param [in] p_upl_ctx pointer to caller allocated upload
510  * session context
511  * [in] input_video_width video width
512  * [in] input_video_height video height
513  * [out] p2p_frame p2p frame
514  *
515  * \return 0 on success
516  * -1 on error
517  ******************************************************************************/
518 int enc_prepare_frame(ni_session_context_t *p_upl_ctx, int input_video_width,
519  int input_video_height, ni_frame_t *p2p_frame)
520 {
521  int ret = 0;
522 
523  p2p_frame->start_of_stream = 0;
524  p2p_frame->end_of_stream = 0;
525  p2p_frame->force_key_frame = 0;
526  p2p_frame->extra_data_len = 0;
527 
528  // Allocate a hardware ni_frame structure for the encoder
530  p2p_frame, input_video_width, input_video_height,
531  (int)p2p_frame->extra_data_len) != NI_RETCODE_SUCCESS)
532  {
533  fprintf(stderr, "Error: could not allocate hw frame buffer!\n");
534  ret = -1;
535  goto fail_out;
536  }
537 
538 #ifndef _WIN32
539  if (ni_device_session_acquire_for_read(p_upl_ctx, p2p_frame))
540  {
541  fprintf(stderr, "Error: failed ni_device_session_acquire()\n");
542  ret = -1;
543  goto fail_out;
544  }
545 #endif
546 
547  return ret;
548 
549 fail_out:
550 
551  ni_frame_buffer_free(p2p_frame);
552  return ret;
553 }
554 
555 /*!****************************************************************************
556  * \brief Send the Quadra encoder a hardware frame which triggers
557  * Quadra to encode the frame
558  *
559  * \param [in] p_enc_ctx pointer to encoder context
560  * [in] p_in_frame pointer to hw frame
561  * [in] input_exhausted flag indicating this is the last frame
562  * [in/out] need_to_resend flag indicating need to re-send
563  *
564  * \return 0 on success
565  * -1 on failure
566  ******************************************************************************/
568  ni_frame_t *p_in_frame, int input_exhausted,
569  int *need_to_resend)
570 {
571  static int started = 0;
572  int oneSent;
573  ni_session_data_io_t in_data;
574 
575  ni_log2(p_enc_ctx, NI_LOG_DEBUG, "===> encoder_encode_frame <===\n");
576 
577  if (enc_eos_sent == 1)
578  {
579  ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encoder_encode_frame: ALL data (incl. eos) sent "
580  "already!\n");
581  return 0;
582  }
583 
584  if (*need_to_resend)
585  {
586  goto send_frame;
587  }
588 
589  p_in_frame->start_of_stream = 0;
590 
591  // If this is the first frame, mark the frame as start-of-stream
592  if (!started)
593  {
594  started = 1;
595  p_in_frame->start_of_stream = 1;
596  }
597 
598  // If this is the last frame, mark the frame as end-of-stream
599  p_in_frame->end_of_stream = input_exhausted ? 1 : 0;
600  p_in_frame->force_key_frame = 0;
601 
602 send_frame:
603 
604  in_data.data.frame = *p_in_frame;
605  oneSent =
606  ni_device_session_write(p_enc_ctx, &in_data, NI_DEVICE_TYPE_ENCODER);
607 
608  if (oneSent < 0)
609  {
610  fprintf(stderr,
611  "Error: failed ni_device_session_write() for encoder\n");
612  *need_to_resend = 1;
613  return -1;
614  } else if (oneSent == 0 && !p_enc_ctx->ready_to_close)
615  {
616  *need_to_resend = 1;
617  ni_log2(p_enc_ctx, NI_LOG_DEBUG, "NEEDED TO RESEND");
618  } else
619  {
620  *need_to_resend = 0;
621 
622  ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encoder_encode_frame: total sent data size=%u\n",
623  p_in_frame->data_len[3]);
624 
625  ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encoder_encode_frame: success\n");
626 
627  if (p_enc_ctx->ready_to_close)
628  {
629  enc_eos_sent = 1;
630  }
631  }
632 
633  return 0;
634 }
635 
636 /*!****************************************************************************
637  * \brief Receive output packet data from the Quadra encoder
638  *
639  * \param [in] p_enc_ctx pointer to encoder session context
640  * [in] p_out_data pointer to output data session
641  * [in] p_file pointer to file to write the packet
642  * [out] total_bytes_received running counter of bytes read
643  * [in] print_time 1 = print the time
644  *
645  * \return 0 - success got packet
646  * 1 - received eos
647  * 2 - got nothing, need retry
648  * -1 - failure
649  ******************************************************************************/
651  ni_session_data_io_t *p_out_data, FILE *p_file,
652  unsigned long long *total_bytes_received,
653  int print_time)
654 {
655  int packet_size = NI_MAX_TX_SZ;
656  int rc = 0;
657  int end_flag = 0;
658  int rx_size = 0;
659  int meta_size = p_enc_ctx->meta_size;
660  ni_packet_t *p_out_pkt = &(p_out_data->data.packet);
661  static int received_stream_header = 0;
662 
663  ni_log2(p_enc_ctx, NI_LOG_DEBUG, "===> encoder_receive_data <===\n");
664 
665  if (NI_INVALID_SESSION_ID == p_enc_ctx->session_id ||
666  NI_INVALID_DEVICE_HANDLE == p_enc_ctx->blk_io_handle)
667  {
668  ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encode session not opened yet, return\n");
669  return 0;
670  }
671 
672  if (p_file == NULL)
673  {
674  ni_log2(p_enc_ctx, NI_LOG_ERROR, "Bad file pointer, return\n");
675  return -1;
676  }
677 
678  rc = ni_packet_buffer_alloc(p_out_pkt, packet_size);
679  if (rc != NI_RETCODE_SUCCESS)
680  {
681  fprintf(stderr, "Error: malloc packet failed, ret = %d!\n", rc);
682  return -1;
683  }
684 
685  /*
686  * The first data read from the encoder session context
687  * is a stream header read.
688  */
689  if (!received_stream_header)
690  {
691  /* Read the encoded stream header */
692  rc = ni_encoder_session_read_stream_header(p_enc_ctx, p_out_data);
693 
694  if (rc > 0)
695  {
696  /* Write out the stream header */
697  if (fwrite((uint8_t *)p_out_pkt->p_data + meta_size,
698  p_out_pkt->data_len - meta_size, 1, p_file) != 1)
699  {
700  fprintf(stderr, "Error: writing data %u bytes error!\n",
701  p_out_pkt->data_len - meta_size);
702  fprintf(stderr, "Error: ferror rc = %d\n", ferror(p_file));
703  }
704 
705  *total_bytes_received += (rx_size - meta_size);
707  received_stream_header = 1;
708  } else if (rc != 0)
709  {
710  fprintf(stderr, "Error: reading header %d\n", rc);
711  return -1;
712  }
713 
714  if (print_time)
715  {
716  int timeDiff = (int)(current_time.tv_sec - start_time.tv_sec);
717  if (timeDiff == 0)
718  {
719  timeDiff = 1;
720  }
721  printf("[R] Got:%d Packets= %u fps=%u Total bytes %llu\n",
722  rx_size, number_of_packets, number_of_packets / timeDiff,
723  *total_bytes_received);
724  }
725 
726  /* This shouldn't happen */
727  if (p_out_pkt->end_of_stream)
728  {
729  return 1;
730  } else if (rc == 0)
731  {
732  return 2;
733  }
734  }
735 
736 receive_data:
737  rc = ni_device_session_read(p_enc_ctx, p_out_data, NI_DEVICE_TYPE_ENCODER);
738 
739  end_flag = p_out_pkt->end_of_stream;
740  rx_size = rc;
741 
742  ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encoder_receive_data: received data size=%d\n", rx_size);
743 
744  if (rx_size > meta_size)
745  {
746  if (fwrite((uint8_t *)p_out_pkt->p_data + meta_size,
747  p_out_pkt->data_len - meta_size, 1, p_file) != 1)
748  {
749  fprintf(stderr, "Error: writing data %u bytes error!\n",
750  p_out_pkt->data_len - meta_size);
751  fprintf(stderr, "Error: ferror rc = %d\n", ferror(p_file));
752  }
753 
754  *total_bytes_received += rx_size - meta_size;
756 
757  ni_log2(p_enc_ctx, NI_LOG_DEBUG, "Got: Packets= %u\n", number_of_packets);
758  } else if (rx_size != 0)
759  {
760  fprintf(stderr, "Error: received %d bytes, <= metadata size %d!\n",
761  rx_size, meta_size);
762  return -1;
763  } else if (!end_flag &&
764  (((ni_xcoder_params_t *)(p_enc_ctx->p_session_config))
765  ->low_delay_mode))
766  {
767  ni_log2(p_enc_ctx, NI_LOG_DEBUG, "low delay mode and NO pkt, keep reading...\n");
768  goto receive_data;
769  }
770 
771  if (print_time)
772  {
773  int timeDiff = (int)(current_time.tv_sec - start_time.tv_sec);
774  if (timeDiff == 0)
775  {
776  timeDiff = 1;
777  }
778  printf("[R] Got:%d Packets= %u fps=%u Total bytes %llu\n", rx_size,
780  *total_bytes_received);
781  }
782 
783  if (end_flag)
784  {
785  printf("Encoder Receiving done\n");
786  return 1;
787  } else if (0 == rx_size)
788  {
789  return 2;
790  }
791 
792  ni_log2(p_enc_ctx, NI_LOG_DEBUG, "encoder_receive_data: success\n");
793 
794  return 0;
795 }
796 
797 /*!****************************************************************************
798  * \brief Open an encoder session to Quadra
799  *
800  * \param [out] p_enc_ctx pointer to an encoder session context
801  * [in] dst_codec_format AVC or HEVC
802  * [in] iXcoderGUID id to identify the Quadra device
803  * [in] p_enc_params sets the encoder parameters
804  * [in] width width of frames to encode
805  * [in] height height of frames to encode
806  *
807  * \return 0 if successful, < 0 otherwise
808  ******************************************************************************/
809 int encoder_open_session(ni_session_context_t *p_enc_ctx, int dst_codec_format,
810  int iXcoderGUID, ni_xcoder_params_t *p_enc_params,
811  int width, int height, ni_frame_t *p_frame)
812 {
813  int ret = 0;
814 
815  // Enable hardware frame encoding
816  p_enc_ctx->hw_action = NI_CODEC_HW_ENABLE;
817  p_enc_params->hwframes = 1;
818 
819  // Provide the first frame to the Quadra encoder
820  p_enc_params->p_first_frame = p_frame;
821 
822  // Specify codec, AVC vs HEVC
823  p_enc_ctx->codec_format = dst_codec_format;
824 
825  p_enc_ctx->p_session_config = p_enc_params;
826  p_enc_ctx->session_id = NI_INVALID_SESSION_ID;
827 
828  // Assign the card GUID in the encoder context to open a session
829  // to that specific Quadra device
830  p_enc_ctx->device_handle = NI_INVALID_DEVICE_HANDLE;
831  p_enc_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE;
832  p_enc_ctx->hw_id = iXcoderGUID;
833 
834  if (g_rgb2yuv_csc)
835  p_enc_ctx->pixel_format = NI_PIX_FMT_ABGR;
836 
837  ni_encoder_set_input_frame_format(p_enc_ctx, p_enc_params, width, height, 8,
839 
840  // Encoder will operate in P2P mode
842  if (ret != NI_RETCODE_SUCCESS)
843  {
844  fprintf(stderr, "Error: encoder open session failure\n");
845  } else
846  {
847  printf("Encoder device %d session open successful\n", iXcoderGUID);
848  }
849 
850  return ret;
851 }
852 
853 /*!****************************************************************************
854  * \brief Open an upload session to Quadra
855  *
856  * \param [out] p_upl_ctx pointer to an upload context of the open session
857  * [in] iXcoderGUID pointer to Quadra card hw id
858  * [in] width width of the frames
859  * [in] height height of the frames
860  * [in] poolsize pool size to create on session
861  * [in] p2p p2p session
862  *
863  * \return 0 if successful, < 0 otherwise
864  ******************************************************************************/
865 int uploader_open_session(ni_session_context_t *p_upl_ctx, int *iXcoderGUID,
866  int width, int height, int poolsize, int p2p)
867 {
868  int ret = 0;
869  ni_pix_fmt_t frame_format;
870 
871  p_upl_ctx->session_id = NI_INVALID_SESSION_ID;
872 
873  // Assign the card GUID in the encoder context
874  p_upl_ctx->device_handle = NI_INVALID_DEVICE_HANDLE;
875  p_upl_ctx->blk_io_handle = NI_INVALID_DEVICE_HANDLE;
876 
877  // Assign the card id to specify the specific Quadra device
878  p_upl_ctx->hw_id = *iXcoderGUID;
879 
880  // Assign the pixel format we want to use
882 
883  // Set the input frame format of the upload session
884  ni_uploader_set_frame_format(p_upl_ctx, width, height, frame_format, 1);
885 
887  if (ret != NI_RETCODE_SUCCESS)
888  {
889  fprintf(stderr, "Error: uploader_open_session failure!\n");
890  return ret;
891  }
892  else
893  {
894  printf("Uploader device %d session opened successfully\n",
895  *iXcoderGUID);
896  *iXcoderGUID = p_upl_ctx->hw_id;
897  }
898 
899  // Create a P2P frame pool for the uploader sesson of pool size 1
900  ret = ni_device_session_init_framepool(p_upl_ctx, poolsize, p2p);
901  if (ret < 0)
902  {
903  fprintf(stderr, "Error: Can't create frame pool\n");
905  } else
906  {
907  printf("Uploader device %d configured successfully\n", *iXcoderGUID);
908  }
909 
910  return ret;
911 }
912 
913 /*!****************************************************************************
914  * \brief Print usage information
915  *
916  * \param none
917  *
918  * \return none
919  ******************************************************************************/
920 void print_usage(void)
921 {
922  printf("Video encoder/P2P application directly using Netint "
923  "Libxcoder release v%s\n"
924  "Usage: xcoderp2p_read [options]\n"
925  "\n"
926  "options:\n"
927  "--------------------------------------------------------------------------------\n"
928  " -h | --help Show help.\n"
929  " -v | --version Print version info.\n"
930  " -l | --loglevel Set loglevel of libxcoder API.\n"
931  " [none, fatal, error, info, debug, trace]\n"
932  " Default: info\n"
933  " -c | --card Set card index to use.\n"
934  " See `ni_rsrc_mon` for cards on system.\n"
935  " (Default: 0)\n"
936  " -g | --gpucard Set gpu card index to use.\n"
937  " See `ni_rsrc_mon` for cards on system.\n"
938  " -i | --input Input file path.\n"
939  " -r | --repeat (Positive integer) to Repeat input X times "
940  "for performance \n"
941  " test. (Default: 1)\n"
942  " -s | --size Resolution of input file in format "
943  "WIDTHxHEIGHT.\n"
944  " (eg. '1920x1080')\n"
945  " -m | --mode Input to output codec processing mode in "
946  "format:\n"
947  " INTYPE2OUTTYPE. [p2a, p2h, r2a, r2h]\n"
948  " Type notation: p=P2P, a=AVC, h=HEVC, r=ABGR\n"
949  " -o | --output Output file path.\n"
950  " -w | --swapchain Set size of swapchain.\n"
951  " (Default: 1) Valid values are 1, 2, or 3.\n",
953 }
954 
955 /*!****************************************************************************
956  * \brief Parse user command line arguments
957  *
958  * \param [in] argc argument count
959  * [in] argv argument vector
960  * [out] input_filename input filename
961  * [out] output_filename output filename
962  * [out] iXcoderGUID Quadra device
963  * [out] iGpuGUID Quadra device (GPU proxy device)
964  * [out] arg_width resolution width
965  * [out] arg_height resolution height
966  * [out] dst_codec_format codec (AVC vs HEVC)
967  *
968  * \return nothing program exit on error
969  ******************************************************************************/
970 void parse_arguments(int argc, char *argv[], char *input_filename,
971  char *output_filename, int *iXcoderGUID, int *iGpuGUID,
972  int *arg_width, int *arg_height, int *dst_codec_format)
973 {
974  char xcoderGUID[32];
975  char gpuGUID[32];
976  char mode_description[128];
977  char *n; // used for parsing width and height from --size
978  size_t i;
979  int opt;
980  int opt_index;
981  ni_log_level_t log_level;
982 
983  static const char *opt_string = "hvl:c:g:i:s:m:o:r:w:";
984  static const struct option long_options[] = {
985  {"help", no_argument, NULL, 'h'},
986  {"version", no_argument, NULL, 'v'},
987  {"loglevel", no_argument, NULL, 'l'},
988  {"card", required_argument, NULL, 'c'},
989  {"gpucard", required_argument, NULL, 'g'},
990  {"input", required_argument, NULL, 'i'},
991  {"size", required_argument, NULL, 's'},
992  {"mode", required_argument, NULL, 'm'},
993  {"output", required_argument, NULL, 'o'},
994  {"repeat", required_argument, NULL, 'r'},
995  {"swapchain", required_argument, NULL, 'w'},
996  {NULL, 0, NULL, 0},
997  };
998 
999  while ((opt = getopt_long(argc, argv, opt_string, long_options,
1000  &opt_index)) != -1)
1001  {
1002  switch (opt)
1003  {
1004  case 'h':
1005  print_usage();
1006  exit(0);
1007  case 'v':
1008  printf("Release ver: %s\n"
1009  "API ver: %s\n"
1010  "Date: %s\n"
1011  "ID: %s\n",
1014  exit(0);
1015  case 'l':
1016  log_level = arg_to_ni_log_level(optarg);
1017  if (log_level != NI_LOG_INVALID)
1018  {
1019  ni_log_set_level(log_level);
1020  } else {
1021  arg_error_exit("-l | --loglevel", optarg);
1022  }
1023  break;
1024  case 'c':
1025  strcpy(xcoderGUID, optarg);
1026  *iXcoderGUID = (int)strtol(optarg, &n, 10);
1027  // No numeric characters found in left side of optarg
1028  if (n == xcoderGUID)
1029  arg_error_exit("-c | --card", optarg);
1030  break;
1031  case 'g':
1032  strcpy(gpuGUID, optarg);
1033  *iGpuGUID = (int)strtol(optarg, &n, 10);
1034  if (n == gpuGUID)
1035  arg_error_exit("-g | --gpu_card", optarg);
1036  break;
1037  case 'i':
1038  strcpy(input_filename, optarg);
1039  break;
1040  case 's':
1041  *arg_width = (int)strtol(optarg, &n, 10);
1042  *arg_height = atoi(n + 1);
1043  if ((*n != 'x') || (!*arg_width || !*arg_height))
1044  arg_error_exit("-s | --size", optarg);
1045  break;
1046  case 'm':
1047  if (!(strlen(optarg) == 3))
1048  arg_error_exit("-m | --mode", optarg);
1049 
1050  // convert to lower case for processing
1051  for (i = 0; i < strlen(optarg); i++)
1052  optarg[i] = (char)tolower((unsigned char)optarg[i]);
1053 
1054  if (strcmp(optarg, "p2a") != 0 && strcmp(optarg, "p2h") != 0 &&
1055  strcmp(optarg, "r2a") != 0 && strcmp(optarg, "r2h") != 0)
1056  arg_error_exit("-, | --mode", optarg);
1057 
1058  // determine codec
1059  sprintf(mode_description, "P2P + Encoding");
1060 
1061  g_rgb2yuv_csc = (optarg[0] == 'r') ? 1 : 0;
1062 
1063  if (optarg[2] == 'a')
1064  {
1065  *dst_codec_format = NI_CODEC_FORMAT_H264;
1066  strcat(mode_description, " to AVC");
1067  }
1068 
1069  if (optarg[2] == 'h')
1070  {
1071  *dst_codec_format = NI_CODEC_FORMAT_H265;
1072  strcat(mode_description, " to HEVC");
1073  }
1074  printf("%s...\n", mode_description);
1075 
1076  break;
1077  case 'o':
1078  strcpy(output_filename, optarg);
1079  break;
1080  case 'r':
1081  if (!(atoi(optarg) >= 1))
1082  arg_error_exit("-r | --repeat", optarg);
1083  g_repeat = atoi(optarg);
1084  break;
1085  case 'w':
1086  if (!(atoi(optarg) >= 1))
1087  arg_error_exit("-w | --swapchain", optarg);
1089  break;
1090  default:
1091  print_usage();
1092  exit(1);
1093  }
1094  }
1095 
1096  // Check required args are present
1097  if (!input_filename[0])
1098  {
1099  printf("Error: missing argument for -i | --input\n");
1100  exit(-1);
1101  }
1102 
1103  if (!output_filename[0])
1104  {
1105  printf("Error: missing argument for -o | --output\n");
1106  exit(-1);
1107  }
1108 
1109  // Check that the GPU card and Xcoder card numbers are different.
1110  // Loopback to the same card not supported.
1111  if (*iXcoderGUID == *iGpuGUID)
1112  {
1113  printf("Error: card and gpucard arguments cannot be the same\n");
1114  exit(-1);
1115  }
1116 
1118  {
1119  printf("Error: swapchain cannot be more than %d\n", MAX_SWAP_SIZE);
1120  exit(-1);
1121  }
1122 }
1123 
1124 int main(int argc, char *argv[])
1125 {
1126  static char input_filename[FILE_NAME_LEN];
1127  static char output_filename[FILE_NAME_LEN];
1128  unsigned long frame_size;
1129  unsigned long long total_bytes_received;
1130  int input_video_width;
1131  int input_video_height;
1132  int iXcoderGUID = 0;
1133  int iGpuGUID = 0;
1134  int arg_width = 0;
1135  int arg_height = 0;
1136  int input_exhausted = 0;
1137  int dst_codec_format = 0;
1138  int ret=0;
1139  int timeDiff;
1140  int print_time;
1141  int need_to_resend = 0;
1142  FILE *p_file = NULL;
1143  ni_xcoder_params_t api_param;
1144  ni_session_context_t enc_ctx = {0};
1145  ni_session_context_t upl_ctx = {0};
1146  ni_session_context_t gpu_ctx = {0};
1147  ni_frame_t p2p_frame = {0};
1148  swapchain_t swapchain = {0};
1149  ni_session_data_io_t out_packet = {0};
1150  int input_file_fd = -1;
1151  ni_p2p_sgl_t dma_addrs[MAX_SWAP_SIZE] = {0};
1152  int swap_index = 0;
1153 
1154  parse_arguments(argc, argv, input_filename, output_filename, &iXcoderGUID,
1155  &iGpuGUID, &arg_width, &arg_height, &dst_codec_format);
1156 
1157  // Get size of input file
1158  if (get_file_size(input_filename, &total_file_size) < 0)
1159  {
1160  exit(-1);
1161  }
1162 
1164 
1165  // Create output file
1166  if (strcmp(output_filename, "null") != 0)
1167  {
1168  p_file = fopen(output_filename, "wb");
1169  if (p_file == NULL)
1170  {
1171  fprintf(stderr, "Error: cannot open %s\n", output_filename);
1172  goto end;
1173  }
1174  }
1175 
1176  printf("SUCCESS: Opened output file: %s\n", output_filename);
1177 
1178  if (ni_device_session_context_init(&enc_ctx) < 0)
1179  {
1180  fprintf(stderr, "Error: init encoder context error\n");
1181  return -1;
1182  }
1183 
1184  if (ni_device_session_context_init(&upl_ctx) < 0)
1185  {
1186  fprintf(stderr, "Error: init uploader context error\n");
1187  return -1;
1188  }
1189 
1190  if (ni_device_session_context_init(&gpu_ctx) < 0)
1191  {
1192  fprintf(stderr, "Error: init gpu uploader context error\n");
1193  return -1;
1194  }
1195 
1196  total_bytes_received = 0;
1197  frame_size = 0;
1198 
1199  send_fin_flag = 0;
1200  receive_fin_flag = 0;
1201 
1202  printf("User video resolution: %dx%d\n", arg_width, arg_height);
1203 
1204  if (arg_width == 0 || arg_height == 0)
1205  {
1206  input_video_width = 1280;
1207  input_video_height = 720;
1208  }
1209  else
1210  {
1211  input_video_width = arg_width;
1212  input_video_height = arg_height;
1213  }
1214 
1215  ni_gettimeofday(&start_time, NULL);
1217  ni_gettimeofday(&current_time, NULL);
1219 
1220  printf("P2P Encoding resolution: %dx%d\n", input_video_width,
1221  input_video_height);
1222 
1223  // Open a P2P upload session to the destination Quadra device that will
1224  // be doing the video encoding
1225  if (uploader_open_session(&upl_ctx, &iXcoderGUID, arg_width, arg_height,
1226  1, 0))
1227  {
1228  goto end;
1229  }
1230 
1231  // Open a P2P upload session for the source Quadra device. The source
1232  // Quadra device acts as a proxy for the GPU card.
1233  if (uploader_open_session(&gpu_ctx, &iGpuGUID, arg_width, arg_height,
1234  g_swapchain_size, 1))
1235  {
1236  goto end;
1237  }
1238 
1239  // Prepare up to three frames on the proxy GPU Quadra device
1240  for (int i = 0; i < g_swapchain_size; i++)
1241  {
1242  if (gpu_prepare_frame(&gpu_ctx, input_video_width, input_video_height,
1243  &swapchain.gpu_frame[i]))
1244  {
1245  goto end;
1246  }
1247  }
1248 
1249 #ifdef _WIN32
1250  input_file_fd = open(input_filename, O_RDONLY | O_BINARY);
1251 #else
1252  input_file_fd = open(input_filename, O_RDONLY);
1253 #endif
1254 
1255  if (input_file_fd < 0)
1256  {
1257  fprintf(stderr, "Error: cannot open input file %s\n", input_filename);
1258  goto end;
1259  }
1260 
1261  // Render a frame on the proxy GPU Quadra device
1262  if (gpu_render_frame(&gpu_ctx, input_file_fd, &g_raw_frame,
1263  &swapchain.gpu_frame[0], input_video_width,
1264  input_video_height, &frame_size, &input_exhausted))
1265  {
1266  fprintf(stderr, "Cannot render frame on source Quadra device\n");
1267  goto end;
1268  }
1269 
1270  for (int i = 0; i < g_swapchain_size; i++)
1271  {
1272  ret = import_dma_buf(&upl_ctx, &swapchain.gpu_frame[i], frame_size,
1273  &dma_addrs[i]);
1274 
1275  if (ret < 0)
1276  {
1277  fprintf(stderr, "Cannot import dma buffer %d\n",ret);
1278  goto end;
1279  }
1280  }
1281 
1282  ret = enc_prepare_frame(&upl_ctx, input_video_width, input_video_height,
1283  &p2p_frame);
1284 
1285  if (ret < 0)
1286  {
1287  goto end;
1288  }
1289 
1290  // Configure the encoder parameter structure. We'll use some basic
1291  // defaults: 30 fps, 200000 bps CBR encoding, AVC or HEVC encoding
1292  if (ni_encoder_init_default_params(&api_param, 30, 1, 200000, arg_width,
1293  arg_height, enc_ctx.codec_format) < 0)
1294  {
1295  fprintf(stderr, "Error: encoder init default set up error\n");
1296  goto end;
1297  }
1298 
1299  // For P2P demo, change some of the encoding parameters from
1300  // the default. Enable low delay encoding.
1301  if ((ret = ni_encoder_params_set_value(&api_param, "lowDelay", "1")) !=
1303  {
1304  fprintf(stderr, "Error: can't set low delay mode %d\n", ret);
1305  goto end;
1306  }
1307 
1308  // Use a GOP preset of 9 which represents a GOP pattern of
1309  // IPPPPPPP....This will be low latency encoding.
1310  if ((ret = ni_encoder_params_set_value(&api_param, "gopPresetIdx", "9")) !=
1312  {
1313  fprintf(stderr, "Error: can't set gop preset %d\n", ret);
1314  goto end;
1315  }
1316 
1317  if (g_rgb2yuv_csc)
1318  {
1319  // Quadra encoder always generates full range YCbCr
1320  if (ni_encoder_params_set_value(&api_param, "videoFullRangeFlag", "1") !=
1322  {
1323  fprintf(stderr, "Error: can't set video full range\n");
1324  goto end;
1325  }
1326 
1327  // sRGB has the same color primaries as BT.709/IEC-61966-2-1
1328  if (ni_encoder_params_set_value(&api_param, "colorPri", "1") !=
1330  {
1331  fprintf(stderr, "Error: can't set color primaries\n");
1332  goto end;
1333  }
1334 
1335  // Quadra encoder converts to YUV420 using BT.709 matrix
1336  if (ni_encoder_params_set_value(&api_param, "colorSpc", "1") !=
1338  {
1339  fprintf(stderr, "Error: can't set color space\n");
1340  goto end;
1341  }
1342 
1343  // sRGB transfer characteristics is IEC-61966-2-1
1344  if (ni_encoder_params_set_value(&api_param, "colorTrc", "13") !=
1346  {
1347  fprintf(stderr, "Error: can't set color transfer characteristics\n");
1348  goto end;
1349  }
1350  }
1351 
1352  // Open the encoder session with given parameters
1353  ret = encoder_open_session(&enc_ctx, dst_codec_format, iXcoderGUID,
1354  &api_param, arg_width, arg_height, &p2p_frame);
1355 
1356  if (ret < 0)
1357  {
1358  fprintf(stderr, "Could not open encoder session\n");
1359  goto end;
1360  }
1361 
1362  while (send_fin_flag == 0 || receive_fin_flag == 0)
1363  {
1364  ni_gettimeofday(&current_time, NULL);
1365 
1366  // Print the time if >= 1 second has passed
1367  print_time = ((current_time.tv_sec - previous_time.tv_sec) > 1);
1368 
1369  // Execute a P2P read into the frame
1370  if (ni_p2p_recv(&upl_ctx, &dma_addrs[swap_index], &p2p_frame) != NI_RETCODE_SUCCESS)
1371  {
1372  fprintf(stderr, "Error: can't read frame\n");
1373  break;
1374  }
1375 
1376  // Encode the frame
1377  send_fin_flag = encoder_encode_frame(&enc_ctx, &p2p_frame,
1378  input_exhausted, &need_to_resend);
1379 
1380  // Error, exit
1381  if (send_fin_flag == 2)
1382  {
1383  break;
1384  }
1385 
1386  // Fill the frame buffer with YUV data while the previous frame is being encoded
1387  if (!input_exhausted && need_to_resend == 0)
1388  {
1389  swap_index = (swap_index + 1) % g_swapchain_size;
1390 
1391  gpu_render_frame(&gpu_ctx, input_file_fd, &g_raw_frame,
1392  &swapchain.gpu_frame[swap_index],
1393  input_video_width, input_video_height,
1394  &frame_size, &input_exhausted);
1395  }
1396 
1397  // Receive encoded packet data from the encoder
1399  &enc_ctx, &out_packet, p_file, &total_bytes_received, print_time);
1400 
1401  if (print_time)
1402  {
1404  }
1405 
1406  // Error or eos
1407  if (receive_fin_flag < 0 || out_packet.data.packet.end_of_stream)
1408  {
1409  break;
1410  }
1411  }
1412 
1413  timeDiff = (int)(current_time.tv_sec - start_time.tv_sec);
1414  timeDiff = (timeDiff > 0) ? timeDiff : 1; // avoid division by zero
1415 
1416  printf("[R] Got: Packets= %u fps=%u Total bytes %llu\n",
1418  total_bytes_received);
1419 
1420 
1421  recycle_frame(&p2p_frame);
1422 
1423  // Clean up and recycle the hardware frames
1424  for (int i = 0; i < g_swapchain_size; i++)
1425  {
1426  unimport_dma_buf(&upl_ctx, &swapchain.gpu_frame[swap_index]);
1427  recycle_frame(&swapchain.gpu_frame[i]);
1428  }
1429 
1433 
1437 
1438  ni_frame_buffer_free(&p2p_frame);
1439 
1440  for (int i = 0; i < g_swapchain_size; i++)
1441  ni_frame_buffer_free(&swapchain.gpu_frame[i]);
1442 
1443  ni_packet_buffer_free(&(out_packet.data.packet));
1444 
1445 end:
1446  if (upl_ctx.session_id != NI_INVALID_SESSION_ID)
1448 
1449  if (gpu_ctx.session_id != NI_INVALID_SESSION_ID)
1451 
1452  if (enc_ctx.session_id != NI_INVALID_SESSION_ID)
1454 
1455  ni_device_close(upl_ctx.blk_io_handle);
1456  ni_device_close(gpu_ctx.blk_io_handle);
1457  ni_device_close(enc_ctx.blk_io_handle);
1458 
1459  if (g_raw_frame != NULL)
1460  {
1461  free(g_raw_frame);
1462  }
1463 
1464  close(input_file_fd);
1465 
1466  if (p_file)
1467  {
1468  fclose(p_file);
1469  }
1470 
1471  printf("All done\n");
1472 
1473  return 0;
1474 }
g_rgb2yuv_csc
uint8_t g_rgb2yuv_csc
Definition: ni_p2p_read_test.c:91
MAX_FRAME_SIZE
#define MAX_FRAME_SIZE
Definition: ni_p2p_read_test.c:61
encoder_open_session
int encoder_open_session(ni_session_context_t *p_enc_ctx, int dst_codec_format, int iXcoderGUID, ni_xcoder_params_t *p_enc_params, int width, int height, ni_frame_t *p_frame)
Open an encoder session to Quadra.
Definition: ni_p2p_read_test.c:809
ni_encoder_session_read_stream_header
int ni_encoder_session_read_stream_header(ni_session_context_t *p_ctx, ni_session_data_io_t *p_data)
Read encoder stream header from the device.
Definition: ni_device_api.c:11232
FILE_NAME_LEN
#define FILE_NAME_LEN
Definition: ni_p2p_read_test.c:66
NI_MAX_TX_SZ
#define NI_MAX_TX_SZ
Definition: ni_defs.h:249
ni_log_level_t
ni_log_level_t
Definition: ni_log.h:55
current_timestamp
time_t current_timestamp
Definition: ni_p2p_read_test.c:84
ni_encoder_params_set_value
ni_retcode_t ni_encoder_params_set_value(ni_xcoder_params_t *p_params, const char *name, const char *value)
Set value referenced by name in encoder parameters structure.
Definition: ni_device_api.c:5635
NI_DEVICE_TYPE_ENCODER
@ NI_DEVICE_TYPE_ENCODER
Definition: ni_defs.h:347
g_swapchain_size
int g_swapchain_size
Definition: ni_p2p_read_test.c:93
_ni_p2p_sgl_t
Definition: ni_defs.h:403
start_timestamp
time_t start_timestamp
Definition: ni_p2p_read_test.c:82
ni_pix_fmt_t
ni_pix_fmt_t
Definition: ni_device_api.h:260
ni_frame_buffer_free
ni_retcode_t ni_frame_buffer_free(ni_frame_t *p_frame)
Free frame buffer that was previously allocated with either ni_frame_buffer_alloc or ni_encoder_frame...
Definition: ni_device_api.c:3561
recycle_frame
int recycle_frame(ni_frame_t *p2p_frame)
Recycle hw frame back to Quadra.
Definition: ni_p2p_read_test.c:201
g_repeat
int g_repeat
Definition: ni_p2p_read_test.c:76
ni_device_close
void ni_device_close(ni_device_handle_t device_handle)
Close device and release resources.
Definition: ni_device_api.c:503
_ni_session_context::fn
unsigned short fn
Definition: ni_device_api.h:1622
_ni_session_context::session_id
uint32_t session_id
Definition: ni_device_api.h:1480
netint_iocmd_import_dmabuf::dma_addr
unsigned long dma_addr[NI_DMABUF_MAX_SGL_ENTRY]
Definition: ni_p2p_ioctl.h:68
_ni_session_context::netint_fd
int netint_fd
Definition: ni_device_api.h:1618
gpu_prepare_frame
int gpu_prepare_frame(ni_session_context_t *p_gpu_ctx, int input_video_width, int input_video_height, ni_frame_t *gpu_frame)
Prepare frame on the proxy GPU Quadra device.
Definition: ni_p2p_read_test.c:467
NI_SW_RELEASE_ID
#define NI_SW_RELEASE_ID
Definition: ni_release_info.h:29
NI_PIX_FMT_YUV420P
@ NI_PIX_FMT_YUV420P
Definition: ni_device_api.h:262
_ni_packet::end_of_stream
uint32_t end_of_stream
Definition: ni_device_api.h:2831
_ni_session_data_io::packet
ni_packet_t packet
Definition: ni_device_api.h:2871
NI_RETCODE_SUCCESS
@ NI_RETCODE_SUCCESS
Definition: ni_defs.h:427
NI_DEVICE_TYPE_UPLOAD
@ NI_DEVICE_TYPE_UPLOAD
Definition: ni_defs.h:353
_ni_session_context::domain
unsigned short domain
Definition: ni_device_api.h:1619
NI_INVALID_SESSION_ID
#define NI_INVALID_SESSION_ID
Definition: ni_device_api.h:111
print_usage
void print_usage(void)
Print usage information.
Definition: ni_p2p_read_test.c:920
current_time
struct timeval current_time
Definition: ni_p2p_read_test.c:80
ni_log_set_level
void ni_log_set_level(ni_log_level_t level)
Set ni_log_level.
Definition: ni_log.c:202
swapchain_t::gpu_frame
ni_frame_t gpu_frame[MAX_SWAP_SIZE]
Definition: ni_p2p_read_test.c:96
required_argument
#define required_argument
Definition: ni_getopt.h:86
NI_XCODER_REVISION
#define NI_XCODER_REVISION
Definition: ni_defs.h:95
gpu_render_frame
int gpu_render_frame(ni_session_context_t *p_ctx, int fd, uint8_t **pp_data, ni_frame_t *p_in_frame, int input_video_width, int input_video_height, unsigned long *bytes_sent, int *input_exhausted)
Reads video data from input file then calls a special libxcoder API function to transfer the video da...
Definition: ni_p2p_read_test.c:309
ni_packet_buffer_free
ni_retcode_t ni_packet_buffer_free(ni_packet_t *p_packet)
Free packet buffer that was previously allocated with ni_packet_buffer_alloc.
Definition: ni_device_api.c:3843
_ni_session_context::blk_io_handle
ni_device_handle_t blk_io_handle
Definition: ni_device_api.h:1465
no_argument
#define no_argument
Definition: ni_getopt.h:85
_ni_session_context::bit_depth_factor
int bit_depth_factor
Definition: ni_device_api.h:1494
_ni_session_context::hw_id
int hw_id
Definition: ni_device_api.h:1478
ni_copy_hw_yuv420p
void ni_copy_hw_yuv420p(uint8_t *p_dst[NI_MAX_NUM_DATA_POINTERS], uint8_t *p_src[NI_MAX_NUM_DATA_POINTERS], int frame_width, int frame_height, int factor, int is_semiplanar, int conf_win_right, int dst_stride[NI_MAX_NUM_DATA_POINTERS], int dst_height[NI_MAX_NUM_DATA_POINTERS], int src_stride[NI_MAX_NUM_DATA_POINTERS], int src_height[NI_MAX_NUM_DATA_POINTERS])
Copy YUV data to Netint HW YUV420p frame layout to be sent to encoder for encoding....
Definition: ni_util.c:2352
enc_eos_sent
int enc_eos_sent
Definition: ni_p2p_read_test.c:71
send_fin_flag
int send_fin_flag
Definition: ni_p2p_read_test.c:69
encoder_receive_data
int encoder_receive_data(ni_session_context_t *p_enc_ctx, ni_session_data_io_t *p_out_data, FILE *p_file, unsigned long long *total_bytes_received, int print_time)
Receive output packet data from the Quadra encoder.
Definition: ni_p2p_read_test.c:650
ni_retcode_t
ni_retcode_t
Definition: ni_defs.h:425
ni_packet_buffer_alloc
ni_retcode_t ni_packet_buffer_alloc(ni_packet_t *p_packet, int packet_size)
Allocate memory for the packet buffer based on provided packet size.
Definition: ni_device_api.c:3713
previous_time
struct timeval previous_time
Definition: ni_p2p_read_test.c:79
ni_device_session_acquire
int ni_device_session_acquire(ni_session_context_t *p_ctx, ni_frame_t *p_frame)
Acquire a P2P frame buffer from the hwupload session.
Definition: ni_device_api.c:10602
arg_to_ni_log_level
ni_log_level_t arg_to_ni_log_level(const char *arg_str)
Convert terminal arg string to ni_log_level_t.
Definition: ni_log.c:262
netint_iocmd_import_dmabuf::fd
int fd
Definition: ni_p2p_ioctl.h:57
NETINT_IOCTL_IMPORT_DMABUF
#define NETINT_IOCTL_IMPORT_DMABUF
Definition: ni_p2p_ioctl.h:101
previous_timestamp
time_t previous_timestamp
Definition: ni_p2p_read_test.c:83
NI_LOG_ERROR
@ NI_LOG_ERROR
Definition: ni_log.h:60
NI_VPU_ALIGN16
#define NI_VPU_ALIGN16(_x)
Definition: ni_device_api.h:331
uploader_open_session
int uploader_open_session(ni_session_context_t *p_upl_ctx, int *iXcoderGUID, int width, int height, int poolsize, int p2p)
Open an upload session to Quadra.
Definition: ni_p2p_read_test.c:865
_ni_frame::data_len
uint32_t data_len[NI_MAX_NUM_DATA_POINTERS]
Definition: ni_device_api.h:2664
_ni_frame::extra_data_len
unsigned int extra_data_len
Definition: ni_device_api.h:2657
ni_p2p_ioctl.h
Definitions related to NETINT P2P kernel driver interface.
g_raw_frame
uint8_t * g_raw_frame
Definition: ni_p2p_read_test.c:89
ni_encoder_init_default_params
ni_retcode_t ni_encoder_init_default_params(ni_xcoder_params_t *p_param, int fps_num, int fps_denom, long bit_rate, int width, int height, ni_codec_format_t codec_format)
Initialize default encoder parameters.
Definition: ni_device_api.c:4147
receive_fin_flag
int receive_fin_flag
Definition: ni_p2p_read_test.c:70
_ni_frame::end_of_stream
uint32_t end_of_stream
Definition: ni_device_api.h:2608
_ni_xcoder_params::hwframes
int hwframes
Definition: ni_device_api.h:2774
_ni_session_context::device_handle
ni_device_handle_t device_handle
Definition: ni_device_api.h:1462
_ni_session_context::p_session_config
void * p_session_config
Definition: ni_device_api.h:1473
NI_SW_RELEASE_TIME
#define NI_SW_RELEASE_TIME
Definition: ni_release_info.h:28
_ni_packet::p_data
void * p_data
Definition: ni_device_api.h:2837
_ni_session_data_io
Definition: ni_device_api.h:2866
ni_log
void ni_log(ni_log_level_t level, const char *fmt,...)
print log message using ni_log_callback
Definition: ni_log.c:183
netint_iocmd_import_dmabuf
Definition: ni_p2p_ioctl.h:56
NI_LOG_INVALID
@ NI_LOG_INVALID
Definition: ni_log.h:57
ni_hwframe_p2p_buffer_recycle
ni_retcode_t ni_hwframe_p2p_buffer_recycle(ni_frame_t *p_frame)
Recycle hw P2P frames.
Definition: ni_device_api.c:10996
getopt_long
int getopt_long(int argc, char *argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: ni_getopt.c:99
ni_uploader_set_frame_format
ni_retcode_t ni_uploader_set_frame_format(ni_session_context_t *p_upl_ctx, int width, int height, ni_pix_fmt_t pixel_format, int isP2P)
Set the outgoing frame format for the uploader.
Definition: ni_device_api.c:11171
_ni_frame::force_key_frame
int force_key_frame
Definition: ni_device_api.h:2624
_ni_packet
Definition: ni_device_api.h:2825
total_file_size
unsigned long total_file_size
Definition: ni_p2p_read_test.c:86
ni_device_session_context_clear
void ni_device_session_context_clear(ni_session_context_t *p_ctx)
Clear already allocated session context.
Definition: ni_device_api.c:249
ni_get_frame_dim
void ni_get_frame_dim(int width, int height, ni_pix_fmt_t pix_fmt, int plane_stride[NI_MAX_NUM_DATA_POINTERS], int plane_height[NI_MAX_NUM_DATA_POINTERS])
Get dimension information of frame to be sent to encoder for encoding. Caller usually retrieves this ...
Definition: ni_util.c:2092
arg_error_exit
void arg_error_exit(char *arg_name, char *param)
Exit on argument error.
Definition: ni_p2p_read_test.c:107
ni_encoder_set_input_frame_format
ni_retcode_t ni_encoder_set_input_frame_format(ni_session_context_t *p_enc_ctx, ni_xcoder_params_t *p_enc_params, int width, int height, int bit_depth, int src_endian, int planar)
Set the incoming frame format for the encoder.
Definition: ni_device_api.c:11083
_ni_frame::p_data
uint8_t * p_data[NI_MAX_NUM_DATA_POINTERS]
Definition: ni_device_api.h:2663
optarg
char * optarg
Definition: ni_getopt.c:33
_ni_session_context::hw_action
int hw_action
Definition: ni_device_api.h:1609
_ni_session_context
Definition: ni_device_api.h:1408
_ni_session_context::bus
unsigned short bus
Definition: ni_device_api.h:1620
ni_device_session_read
int ni_device_session_read(ni_session_context_t *p_ctx, ni_session_data_io_t *p_data, ni_device_type_t device_type)
Read data from the device If device_type is NI_DEVICE_TYPE_DECODER reads data packet from decoder If ...
Definition: ni_device_api.c:1769
_niFrameSurface1
Definition: ni_device_api.h:2793
NI_CODEC_HW_ENABLE
@ NI_CODEC_HW_ENABLE
Definition: ni_device_api.h:940
ni_frame_buffer_alloc_hwenc
ni_retcode_t ni_frame_buffer_alloc_hwenc(ni_frame_t *p_frame, int video_width, int video_height, int extra_len)
Allocate memory for the hwDescriptor buffer based on provided parameters taking into account pic size...
Definition: ni_device_api.c:8399
NI_MAX_NUM_DATA_POINTERS
#define NI_MAX_NUM_DATA_POINTERS
Definition: ni_defs.h:232
_ni_session_data_io::data
union _ni_session_data_io::@19 data
_ni_frame
Definition: ni_device_api.h:2601
ni_device_session_open
ni_retcode_t ni_device_session_open(ni_session_context_t *p_ctx, ni_device_type_t device_type)
Open a new device session depending on the device_type parameter If device_type is NI_DEVICE_TYPE_DEC...
Definition: ni_device_api.c:710
NI_VPU_ALIGN4096
#define NI_VPU_ALIGN4096(_x)
Definition: ni_device_api.h:338
NI_PIX_FMT_ABGR
@ NI_PIX_FMT_ABGR
Definition: ni_device_api.h:269
_ni_xcoder_params
Definition: ni_device_api.h:2713
option
Definition: ni_getopt.h:73
_ni_session_context::ready_to_close
uint32_t ready_to_close
Definition: ni_device_api.h:1544
data_left_size
uint64_t data_left_size
Definition: ni_p2p_read_test.c:75
number_of_frames
uint32_t number_of_frames
Definition: ni_p2p_read_test.c:73
_ni_session_context::codec_format
uint32_t codec_format
Definition: ni_device_api.h:1486
ni_posix_memalign
int ni_posix_memalign(void **memptr, size_t alignment, size_t size)
Allocate aligned memory.
Definition: ni_util.c:198
ni_log2
void ni_log2(const void *p_context, ni_log_level_t level, const char *fmt,...)
print log message and additional information using ni_log_callback,
Definition: ni_log.c:337
main
int main(int argc, char *argv[])
Definition: ni_p2p_read_test.c:1124
parse_arguments
void parse_arguments(int argc, char *argv[], char *input_filename, char *output_filename, int *iXcoderGUID, int *iGpuGUID, int *arg_width, int *arg_height, int *dst_codec_format)
Parse user command line arguments.
Definition: ni_p2p_read_test.c:970
g_curr_cache_pos
uint8_t * g_curr_cache_pos
Definition: ni_p2p_read_test.c:88
ni_device_session_acquire_for_read
int ni_device_session_acquire_for_read(ni_session_context_t *p_ctx, ni_frame_t *p_frame)
Acquire a P2P frame buffer from the hwupload session for P2P read.
Definition: ni_device_api.c:10697
_ni_session_data_io::frame
ni_frame_t frame
Definition: ni_device_api.h:2870
atoi
#define atoi(p_str)
Definition: ni_device_api.c:7178
_ni_frame::video_height
uint32_t video_height
Definition: ni_device_api.h:2611
encoder_encode_frame
int encoder_encode_frame(ni_session_context_t *p_enc_ctx, ni_frame_t *p_in_frame, int input_exhausted, int *need_to_resend)
Send the Quadra encoder a hardware frame which triggers Quadra to encode the frame.
Definition: ni_p2p_read_test.c:567
LIBXCODER_API_VERSION
#define LIBXCODER_API_VERSION
Definition: ni_defs.h:112
ni_p2p_recv
ni_retcode_t ni_p2p_recv(ni_session_context_t *pSession, const ni_p2p_sgl_t *dmaAddrs, ni_frame_t *pDstFrame)
Initiate a P2P transfer (P2P read)
Definition: ni_device_api.c:12866
ni_device_session_write
int ni_device_session_write(ni_session_context_t *p_ctx, ni_session_data_io_t *p_data, ni_device_type_t device_type)
Sends data to the device If device_type is NI_DEVICE_TYPE_DECODER sends data packet to decoder If dev...
Definition: ni_device_api.c:1668
ni_gettimeofday
int32_t ni_gettimeofday(struct timeval *p_tp, void *p_tzp)
Get time for logs with microsecond timestamps.
Definition: ni_util.c:139
ni_device_api.h
Public definitions for operating NETINT video processing devices for video processing.
_ni_session_context::meta_size
uint32_t meta_size
Params used in VFR mode Done///.
Definition: ni_device_api.h:1638
_niFrameSurface1::dma_buf_fd
int32_t dma_buf_fd
Definition: ni_device_api.h:2805
read_next_chunk_from_file
int read_next_chunk_from_file(int fd, uint8_t *p_dst, uint32_t to_read)
Read the next frame.
Definition: ni_p2p_read_test.c:123
_ni_frame::start_of_stream
uint32_t start_of_stream
Definition: ni_device_api.h:2609
ni_util.h
Utility definitions.
MAX_SWAP_SIZE
#define MAX_SWAP_SIZE
Definition: ni_p2p_read_test.c:67
get_file_size
int get_file_size(const char *filename, unsigned long *bytes_read)
Get file size.
Definition: ni_p2p_read_test.c:171
number_of_packets
uint32_t number_of_packets
Definition: ni_p2p_read_test.c:74
_ni_session_context::dev
unsigned short dev
Definition: ni_device_api.h:1621
ni_uploader_p2p_test_load
ni_retcode_t ni_uploader_p2p_test_load(ni_session_context_t *p_upl_ctx, uint8_t *p_data, uint32_t len, ni_frame_t *p_hwframe)
Special P2P test API function. Copies video data from the software frame to the hardware P2P frame on...
Definition: ni_device_api.c:10924
NI_CODEC_FORMAT_H264
@ NI_CODEC_FORMAT_H264
Definition: ni_device_api.h:911
_ni_frame::video_width
uint32_t video_width
Definition: ni_device_api.h:2610
NI_FRAME_LITTLE_ENDIAN
#define NI_FRAME_LITTLE_ENDIAN
Definition: ni_device_api.h:108
ni_device_session_context_init
ni_retcode_t ni_device_session_context_init(ni_session_context_t *p_ctx)
Initialize already allocated session context to a known state.
Definition: ni_device_api.c:156
ni_device_session_init_framepool
int ni_device_session_init_framepool(ni_session_context_t *p_ctx, uint32_t pool_size, uint32_t pool)
Sends frame pool setup info to device.
Definition: ni_device_api.c:8564
_ni_session_context::pixel_format
int pixel_format
Definition: ni_device_api.h:1616
NI_LOG_DEBUG
@ NI_LOG_DEBUG
Definition: ni_log.h:62
enc_prepare_frame
int enc_prepare_frame(ni_session_context_t *p_upl_ctx, int input_video_width, int input_video_height, ni_frame_t *p2p_frame)
Prepare frame on the encoding Quadra device.
Definition: ni_p2p_read_test.c:518
ni_device_session_close
ni_retcode_t ni_device_session_close(ni_session_context_t *p_ctx, int eos_recieved, ni_device_type_t device_type)
Close device session that was previously opened by calling ni_device_session_open() If device_type is...
Definition: ni_device_api.c:1379
swapchain_t
Definition: ni_p2p_read_test.c:95
_ni_xcoder_params::p_first_frame
ni_frame_t * p_first_frame
Definition: ni_device_api.h:2776
start_time
struct timeval start_time
Definition: ni_p2p_read_test.c:78
NI_CODEC_FORMAT_H265
@ NI_CODEC_FORMAT_H265
Definition: ni_device_api.h:912
_ni_packet::data_len
uint32_t data_len
Definition: ni_device_api.h:2838