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