uvg266/src/input_frame_buffer.c

217 lines
7.7 KiB
C
Raw Normal View History

/*****************************************************************************
2021-11-23 06:46:06 +00:00
* This file is part of uvg266 VVC encoder.
*
* Copyright (c) 2021, Tampere University, ITU/ISO/IEC, project contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* * Neither the name of the Tampere University or ITU/ISO/IEC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN ANY WAY OUT OF THE USE OF THIS
****************************************************************************/
#include "input_frame_buffer.h"
#include "encoder.h"
#include "encoderstate.h"
#include "image.h"
2022-04-28 11:18:09 +00:00
void uvg_init_input_frame_buffer(input_frame_buffer_t *input_buffer)
{
FILL(input_buffer->pic_buffer, 0);
FILL(input_buffer->pts_buffer, 0);
input_buffer->num_in = 0;
input_buffer->num_out = 0;
input_buffer->delay = 0;
input_buffer->gop_skipped = 0;
}
/**
* \brief Pass an input frame to the encoder state.
*
* Returns the image that should be encoded next if there is a suitable
* image available.
*
* 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
* \param first_done whether the first frame has been done,
* needed for the OBA rc
* \return pointer to the next picture, or NULL if no picture is
* available
*/
2022-04-28 11:18:09 +00:00
uvg_picture* uvg_encoder_feed_frame(input_frame_buffer_t *buf,
encoder_state_t *const state,
2022-04-28 11:18:09 +00:00
uvg_picture *const img_in,
int first_done)
{
const encoder_control_t* const encoder = state->encoder_control;
2022-04-28 11:18:09 +00:00
const uvg_config* const cfg = &encoder->cfg;
const int gop_buf_size = 3 * cfg->gop_len;
bool is_closed_gop = false;
// Check for closed gop, we need an extra frame in the buffer in this case
if (!cfg->open_gop && cfg->intra_period > 0 && cfg->gop_len > 0) is_closed_gop = true;
if (cfg->gop_len == 0 || cfg->gop_lowdelay) {
// No reordering of output pictures necessary.
if (img_in == NULL) return NULL;
img_in->dts = img_in->pts;
state->frame->gop_offset = 0;
if (cfg->gop_len > 0) {
// Using a low delay GOP structure.
uint64_t frame_num = buf->num_out;
if (cfg->intra_period) {
frame_num %= cfg->intra_period;
}
state->frame->gop_offset = (frame_num + cfg->gop_len - 1) % cfg->gop_len;
}
buf->num_in++;
buf->num_out++;
2022-04-28 11:18:09 +00:00
return uvg_image_copy_ref(img_in);
}
if (img_in != NULL) {
// Index of the next input picture, in range [-1, +inf). Values
// i and j refer to the same indices in buf->pic_buffer iff
// i === j (mod gop_buf_size).
int64_t idx_in = buf->num_in - 1;
// Index in buf->pic_buffer and buf->pts_buffer.
int buf_idx = (idx_in + gop_buf_size) % gop_buf_size;
// Save the input image in the buffer.
assert(buf_idx >= 0 && buf_idx < gop_buf_size);
assert(buf->pic_buffer[buf_idx] == NULL);
2022-04-28 11:18:09 +00:00
buf->pic_buffer[buf_idx] = uvg_image_copy_ref(img_in);
buf->pts_buffer[buf_idx] = img_in->pts;
buf->num_in++;
if (buf->num_in < cfg->gop_len + is_closed_gop ? 1 : 0) {
// Not enough frames to start output.
return 0;
} else if (buf->num_in == cfg->gop_len + is_closed_gop ? 1 : 0) {
// Now we known the PTSs that are needed to compute the delay.
buf->delay = buf->pts_buffer[gop_buf_size - 1] - img_in->pts;
}
}
if (buf->num_out == buf->num_in) {
// All frames returned.
return NULL;
}
if (img_in == NULL && buf->num_in < cfg->gop_len + is_closed_gop ? 1 : 0) {
// End of the sequence but we have less than a single GOP of frames. Use
// the difference between the PTSs of the first and the last frame as the
// delay.
int first_pic_idx = gop_buf_size - 1;
int last_pic_idx = (buf->num_in - 2 + gop_buf_size) % gop_buf_size;
buf->delay = buf->pts_buffer[first_pic_idx] - buf->pts_buffer[last_pic_idx];
}
// Index of the next output picture, in range [-1, +inf). Values
// i and j refer to the same indices in buf->pic_buffer iff
// i === j (mod gop_buf_size).
int64_t idx_out;
// DTS of the output picture.
int64_t dts_out;
// Number of the next output picture in the GOP.
int gop_offset;
if (buf->num_out == 0) {
// Output the first frame.
idx_out = -1;
dts_out = buf->pts_buffer[gop_buf_size - 1] + buf->delay;
gop_offset = 0; // highest quality picture
} else if(first_done) {
gop_offset = (buf->num_out - 1) % cfg->gop_len;
// For closed gop, calculate the gop_offset again
if (!cfg->open_gop && cfg->intra_period > 0) {
// Offset the GOP position for each extra I-frame added to the structure
// in closed gop case
int num_extra_frames = (buf->num_out - 1) / (cfg->intra_period + 1);
gop_offset = (buf->num_out - 1 - num_extra_frames) % cfg->gop_len;
}
// Index of the first picture in the GOP that is being output.
int gop_start_idx = buf->num_out - 1 - gop_offset;
// Skip pictures until we find an available one.
gop_offset += buf->gop_skipped;
// Every closed-gop IRAP handled here
if (is_closed_gop && (!cfg->open_gop && ((buf->num_out - 1) % (cfg->intra_period + 1)) == cfg->intra_period)) {
idx_out = gop_start_idx;
} else {
for (;;) {
assert(gop_offset < cfg->gop_len + is_closed_gop ? 1 : 0);
idx_out = gop_start_idx + cfg->gop[gop_offset].poc_offset - 1;
if (idx_out < buf->num_in - 1) {
// An available picture found.
break;
}
buf->gop_skipped++;
gop_offset++;
}
}
if (buf->num_out < cfg->gop_len - 1) {
// This picture needs a DTS that is less than the PTS of the first
// frame so the delay must be applied.
int dts_idx = buf->num_out - 1;
dts_out = buf->pts_buffer[dts_idx % gop_buf_size] + buf->delay;
} else {
int dts_idx = buf->num_out - (cfg->gop_len - 1);
dts_out = buf->pts_buffer[dts_idx % gop_buf_size] - 1;
}
}
else {
return NULL;
}
// Index in buf->pic_buffer and buf->pts_buffer.
int buf_idx = (idx_out + gop_buf_size) % gop_buf_size;
2022-04-28 11:18:09 +00:00
uvg_picture* next_pic = buf->pic_buffer[buf_idx];
assert(next_pic != NULL);
next_pic->dts = dts_out;
buf->pic_buffer[buf_idx] = NULL;
state->frame->gop_offset = gop_offset;
buf->num_out++;
return next_pic;
}