mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-30 20:54:07 +00:00
y4m start header parsing ready
This commit is contained in:
parent
c10b841e7c
commit
cbcee67821
15
src/cfg.c
15
src/cfg.c
|
@ -163,6 +163,8 @@ int kvz_config_init(kvz_config *cfg)
|
||||||
cfg->intra_bit_allocation = false;
|
cfg->intra_bit_allocation = false;
|
||||||
cfg->clip_neighbour = true;
|
cfg->clip_neighbour = true;
|
||||||
|
|
||||||
|
cfg->file_format = KVZ_FORMAT_AUTO;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,8 +450,10 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
|
||||||
static const char * const scaling_list_names[] = { "off", "custom", "default", NULL };
|
static const char * const scaling_list_names[] = { "off", "custom", "default", NULL };
|
||||||
|
|
||||||
static const char * const rc_algorithm_names[] = { "no-rc", "lambda", "oba", NULL };
|
static const char * const rc_algorithm_names[] = { "no-rc", "lambda", "oba", NULL };
|
||||||
static const char * const preset_values[11][25*2] = {
|
|
||||||
|
|
||||||
|
static const char * const file_format_names[] = {"y4m", NULL};
|
||||||
|
|
||||||
|
static const char * const preset_values[11][25*2] = {
|
||||||
{
|
{
|
||||||
"ultrafast",
|
"ultrafast",
|
||||||
"rd", "0",
|
"rd", "0",
|
||||||
|
@ -1359,6 +1363,15 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
|
||||||
else if OPT("clip-neighbour") {
|
else if OPT("clip-neighbour") {
|
||||||
cfg->clip_neighbour = atobool(value);
|
cfg->clip_neighbour = atobool(value);
|
||||||
}
|
}
|
||||||
|
else if OPT("input-file-format") {
|
||||||
|
int8_t file_format = 0;
|
||||||
|
if (!parse_enum(value, file_format_names, &file_format)) {
|
||||||
|
fprintf(stderr, "Invalid input file format %s. Valid values include %s\n", value,
|
||||||
|
file_format_names[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cfg->file_format = file_format;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
31
src/cli.c
31
src/cli.c
|
@ -149,6 +149,7 @@ static const struct option long_options[] = {
|
||||||
{ "no-intra-bits", no_argument, NULL, 0 },
|
{ "no-intra-bits", no_argument, NULL, 0 },
|
||||||
{ "clip-neighbour", no_argument, NULL, 0 },
|
{ "clip-neighbour", no_argument, NULL, 0 },
|
||||||
{ "no-clip-neighbour", no_argument, NULL, 0 },
|
{ "no-clip-neighbour", no_argument, NULL, 0 },
|
||||||
|
{ "input-file-format", required_argument, NULL, 0 },
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -184,6 +185,26 @@ static int select_input_res_auto(const char *file_name, int32_t *out_width, int3
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Try to detect file format from file name automatically
|
||||||
|
*
|
||||||
|
* \param file_name file name to get format from
|
||||||
|
* \return 0 (auto) if no format is detected, or id of the format
|
||||||
|
*/
|
||||||
|
static int detect_file_format(const char *file_name) {
|
||||||
|
if (!file_name) return 0;
|
||||||
|
|
||||||
|
// Find the last delimiter char ( / or \ ). Hope the other kind is not used in the name.
|
||||||
|
// If delim is not found, set pointer to the beginning.
|
||||||
|
unsigned char* sub_str = (unsigned char*)strrchr(file_name, '.');
|
||||||
|
if (!sub_str) return 0;
|
||||||
|
|
||||||
|
// KVZ_FILE_FORMAT
|
||||||
|
if (strcmp(sub_str, ".y4m") == 0) return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Parse command line arguments.
|
* \brief Parse command line arguments.
|
||||||
* \param argc Number of arguments
|
* \param argc Number of arguments
|
||||||
|
@ -289,8 +310,13 @@ cmdline_opts_t* cmdline_opts_parse(const kvz_api *const api, int argc, char *arg
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the file name for format
|
||||||
|
if (opts->config->file_format == KVZ_FORMAT_AUTO) {
|
||||||
|
opts->config->file_format = detect_file_format(opts->input);
|
||||||
|
}
|
||||||
|
|
||||||
// Set resolution automatically if necessary
|
// Set resolution automatically if necessary
|
||||||
if (opts->config->width == 0 && opts->config->height == 0) {
|
if (opts->config->file_format == KVZ_FORMAT_AUTO && opts->config->width == 0 && opts->config->height == 0) {
|
||||||
ok = select_input_res_auto(opts->input, &opts->config->width, &opts->config->height);
|
ok = select_input_res_auto(opts->input, &opts->config->width, &opts->config->height);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -370,6 +396,9 @@ void print_help(void)
|
||||||
" --input-format <string> : P420 or P400 [P420]\n"
|
" --input-format <string> : P420 or P400 [P420]\n"
|
||||||
" --input-bitdepth <int> : 8-16 [8]\n"
|
" --input-bitdepth <int> : 8-16 [8]\n"
|
||||||
" --loop-input : Re-read input file forever.\n"
|
" --loop-input : Re-read input file forever.\n"
|
||||||
|
" --input-file-format <string> : Input file format if other than RAW [auto]\n"
|
||||||
|
" - auto: Check the file ending for format\n"
|
||||||
|
" - y4m\n"
|
||||||
"\n"
|
"\n"
|
||||||
/* Word wrap to this width to stay under 80 characters (including ") *************/
|
/* Word wrap to this width to stay under 80 characters (including ") *************/
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
|
|
|
@ -310,6 +310,92 @@ static double calc_avg_qp(uint64_t qp_sum, uint32_t frames_done)
|
||||||
return (double)qp_sum / (double)frames_done;
|
return (double)qp_sum / (double)frames_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Reads the information in y4m header
|
||||||
|
*
|
||||||
|
* \param input Pointer to the input file
|
||||||
|
* \param config Pointer to the config struct
|
||||||
|
*/
|
||||||
|
static bool read_header(FILE* input, kvz_config* config) {
|
||||||
|
char buffer[256];
|
||||||
|
bool end_of_header = false;
|
||||||
|
|
||||||
|
while(!end_of_header) {
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
buffer[i] = getc(input);
|
||||||
|
// Start code of frame data
|
||||||
|
if (buffer[i] == 0x0A) {
|
||||||
|
for (; i > 0; i--) {
|
||||||
|
ungetc(buffer[i], input);
|
||||||
|
}
|
||||||
|
end_of_header = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Header sections are separated by space (ascii 0x20)
|
||||||
|
if (buffer[i] == 0x20) {
|
||||||
|
// Header start sequence does not hold any addition information, so it can be skipped
|
||||||
|
if ((i == 9) && strncmp(buffer, "YUV4MPEG2 ", 10) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (buffer[0]) {
|
||||||
|
// Width
|
||||||
|
case 'W':
|
||||||
|
// Exclude starting 'W' and the space at the end with substr
|
||||||
|
config->width = atoi(&buffer[1]);
|
||||||
|
break;
|
||||||
|
// Height
|
||||||
|
case 'H':
|
||||||
|
// Exclude starting 'H' and the space at the end with substr
|
||||||
|
config->height = atoi(&buffer[1]);
|
||||||
|
break;
|
||||||
|
// Framerate (or start code of frame)
|
||||||
|
case 'F':
|
||||||
|
// The header has no ending signature other than the start code of a frame
|
||||||
|
if (i > 5 && strncmp(buffer, "FRAME", 5) == 0) {
|
||||||
|
for (; i > 0; i--) {
|
||||||
|
ungetc(buffer[i], input);
|
||||||
|
}
|
||||||
|
end_of_header = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
config->framerate_num = atoi(&buffer[1]);
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
if (buffer[j] == ':') {
|
||||||
|
config->framerate_denom = atoi(&buffer[j + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Interlacing
|
||||||
|
case 'I':
|
||||||
|
break;
|
||||||
|
// Aspect ratio
|
||||||
|
case 'A':
|
||||||
|
break;
|
||||||
|
// Colour space
|
||||||
|
case 'C':
|
||||||
|
break;
|
||||||
|
// Comment
|
||||||
|
case 'X':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown header argument starting with '%i'\n", buffer[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->width == 0 || config->height == 0 || config->framerate_num == 0 || config->framerate_denom == 0) {
|
||||||
|
fprintf(stderr, "Failed to read necessary info from y4m headers. Width, height and frame rate must be present in the headers.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Program main function.
|
* \brief Program main function.
|
||||||
* \param argc Argument count from commandline
|
* \param argc Argument count from commandline
|
||||||
|
@ -409,6 +495,13 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse headers if input data is in y4m container
|
||||||
|
if (opts->config->file_format == KVZ_FORMAT_Y4M) {
|
||||||
|
if (!read_header(input, opts->config)) {
|
||||||
|
goto exit_failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enc = api->encoder_open(opts->config);
|
enc = api->encoder_open(opts->config);
|
||||||
if (!enc) {
|
if (!enc) {
|
||||||
fprintf(stderr, "Failed to open encoder.\n");
|
fprintf(stderr, "Failed to open encoder.\n");
|
||||||
|
|
|
@ -227,6 +227,14 @@ enum kvz_rc_algorithm
|
||||||
KVZ_LAMBDA = 1,
|
KVZ_LAMBDA = 1,
|
||||||
KVZ_OBA = 2,
|
KVZ_OBA = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum kvz_file_format
|
||||||
|
{
|
||||||
|
KVZ_FORMAT_AUTO = 0,
|
||||||
|
KVZ_FORMAT_Y4M = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Map from input format to chroma format.
|
// Map from input format to chroma format.
|
||||||
#define KVZ_FORMAT2CSP(format) ((enum kvz_chroma_format)"\0\1\2\3"[format])
|
#define KVZ_FORMAT2CSP(format) ((enum kvz_chroma_format)"\0\1\2\3"[format])
|
||||||
|
|
||||||
|
@ -437,6 +445,8 @@ typedef struct kvz_config
|
||||||
uint8_t intra_bit_allocation;
|
uint8_t intra_bit_allocation;
|
||||||
|
|
||||||
uint8_t clip_neighbour;
|
uint8_t clip_neighbour;
|
||||||
|
|
||||||
|
enum kvz_file_format file_format;
|
||||||
} kvz_config;
|
} kvz_config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue