258 lines
7.4 KiB
C++
258 lines
7.4 KiB
C++
#include <kvazaar.h>
|
|
|
|
#include "util.hh"
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
int kvazaar_encode(const std::string& input, const std::string& output, const std::string& memory_filename,
|
|
int width, int height, int qp, int fps, int period, std::string& preset);
|
|
|
|
bool encode_frame(kvz_picture* input, int& rvalue, std::ofstream& outputFile, std::ofstream& memoryFile,
|
|
const kvz_api* api, kvz_encoder* enc);
|
|
void cleanup_kvazaar(kvz_picture* input, const kvz_api* api, kvz_encoder* enc, kvz_config* config);
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
if (argc != 8) {
|
|
fprintf(stderr, "usage: ./%s <filename> <width> <height> <qp> <fps> <period> <preset>\n", __FILE__);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
std::string input_file = argv[1];
|
|
std::string output_file = argv[1];
|
|
|
|
// remove any possible file extensions and add hevc
|
|
size_t lastindex = input_file.find_last_of(".");
|
|
if (lastindex != std::string::npos)
|
|
{
|
|
output_file = input_file.substr(0, lastindex);
|
|
}
|
|
|
|
// add hevc file ending
|
|
output_file = output_file + ".hevc";
|
|
|
|
if (input_file == output_file)
|
|
{
|
|
output_file = "out_" + output_file;
|
|
}
|
|
|
|
std::string mem_file = get_chunk_filename(output_file);
|
|
|
|
int width = atoi(argv[2]);
|
|
int height = atoi(argv[3]);
|
|
|
|
int qp = atoi(argv[4]);
|
|
int fps = atoi(argv[5]);
|
|
int intra_period = atoi(argv[6]);
|
|
|
|
std::string preset = argv[7];
|
|
|
|
if (!width || !height || !qp || !fps || !intra_period || preset == "")
|
|
{
|
|
std::cerr << "Invalid command line arguments" << std::endl;
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
return kvazaar_encode(input_file, output_file, mem_file, width, height, qp, fps, intra_period, preset);
|
|
}
|
|
|
|
int kvazaar_encode(const std::string& input, const std::string& output, const std::string& memory_filename,
|
|
int width, int height, int qp, int fps, int period, std::string& preset)
|
|
{
|
|
std::cout << "Opening files. Input: " << input << " Output: " << output << std::endl;
|
|
std::cout << "Parameters. Res: " << width << "x" << height << " fps: " << fps << " qp: " << qp << std::endl;
|
|
|
|
std::ifstream inputFile (input, std::ios::in | std::ios::binary);
|
|
std::ofstream outputFile(output, std::ios::out | std::ios::binary);
|
|
std::ofstream memoryFile(memory_filename, std::ios::out | std::ios::binary);
|
|
|
|
if (!inputFile.good())
|
|
{
|
|
if (inputFile.eof())
|
|
{
|
|
std::cerr << "Input eof before starting" << std::endl;
|
|
}
|
|
else if (inputFile.bad())
|
|
{
|
|
std::cerr << "Input bad before starting" << std::endl;
|
|
}
|
|
else if (inputFile.fail())
|
|
{
|
|
std::cerr << "Input fail before starting" << std::endl;
|
|
}
|
|
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (!outputFile.good() || !memoryFile.good())
|
|
{
|
|
if (outputFile.eof() || memoryFile.eof())
|
|
{
|
|
std::cerr << "Output eof before starting" << std::endl;
|
|
}
|
|
else if (outputFile.bad() || memoryFile.bad())
|
|
{
|
|
std::cerr << "Output bad before starting" << std::endl;
|
|
}
|
|
else if (outputFile.fail() || memoryFile.fail())
|
|
{
|
|
std::cerr << "Output fail before starting" << std::endl;
|
|
}
|
|
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
kvz_encoder* enc = NULL;
|
|
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());
|
|
config->width = width;
|
|
config->height = height;
|
|
config->hash = kvz_hash::KVZ_HASH_NONE;
|
|
config->intra_period = period;
|
|
config->qp = qp;
|
|
config->framerate_num = fps;
|
|
config->framerate_denom = 1;
|
|
|
|
enc = api->encoder_open(config);
|
|
kvz_picture* img_in = api->picture_alloc(width, height);
|
|
|
|
if (!enc || !img_in) {
|
|
std::cerr << "Failed to open kvazaar encoder!" << std::endl;
|
|
inputFile.close();
|
|
outputFile.close();
|
|
memoryFile.close();
|
|
cleanup_kvazaar(img_in, api, enc, config);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
int frame_count = 1;
|
|
bool input_has_been_read = false;
|
|
|
|
while (!input_has_been_read) {
|
|
|
|
if (!inputFile.read((char*)img_in->y, width * height) ||
|
|
!inputFile.read((char*)img_in->u, width * height/4) ||
|
|
!inputFile.read((char*)img_in->v, width * height/4)) {
|
|
|
|
if (inputFile.eof())
|
|
{
|
|
std::cout << "End of input file reached" << std::endl;
|
|
}
|
|
else if (inputFile.bad())
|
|
{
|
|
std::cerr << "Input bad" << std::endl;
|
|
}
|
|
else if (inputFile.fail())
|
|
{
|
|
std::cerr << "Input fails" << std::endl;
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "Unknown Input error" << std::endl;
|
|
}
|
|
|
|
input_has_been_read = true;
|
|
inputFile.close();
|
|
continue;
|
|
}
|
|
|
|
std::cout << "Start encoding frame " << frame_count << std::endl;
|
|
++frame_count;
|
|
|
|
// feed input to kvazaar and write output to file
|
|
int rvalue = EXIT_FAILURE;
|
|
if (!encode_frame(img_in, rvalue, outputFile, memoryFile, api, enc))
|
|
{
|
|
// if encoding fails
|
|
outputFile.close();
|
|
memoryFile.close();
|
|
cleanup_kvazaar(img_in, api, enc, config);
|
|
return rvalue;
|
|
}
|
|
}
|
|
|
|
// write the rest of the frames that are being encoded to file
|
|
int rvalue = EXIT_FAILURE;
|
|
while (encode_frame(nullptr, rvalue, outputFile, memoryFile, api, enc));
|
|
|
|
memoryFile.close();
|
|
outputFile.close();
|
|
cleanup_kvazaar(img_in, api, enc, config);
|
|
return rvalue;
|
|
}
|
|
|
|
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, std::ofstream& outputFile, std::ofstream& memoryFile,
|
|
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;
|
|
memoryFile.write((char*)(&written), sizeof(uint64_t));
|
|
|
|
// write the chunks into the file
|
|
for (kvz_data_chunk* chunk = chunks_out; chunk != nullptr; chunk = chunk->next) {
|
|
|
|
outputFile.write((char*)(chunk->data), chunk->len);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
} |