Remove static variables from kvz_encoder_feed_frame.

Adds struct input_frame_buffer_t for storing the input buffer state.
This commit is contained in:
Arttu Ylä-Outinen 2015-09-08 08:52:23 +03:00
parent 1d2a398197
commit 25c23aa298
4 changed files with 71 additions and 34 deletions

View file

@ -26,6 +26,15 @@
#include "encoderstate.h"
#include <assert.h>
void kvz_init_input_frame_buffer(input_frame_buffer_t *input_buffer)
{
FILL(input_buffer->pic_buffer, 0);
input_buffer->pictures_available = 0;
input_buffer->write_idx = 0;
input_buffer->read_idx = 0;
input_buffer->gop_offset = 0;
}
/**
* \brief Pass an input frame to the encoder state.
*
@ -34,22 +43,18 @@
*
* The caller must not modify img_in after calling this function.
*
* \param buf an input frame buffer
* \param state a main encoder state
* \param img_in input frame or NULL
* \return 1 if the source image was set, 0 if not
*/
int kvz_encoder_feed_frame(encoder_state_t *const state, kvz_picture *const img_in)
int kvz_encoder_feed_frame(input_frame_buffer_t *buf,
encoder_state_t *const state,
kvz_picture *const img_in)
{
const encoder_control_t* const encoder = state->encoder_control;
const kvz_config* const cfg = encoder->cfg;
// TODO: Get rid of static variables.
static kvz_picture *gop_buffer[2 * KVZ_MAX_GOP_LENGTH] = { NULL };
static int gop_buf_write_idx = 0;
static int gop_buf_read_idx = 0;
static int gop_pictures_available = 0;
static int gop_offset = 0;
const int gop_buf_size = 2 * cfg->gop_len;
assert(state->global->frame >= 0);
@ -66,50 +71,52 @@ int kvz_encoder_feed_frame(encoder_state_t *const state, kvz_picture *const img_
if (img_in != NULL) {
// Save the input image in the buffer.
assert(gop_pictures_available < gop_buf_size);
assert(gop_buffer[gop_buf_write_idx] == NULL);
gop_buffer[gop_buf_write_idx] = kvz_image_copy_ref(img_in);
assert(buf->pictures_available < gop_buf_size);
assert(buf->pic_buffer[buf->write_idx] == NULL);
buf->pic_buffer[buf->write_idx] = kvz_image_copy_ref(img_in);
++gop_pictures_available;
if (++gop_buf_write_idx >= gop_buf_size) {
gop_buf_write_idx = 0;
buf->pictures_available++;
buf->write_idx++;
if (buf->write_idx >= gop_buf_size) {
buf->write_idx = 0;
}
}
if (gop_pictures_available < cfg->gop_len) {
if (img_in != NULL || gop_pictures_available == 0) {
if (buf->pictures_available < cfg->gop_len) {
if (img_in != NULL || buf->pictures_available == 0) {
// Either start of the sequence with no full GOP available yet, or the
// end of the sequence with all pics encoded.
return 0;
}
// End of the sequence and a full GOP is not available.
// Skip pictures until an available one is found.
for (; gop_offset < cfg->gop_len &&
cfg->gop[gop_offset].poc_offset - 1 >= gop_pictures_available;
++gop_offset);
for (; buf->gop_offset < cfg->gop_len &&
cfg->gop[buf->gop_offset].poc_offset - 1 >= buf->pictures_available;
buf->gop_offset++) {}
if (gop_offset >= cfg->gop_len) {
if (buf->gop_offset >= cfg->gop_len) {
// All available pictures used.
gop_offset = 0;
gop_pictures_available = 0;
buf->gop_offset = 0;
buf->pictures_available = 0;
return 0;
}
}
// Move image from buffer to state.
int buffer_index = gop_buf_read_idx + cfg->gop[gop_offset].poc_offset - 1;
assert(gop_buffer[buffer_index] != NULL);
int buffer_index = buf->read_idx + cfg->gop[buf->gop_offset].poc_offset - 1;
assert(buf->pic_buffer[buffer_index] != NULL);
assert(state->tile->frame->source == NULL);
state->tile->frame->source = gop_buffer[buffer_index];
state->tile->frame->rec->pts = gop_buffer[buffer_index]->pts;
gop_buffer[buffer_index] = NULL;
state->tile->frame->source = buf->pic_buffer[buffer_index];
state->tile->frame->rec->pts = buf->pic_buffer[buffer_index]->pts;
buf->pic_buffer[buffer_index] = NULL;
state->global->gop_offset = gop_offset;
state->global->gop_offset = buf->gop_offset;
if (++gop_offset >= cfg->gop_len) {
gop_offset = 0;
gop_pictures_available = MAX(0, gop_pictures_available - cfg->gop_len);
gop_buf_read_idx = (gop_buf_read_idx + cfg->gop_len) % gop_buf_size;
buf->gop_offset++;
if (buf->gop_offset >= cfg->gop_len) {
buf->gop_offset = 0;
buf->pictures_available = MAX(0, buf->pictures_available - cfg->gop_len);
buf->read_idx = (buf->read_idx + cfg->gop_len) % gop_buf_size;
}
return 1;

View file

@ -29,7 +29,28 @@
// Forward declaration.
struct encoder_state_t;
int kvz_encoder_feed_frame(struct encoder_state_t *const state,
typedef struct input_frame_buffer_t {
/** \brief An array for stroring the input frames. */
struct kvz_picture *pic_buffer[2 * KVZ_MAX_GOP_LENGTH];
/** \brief Number of pictures in the buffer. */
int pictures_available;
/** \brief Index where the next input frame is put to. */
int write_idx;
/** \brief Index of the first frame of the current GOP. */
int read_idx;
/** \brief Number of the next frame in the current GOP. */
int gop_offset;
} input_frame_buffer_t;
void kvz_init_input_frame_buffer(input_frame_buffer_t *input_buffer);
int kvz_encoder_feed_frame(input_frame_buffer_t *buf,
struct encoder_state_t *const state,
struct kvz_picture *const img_in);
#endif // INPUT_FRAME_BUFFER_H_

View file

@ -76,6 +76,9 @@ static kvz_encoder * kvazaar_open(const kvz_config *cfg)
encoder->out_state_num = 0;
encoder->frames_started = 0;
encoder->frames_done = 0;
kvz_init_input_frame_buffer(&encoder->input_buffer);
encoder->states = calloc(encoder->num_encoder_states, sizeof(encoder_state_t));
if (!encoder->states) {
goto kvazaar_open_failure;
@ -131,7 +134,7 @@ static int kvazaar_encode(kvz_encoder *enc,
CHECKPOINT_MARK("read source frame: %d", state->global->frame + enc->control->cfg->seek);
}
if (kvz_encoder_feed_frame(state, pic_in)) {
if (kvz_encoder_feed_frame(&enc->input_buffer, state, pic_in)) {
assert(state->global->frame == enc->frames_started);
// Start encoding.
kvz_encode_one_frame(state);

View file

@ -21,6 +21,7 @@
****************************************************************************/
#include "kvazaar.h"
#include "input_frame_buffer.h"
// Forward declarations.
struct encoder_state_t;
@ -44,6 +45,11 @@ struct kvz_encoder {
*/
unsigned out_state_num;
/**
* \brief Buffer for input frames.
*/
input_frame_buffer_t input_buffer;
unsigned frames_started;
unsigned frames_done;
};