mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-27 19:24:06 +00:00
Make kvazaar_encode consume one frame on each call.
- Replaces read_one_frame by encoder_feed_frame. - Adds field "prepared" to encoderstate_t to indicate that encoder_next_frame has been called. - Input frames are read in the main function and passed to encoder_encode.
This commit is contained in:
parent
012c0580df
commit
7e20e62cc7
|
@ -172,46 +172,52 @@ int main(int argc, char *argv[])
|
||||||
encoding_start_cpu_time = clock();
|
encoding_start_cpu_time = clock();
|
||||||
|
|
||||||
uint64_t bitstream_length = 0;
|
uint64_t bitstream_length = 0;
|
||||||
uint32_t frames_started = 0;
|
uint32_t frames_read = 0;
|
||||||
uint32_t frames_done = 0;
|
uint32_t frames_done = 0;
|
||||||
double psnr_sum[3] = { 0.0, 0.0, 0.0 };
|
double psnr_sum[3] = { 0.0, 0.0, 0.0 };
|
||||||
|
|
||||||
// Start coding cycle while data on input and not on the last frame
|
for (;;) {
|
||||||
while (cfg->frames == 0 || frames_started < cfg->frames) {
|
|
||||||
encoder_state_t *state = &enc->states[enc->cur_state_num];
|
encoder_state_t *state = &enc->states[enc->cur_state_num];
|
||||||
|
|
||||||
frames_started += 1;
|
image_t *img_in = NULL;
|
||||||
|
if (!feof(input) && (cfg->frames == 0 || frames_read < cfg->frames)) {
|
||||||
|
// Try to read an input frame.
|
||||||
|
img_in = image_alloc(encoder->in.width, encoder->in.height);
|
||||||
|
if (!img_in) {
|
||||||
|
fprintf(stderr, "Failed to allocate image.\n");
|
||||||
|
goto exit_failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yuv_io_read(input, cfg->width, cfg->height, img_in)) {
|
||||||
image_t *img_in = image_alloc(state->tile->frame->width, state->tile->frame->height);
|
frames_read += 1;
|
||||||
if (!img_in) {
|
} else {
|
||||||
fprintf(stderr, "Failed to allocate image.\n");
|
// EOF or some error
|
||||||
goto exit_failure;
|
image_free(img_in);
|
||||||
}
|
img_in = NULL;
|
||||||
|
if (!feof(input)) {
|
||||||
// Clear the encoder state.
|
fprintf(stderr, "Failed to read a frame %d\n", frames_read);
|
||||||
encoder_next_frame(state, img_in);
|
goto exit_failure;
|
||||||
|
}
|
||||||
// Read one frame from the input
|
}
|
||||||
if (!read_one_frame(input, &enc->states[enc->cur_state_num], img_in)) {
|
|
||||||
if (!feof(input))
|
|
||||||
fprintf(stderr, "Failed to read a frame %d\n", enc->states[enc->cur_state_num].global->frame);
|
|
||||||
image_free(img_in);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
image_t *img_out = NULL;
|
image_t *img_out = NULL;
|
||||||
if (1 != api->encoder_encode(enc, img_in, &img_out, &output_stream)) {
|
if (!api->encoder_encode(enc, img_in, &img_out, &output_stream)) {
|
||||||
fprintf(stderr, "Failed to encode image.\n");
|
fprintf(stderr, "Failed to encode image.\n");
|
||||||
image_free(img_in);
|
image_free(img_in);
|
||||||
goto exit_failure;
|
goto exit_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (img_out == NULL && img_in == NULL) {
|
||||||
|
// We are done since there is no more input and output left.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (img_out != NULL) {
|
if (img_out != NULL) {
|
||||||
state = &enc->states[enc->cur_state_num];
|
state = &enc->states[enc->cur_state_num];
|
||||||
double frame_psnr[3] = { 0.0, 0.0, 0.0 };
|
double frame_psnr[3] = { 0.0, 0.0, 0.0 };
|
||||||
encoder_compute_stats(state, recout, frame_psnr, &bitstream_length);
|
encoder_compute_stats(state, recout, frame_psnr, &bitstream_length);
|
||||||
|
|
||||||
frames_done += 1;
|
frames_done += 1;
|
||||||
psnr_sum[0] += frame_psnr[0];
|
psnr_sum[0] += frame_psnr[0];
|
||||||
psnr_sum[1] += frame_psnr[1];
|
psnr_sum[1] += frame_psnr[1];
|
||||||
|
@ -223,28 +229,7 @@ int main(int argc, char *argv[])
|
||||||
image_free(img_in);
|
image_free(img_in);
|
||||||
image_free(img_out);
|
image_free(img_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Compute stats for the remaining encoders
|
|
||||||
{
|
|
||||||
image_t *img_out = NULL;
|
|
||||||
while (1 == api->encoder_encode(enc, NULL, &img_out, &output_stream)) {
|
|
||||||
if (img_out != NULL) {
|
|
||||||
double frame_psnr[3] = { 0.0, 0.0, 0.0 };
|
|
||||||
encoder_state_t *state = &enc->states[enc->cur_state_num];
|
|
||||||
|
|
||||||
encoder_compute_stats(state, recout, frame_psnr, &bitstream_length);
|
|
||||||
print_frame_info(state, frame_psnr);
|
|
||||||
frames_done += 1;
|
|
||||||
psnr_sum[0] += frame_psnr[0];
|
|
||||||
psnr_sum[1] += frame_psnr[1];
|
|
||||||
psnr_sum[2] += frame_psnr[2];
|
|
||||||
|
|
||||||
image_free(img_out);
|
|
||||||
img_out = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GET_TIME(&encoding_end_real_time);
|
GET_TIME(&encoding_end_real_time);
|
||||||
encoding_end_cpu_time = clock();
|
encoding_end_cpu_time = clock();
|
||||||
|
|
||||||
|
|
|
@ -285,6 +285,7 @@ int encoder_state_init(encoder_state_t * const child_state, encoder_state_t * co
|
||||||
child_state->children[0].encoder_control = NULL;
|
child_state->children[0].encoder_control = NULL;
|
||||||
child_state->tqj_bitstream_written = NULL;
|
child_state->tqj_bitstream_written = NULL;
|
||||||
child_state->tqj_recon_done = NULL;
|
child_state->tqj_recon_done = NULL;
|
||||||
|
child_state->prepared = 0;
|
||||||
child_state->frame_done = 1;
|
child_state->frame_done = 1;
|
||||||
|
|
||||||
if (!parent_state) {
|
if (!parent_state) {
|
||||||
|
|
|
@ -860,84 +860,97 @@ void encode_one_frame(encoder_state_t * const state)
|
||||||
//threadqueue_flush(main_state->encoder_control->threadqueue);
|
//threadqueue_flush(main_state->encoder_control->threadqueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_one_frame(FILE* file, const encoder_state_t * const state, image_t *img_out)
|
/**
|
||||||
|
* \brief Pass an input frame to the encoder state.
|
||||||
|
*
|
||||||
|
* Sets the source image of the encoder state if there is a suitable image
|
||||||
|
* available.
|
||||||
|
*
|
||||||
|
* The caller must not modify img_in after calling this function.
|
||||||
|
*
|
||||||
|
* \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 encoder_feed_frame(encoder_state_t* const state, image_t* const img_in)
|
||||||
{
|
{
|
||||||
unsigned width = state->encoder_control->in.real_width;
|
const encoder_control_t* const encoder = state->encoder_control;
|
||||||
unsigned height = state->encoder_control->in.real_height;
|
const config_t* const cfg = encoder->cfg;
|
||||||
unsigned array_width = state->tile->frame->width;
|
|
||||||
unsigned array_height = state->tile->frame->height;
|
|
||||||
|
|
||||||
// storing GOP pictures
|
// TODO: Get rid of static variables.
|
||||||
static int8_t gop_init = 0;
|
static image_t *gop_buffer[2 * MAX_GOP] = { NULL };
|
||||||
static int8_t gop_pictures_available = 0;
|
static int gop_buf_write_idx = 0;
|
||||||
static videoframe_t gop_pictures[MAX_GOP];
|
static int gop_buf_read_idx = 0;
|
||||||
static int8_t gop_skip_frames = 0;
|
static int gop_pictures_available = 0;
|
||||||
static int8_t gop_skipped = 0;
|
static int gop_offset = 0;
|
||||||
|
|
||||||
// Initialize GOP structure when gop is enabled and not initialized
|
const int gop_buf_size = 2 * cfg->gop_len;
|
||||||
if (state->encoder_control->cfg->gop_len && !gop_init) {
|
|
||||||
int i;
|
assert(state->global->frame >= 0);
|
||||||
for (i = 0; i < state->encoder_control->cfg->gop_len; i++) {
|
assert(state->tile->frame->source == NULL);
|
||||||
gop_pictures[i].source = image_alloc(array_width, array_height);
|
|
||||||
assert(gop_pictures[i].source);
|
if (cfg->gop_len == 0 || state->global->frame == 0) {
|
||||||
}
|
if (img_in == NULL) return 0;
|
||||||
|
state->tile->frame->source = image_copy_ref(img_in);
|
||||||
state->global->gop_offset = 0;
|
state->global->gop_offset = 0;
|
||||||
gop_init = 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
// GOP enabled and not the first frame
|
||||||
|
|
||||||
// If GOP is present but no pictures found
|
if (img_in != NULL) {
|
||||||
if (state->global->frame &&
|
// Save the input image in the buffer.
|
||||||
state->encoder_control->cfg->gop_len &&
|
assert(gop_pictures_available < gop_buf_size);
|
||||||
!gop_pictures_available) {
|
assert(gop_buffer[gop_buf_write_idx] == NULL);
|
||||||
for (int i = 0; i < state->encoder_control->cfg->gop_len; i++, gop_pictures_available++) {
|
gop_buffer[gop_buf_write_idx] = image_copy_ref(img_in);
|
||||||
if (state->encoder_control->cfg->frames
|
|
||||||
&& state->global->frame + gop_pictures_available >= state->encoder_control->cfg->frames) {
|
++gop_pictures_available;
|
||||||
if (gop_pictures_available) {
|
if (++gop_buf_write_idx >= gop_buf_size) {
|
||||||
gop_skip_frames = state->encoder_control->cfg->gop_len - gop_pictures_available;
|
gop_buf_write_idx = 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
else return 0;
|
|
||||||
}
|
|
||||||
if (!yuv_io_read(file, width, height, gop_pictures[i].source)) {
|
|
||||||
if (gop_pictures_available) {
|
|
||||||
gop_skip_frames = state->encoder_control->cfg->gop_len - gop_pictures_available;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If GOP is present, fetch the data from our GOP picture buffer
|
if (gop_pictures_available < cfg->gop_len) {
|
||||||
if (state->global->frame && state->encoder_control->cfg->gop_len) {
|
if (img_in != NULL || gop_pictures_available == 0) {
|
||||||
int cur_gop_idx = state->encoder_control->cfg->gop_len - (gop_pictures_available + gop_skip_frames) + gop_skipped;
|
// Either start of the sequence with no full GOP available yet, or the
|
||||||
int cur_gop = state->encoder_control->cfg->gop[cur_gop_idx].poc_offset - 1;
|
// end of the sequence with all pics encoded.
|
||||||
// Special case when end of the sequence and not all pictures are available
|
return 0;
|
||||||
if (gop_skip_frames && cur_gop >= state->encoder_control->cfg->gop_len - gop_skip_frames) {
|
}
|
||||||
for (; cur_gop >= state->encoder_control->cfg->gop_len - gop_skip_frames; cur_gop_idx++) {
|
// End of the sequence and a full GOP is not available.
|
||||||
cur_gop = state->encoder_control->cfg->gop[cur_gop_idx].poc_offset - 1;
|
// Skip pictures until an available one is found.
|
||||||
gop_skipped++;
|
for (; gop_offset < cfg->gop_len &&
|
||||||
}
|
cfg->gop[gop_offset].poc_offset - 1 >= gop_pictures_available;
|
||||||
cur_gop_idx--;
|
++gop_offset);
|
||||||
gop_skipped--;
|
|
||||||
|
if (gop_offset >= cfg->gop_len) {
|
||||||
|
// All available pictures used.
|
||||||
|
gop_offset = 0;
|
||||||
|
gop_pictures_available = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
state->global->gop_offset = cur_gop_idx;
|
|
||||||
memcpy(img_out->y, gop_pictures[cur_gop].source->y, width * height);
|
|
||||||
memcpy(img_out->u, gop_pictures[cur_gop].source->u, (width >> 1) * (height >> 1));
|
|
||||||
memcpy(img_out->v, gop_pictures[cur_gop].source->v, (width >> 1) * (height >> 1));
|
|
||||||
gop_pictures_available--;
|
|
||||||
} else {
|
|
||||||
return yuv_io_read(file, width, height, img_out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
assert(state->tile->frame->source == NULL);
|
||||||
|
state->tile->frame->source = gop_buffer[buffer_index];
|
||||||
|
gop_buffer[buffer_index] = NULL;
|
||||||
|
|
||||||
|
state->global->gop_offset = 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;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void encoder_compute_stats(encoder_state_t *state, FILE * const recout, double frame_psnr[3], uint64_t *bitstream_length)
|
void encoder_compute_stats(encoder_state_t *state, FILE * const recout, double frame_psnr[3], uint64_t *bitstream_length)
|
||||||
{
|
{
|
||||||
const encoder_control_t * const encoder = state->encoder_control;
|
const encoder_control_t * const encoder = state->encoder_control;
|
||||||
|
|
||||||
//Blocking call
|
//Blocking call
|
||||||
threadqueue_waitfor(encoder->threadqueue, state->tqj_bitstream_written);
|
threadqueue_waitfor(encoder->threadqueue, state->tqj_bitstream_written);
|
||||||
|
|
||||||
|
@ -953,24 +966,21 @@ void encoder_compute_stats(encoder_state_t *state, FILE * const recout, double f
|
||||||
*bitstream_length += state->stats_bitstream_length;
|
*bitstream_length += state->stats_bitstream_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void encoder_next_frame(encoder_state_t *state, image_t *img_in)
|
void encoder_next_frame(encoder_state_t *state)
|
||||||
{
|
{
|
||||||
const encoder_control_t * const encoder = state->encoder_control;
|
const encoder_control_t * const encoder = state->encoder_control;
|
||||||
//Blocking call
|
//Blocking call
|
||||||
threadqueue_waitfor(encoder->threadqueue, state->tqj_bitstream_written);
|
threadqueue_waitfor(encoder->threadqueue, state->tqj_bitstream_written);
|
||||||
|
|
||||||
if (state->tile->frame->source) {
|
|
||||||
image_free(state->tile->frame->source);
|
|
||||||
}
|
|
||||||
state->tile->frame->source = image_copy_ref(img_in);
|
|
||||||
|
|
||||||
if (state->global->frame == -1) {
|
if (state->global->frame == -1) {
|
||||||
//We're at the first frame, so don't care about all this stuff;
|
//We're at the first frame, so don't care about all this stuff;
|
||||||
state->global->frame = 0;
|
state->global->frame = 0;
|
||||||
state->global->poc = 0;
|
state->global->poc = 0;
|
||||||
|
assert(!state->tile->frame->source);
|
||||||
assert(!state->tile->frame->rec);
|
assert(!state->tile->frame->rec);
|
||||||
state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height);
|
state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height);
|
||||||
assert(state->tile->frame->rec);
|
assert(state->tile->frame->rec);
|
||||||
|
state->prepared = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -981,9 +991,10 @@ void encoder_next_frame(encoder_state_t *state, image_t *img_in)
|
||||||
state->global->frame = prev_state->global->frame + 1;
|
state->global->frame = prev_state->global->frame + 1;
|
||||||
state->global->poc = prev_state->global->poc + 1;
|
state->global->poc = prev_state->global->poc + 1;
|
||||||
|
|
||||||
image_free(state->tile->frame->rec);
|
|
||||||
cu_array_free(state->tile->frame->cu_array);
|
cu_array_free(state->tile->frame->cu_array);
|
||||||
|
image_free(state->tile->frame->source);
|
||||||
|
state->tile->frame->source = NULL;
|
||||||
|
image_free(state->tile->frame->rec);
|
||||||
state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height);
|
state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height);
|
||||||
assert(state->tile->frame->rec);
|
assert(state->tile->frame->rec);
|
||||||
{
|
{
|
||||||
|
@ -1003,6 +1014,7 @@ void encoder_next_frame(encoder_state_t *state, image_t *img_in)
|
||||||
prev_state->global->poc);
|
prev_state->global->poc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state->prepared = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1021,12 +1033,17 @@ void encoder_next_frame(encoder_state_t *state, image_t *img_in)
|
||||||
state->global->frame++;
|
state->global->frame++;
|
||||||
state->global->poc++;
|
state->global->poc++;
|
||||||
|
|
||||||
//Remove current reconstructed picture, and alloc a new one
|
// Remove current source picture.
|
||||||
|
image_free(state->tile->frame->source);
|
||||||
|
state->tile->frame->source = NULL;
|
||||||
|
|
||||||
|
// Remove current reconstructed picture, and alloc a new one
|
||||||
image_free(state->tile->frame->rec);
|
image_free(state->tile->frame->rec);
|
||||||
|
|
||||||
state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height);
|
state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height);
|
||||||
assert(state->tile->frame->rec);
|
assert(state->tile->frame->rec);
|
||||||
videoframe_set_poc(state->tile->frame, state->global->poc);
|
videoframe_set_poc(state->tile->frame, state->global->poc);
|
||||||
|
state->prepared = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -184,6 +184,12 @@ typedef struct encoder_state_t {
|
||||||
bitstream_t stream;
|
bitstream_t stream;
|
||||||
cabac_data_t cabac;
|
cabac_data_t cabac;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Indicates that this encoder state is ready for encoding the
|
||||||
|
* next frame i.e. encoder_next_frame has been called.
|
||||||
|
*/
|
||||||
|
int prepared;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Indicates that the previous frame has been encoded and the
|
* \brief Indicates that the previous frame has been encoded and the
|
||||||
* encoded data written and the encoding the next frame has not been
|
* encoded data written and the encoding the next frame has not been
|
||||||
|
@ -201,10 +207,10 @@ typedef struct encoder_state_t {
|
||||||
|
|
||||||
|
|
||||||
void encode_one_frame(encoder_state_t *state);
|
void encode_one_frame(encoder_state_t *state);
|
||||||
int read_one_frame(FILE* file, const encoder_state_t *state, image_t *img_out);
|
int encoder_feed_frame(encoder_state_t* const state, image_t* const img_in);
|
||||||
|
|
||||||
void encoder_compute_stats(encoder_state_t *state, FILE * const recout, double psnr[3], uint64_t *bitstream_length);
|
void encoder_compute_stats(encoder_state_t *state, FILE * const recout, double psnr[3], uint64_t *bitstream_length);
|
||||||
void encoder_next_frame(encoder_state_t *state, image_t *img_in);
|
void encoder_next_frame(encoder_state_t *state);
|
||||||
|
|
||||||
|
|
||||||
void encode_coding_tree(encoder_state_t *state, uint16_t x_ctb,
|
void encode_coding_tree(encoder_state_t *state, uint16_t x_ctb,
|
||||||
|
|
|
@ -111,29 +111,38 @@ kvazaar_open_failure:
|
||||||
|
|
||||||
static int kvazaar_encode(kvz_encoder *enc, kvz_picture *img_in, kvz_picture **img_out, kvz_payload *payload)
|
static int kvazaar_encode(kvz_encoder *enc, kvz_picture *img_in, kvz_picture **img_out, kvz_payload *payload)
|
||||||
{
|
{
|
||||||
// If img_in is NULL, just return the next unfinished frame.
|
*img_out = NULL;
|
||||||
|
|
||||||
|
encoder_state_t *state = &enc->states[enc->cur_state_num];
|
||||||
|
|
||||||
|
if (!state->prepared) {
|
||||||
|
encoder_next_frame(state);
|
||||||
|
}
|
||||||
|
|
||||||
if (img_in != NULL) {
|
if (img_in != NULL) {
|
||||||
encoder_state_t *state = &enc->states[enc->cur_state_num];
|
// FIXME: The frame number printed here is wrong when GOP is enabled.
|
||||||
|
|
||||||
enc->frames_started += 1;
|
|
||||||
|
|
||||||
CHECKPOINT_MARK("read source frame: %d", state->global->frame + enc->control->cfg->seek);
|
CHECKPOINT_MARK("read source frame: %d", state->global->frame + enc->control->cfg->seek);
|
||||||
|
}
|
||||||
|
|
||||||
// The actual coding happens here, after this function we have a coded frame
|
if (encoder_feed_frame(state, img_in)) {
|
||||||
|
assert(state->global->frame == enc->frames_started);
|
||||||
|
// Start encoding.
|
||||||
encode_one_frame(state);
|
encode_one_frame(state);
|
||||||
|
enc->frames_started += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have finished encoding as many frames as we have started, we are done.
|
// If we have finished encoding as many frames as we have started, we are done.
|
||||||
if (enc->frames_done == enc->frames_started) {
|
if (enc->frames_done == enc->frames_started) {
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move to the next encoder state.
|
||||||
enc->cur_state_num = (enc->cur_state_num + 1) % (enc->num_encoder_states);
|
enc->cur_state_num = (enc->cur_state_num + 1) % (enc->num_encoder_states);
|
||||||
encoder_state_t *state = &enc->states[enc->cur_state_num];
|
state = &enc->states[enc->cur_state_num];
|
||||||
|
|
||||||
if (enc->frames_started >= enc->num_encoder_states && !state->frame_done) {
|
if (!state->frame_done) {
|
||||||
threadqueue_waitfor(enc->control->threadqueue, state->tqj_bitstream_written);
|
threadqueue_waitfor(enc->control->threadqueue, state->tqj_bitstream_written);
|
||||||
|
|
||||||
bitstream_append(payload, &state->stream);
|
bitstream_append(payload, &state->stream);
|
||||||
|
|
||||||
// Flush the output in case someone is reading the file on the other end.
|
// Flush the output in case someone is reading the file on the other end.
|
||||||
|
@ -143,8 +152,9 @@ static int kvazaar_encode(kvz_encoder *enc, kvz_picture *img_in, kvz_picture **i
|
||||||
|
|
||||||
*img_out = image_copy_ref(state->tile->frame->rec);
|
*img_out = image_copy_ref(state->tile->frame->rec);
|
||||||
|
|
||||||
enc->frames_done += 1;
|
|
||||||
state->frame_done = 1;
|
state->frame_done = 1;
|
||||||
|
state->prepared = 0;
|
||||||
|
enc->frames_done += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -97,11 +97,11 @@ typedef struct kvz_api {
|
||||||
void (*encoder_close)(kvz_encoder *);
|
void (*encoder_close)(kvz_encoder *);
|
||||||
|
|
||||||
// \brief Encode one picture.
|
// \brief Encode one picture.
|
||||||
// \param encoder
|
// \param encoder Encoder
|
||||||
// \param pic_in Picture containing the encoded data.
|
// \param pic_in Input frame
|
||||||
// \param pic_out Picture containing the reconstructed data.
|
// \param pic_out Returns the reconstructed picture.
|
||||||
// \param nals_out The first NAL containing bitstream generated, or NULL.
|
// \param payload Bitstream for writing the encoded data
|
||||||
// \return 1 on success, negative on error.
|
// \return 1 on success, 0 on error.
|
||||||
int (*encoder_encode)(kvz_encoder *encoder, kvz_picture *pic_in, kvz_picture **pic_out, kvz_payload *payload);
|
int (*encoder_encode)(kvz_encoder *encoder, kvz_picture *pic_in, kvz_picture **pic_out, kvz_payload *payload);
|
||||||
} kvz_api;
|
} kvz_api;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue