mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-27 11:24:05 +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->clip_neighbour = true;
|
||||
|
||||
cfg->file_format = KVZ_FORMAT_AUTO;
|
||||
|
||||
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 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",
|
||||
"rd", "0",
|
||||
|
@ -1359,6 +1363,15 @@ int kvz_config_parse(kvz_config *cfg, const char *name, const char *value)
|
|||
else if OPT("clip-neighbour") {
|
||||
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 {
|
||||
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 },
|
||||
{ "clip-neighbour", no_argument, NULL, 0 },
|
||||
{ "no-clip-neighbour", no_argument, NULL, 0 },
|
||||
{ "input-file-format", required_argument, NULL, 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \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.
|
||||
* \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;
|
||||
}
|
||||
|
||||
// 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
|
||||
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);
|
||||
goto done;
|
||||
}
|
||||
|
@ -370,6 +396,9 @@ void print_help(void)
|
|||
" --input-format <string> : P420 or P400 [P420]\n"
|
||||
" --input-bitdepth <int> : 8-16 [8]\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"
|
||||
/* Word wrap to this width to stay under 80 characters (including ") *************/
|
||||
"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;
|
||||
}
|
||||
|
||||
/**
|
||||
* \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.
|
||||
* \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);
|
||||
if (!enc) {
|
||||
fprintf(stderr, "Failed to open encoder.\n");
|
||||
|
|
|
@ -227,6 +227,14 @@ enum kvz_rc_algorithm
|
|||
KVZ_LAMBDA = 1,
|
||||
KVZ_OBA = 2,
|
||||
};
|
||||
|
||||
enum kvz_file_format
|
||||
{
|
||||
KVZ_FORMAT_AUTO = 0,
|
||||
KVZ_FORMAT_Y4M = 1
|
||||
};
|
||||
|
||||
|
||||
// Map from input format to chroma 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 clip_neighbour;
|
||||
|
||||
enum kvz_file_format file_format;
|
||||
} kvz_config;
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue