diff --git a/create.pl b/create.pl index ea72a93..42c1fb3 100755 --- a/create.pl +++ b/create.pl @@ -18,16 +18,16 @@ sub print_help { } GetOptions( - "input|i=s" => \(my $filename = ""), - "resolution|res=s" => \(my $resolution = "3840x2160"), - "quantization|qp=i" => \(my $qp = 32), - "framerate|fps=i" => \(my $fps = 30), - "intra-period|intra=i" => \(my $period = 64), - "preset|pre=s" => \(my $preset = "ultrafast"), - "help" => \(my $help = 0) + "input|file|filename|i=s" => \(my $filename = ""), + "resolution|res=s" => \(my $resolution = "3840x2160"), + "quantization|qp=i" => \(my $qp = 32), + "framerate|fps=i" => \(my $fps = 30), + "intra-period|intra=i" => \(my $period = 64), + "preset|pre=s" => \(my $preset = "ultrafast"), + "help" => \(my $help = 0) ) or die "failed to parse command line!\n"; -print_help() if $help or !$filename or !$resolution; +print_help() if $help or !$filename; # check that parameters make sense die "" if $help; diff --git a/util/test_file_creation.cc b/util/test_file_creation.cc index c05c97a..0a2f15d 100644 --- a/util/test_file_creation.cc +++ b/util/test_file_creation.cc @@ -11,7 +11,10 @@ int kvazaar_encode(const std::string& input, const std::string& output, int width, int height, int qp, int fps, int period, std::string& preset); -void cleanup(FILE* inputFile, FILE* outputFile); +bool encode_frame(kvz_picture* input, int& rvalue, FILE* outputFile, const kvz_api* api, kvz_encoder* enc); + +void cleanup_files(FILE* inputFile, FILE* outputFile); +void cleanup_kvazaar(kvz_picture* input, const kvz_api* api, kvz_encoder* enc, kvz_config* config); int main(int argc, char** argv) { @@ -67,12 +70,12 @@ int kvazaar_encode(const std::string& input, const std::string& output, if (inputFile == NULL || outputFile == NULL) { std::cerr << "Failed to open input or output file!" << std::endl; - cleanup(inputFile, outputFile); + cleanup_files(inputFile, outputFile); return EXIT_FAILURE; } kvz_encoder* enc = NULL; - const kvz_api* const api = kvz_api_get(8); + const kvz_api* api = kvz_api_get(8); kvz_config* config = api->config_alloc(); api->config_init(config); api->config_parse(config, "preset", preset.c_str()); @@ -85,101 +88,51 @@ int kvazaar_encode(const std::string& input, const std::string& output, config->framerate_denom = 1; enc = api->encoder_open(config); - if (!enc) { + kvz_picture* img_in = api->picture_alloc(width, height); + + if (!enc || !img_in) { std::cerr << "Failed to open kvazaar encoder!" << std::endl; - cleanup(inputFile, outputFile); + cleanup_files(inputFile, outputFile); + cleanup_kvazaar(img_in, api, enc, config); return EXIT_FAILURE; } - kvz_picture* img_in[16]; - for (uint32_t i = 0; i < 16; ++i) { - img_in[i] = api->picture_alloc_csp(KVZ_CSP_420, width, height); - } - - uint8_t inputCounter = 0; - uint8_t outputCounter = 0; int frame_count = 1; - bool done = false; - /* int r = 0; */ + bool input_has_been_read = false; - std::cout << "Start creating the HEVC benchmark file from " << input << std::endl; + while (!input_has_been_read) { - while (!done) { - kvz_data_chunk* chunks_out = NULL; - kvz_picture* img_rec = NULL; - kvz_picture* img_src = NULL; - uint32_t len_out = 0; - kvz_frame_info info_out; + if (fread(img_in->y, width * height, 1, inputFile) == 0 || + fread(img_in->u, width * height >> 2, 1, inputFile) == 0 || + fread(img_in->v, width * height >> 2, 1, inputFile) == 0) { + std::cout << "Cannot read more values from file" << std::endl; + input_has_been_read = true; + continue; + } std::cout << "Start encoding frame " << frame_count << std::endl; ++frame_count; - if (fread(img_in[inputCounter]->y, width * height, 1, inputFile) == 0) { - std::cout << "Cannot read y values size " << (width * height) << std::endl; - done = true; - continue; - } - if (fread(img_in[inputCounter]->u, width * height >> 2, 1, inputFile) == 0) { - std::cout << "Cannot read u values size " << (width * height >> 2) << std::endl; - done = true; - continue; - } - if (fread(img_in[inputCounter]->v, width * height >> 2, 1, inputFile) == 0) { - std::cout << "Cannot read v values size " << (width * height >> 2) << std::endl; - done = true; - continue; - } - - if (!api->encoder_encode(enc, - img_in[inputCounter], - &chunks_out, &len_out, &img_rec, &img_src, &info_out)) + // feed input to kvazaar and write output to file + int rvalue = EXIT_FAILURE; + if (!encode_frame(img_in, rvalue, outputFile, api, enc)) { - fprintf(stderr, "Failed to encode image.\n"); - for (uint32_t i = 0; i < 16; i++) { - api->picture_free(img_in[i]); - } - cleanup(inputFile, outputFile); - return EXIT_FAILURE; - } - inputCounter = (inputCounter + 1) % 16; - - - if (chunks_out == NULL && img_in == NULL) { - // We are done since there is no more input and output left. - cleanup(inputFile, outputFile); - std::cout << "No more input or output. Finished creating the HEVC benchmark file to " << output << std::endl; - return EXIT_SUCCESS; - } - - if (chunks_out != NULL) { - uint64_t written = 0; - - // Write data into the output file. - for (kvz_data_chunk* chunk = chunks_out; chunk != NULL; chunk = chunk->next) { - written += chunk->len; - } - - fprintf(stderr, "write chunk size: %lu\n", written); - fwrite(&written, sizeof(uint64_t), 1, outputFile); - for (kvz_data_chunk* chunk = chunks_out; chunk != NULL; chunk = chunk->next) { - fwrite(chunk->data, chunk->len, 1, outputFile); - } - - outputCounter = (outputCounter + 1) % 16; - - /* if (++r > 5) */ - /* goto cleanup; */ + cleanup_files(inputFile, outputFile); + cleanup_kvazaar(img_in, api, enc, config); + return rvalue; } } - std::cout << "Finished creating the HEVC benchmark file to " << output << std::endl; + // write the rest of the frames that are being encoded to file + int rvalue = EXIT_FAILURE; + while (encode_frame(nullptr, rvalue, outputFile, api, enc)); - cleanup(inputFile, outputFile); - - return EXIT_SUCCESS; + cleanup_files(inputFile, outputFile); + cleanup_kvazaar(img_in, api, enc, config); + return rvalue; } -void cleanup(FILE* inputFile, FILE* outputFile) +void cleanup_files(FILE* inputFile, FILE* outputFile) { if (inputFile) { @@ -190,4 +143,73 @@ void cleanup(FILE* inputFile, FILE* outputFile) { fclose(outputFile); } +} + +void cleanup_kvazaar(kvz_picture* input, const kvz_api* api, kvz_encoder* enc, kvz_config* config) +{ + if (api) + { + if (enc) + { + api->encoder_close(enc); + } + + if (config) + { + api->config_destroy(config); + } + + if (input) + { + api->picture_free(input); + } + } +} + + +bool encode_frame(kvz_picture* input, int& rvalue, FILE* outputFile, const kvz_api* api, kvz_encoder* enc) +{ + kvz_picture* img_rec = nullptr; + kvz_picture* img_src = nullptr; + uint32_t len_out = 0; + kvz_frame_info info_out; + kvz_data_chunk* chunks_out = nullptr; + + if (!api->encoder_encode(enc, input, &chunks_out, &len_out, &img_rec, &img_src, &info_out)) + { + fprintf(stderr, "Failed to encode image.\n"); + for (uint32_t i = 0; i < 16; i++) { + api->picture_free(input); + } + rvalue = EXIT_FAILURE; + return false; + } + + if (chunks_out == nullptr && input == nullptr) { + // We are done since there is no more input or output left. + rvalue = EXIT_SUCCESS; + return false; + } + + if (chunks_out != NULL) { + uint64_t written = 0; + + // Calculate the total size of the chunks + for (kvz_data_chunk* chunk = chunks_out; chunk != nullptr; chunk = chunk->next) { + written += chunk->len; + } + + std::cout << "Write the size of the chunk: " << written << std::endl; + + // write the size of the chunks into the file also. This makes the files unusable for normal + // viewing. It would be better to write the sizes to a separate file + fwrite(&written, sizeof(uint64_t), 1, outputFile); + + // write the chunks into the file + for (kvz_data_chunk* chunk = chunks_out; chunk != nullptr; chunk = chunk->next) { + fwrite(chunk->data, chunk->len, 1, outputFile); + } + } + + return true; } \ No newline at end of file