libxcoder 5.9.0
Loading...
Searching...
No Matches
ni_xcoder_scale.c
Go to the documentation of this file.
1/*******************************************************************************
2 *
3 * Copyright (C) 2022 NETINT Technologies
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18 * SOFTWARE.
19 *
20 ******************************************************************************/
21
22/*!*****************************************************************************
23 * \file ni_xcoder_scale.c
24 *
25 * \brief Video scaling demo application directly using Netint Libxcoder API
26 ******************************************************************************/
27
28#include "ni_generic_utils.h"
29#include "ni_filter_utils.h"
30#include "ni_log.h"
31#include "ni_util.h"
32
33#ifdef _WIN32
34#include "ni_getopt.h"
35#elif __linux__ || __APPLE__
36#include <getopt.h>
37#include <unistd.h>
38#endif
39
40static void print_usage(void)
41{
43 "Video scaling demo application directly using Netint Libxcoder version %s\n"
44 "Usage: ni_xcoder_scale [options]\n"
45 "\n"
46 "options:\n"
47 "-h | --help Show this message.\n"
48 "-v | --version Print version info.\n"
49 "-i | --input (Required) Input file path.\n"
50 "-o | --output (Required) Output file path.\n"
51 " Can be specified multiple (max %d) times\n"
52 " to run multiple scaling instances simultaneously.\n"
53 "-l | --loglevel Set loglevel of this application and libxcoder API.\n"
54 " [none, fatal, error, info, debug, trace]\n"
55 " (Default: info)\n"
56 "-c | --card Set card index to use.\n"
57 " See `ni_rsrc_mon` for info of cards on system.\n"
58 " (Default: 0)\n"
59 "-r | --repeat To loop input X times. Must be a positive integer\n"
60 " (Default: 1)\n"
61 "-p | --pix_fmt Indicate the pixel format of the input.\n"
62 " [yuv420p, yuv420p10le, nv12, p010le, rgba, bgra, argb, abgr, bgr0]\n"
63 " (Default: yuv420p)\n"
64 "-s | --size (Required) Resolution of input file in format WIDTHxHEIGHT.\n"
65 " (eg. '1920x1080')\n"
66 "-f | --vf Video filter params. The only supported filter in this demo is:\n"
67 " ni_quadra_scale - supported params [width, height, format]\n"
68 " e.g. ni_quadra_scale=width=1280:height=720:format=yuv420p\n"
69 " (Default: \"\")\n"
71}
72
73int main(int argc, char *argv[])
74{
75 int i, ret = 0;
76 ni_demo_context_t ctx = {0};
77 char in_filename[FILE_NAME_LEN] = {0};
78 char out_filename[MAX_OUTPUT_FILES][FILE_NAME_LEN] = {0};
79 FILE *input_fp = NULL;
80 FILE *output_fp[MAX_OUTPUT_FILES] = {0};
81 int o_index = 0, f_index = 0;
82 int output_total = 0;
83 int input_width = 0, input_height = 0;
84 int bit_depth_factor[MAX_OUTPUT_FILES] = {0};
85 int output_width[MAX_OUTPUT_FILES] = {0};
86 int output_height[MAX_OUTPUT_FILES] = {0};
87 int chunk_size = 0, eos = 0;
88 void *yuv_buf = NULL;
89 ni_log_level_t log_level;
90 int xcoderGUID = 0;
91 char *n;
92 char filter_conf_params[MAX_OUTPUT_FILES][2048] = {0};
93 ni_session_context_t upl_ctx = {0};
96 ni_session_data_io_t sw_in_frame = {0};
97 ni_session_data_io_t hw_in_frame = {0};
98 ni_session_data_io_t scaled_frame[MAX_OUTPUT_FILES] = {0};
99 ni_session_data_io_t download_frame[MAX_OUTPUT_FILES] = {0};
100 niFrameSurface1_t *p_hwframe = NULL;
101 ni_scale_params_t scale_params[MAX_OUTPUT_FILES] = {0};
102 ni_drawbox_params_t drawbox_params = {0};
103 ni_ai_pre_params_t ai_pre_params = {0}; // ai_pre not supported in this demo
105
106 int opt;
107 int opt_index;
108 const char *opt_string = "hvi:o:l:c:r:p:s:f:";
109 static struct option long_options[] = {
110 {"help", no_argument, NULL, 'h'},
111 {"version", no_argument, NULL, 'v'},
112 {"input", required_argument, NULL, 'i'},
113 {"output", required_argument, NULL, 'o'},
114 {"loglevel", required_argument, NULL, 'l'},
115 {"card", required_argument, NULL, 'c'},
116 {"repeat", required_argument, NULL, 'r'},
117 {"pix_fmt", required_argument, NULL, 'p'},
118 {"size", required_argument, NULL, 's'},
119 {"vf", required_argument, NULL, 'f'},
120 {NULL, 0, NULL, 0},
121 };
122
123 while ((opt = getopt_long(argc, argv, opt_string, long_options, &opt_index)) != -1)
124 {
125 switch (opt)
126 {
127 case 'h':
128 print_usage();
129 ret = 0;
130 goto end;
131 case 'v':
133 ret = 0;
134 goto end;
135 case 'i':
136 ni_strcpy(in_filename, FILE_NAME_LEN, optarg);
137 break;
138 case 'o':
139 if (o_index == MAX_OUTPUT_FILES)
140 {
141 ni_log(NI_LOG_ERROR, "Error: number of output files cannot exceed %d\n", MAX_OUTPUT_FILES);
142 ret = -1;
143 goto end;
144 }
145
146 for (i = 0; i < o_index; i++)
147 {
148 if (0 == strcmp(out_filename[i], optarg))
149 {
150 ni_log(NI_LOG_ERROR, "Error: output file names must be unique: %s\n", optarg);
151 ret = -1;
152 goto end;
153 }
154 }
155
156 ni_strcpy(out_filename[o_index], FILE_NAME_LEN, optarg);
157 o_index++;
158 break;
159 case 'l':
160 log_level = arg_to_ni_log_level(optarg);
161 if (log_level != NI_LOG_INVALID)
162 {
163 ni_log_set_level(log_level);
164 }
165 else
166 {
167 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -l | --loglevel option\n"
168 "Must be one of [none, fatal, error, info, debug, trace]\n", optarg);
169 ret = -1;
170 goto end;
171 }
172 break;
173 case 'c':
174 xcoderGUID = (int)strtol(optarg, &n, 10);
175 if (n == optarg || *n != '\0' || xcoderGUID < 0)
176 {
177 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -c | --card option\n"
178 "Must be a non-negative integer\n", optarg);
179 ret = -1;
180 goto end;
181 }
182 break;
183 case 'r':
184 ctx.loops_left = strtol(optarg, &n, 10);
185 if (n == optarg || *n != '\0' || !(ctx.loops_left >= 1))
186 {
187 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -r | --repeat option\n"
188 "Must be a positive integer\n", optarg);
189 ret = -1;
190 goto end;
191 }
192 break;
193 case 'p':
195 if (pix_fmt == NI_PIX_FMT_NONE)
196 {
197 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -p | --pix_fmt option\n"
198 "Must be one of [yuv420p, yuv420p10le, nv12, p010le, rgba, gbra, argb, abgr, bgr0, yuv444p]\n",
199 optarg);
200 ret = -1;
201 goto end;
202 }
203 break;
204 case 's':
205 input_width = (int)strtol(optarg, &n, 10);
206 {
207 int32_t tmp_height;
208 if (ni_strtoi(n + 1, &tmp_height) != NI_RETCODE_SUCCESS)
209 tmp_height = 0;
210 input_height = tmp_height;
211 }
212 if ((*n != 'x') || (input_width <= 0 || input_height <= 0))
213 {
214 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -s | --size option\n"
215 "Must be in format [WIDTHxHEIGHT] (e.g. 1920x1080)\n", optarg);
216 ret = -1;
217 goto end;
218 }
219 break;
220 case 'f':
221 if (f_index == MAX_OUTPUT_FILES)
222 {
223 ni_log(NI_LOG_ERROR, "Error: number of filter config cannot exceed %d\n", MAX_OUTPUT_FILES);
224 ret = -1;
225 goto end;
226 }
227 ni_strcpy(filter_conf_params[f_index], sizeof(filter_conf_params[f_index]), optarg);
228 f_index++;
229 break;
230 default:
231 print_usage();
232 ret = -1;
233 goto end;
234 }
235 }
236
237 if (!in_filename[0]) {
238 ni_log(NI_LOG_ERROR, "Error: Missing input file argument (-i | --input)\n");
239 ret = -1;
240 goto end;
241 }
242
243 if (o_index == 0) {
244 ni_log(NI_LOG_ERROR, "Error: Missing output file argument (-o | --output)\n");
245 ret = -1;
246 goto end;
247 }
248
249 if (ni_posix_memalign(&yuv_buf, sysconf(_SC_PAGESIZE), MAX_YUV_FRAME_SIZE))
250 {
251 ni_log(NI_LOG_ERROR, "Error: failed to allocate YUV data buffer\n");
252 ret = -1;
253 goto end;
254 }
255
256 ni_fopen(&(input_fp), in_filename, "rb");
257 if (!input_fp)
258 {
259 ni_log(NI_LOG_ERROR, "Error: Failed to open input %s\n", in_filename);
260 ret = -1;
261 goto end;
262 }
263 ni_log(NI_LOG_INFO, "Opened input file: %s\n", in_filename);
264
265 ctx.total_file_size = get_total_file_size(input_fp);
266 ctx.curr_file_offset = 0;
267
268 output_total = o_index;
269 for (i = 0; i < output_total; i++)
270 {
271 if (strcmp(out_filename[i], "null") != 0 &&
272 strcmp(out_filename[i], "/dev/null") != 0)
273 {
274 output_fp[i] = NULL;
275 ni_fopen(&(output_fp[i]), out_filename[i], "wb");
276 if (!output_fp[i])
277 {
278 ni_log(NI_LOG_ERROR, "Error: Failed to open %s\n", out_filename[i]);
279 ret = -1;
280 goto end;
281 }
282 ni_log(NI_LOG_INFO, "Opened output file: %s\n", out_filename[i]);
283 } else
284 {
285 output_fp[i] = NULL;
286 ni_log(NI_LOG_INFO, "Note: Requested NULL output for index %d, no output file will be generated\n", i);
287 }
288 }
289
290 for (i = 0; i < output_total; i++)
291 {
292 output_width[i] = input_width;
293 output_height[i] = input_height;
294 }
295
296 if (ni_device_session_context_init(&upl_ctx) < 0)
297 {
298 ni_log(NI_LOG_ERROR, "Error: init uploader context error\n");
299 ret = -1;
300 goto end;
301 }
302
303 for (i = 0; i < output_total; i++)
304 {
305 if (filter_conf_params[i][0])
306 {
307 ret = retrieve_filter_params(filter_conf_params[i], &scale_params[i], &drawbox_params, &ai_pre_params);
308 if (ret)
309 {
310 ni_log(NI_LOG_ERROR, "Error: failed to parse filter parameters: %s\n", filter_conf_params[i]);
311 goto end;
312 }
313 if (ai_pre_params.enabled)
314 {
315 ni_log(NI_LOG_ERROR, "Error: ni_quadra_ai_pre is not supported in this demo\n");
316 ret = -1;
317 goto end;
318 }
319 }
320
321 if (!scale_params[i].enabled)
322 {
323 ni_log(NI_LOG_ERROR, "Error: scale parameters not set for output #%d\n", i);
324 ret = -1;
325 goto end;
326 }
327 else
328 {
329 ret = ni_device_session_context_init(&sca_ctx[i]);
330 if (ret)
331 {
332 ni_log(NI_LOG_ERROR, "Error: Failed to init scale context\n");
333 goto end;
334 }
335 output_width[i] = scale_params[i].width;
336 output_height[i] = scale_params[i].height;
337 bit_depth_factor[i] = 1;
338 if (scale_params[i].format == GC620_I010 || scale_params[i].format == GC620_P010_MSB)
339 {
340 bit_depth_factor[i] = 2;
341 }
342 }
343 }
344
345 ret = uploader_open_session(&upl_ctx, xcoderGUID, input_width < NI_MIN_WIDTH ? NI_MIN_WIDTH : input_width,
346 input_height < NI_MIN_HEIGHT ? NI_MIN_HEIGHT : input_height, pix_fmt, 0, 3);
347 if (ret != 0)
348 {
349 ni_log(NI_LOG_ERROR, "Error: Failed to open uploader session\n");
350 goto end;
351 }
352
353 for (i = 0; i < output_total; i++)
354 {
355 ni_log(NI_LOG_INFO, "(Task %d) Starting to scale: video resolution %dx%d -> %dx%d\n",
356 i, input_width, input_height, output_width[i], output_height[i]);
357 }
358
361
362 while (!eos)
363 {
364 chunk_size = read_yuv_from_file(&ctx, input_fp, yuv_buf, input_width, input_height, pix_fmt,
366 if (chunk_size < 0)
367 {
368 ni_log(NI_LOG_ERROR, "Error: read yuv file error\n");
369 ret = -1;
370 break;
371 }
372
373 ret = upload_send_data_get_desc(&ctx, &upl_ctx, &sw_in_frame, &hw_in_frame, input_width,
374 input_height, eos ? NULL : yuv_buf);
375 if (ret)
376 {
377 ni_log(NI_LOG_ERROR, "Error: upload frame error\n");
378 break;
379 }
380
381 p_hwframe = (niFrameSurface1_t *)hw_in_frame.data.frame.p_data[3];
382 ni_hw_frame_ref(p_hwframe);
383 for (i = 0; i < output_total; i++)
384 {
385 scale_filter(&sca_ctx[i], &hw_in_frame.data.frame, &scaled_frame[i], xcoderGUID,
386 scale_params[i].width, scale_params[i].height,
387 ni_to_gc620_pix_fmt(pix_fmt), scale_params[i].format);
388 if (ret)
389 {
390 ni_log(NI_LOG_ERROR, "Error: Failed to run scale filter\n");
391 goto end;
392 }
393
394 p_hwframe = (niFrameSurface1_t *)scaled_frame[i].data.frame.p_data[3];
395 p_hwframe->ui16width = scale_params[i].width;
396 p_hwframe->ui16height = scale_params[i].height;
397 p_hwframe->bit_depth = bit_depth_factor[i];
398 if (scale_params[i].format == GC620_I420 || scale_params[i].format == GC620_I010)
400 else
402 ni_hw_frame_ref(p_hwframe);
403 ret = hwdl_frame(&sca_ctx[i], &download_frame[i], &scaled_frame[i].data.frame,
404 gc620_to_ni_pix_fmt(scale_params[i].format));
405 if (ret <= 0)
406 {
407 ni_log(NI_LOG_ERROR, "Error: Failed to download output frame\n");
408 goto end;
409 }
411
412 ret = write_rawvideo_data(output_fp[i], (output_width[i] * bit_depth_factor[i] + 127) / 128 * 128,
413 (output_height[i] + 1) / 2 * 2, output_width[i], output_height[i],
414 gc620_to_ni_pix_fmt(scale_params[i].format), &download_frame[i].data.frame);
415 }
416 p_hwframe = (niFrameSurface1_t *)hw_in_frame.data.frame.p_data[3];
418
420 if (current_time - previous_time >= (uint64_t)1000000000)
421 {
422 ni_log(NI_LOG_INFO, "Scaler stats: processed %u frames, fps %.2f\n",
424 (float)ctx.num_frames_received / (float)(current_time - ctx.start_time) * (float)1000000000);
426 }
427 }
428
429end:
431 for (i = 0; i < output_total; i++)
432 {
434 }
435
436#ifdef _WIN32
438 for (i = 0; i < output_total; i++)
439 {
440 ni_device_close(sca_ctx[i].device_handle);
441 }
442#elif __linux__
445 for (i = 0; i < output_total; i++)
446 {
447 ni_device_close(sca_ctx[i].device_handle);
448 ni_device_close(sca_ctx[i].blk_io_handle);
449 }
450#endif
451
452 ni_frame_buffer_free(&sw_in_frame.data.frame);
453 ni_frame_buffer_free(&hw_in_frame.data.frame);
454 for (i = 0; i < output_total; i++)
455 {
456 ni_frame_buffer_free(&scaled_frame[i].data.frame);
457 ni_frame_buffer_free(&download_frame[i].data.frame);
458 }
459
461 for (i = 0; i < output_total; i++)
462 {
464 if (output_fp[i] != NULL)
465 {
466 fclose(output_fp[i]);
467 }
468 }
469
470 if (input_fp)
471 {
472 fclose(input_fp);
473 }
474
475 ni_aligned_free(yuv_buf);
476
477 for(i = 0; i < MAX_OUTPUT_FILES; ++i)
478 {
479 free(ctx.enc_pts_queue[i]);
480 ctx.enc_pts_queue[i] = NULL;
481 }
482
483 return ret;
484}
int main()
Definition client.cpp:51
#define NI_XCODER_REVISION
Definition ni_defs.h:98
@ NI_DEVICE_TYPE_SCALER
Definition ni_defs.h:362
@ NI_DEVICE_TYPE_UPLOAD
Definition ni_defs.h:367
@ NI_RETCODE_SUCCESS
Definition ni_defs.h:448
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_context_init(ni_session_context_t *p_ctx)
Initialize already allocated session context to a known state.
void ni_device_close(ni_device_handle_t device_handle)
Close device and release resources.
void ni_device_session_context_clear(ni_session_context_t *p_ctx)
Clear already allocated session context.
#define NI_MIN_HEIGHT
#define GC620_I420
#define NI_MIN_WIDTH
@ NI_PIXEL_PLANAR_FORMAT_SEMIPLANAR
@ NI_PIXEL_PLANAR_FORMAT_PLANAR
#define GC620_P010_MSB
ni_pix_fmt_t
@ NI_PIX_FMT_YUV420P
@ NI_PIX_FMT_NONE
#define GC620_I010
int scale_filter(ni_session_context_t *p_ctx, ni_frame_t *p_frame_in, ni_session_data_io_t *p_data_out, int iXcoderGUID, int scale_width, int scale_height, int in_format, int out_format)
Do a scale and/or format-change operation.
int retrieve_filter_params(char filter_params[], ni_scale_params_t *scale_params, ni_drawbox_params_t *drawbox_params, ni_ai_pre_params_t *ai_pre_params)
ni_pix_fmt_t gc620_to_ni_pix_fmt(int pix_fmt)
ni_pix_fmt_t ni_pixel_format_search(const char *name)
int read_yuv_from_file(ni_demo_context_t *p_ctx, FILE *pfs, void *yuv_buf, int width, int height, ni_pix_fmt_t pix_fmt, ni_sw_pix_fmt_t sw_pix_fmt, int *eos, ni_session_run_state_t run_state)
void ni_hw_frame_unref(uint16_t hwframe_index)
int ni_to_gc620_pix_fmt(ni_pix_fmt_t pix_fmt)
uint64_t get_total_file_size(FILE *fp)
int upload_send_data_get_desc(ni_demo_context_t *p_ctx, ni_session_context_t *p_upl_ctx, ni_session_data_io_t *p_swin_data, ni_session_data_io_t *p_in_data, int input_video_width, int input_video_height, void *yuv_buf)
Read from input file, upload to encoder, retrieve HW descriptor.
int hwdl_frame(ni_session_context_t *p_ctx, ni_session_data_io_t *p_session_data, ni_frame_t *p_src_frame, int output_format)
Download hw frames by HwDesc.
void print_version(void)
int write_rawvideo_data(FILE *p_file, int input_aligned_width, int input_aligned_height, int output_width, int output_height, int format, ni_frame_t *p_out_frame)
Write hwdl data to files.
int uploader_open_session(ni_session_context_t *p_upl_ctx, int iXcoderGUID, int width, int height, ni_pix_fmt_t pix_fmt, int is_p2p, int pool_size)
Uploader session open.
void ni_hw_frame_ref(const niFrameSurface1_t *p_surface)
#define MAX_YUV_FRAME_SIZE
#define MAX_OUTPUT_FILES
@ NI_SW_PIX_FMT_NONE
#define FILE_NAME_LEN
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
Implementation of getopt() and getopt_long() for Windows environment.
#define no_argument
Definition ni_getopt.h:85
#define required_argument
Definition ni_getopt.h:86
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
Logging definitions.
ni_log_level_t
Definition ni_log.h:58
@ NI_LOG_ERROR
Definition ni_log.h:62
@ NI_LOG_INFO
Definition ni_log.h:63
@ NI_LOG_INVALID
Definition ni_log.h:59
struct timeval current_time
struct timeval previous_time
int ni_posix_memalign(void **memptr, size_t alignment, size_t size)
Allocate aligned memory.
Definition ni_util.c:206
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
uint64_t ni_gettime_ns(void)
Definition ni_util.c:2701
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
Utility definitions.
#define ni_aligned_free(p_memptr)
Definition ni_util.h:402
ni_pts_queue * enc_pts_queue[MAX_OUTPUT_FILES]
uint8_t * p_data[NI_MAX_NUM_DATA_POINTERS]
ni_device_handle_t device_handle
ni_device_handle_t blk_io_handle
ni_session_run_state_t session_run_state
union _ni_session_data_io::@19 data