libxcoder 5.6.0
Loading...
Searching...
No Matches
ni_xcoder_decode.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_decode.c
24 *
25 * \brief Video decoding demo application directly using Netint Libxcoder API
26 ******************************************************************************/
27
28#include "ni_generic_utils.h"
29#include "ni_decode_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#endif
38
39static void print_usage(void)
40{
42 "Video decoding demo application directly using Netint Libxcoder version %s\n"
43 "Usage: ni_xcoder_decode [options]\n"
44 "\n"
45 "options:\n"
46 "-h | --help Show this message.\n"
47 "-v | --version Print version info.\n"
48 "-i | --input (Required) Input file path.\n"
49 "-o | --output (Required) Output file path.\n"
50 "-m | --dec-codec (Required) Decoder codec format. Must match the codec of input file.\n"
51 " [a|avc, h|hevc, v|vp9]\n"
52 "-l | --loglevel Set loglevel of this application and libxcoder API.\n"
53 " [none, fatal, error, info, debug, trace]\n"
54 " (Default: info)\n"
55 "-c | --card Set card index to use.\n"
56 " See `ni_rsrc_mon` for info of cards on system.\n"
57 " (Default: 0)\n"
58 "-r | --repeat To loop input X times. Must be a positive integer\n"
59 " (Default: 1)\n"
60 "-d | --decoder-params Decoding params. See \"Decoding Parameters\" chapter in\n"
61 " QuadraIntegration&ProgrammingGuide*.pdf for help.\n"
62 " (Default: \"\")\n"
64}
65
66int main(int argc, char *argv[])
67{
68 int i, ret = 0;
69 ni_demo_context_t ctx = {0};
70 char in_filename[FILE_NAME_LEN] = {0};
71 char out_filename[FILE_NAME_LEN] = {0};
72 FILE *output_fp = NULL;
73 int video_width = 0;
74 int video_height = 0;
75 int bit_depth = 0;
76 int dec_codec_format = -1;
77 ni_log_level_t log_level;
78 int xcoderGUID = 0;
79 char *n;
80 char dec_conf_params[2048] = {0};
81 ni_h264_sps_t avc_sps = {0};
82 ni_h265_sps_t hevc_sps = {0};
83 ni_vp9_header_info_t vp9_info = {0};
84 int send_rc = NI_TEST_RETCODE_SUCCESS, receive_rc = NI_TEST_RETCODE_SUCCESS, rx_size = 0;
85 ni_xcoder_params_t *p_dec_api_param = NULL;
86 ni_session_context_t dec_ctx = {0};
87 ni_frame_t *p_ni_frame;
88 niFrameSurface1_t * p_hwframe;
89 void *p_stream_info = NULL;
90 ni_session_data_io_t in_pkt = {0};
91 ni_session_data_io_t out_frame = {0};
93
94 int opt;
95 int opt_index;
96 const char *opt_string = "hvi:o:m:l:c:r:d:";
97 static struct option long_options[] = {
98 {"help", no_argument, NULL, 'h'},
99 {"version", no_argument, NULL, 'v'},
100 {"input", required_argument, NULL, 'i'},
101 {"output", required_argument, NULL, 'o'},
102 {"dec-codec", required_argument, NULL, 'm'},
103 {"loglevel", required_argument, NULL, 'l'},
104 {"card", required_argument, NULL, 'c'},
105 {"repeat", required_argument, NULL, 'r'},
106 {"decoder-params", required_argument, NULL, 'd'},
107 {NULL, 0, NULL, 0},
108 };
109
110 while ((opt = getopt_long(argc, argv, opt_string, long_options, &opt_index)) != -1)
111 {
112 switch (opt)
113 {
114 case 'h':
115 print_usage();
116 ret = 0;
117 goto end;
118 case 'v':
120 ret = 0;
121 goto end;
122 case 'i':
123 ni_strcpy(in_filename, FILE_NAME_LEN, optarg);
124 break;
125 case 'o':
126 ni_strcpy(out_filename, FILE_NAME_LEN, optarg);
127 break;
128 case 'm':
129 // Accept both upper and lower case
130 for (i = 0; i < strlen(optarg); i++)
131 {
132 optarg[i] = (char)tolower((unsigned char)optarg[i]);
133 }
134 if (strcmp(optarg, "a") == 0 || strcmp(optarg, "avc") == 0)
135 {
136 dec_codec_format = NI_CODEC_FORMAT_H264;
137 }
138 else if (strcmp(optarg, "h") == 0 || strcmp(optarg, "hevc") == 0)
139 {
140 dec_codec_format = NI_CODEC_FORMAT_H265;
141 }
142 else if (strcmp(optarg, "v") == 0 || strcmp(optarg, "vp9") == 0)
143 {
144 dec_codec_format = NI_CODEC_FORMAT_VP9;
145 }
146 else
147 {
148 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -m | --dec-codec option\n"
149 "Must be one of [a|avc, h|hevc, v|vp9]\n", optarg);
150 ret = -1;
151 goto end;
152 }
153 break;
154 case 'l':
155 log_level = arg_to_ni_log_level(optarg);
156 if (log_level != NI_LOG_INVALID)
157 {
158 ni_log_set_level(log_level);
159 }
160 else
161 {
162 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -l | --loglevel option\n"
163 "Must be one of [none, fatal, error, info, debug, trace]\n", optarg);
164 ret = -1;
165 goto end;
166 }
167 break;
168 case 'c':
169 xcoderGUID = (int)strtol(optarg, &n, 10);
170 if (n == optarg || *n != '\0' || xcoderGUID < 0)
171 {
172 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -c | --card option\n"
173 "Must be a non-negative integer\n", optarg);
174 ret = -1;
175 goto end;
176 }
177 break;
178 case 'r':
179 ctx.loops_left = strtol(optarg, &n, 10);
180 if (n == optarg || *n != '\0' || !(ctx.loops_left >= 1))
181 {
182 ni_log(NI_LOG_ERROR, "Error: Invalid value \"%s\" for -r | --repeat option\n"
183 "Must be a positive integer\n", optarg);
184 ret = -1;
185 goto end;
186 }
187 break;
188 case 'd':
189 ni_strcpy(dec_conf_params, sizeof(dec_conf_params), optarg);
190 break;
191 default:
192 print_usage();
193 ret = -1;
194 goto end;
195 }
196 }
197
198 if (!in_filename[0]) {
199 ni_log(NI_LOG_ERROR, "Error: Missing input file argument (-i | --input)\n");
200 ret = -1;
201 goto end;
202 }
203
204 if (!out_filename[0]) {
205 ni_log(NI_LOG_ERROR, "Error: Missing output file argument (-o | --output)\n");
206 ret = -1;
207 goto end;
208 }
209
210 if (dec_codec_format == -1) {
211 ni_log(NI_LOG_ERROR, "Error: Missing decoder codec argument (-m | --dec-codec)\n");
212 ret = -1;
213 goto end;
214 }
215
216 p_dec_api_param = malloc(sizeof(ni_xcoder_params_t));
217 if (!p_dec_api_param)
218 {
219 ni_log(NI_LOG_ERROR, "Error: failed to allocate p_dec_api_param\n");
220 ret = -1;
221 goto end;
222 }
223
224 ret = read_and_cache_file(&ctx, in_filename);
225 if (ret)
226 {
227 ni_log(NI_LOG_ERROR, "Error: Read input file failure\n");
228 goto end;
229 }
230
231 if (strcmp(out_filename, "null") != 0 &&
232 strcmp(out_filename, "/dev/null") != 0)
233 {
234 ni_fopen(&output_fp, out_filename, "wb");
235 if (!output_fp)
236 {
237 ni_log(NI_LOG_ERROR, "Error: Failed to open %s\n", out_filename);
238 ret = -1;
239 goto end;
240 }
241 ni_log(NI_LOG_INFO, "Opened output file: %s\n", out_filename);
242 } else
243 {
244 output_fp = NULL;
245 ni_log(NI_LOG_INFO, "Note: Requested NULL output, no output file will be generated\n");
246 }
247
248 if (dec_codec_format == NI_CODEC_FORMAT_H264)
249 {
250 ret = probe_h264_stream_info(&ctx, &avc_sps);
251 if (ret)
252 {
254 "ERROR: Failed to probe input file as H.264, file format not supported!\n");
255 goto end;
256 }
257
258 bit_depth = avc_sps.bit_depth_luma;
259 video_width = avc_sps.width;
260 video_height = avc_sps.height;
261 ni_log(NI_LOG_DEBUG, "Using probed H.264 source info: %d bits, resolution %dx%d\n",
262 bit_depth, video_width, video_height);
263 } else if (dec_codec_format == NI_CODEC_FORMAT_H265)
264 {
265 ret = probe_h265_stream_info(&ctx, &hevc_sps);
266 if (ret)
267 {
269 "ERROR: Failed to probe input file as H.265, file format not supported!\n");
270 goto end;
271 }
272 bit_depth = hevc_sps.bit_depth_chroma;
273 video_width = (int)(hevc_sps.width -
274 (hevc_sps.pic_conf_win.left_offset +
275 hevc_sps.pic_conf_win.right_offset));
276 video_height = (int)(hevc_sps.height -
277 (hevc_sps.pic_conf_win.top_offset +
278 hevc_sps.pic_conf_win.bottom_offset));
279 ni_log(NI_LOG_INFO, "Using probed H.265 source info: %d bits, resolution %dx%d\n",
280 bit_depth, video_width, video_height);
281 } else if (dec_codec_format == NI_CODEC_FORMAT_VP9)
282 {
283 ret = probe_vp9_stream_info(&ctx, &vp9_info);
284 if (ret)
285 {
287 "ERROR: Failed to probe input file as VP9, file format not supported!\n");
288 goto end;
289 }
290 bit_depth = vp9_info.profile ? 10 : 8;
291 video_width = vp9_info.width;
292 video_height = vp9_info.height;
294 "Using probed VP9 source info: %d bits, resolution %dx%d, timebase %u/%u\n",
295 bit_depth, video_width, video_height,
296 vp9_info.timebase.den, vp9_info.timebase.num);
297 }
298
299 // set up decoder config params with some hard-coded values
300 ret = ni_decoder_init_default_params(p_dec_api_param, 25, 1, 200000, video_width, video_height);
301 if (ret)
302 {
303 ni_log(NI_LOG_ERROR, "Error: Failed to init default decoder config\n");
304 goto end;
305 }
306
307 ret = ni_device_session_context_init(&dec_ctx);
308 if (ret)
309 {
310 ni_log(NI_LOG_ERROR, "Error: Failed to init decoder context\n");
311 goto end;
312 }
313
314 dec_ctx.codec_format = dec_codec_format;
315 dec_ctx.src_bit_depth = bit_depth;
316 dec_ctx.bit_depth_factor = 1;
317 if (10 == dec_ctx.src_bit_depth)
318 {
319 dec_ctx.bit_depth_factor = 2;
320 }
321
322 // check and set ni_decoder_params from --xcoder-params
323 ret = ni_retrieve_decoder_params(dec_conf_params, p_dec_api_param, &dec_ctx);
324 if (ret)
325 {
326 ni_log(NI_LOG_ERROR, "Error: decoder config params parsing error\n");
327 goto end;
328 }
329
330 // Decode, use all the parameters specified by user
331 ret = decoder_open_session(&dec_ctx, xcoderGUID, p_dec_api_param);
332 if (ret)
333 {
334 ni_log(NI_LOG_ERROR, "Error: Failed to open decoder session\n");
335 goto end;
336 }
337
338 ni_log(NI_LOG_INFO, "Starting to decode: HWFrames %d\n", dec_ctx.hw_action);
339
340 if (dec_codec_format == NI_CODEC_FORMAT_H264)
341 p_stream_info = &avc_sps;
342 else if (dec_codec_format == NI_CODEC_FORMAT_H265)
343 p_stream_info = &hevc_sps;
344 else if (dec_codec_format == NI_CODEC_FORMAT_VP9)
345 p_stream_info = &vp9_info;
346
349
350 while (send_rc == NI_TEST_RETCODE_SUCCESS || receive_rc == NI_TEST_RETCODE_SUCCESS ||
351 (send_rc == NI_TEST_RETCODE_EAGAIN && receive_rc == NI_TEST_RETCODE_EAGAIN))
352 {
353 // Sending
354 send_rc = decoder_send_data(&ctx, &dec_ctx, &in_pkt, video_width,
355 video_height, p_stream_info);
356 if (send_rc < 0)
357 {
359 "Error: decoder_send_data() failed, rc: %d\n",
360 send_rc);
361 break;
362 }
363
364 // Receiving
365 do
366 {
367 rx_size = 0;
368 receive_rc = decoder_receive_data(&ctx, &dec_ctx, &out_frame, video_width, video_height,
369 output_fp, 1, &rx_size);
370
371 if (dec_ctx.hw_action == NI_CODEC_HW_ENABLE)
372 {
373 if (receive_rc != NI_TEST_RETCODE_EAGAIN &&
374 receive_rc != NI_TEST_RETCODE_END_OF_STREAM)
375 {
376 p_ni_frame = &out_frame.data.frame;
377 p_hwframe = (niFrameSurface1_t *)p_ni_frame->p_data[3];
378 ni_log(NI_LOG_DEBUG, "decoder_receive_data HW decode-only. recycle HW frame idx %u\n", p_hwframe->ui16FrameIdx);
380 ni_frame_buffer_free(p_ni_frame);
381 }
382 }
383 else
384 {
386 }
387
388 // Error or eos
389 if (receive_rc < 0 || out_frame.data.frame.end_of_stream)
390 {
391 break;
392 }
393
395 if (current_time - previous_time >= (uint64_t)1000000000)
396 {
397 ni_log(NI_LOG_INFO, "Decoder stats: received %u frames, fps %.2f, total bytes %u\n",
399 (float)ctx.num_frames_received / (float)(current_time - ctx.start_time) * (float)1000000000,
402 }
403
404 } while (!dec_ctx.decoder_low_delay && rx_size > 0); //drain consecutive outputs
405
406 // Error or eos
407 if (receive_rc < 0 || out_frame.data.frame.end_of_stream)
408 {
409 break;
410 }
411 }
412
413 decoder_stat_report_and_close(&ctx, &dec_ctx);
414
415end:
417 if (dec_ctx.hw_action == NI_CODEC_HW_ENABLE)
418 {
419 ni_frame_buffer_free(&out_frame.data.frame);
420 } else
421 {
423 }
424
426
427 free(p_dec_api_param);
428 free(ctx.file_cache);
429 for(i = 0; i < MAX_OUTPUT_FILES; ++i)
430 {
431 free(ctx.enc_pts_queue[i]);
432 ctx.enc_pts_queue[i] = NULL;
433 }
434 if (output_fp != NULL)
435 {
436 fclose(output_fp);
437 }
438
439 return ret;
440}
int main()
Definition client.cpp:51
void decoder_stat_report_and_close(ni_demo_context_t *p_ctx, ni_session_context_t *p_dec_ctx)
int probe_h264_stream_info(ni_demo_context_t *p_ctx, ni_h264_sps_t *sps)
int decoder_receive_data(ni_demo_context_t *p_ctx, ni_session_context_t *p_dec_ctx, ni_session_data_io_t *p_out_data, int output_video_width, int output_video_height, FILE *p_file, int write_to_file, int *p_rx_size)
Receive decoded output data from decoder.
int decoder_open_session(ni_session_context_t *p_dec_ctx, int iXcoderGUID, ni_xcoder_params_t *p_dec_params)
decoder session open
int probe_h265_stream_info(ni_demo_context_t *p_ctx, ni_h265_sps_t *sps)
int probe_vp9_stream_info(ni_demo_context_t *p_ctx, ni_vp9_header_info_t *vp9_info)
int decoder_send_data(ni_demo_context_t *p_ctx, ni_session_context_t *p_dec_ctx, ni_session_data_io_t *p_in_data, int input_video_width, int input_video_height, void *stream_info)
Send decoder input data.
#define NI_XCODER_REVISION
Definition ni_defs.h:98
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_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_buffer_recycle2(niFrameSurface1_t *surface)
Recycle a frame buffer on card, only hwframe descriptor is needed.
ni_retcode_t ni_device_session_context_init(ni_session_context_t *p_ctx)
Initialize already allocated session context to a known state.
ni_retcode_t ni_decoder_init_default_params(ni_xcoder_params_t *p_param, int fps_num, int fps_denom, long bit_rate, int width, int height)
Initialize default decoder parameters.
void ni_device_session_context_clear(ni_session_context_t *p_ctx)
Clear already allocated session context.
ni_retcode_t ni_decoder_frame_buffer_free(ni_frame_t *p_frame)
Free decoder frame buffer that was previously allocated with ni_decoder_frame_buffer_alloc,...
@ NI_CODEC_HW_ENABLE
@ NI_CODEC_FORMAT_H265
@ NI_CODEC_FORMAT_H264
@ NI_CODEC_FORMAT_VP9
int read_and_cache_file(ni_demo_context_t *ctx, char *filename)
void print_version(void)
#define MAX_OUTPUT_FILES
#define NI_TEST_RETCODE_SUCCESS
#define NI_TEST_RETCODE_EAGAIN
#define NI_TEST_RETCODE_END_OF_STREAM
#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_DEBUG
Definition ni_log.h:64
@ 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
ni_retcode_t ni_fopen(FILE **fp, const char *filename, const char *mode)
Definition ni_util.c:983
ni_retcode_t ni_strcpy(char *dest, size_t dmax, const char *src)
Definition ni_util.c:453
int ni_retrieve_decoder_params(char xcoderParams[], ni_xcoder_params_t *params, ni_session_context_t *ctx)
retrieve decoder config parameter values from –decoder-params
Definition ni_util.c:4560
uint64_t ni_gettime_ns(void)
Definition ni_util.c:2622
Utility definitions.
uint64_t dec_total_bytes_received
ni_pts_queue * enc_pts_queue[MAX_OUTPUT_FILES]
uint32_t end_of_stream
uint8_t * p_data[NI_MAX_NUM_DATA_POINTERS]
int bit_depth_luma
bit_depth_luma_minus8 + 8
ni_h265_window_t pic_conf_win
unsigned int left_offset
unsigned int bottom_offset
unsigned int right_offset
unsigned int top_offset
union _ni_session_data_io::@19 data
struct _ni_vp9_header_info::@3 timebase