Add kvazaar.h to hold high-level encoder API.

- Move encoder initialization from main to kvazaar.c.
- Have main use the API for initialization.

Conflicts:
	src/encmain.c
This commit is contained in:
Ari Koivula 2015-05-18 11:43:10 +03:00 committed by Arttu Ylä-Outinen
parent 238b1bbcff
commit ad11d1bca5
8 changed files with 306 additions and 47 deletions

View file

@ -125,6 +125,7 @@
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kvazaar.c" />
<ClCompile Include="..\..\src\bitstream.c" />
<ClCompile Include="..\..\src\cabac.c" />
<ClCompile Include="..\..\src\cli.c" />
@ -205,6 +206,8 @@
<ClInclude Include="..\..\src\global.h" />
<ClInclude Include="..\..\src\inter.h" />
<ClInclude Include="..\..\src\intra.h" />
<ClInclude Include="..\..\src\kvazaar.h" />
<ClInclude Include="..\..\src\kvazaar_version.h" />
<ClInclude Include="..\..\src\nal.h" />
<ClInclude Include="..\..\src\rate_control.h" />
<ClInclude Include="..\..\src\rdo.h" />

View file

@ -189,6 +189,9 @@
<ClCompile Include="..\..\src\cli.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kvazaar.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\rate_control.c">
<Filter>Source Files</Filter>
</ClCompile>
@ -335,6 +338,12 @@
<ClInclude Include="..\..\src\cli.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kvazaar.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kvazaar_version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\rate_control.h">
<Filter>Header Files</Filter>
</ClInclude>

View file

@ -91,6 +91,7 @@ OBJS = \
filter.o \
inter.o \
intra.o \
kvazaar.o \
nal.o \
imagelist.o \
rdo.o \

View file

@ -43,7 +43,7 @@ typedef struct {
/*!
\brief Struct which contains all configuration data
*/
typedef struct
typedef struct config_t
{
char *input; /*!< \brief Pointer to input filename */
char *output; /*!< \brief Pointer to output filename */

View file

@ -47,6 +47,7 @@
#include "scalinglist.h"
#include "strategyselector.h"
#include "cli.h"
#include "kvazaar.h"
/**
@ -60,7 +61,6 @@ int main(int argc, char *argv[])
config_t *cfg = NULL; //!< Global configuration
FILE *input = NULL; //!< input file (YUV)
FILE *output = NULL; //!< output file (HEVC NAL stream)
encoder_control_t encoder;
uint64_t curpos = 0;
FILE *recout = NULL; //!< reconstructed YUV output, --debug
clock_t start_time = clock();
@ -139,48 +139,33 @@ int main(int argc, char *argv[])
goto exit_failure;
}
if (!encoder_control_init(&encoder, cfg)) {
const kvz_api *api = kvz_api_get(8);
kvz_encoder* enc = api->encoder_open(cfg);
if (!enc) {
fprintf(stderr, "Failed to open encoder.");
goto exit_failure;
}
for (unsigned i = 0; i <= cfg->owf; ++i) {
enc->states[i].stream.file.output = output;
}
encoder_control_t *encoder = enc->control;
fprintf(stderr, "Input: %s, output: %s\n", cfg->input, cfg->output);
fprintf(stderr, " Video size: %dx%d (input=%dx%d)\n",
encoder.in.width, encoder.in.height,
encoder.in.real_width, encoder.in.real_height);
encoder->in.width, encoder->in.height,
encoder->in.real_width, encoder->in.real_height);
//Now, do the real stuff
{
encoder_state_t *encoder_states = malloc((encoder.owf + 1) * sizeof(encoder_state_t));
if (encoder_states == NULL) {
fprintf(stderr, "Failed to allocate memory.");
goto exit_failure;
}
int i;
int current_encoder_state = 0;
for (i = 0; i <= encoder.owf; ++i) {
encoder_states[i].encoder_control = &encoder;
if (i > 0) {
encoder_states[i].previous_encoder_state = &encoder_states[i-1];
} else {
//i == 0, use last encoder as the previous one
encoder_states[i].previous_encoder_state = &encoder_states[encoder.owf];
}
if (!encoder_state_init(&encoder_states[i], NULL)) {
goto exit_failure;
}
encoder_states[i].stream.file.output = output;
encoder_states[i].global->QP = (int8_t)encoder.cfg->qp;
}
for (i = 0; i <= encoder.owf; ++i) {
encoder_state_match_children_of_previous_frame(&encoder_states[i]);
}
//Initial frame
encoder_states[current_encoder_state].global->frame = -1;
// Skip '--seek' frames before input.
if (cfg->seek > 0) {
int frame_bytes = cfg->width * cfg->height * 3 / 2;
int error = 0;
@ -189,7 +174,7 @@ int main(int argc, char *argv[])
// Input is stdin.
int i;
for (i = 0; !error && i < cfg->seek; ++i) {
error = !read_one_frame(input, &encoder_states[current_encoder_state]);
error = !read_one_frame(input, &enc->states[current_encoder_state]);
}
} else {
// input is a file. We hope. Proper detection is OS dependent.
@ -211,13 +196,13 @@ int main(int argc, char *argv[])
// Start coding cycle while data on input and not on the last frame
while (cfg->frames == 0 || frames_started < cfg->frames) {
encoder_state_t *state = &encoder_states[current_encoder_state];
encoder_state_t *state = &enc->states[current_encoder_state];
// If we have started as many frames as we are going to encode in parallel, wait for the first one we started encoding to finish before
// encoding more.
if (frames_started > cfg->owf) {
double frame_psnr[3] = { 0.0, 0.0, 0.0 };
encoder_compute_stats(&encoder_states[current_encoder_state], recout, frame_psnr, &bitstream_length);
encoder_compute_stats(&enc->states[current_encoder_state], recout, frame_psnr, &bitstream_length);
frames_done += 1;
psnr_sum[0] += frame_psnr[0];
psnr_sum[1] += frame_psnr[1];
@ -228,25 +213,25 @@ int main(int argc, char *argv[])
frames_started += 1;
//Clear encoder
encoder_next_frame(&encoder_states[current_encoder_state]);
encoder_next_frame(&enc->states[current_encoder_state]);
CHECKPOINT_MARK("read source frame: %d", encoder_states[current_encoder_state].global->frame + cfg->seek);
// Read one frame from the input
if (!read_one_frame(input, &encoder_states[current_encoder_state])) {
if (!read_one_frame(input, &enc->states[current_encoder_state])) {
if (!feof(input))
fprintf(stderr, "Failed to read a frame %d\n", encoder_states[current_encoder_state].global->frame);
fprintf(stderr, "Failed to read a frame %d\n", enc->states[current_encoder_state].global->frame);
//Ignore this frame, which is not valid...
encoder_states[current_encoder_state].stats_done = 1;
enc->states[current_encoder_state].stats_done = 1;
break;
}
// The actual coding happens here, after this function we have a coded frame
encode_one_frame(&encoder_states[current_encoder_state]);
encode_one_frame(&enc->states[current_encoder_state]);
//Switch to the next encoder
current_encoder_state = (current_encoder_state + 1) % (encoder.owf + 1);
current_encoder_state = (current_encoder_state + 1) % (encoder->owf + 1);
}
//Compute stats for the remaining encoders
@ -254,7 +239,7 @@ int main(int argc, char *argv[])
int first_enc = current_encoder_state;
do {
double frame_psnr[3] = { 0.0, 0.0, 0.0 };
encoder_state_t *state = &encoder_states[current_encoder_state];
encoder_state_t *state = &enc->states[current_encoder_state];
if (!state->stats_done) {
encoder_compute_stats(state, recout, frame_psnr, &bitstream_length);
@ -265,14 +250,14 @@ int main(int argc, char *argv[])
psnr_sum[2] += frame_psnr[2];
}
current_encoder_state = (current_encoder_state + 1) % (encoder.owf + 1);
current_encoder_state = (current_encoder_state + 1) % (encoder->owf + 1);
} while (current_encoder_state != first_enc);
}
GET_TIME(&encoding_end_real_time);
encoding_end_cpu_time = clock();
threadqueue_flush(encoder.threadqueue);
threadqueue_flush(encoder->threadqueue);
// Coding finished
@ -297,16 +282,15 @@ int main(int argc, char *argv[])
fclose(output);
if(recout != NULL) fclose(recout);
for (i = 0; i <= encoder.owf; ++i) {
encoder_state_finalize(&encoder_states[i]);
for (i = 0; i <= encoder->owf; ++i) {
encoder_state_finalize(&enc->states[i]);
}
free(encoder_states);
api->encoder_close(enc);
}
// Deallocating
config_destroy(cfg);
encoder_control_finalize(&encoder);
free_exp_golomb();

130
src/kvazaar.c Normal file
View file

@ -0,0 +1,130 @@
/*****************************************************************************
* This file is part of Kvazaar HEVC encoder.
*
* Copyright (C) 2013-2015 Tampere University of Technology and others (see
* COPYING file).
*
* Kvazaar is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* Kvazaar is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with Kvazaar. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "kvazaar.h"
#include <stdlib.h>
#include "config.h"
#include "encoder.h"
#include "strategyselector.h"
#include "encoderstate.h"
static void kvazaar_close(kvz_encoder *encoder)
{
if (encoder) {
if (encoder->control) {
encoder_control_finalize(encoder->control);
}
FREE_POINTER(encoder->control);
FREE_POINTER(encoder->states);
}
FREE_POINTER(encoder);
}
static kvz_encoder * kvazaar_open(config_t *cfg)
{
kvz_encoder *encoder = NULL;
//Initialize strategies
// TODO: Make strategies non-global
if (!strategyselector_init(cfg->cpuid)) {
fprintf(stderr, "Failed to initialize strategies.\n");
goto kvazaar_open_failure;
}
//Allocate and init exp golomb table
if (!init_exp_golomb(4096 * 8)) {
fprintf(stderr, "Failed to allocate the exp golomb code table, shutting down!\n");
goto kvazaar_open_failure;
}
encoder = MALLOC(kvz_encoder, 1);
if (!encoder) {
goto kvazaar_open_failure;
}
encoder->control = MALLOC(encoder_control_t, 1);
if (!encoder->control || !encoder_control_init(encoder->control, cfg)) {
goto kvazaar_open_failure;
}
encoder->num_encoder_states = cfg->owf + 1;
encoder->cur_state_num = 0;
encoder->states = MALLOC(encoder_state_t, encoder->num_encoder_states);
if (!encoder->states) {
goto kvazaar_open_failure;
}
for (unsigned i = 0; i <= cfg->owf; ++i) {
encoder->states[i].encoder_control = encoder->control;
if (!encoder_state_init(&encoder->states[i], NULL)) {
goto kvazaar_open_failure;
}
encoder->states[i].global->QP = (int8_t)cfg->qp;
}
for (int i = 0; i <= cfg->owf; ++i) {
if (i == 0) {
encoder->states[i].previous_encoder_state = &encoder->states[encoder->num_encoder_states - 1];
} else {
encoder->states[i].previous_encoder_state = &encoder->states[(i - 1) % encoder->num_encoder_states];
}
encoder_state_match_children_of_previous_frame(&encoder->states[i]);
}
encoder->states[encoder->cur_state_num].global->frame = -1;
return encoder;
kvazaar_open_failure:
kvazaar_close(encoder);
return NULL;
}
static int kvazaar_encode(kvz_encoder *encoder, kvz_picture *pic_in, kvz_picture *pic_out, kvz_payload **payload)
{
return 0;
}
kvz_api kvz_8bit_api = {
.config_alloc = config_alloc,
.config_init = config_init,
.config_read = config_read,
.config_destroy = config_destroy,
.picture_create = NULL,
.picture_destroy = NULL,
.encoder_open = kvazaar_open,
.encoder_close = kvazaar_close,
.encoder_encode = kvazaar_encode,
};
const kvz_api * kvz_api_get(int bit_depth)
{
return &kvz_8bit_api;
}

106
src/kvazaar.h Normal file
View file

@ -0,0 +1,106 @@
#ifndef KVAZAAR_H_
#define KVAZAAR_H_
/*****************************************************************************
* This file is part of Kvazaar HEVC encoder.
*
* Copyright (C) 2013-2015 Tampere University of Technology and others (see
* COPYING file).
*
* Kvazaar is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* Kvazaar is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with Kvazaar. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
/**
* \file
* \brief This file defines the public API of Kvazaar when used as a library.
*/
#include <stddef.h>
#include <stdint.h>
#include "kvazaar_version.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct config_t kvz_cfg;
typedef struct encoder_state_t encoder_state_t;
typedef struct kvz_payload kvz_payload;
typedef struct encoder_control_t encoder_control_t;
/**
* A payload unit containing at most a single frame.
* If next is not NULL, the bytestream continues in that payload unit.
*/
typedef struct kvz_payload {
uint32_t type;
uint32_t size_bytes;
uint8_t *payload;
kvz_payload *next;
} kvz_payload;
typedef struct kvz_picture {
void* planes[3];
uint32_t stride[3];
uint8_t bit_depth;
uint8_t poc;
} kvz_picture;
/**
* Main datastructure representing one instance of the encoder.
* - encoder_open
* - encoder_close
*/
typedef struct kvz_encoder {
encoder_control_t* control;
encoder_state_t* states;
int num_encoder_states;
int cur_state_num;
size_t bitstream_length;
} kvz_encoder;
typedef struct kvz_api {
kvz_cfg * (*config_alloc)(void);
int (*config_destroy)(kvz_cfg *);
int (*config_init)(kvz_cfg *);
int (*config_read)(kvz_cfg *, int argc, char *argv[]);
kvz_picture * (*picture_create)(void);
void (*picture_destroy)(kvz_picture *);
kvz_encoder * (*encoder_open)(kvz_cfg *);
void (*encoder_close)(kvz_encoder *);
// \brief Encode one picture.
// \param encoder
// \param pic_in Picture containing the encoded data.
// \param pic_out Picture containing the reconstructed data.
// \param nals_out The first NAL containing bitstream generated, or NULL.
// \return 1 on success, negative on error.
int (*encoder_encode)(kvz_encoder *encoder, kvz_picture *pic_in, kvz_picture *pic_out, kvz_payload **payload);
} kvz_api;
// Append API version to the getters name to prevent linking against incompatible versions.
#define KVZ_API_CONCAT(func, version) func ## _apiv ## version
#define KVZ_API_EXPAND_VERSION(func, version) KVZ_API_CONCAT(func, version)
#define kvz_api_get KVZ_API_EXPAND_VERSION(kvz_api_get, KVZ_API_VERSION)
const kvz_api* kvz_api_get(int bit_depth);
#ifdef __cplusplus
}
#endif
#endif // KVAZAAR_H_

26
src/kvazaar_version.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef KVAZAAR_VERSION_H_
#define KVAZAAR_VERSION_H_
/*****************************************************************************
* This file is part of Kvazaar HEVC encoder.
*
* Copyright (C) 2013-2015 Tampere University of Technology and others (see
* COPYING file).
*
* Kvazaar is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* Kvazaar is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with Kvazaar. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
// KVZ_API_VERSION is incremented every time the public api changes.
#define KVZ_API_VERSION 1
#endif // KVAZAAR_VERSION_H_