Fix issues with file creation

Not all of the frames were even fetched from Kvazaar after encoding!
This commit fixes this issue.

Also the Kvazaar structures were not freed, now they are.
This commit is contained in:
Joni Räsänen 2021-11-21 09:08:37 +02:00
parent ee19be93dd
commit c93b988bed
2 changed files with 110 additions and 88 deletions

View File

@ -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;

View File

@ -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;
}