mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-23 18:14:06 +00:00
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:
parent
238b1bbcff
commit
ad11d1bca5
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -91,6 +91,7 @@ OBJS = \
|
|||
filter.o \
|
||||
inter.o \
|
||||
intra.o \
|
||||
kvazaar.o \
|
||||
nal.o \
|
||||
imagelist.o \
|
||||
rdo.o \
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
130
src/kvazaar.c
Normal 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
106
src/kvazaar.h
Normal 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
26
src/kvazaar_version.h
Normal 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_
|
Loading…
Reference in a new issue