00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <iostream>
00030 #include <cstdlib>
00031 #include <cstring>
00032 #include <linux/v4l2-controls.h>
00033 #include "video_encode.h"
00034
00035 #define CHECK_OPTION_VALUE(argp) if(!*argp || (*argp)[0] == '-') \
00036 { \
00037 cerr << "Error: value not specified for option " << arg << endl; \
00038 goto error; \
00039 }
00040
00041 #define CSV_PARSE_CHECK_ERROR(condition, str) \
00042 if (condition) {\
00043 cerr << "Error: " << str << endl; \
00044 goto error; \
00045 }
00046
00047 using namespace std;
00048
00049 static void
00050 print_help(void)
00051 {
00052 cerr << "\nvideo_encode <in-file> <in-width> <in-height> <encoder-type> <out-file> [OPTIONS]\n\n"
00053 "Encoder Types:\n"
00054 "\tH264\n"
00055 "\tH265\n\n"
00056 "OPTIONS:\n"
00057 "\t-h,--help Prints this text\n"
00058 "\t--dbg-level <level> Sets the debug level [Values 0-3]\n\n"
00059 "\t-br <bitrate> Bitrate [Default = 4000000]\n"
00060 "\t-p <profile> Encoding Profile [Default = baseline]\n"
00061 "\t-rc <rate-control> Ratecontrol mode [Default = cbr]\n"
00062 "\t-ifi <interval> I-frame Interval [Default = 30]\n"
00063 "\t-idri <interval> IDR Interval [Default = 256]\n"
00064 "\t--insert-spspps-idr Insert SPS PPS at every IDR [Default = disabled]\n"
00065 "\t-fps <num> <den> Encoding fps in num/den [Default = 30/1]\n\n"
00066 "\t-tt <level> Temporal Tradeoff level [Default = 0]\n"
00067 "\t-vbs <size> Virtual buffer size [Default = 0]\n"
00068 "\t-nrf <num> Number of reference frames [Default = 0]\n\n"
00069 "\t-slt <type> Slice length type (1 = Number of MBs, 2 = Bytes) [Default = 1]\n"
00070 "\t-slen <length> Slice length [Default = 0]\n"
00071 "\t-sir <interval> Slice intrarefresh interval [Default = 0]\n\n"
00072 "\t-nbf <num> Number of B frames [Default = 0]\n\n"
00073 "\t-rpc <string> Change configurable parameters at runtime\n\n"
00074 "\t--report-metadata Print encoder output metadata\n"
00075 "\t--mvdump Dump encoded motion vectors\n\n"
00076 "\t-roi <roi_file_path> Specify roi param file [Default = disabled]\n\n"
00077 "\t-MinQpI Specify minimum Qp Value for I frame\n\n"
00078 "\t-MaxQpI Specify maximum Qp Value for I frame\n\n"
00079 "\t-MinQpP Specify minimum Qp Value for P frame\n\n"
00080 "\t-MaxQpP Specify maximum Qp Value for P frame\n\n"
00081 "\t-MinQpB Specify minimum Qp Value for B frame\n\n"
00082 "\t-MaxQpB Specify maximum Qp Value for B frame\n\n"
00083 "NOTE: roi parameters need to be feed per frame in following format\n"
00084 " <no. of roi regions> <Qpdelta> <left> <top> <width> <height> ...\n"
00085 " e.g. [Each line corresponds roi parameters for one frame] \n"
00086 " 2 -2 34 33 16 19 -3 68 68 16 16\n"
00087 " 1 -5 40 40 40 40\n"
00088 " 3 -4 34 34 16 16 -5 70 70 18 18 -3 100 100 34 34\n"
00089 "Supported Encoding profiles for H.264:\n"
00090 "\tbaseline\tmain\thigh\n"
00091 "Supported Encoding profiles for H.265:\n"
00092 "\tmain\n"
00093 "Supported Encoding rate control modes:\n"
00094 "\tcbr\tvbr\n\n"
00095 "Supported Temporal Tradeoff levels:\n"
00096 "0:Drop None 1:Drop 1 in 5 2:Drop 1 in 3\n"
00097 "3:Drop 1 in 2 4:Drop 2 in 3\n\n"
00098 "Runtime configurable parameter string should be of the form:\n"
00099 "\"f<frame_num1>,<prop_id1><val>,<prop_id2><val>;f<frame_num1>,<prop_id1><val>,<prop_id2><val>;...\"\n"
00100 "e.g. \"f20,b8000000,i1;f300,b6000000,r40/1\"\n\n"
00101 "Property ids:\n"
00102 "\tb<bitrate> Bitrate\n"
00103 "\tr<num/den> Framerate\n"
00104 "\ti1 Force I-frame\n\n"
00105 "NOTE: These encoding parameters are slightly imprecisely updated depending upon the number of\n"
00106 "frames in queue and/or processed already.\n";
00107 }
00108
00109 static uint32_t
00110 get_encoder_type(char *arg)
00111 {
00112 if (!strcmp(arg, "H264"))
00113 return V4L2_PIX_FMT_H264;
00114 if (!strcmp(arg, "H265"))
00115 return V4L2_PIX_FMT_H265;
00116 return 0;
00117 }
00118
00119 static int32_t
00120 get_encoder_ratecontrol(char *arg)
00121 {
00122 if (!strcmp(arg, "cbr"))
00123 return V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
00124
00125 if (!strcmp(arg, "vbr"))
00126 return V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
00127
00128 return -1;
00129 }
00130
00131 static int32_t
00132 get_encoder_profile_h264(char *arg)
00133 {
00134 if (!strcmp(arg, "baseline"))
00135 return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
00136
00137 if (!strcmp(arg, "main"))
00138 return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
00139
00140 if (!strcmp(arg, "high"))
00141 return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
00142 return -1;
00143 }
00144
00145 static int32_t
00146 get_encoder_profile_h265(char *arg)
00147 {
00148 if (!strcmp(arg, "main"))
00149 return V4L2_MPEG_VIDEO_H265_PROFILE_MAIN;
00150
00151 return -1;
00152 }
00153
00154 static int32_t
00155 get_encoder_level(char *arg)
00156 {
00157 if (!strcmp(arg, "1.0"))
00158 return V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
00159
00160 if (!strcmp(arg, "1b"))
00161 return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
00162
00163 if (!strcmp(arg, "1.1"))
00164 return V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
00165
00166 if (!strcmp(arg, "1.2"))
00167 return V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
00168
00169 if (!strcmp(arg, "1.3"))
00170 return V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
00171
00172 if (!strcmp(arg, "2.0"))
00173 return V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
00174
00175 if (!strcmp(arg, "2.1"))
00176 return V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
00177
00178 if (!strcmp(arg, "2.2"))
00179 return V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
00180
00181 if (!strcmp(arg, "3.0"))
00182 return V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
00183
00184 if (!strcmp(arg, "3.1"))
00185 return V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
00186
00187 if (!strcmp(arg, "3.2"))
00188 return V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
00189
00190 if (!strcmp(arg, "4.0"))
00191 return V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
00192
00193 if (!strcmp(arg, "4.1"))
00194 return V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
00195
00196 if (!strcmp(arg, "4.2"))
00197 return V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
00198
00199 if (!strcmp(arg, "5.0"))
00200 return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
00201
00202 if (!strcmp(arg, "5.1"))
00203 return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
00204
00205 return -1;
00206 }
00207
00208 static int32_t
00209 get_dbg_level(char *arg)
00210 {
00211 int32_t log_level = atoi(arg);
00212
00213 if (log_level < 0)
00214 {
00215 cout << "Warning: invalid log level input, defaulting to setting 0" << endl;
00216 return 0;
00217 }
00218
00219 if (log_level > 3)
00220 {
00221 cout << "Warning: invalid log level input, defaulting to setting 3" << endl;
00222 return 3;
00223 }
00224
00225 return log_level;
00226 }
00227
00228 int
00229 parse_csv_args(context_t * ctx, int argc, char *argv[])
00230 {
00231 char **argp = argv;
00232 char *arg = *(++argp);
00233 int32_t intval;
00234
00235 if (argc == 1 || (arg && (!strcmp(arg, "-h") || !strcmp(arg, "--help"))))
00236 {
00237 print_help();
00238 exit(EXIT_SUCCESS);
00239 }
00240
00241 CSV_PARSE_CHECK_ERROR(argc < 6, "Insufficient arguments");
00242
00243 ctx->in_file_path = strdup(*argp);
00244 CSV_PARSE_CHECK_ERROR(!ctx->in_file_path, "Input file not specified");
00245
00246 ctx->width = atoi(*(++argp));
00247 CSV_PARSE_CHECK_ERROR(ctx->width == 0, "Input width should be > 0");
00248
00249 ctx->height = atoi(*(++argp));
00250 CSV_PARSE_CHECK_ERROR(ctx->height == 0, "Input height should be > 0");
00251
00252 ctx->encoder_pixfmt = get_encoder_type(*(++argp));
00253 CSV_PARSE_CHECK_ERROR(ctx->encoder_pixfmt == 0,
00254 "Incorrect encoder type");
00255
00256 ctx->out_file_path = strdup(*(++argp));
00257 CSV_PARSE_CHECK_ERROR(!ctx->out_file_path, "Output file not specified");
00258
00259 while ((arg = *(++argp)))
00260 {
00261 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
00262 {
00263 print_help();
00264 exit(EXIT_SUCCESS);
00265 }
00266 else if (!strcmp(arg, "--dbg-level"))
00267 {
00268 argp++;
00269 CHECK_OPTION_VALUE(argp);
00270 log_level = get_dbg_level(*argp);
00271 }
00272 else if (!strcmp(arg, "-roi"))
00273 {
00274 argp++;
00275 CHECK_OPTION_VALUE(argp);
00276 ctx->ROI_Param_file_path = strdup(*argp);
00277 }
00278 else if (!strcmp(arg, "-fps"))
00279 {
00280 argp++;
00281 CHECK_OPTION_VALUE(argp);
00282 ctx->fps_n = atoi(*argp);
00283 argp++;
00284 CHECK_OPTION_VALUE(argp);
00285 ctx->fps_d = atoi(*argp);
00286 CSV_PARSE_CHECK_ERROR(ctx->fps_d == 0, "fps den should be > 0");
00287 }
00288 else if (!strcmp(arg, "-br"))
00289 {
00290 argp++;
00291 CHECK_OPTION_VALUE(argp);
00292 ctx->bitrate = atoi(*argp);
00293 CSV_PARSE_CHECK_ERROR(ctx->bitrate == 0, "bit rate should be > 0");
00294 }
00295 else if (!strcmp(arg, "-ifi"))
00296 {
00297 argp++;
00298 CHECK_OPTION_VALUE(argp);
00299 ctx->iframe_interval = atoi(*argp);
00300 CSV_PARSE_CHECK_ERROR(ctx->iframe_interval == 0,
00301 "ifi size shoudl be > 0");
00302 }
00303 else if (!strcmp(arg, "-idri"))
00304 {
00305 argp++;
00306 CHECK_OPTION_VALUE(argp);
00307 ctx->idr_interval = atoi(*argp);
00308 CSV_PARSE_CHECK_ERROR(ctx->idr_interval == 0,
00309 "idri size shoudl be > 0");
00310 }
00311 else if (!strcmp(arg, "--insert-spspps-idr"))
00312 {
00313 ctx->insert_sps_pps_at_idr = true;
00314 }
00315 else if (!strcmp(arg, "-l"))
00316 {
00317 argp++;
00318 CHECK_OPTION_VALUE(argp);
00319 intval = get_encoder_level(*argp);
00320 CSV_PARSE_CHECK_ERROR(intval == -1,
00321 "Unsupported value for level: " << *argp);
00322 ctx->level = (enum v4l2_mpeg_video_h264_level) intval;
00323 }
00324 else if (!strcmp(arg, "-rc"))
00325 {
00326 argp++;
00327 CHECK_OPTION_VALUE(argp);
00328 intval = get_encoder_ratecontrol(*argp);
00329 CSV_PARSE_CHECK_ERROR(intval == -1,
00330 "Unsupported value for ratecontrol: " << *argp);
00331 ctx->ratecontrol = (enum v4l2_mpeg_video_bitrate_mode) intval;
00332 }
00333 else if (!strcmp(arg, "-rpc"))
00334 {
00335 argp++;
00336 CHECK_OPTION_VALUE(argp);
00337 ctx->runtime_params_str = new stringstream(*argp);
00338 }
00339 else if (!strcmp(arg, "-p"))
00340 {
00341 argp++;
00342 CHECK_OPTION_VALUE(argp);
00343 if (ctx->encoder_pixfmt == V4L2_PIX_FMT_H264)
00344 {
00345 ctx->profile = get_encoder_profile_h264(*argp);
00346 }
00347 else if (ctx->encoder_pixfmt == V4L2_PIX_FMT_H265)
00348 {
00349 ctx->profile = get_encoder_profile_h265(*argp);
00350 }
00351 CSV_PARSE_CHECK_ERROR(ctx->profile == (uint32_t) -1,
00352 "Unsupported value for profile: " << *argp);
00353 }
00354 else if (!strcmp(arg, "-tt"))
00355 {
00356 argp++;
00357 CHECK_OPTION_VALUE(argp);
00358 ctx->temporal_tradeoff_level =
00359 (enum v4l2_enc_temporal_tradeoff_level_type) atoi(*argp);
00360 CSV_PARSE_CHECK_ERROR(
00361 (ctx->temporal_tradeoff_level <
00362 V4L2_ENC_TEMPORAL_TRADEOFF_LEVEL_DROPNONE ||
00363 ctx->temporal_tradeoff_level >
00364 V4L2_ENC_TEMPORAL_TRADEOFF_LEVEL_DROP2IN3),
00365 "Unsupported value for temporal tradeoff: " << *argp);
00366 }
00367 else if (!strcmp(arg, "-slt"))
00368 {
00369 argp++;
00370 CHECK_OPTION_VALUE(argp);
00371 switch (atoi(*argp))
00372 {
00373 case 1:
00374 ctx->slice_length_type = V4L2_ENC_SLICE_LENGTH_TYPE_MBLK;
00375 break;
00376 case 2:
00377 ctx->slice_length_type = V4L2_ENC_SLICE_LENGTH_TYPE_BITS;
00378 break;
00379 default:
00380 CSV_PARSE_CHECK_ERROR(true,
00381 "Unsupported value for slice length type: " << *argp);
00382 }
00383 }
00384 else if (!strcmp(arg, "-slen"))
00385 {
00386 argp++;
00387 CHECK_OPTION_VALUE(argp);
00388 ctx->slice_length = (uint32_t) atoi(*argp);
00389 CSV_PARSE_CHECK_ERROR(ctx->slice_length == 0,
00390 "Slice length should be > 0");
00391 }
00392 else if (!strcmp(arg, "-vbs"))
00393 {
00394 argp++;
00395 CHECK_OPTION_VALUE(argp);
00396 ctx->virtual_buffer_size = (uint32_t) atoi(*argp);
00397 CSV_PARSE_CHECK_ERROR(ctx->virtual_buffer_size == 0,
00398 "Virtual buffer size should be > 0");
00399 }
00400 else if (!strcmp(arg, "-nbf"))
00401 {
00402 argp++;
00403 CHECK_OPTION_VALUE(argp);
00404 ctx->num_b_frames = (uint32_t) atoi(*argp);
00405 }
00406 else if (!strcmp(arg, "-nrf"))
00407 {
00408 argp++;
00409 CHECK_OPTION_VALUE(argp);
00410 ctx->num_reference_frames = (uint32_t) atoi(*argp);
00411 CSV_PARSE_CHECK_ERROR(ctx->num_reference_frames == 0,
00412 "Num reference frames should be > 0");
00413 }
00414 else if (!strcmp(arg, "-sir"))
00415 {
00416 argp++;
00417 CHECK_OPTION_VALUE(argp);
00418 ctx->slice_intrarefresh_interval = (uint32_t) atoi(*argp);
00419 CSV_PARSE_CHECK_ERROR(ctx->slice_intrarefresh_interval == 0,
00420 "Slice intrarefresh interval should be > 0");
00421 }
00422 else if (!strcmp(arg, "-MinQpI"))
00423 {
00424 argp++;
00425 CHECK_OPTION_VALUE(argp);
00426 ctx->nMinQpI = atoi(*argp);
00427 CSV_PARSE_CHECK_ERROR(ctx->nMinQpI < 0, "Min Qp should be >= 0");
00428 }
00429 else if (!strcmp(arg, "-MaxQpI"))
00430 {
00431 argp++;
00432 CHECK_OPTION_VALUE(argp);
00433 ctx->nMaxQpI = atoi(*argp);
00434 CSV_PARSE_CHECK_ERROR(ctx->nMaxQpI > 51, "Max Qp should be <= 51");
00435 }
00436 else if (!strcmp(arg, "-MinQpP"))
00437 {
00438 argp++;
00439 CHECK_OPTION_VALUE(argp);
00440 ctx->nMinQpP = atoi(*argp);
00441 CSV_PARSE_CHECK_ERROR(ctx->nMinQpP < 0, "Min Qp should be >= 0");
00442 }
00443 else if (!strcmp(arg, "-MaxQpP"))
00444 {
00445 argp++;
00446 CHECK_OPTION_VALUE(argp);
00447 ctx->nMaxQpP = atoi(*argp);
00448 CSV_PARSE_CHECK_ERROR(ctx->nMaxQpP > 51, "Max Qp should be <= 51");
00449 }
00450 else if (!strcmp(arg, "-MinQpB"))
00451 {
00452 argp++;
00453 CHECK_OPTION_VALUE(argp);
00454 ctx->nMinQpB = atoi(*argp);
00455 CSV_PARSE_CHECK_ERROR(ctx->nMinQpB < 0, "Min Qp should be >= 0");
00456 }
00457 else if (!strcmp(arg, "-MaxQpB"))
00458 {
00459 argp++;
00460 CHECK_OPTION_VALUE(argp);
00461 ctx->nMaxQpB = atoi(*argp);
00462 CSV_PARSE_CHECK_ERROR(ctx->nMaxQpB > 51, "Max Qp should be <= 51");
00463 }
00464 else if (!strcmp(arg, "--report-metadata"))
00465 {
00466 ctx->report_metadata = true;
00467 }
00468 else if (!strcmp(arg, "--mvdump"))
00469 {
00470 ctx->dump_mv = true;
00471 }
00472 else
00473 {
00474 CSV_PARSE_CHECK_ERROR(ctx->out_file_path, "Unknown option " << arg);
00475 }
00476 }
00477
00478 return 0;
00479
00480 error:
00481 print_help();
00482 return -1;
00483 }