mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-24 02:24:07 +00:00
Works when not using tiles
This commit is contained in:
parent
24c2bd70ca
commit
e144f817ef
304
src/encoder.c
304
src/encoder.c
|
@ -969,6 +969,7 @@ void encoder_state_finalize(encoder_state * const encoder_state) {
|
|||
|
||||
|
||||
static void encoder_state_clear_refs(encoder_state *encoder_state) {
|
||||
//FIXME: Do we need to handle children? At present they all share the same global
|
||||
while (encoder_state->global->ref->used_size) {
|
||||
picture_list_rem(encoder_state->global->ref, encoder_state->global->ref->used_size - 1);
|
||||
}
|
||||
|
@ -976,6 +977,55 @@ static void encoder_state_clear_refs(encoder_state *encoder_state) {
|
|||
encoder_state->global->poc = 0;
|
||||
}
|
||||
|
||||
static void encoder_state_blit_pixels(const encoder_state * const target_enc, pixel * const target, const encoder_state * const source_enc, const pixel * const source, const int is_y_channel) {
|
||||
const int source_offset_x = source_enc->tile->lcu_offset_x * LCU_WIDTH;
|
||||
const int source_offset_y = source_enc->tile->lcu_offset_y * LCU_WIDTH;
|
||||
|
||||
const int target_offset_x = target_enc->tile->lcu_offset_x * LCU_WIDTH;
|
||||
const int target_offset_y = target_enc->tile->lcu_offset_y * LCU_WIDTH;
|
||||
|
||||
int source_stride = source_enc->tile->cur_pic->width;
|
||||
int target_stride = target_enc->tile->cur_pic->width;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
int source_offset;
|
||||
int target_offset;
|
||||
|
||||
//Do nothing if the source and the destination is the same!
|
||||
if (source_enc->tile == target_enc->tile) return;
|
||||
|
||||
if (is_y_channel) {
|
||||
target_offset = source_offset_x + source_offset_y * target_enc->tile->cur_pic->width;
|
||||
source_offset = target_offset_x + target_offset_y * source_enc->tile->cur_pic->width;
|
||||
} else {
|
||||
target_offset = source_offset_x/2 + source_offset_y/2 * target_enc->tile->cur_pic->width/2;
|
||||
source_offset = target_offset_x/2 + target_offset_y/2 * source_enc->tile->cur_pic->width/2;
|
||||
}
|
||||
|
||||
if (target_enc->children) {
|
||||
//Use information from the source
|
||||
width = MIN(source_enc->tile->cur_pic->width_in_lcu * LCU_WIDTH, target_enc->tile->cur_pic->width - source_offset_x);
|
||||
height = MIN(source_enc->tile->cur_pic->height_in_lcu * LCU_WIDTH, target_enc->tile->cur_pic->height - source_offset_y);
|
||||
} else {
|
||||
//Use information from the target
|
||||
width = MIN(target_enc->tile->cur_pic->width_in_lcu * LCU_WIDTH, source_enc->tile->cur_pic->width - target_offset_x);
|
||||
height = MIN(target_enc->tile->cur_pic->height_in_lcu * LCU_WIDTH, source_enc->tile->cur_pic->height - target_offset_y);
|
||||
}
|
||||
|
||||
if (!is_y_channel) {
|
||||
width /= 2;
|
||||
height /= 2;
|
||||
|
||||
source_stride /= 2;
|
||||
target_stride /= 2;
|
||||
}
|
||||
|
||||
//picture_blit_pixels(source + source_offset, target + target_offset, width, height, source_enc->cur_pic->width, target_enc->cur_pic->width);
|
||||
picture_blit_pixels(source + source_offset, target + target_offset, width, height, source_stride, target_stride);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void write_aud(encoder_state * const encoder_state)
|
||||
|
@ -986,36 +1036,8 @@ static void write_aud(encoder_state * const encoder_state)
|
|||
bitstream_align(stream);
|
||||
}
|
||||
|
||||
static void substream_write_bitstream(encoder_state * const encoder_state, const int end_of_sub_stream) {
|
||||
const encoder_control * const encoder = encoder_state->encoder_control;
|
||||
const picture* const cur_pic = encoder_state->tile->cur_pic;
|
||||
const int lcu_count = cur_pic->width_in_lcu * cur_pic->height_in_lcu;
|
||||
int lcu_id;
|
||||
vector2d lcu;
|
||||
|
||||
for (lcu_id = 0; lcu_id < lcu_count; ++lcu_id) {
|
||||
lcu.x = lcu_id % cur_pic->width_in_lcu;
|
||||
lcu.y = lcu_id / cur_pic->width_in_lcu;
|
||||
|
||||
//Write bitstream
|
||||
if (encoder->sao_enable) {
|
||||
encode_sao(encoder_state, lcu.x, lcu.y, &cur_pic->sao_luma[lcu.y * cur_pic->width_in_lcu + lcu.x], &cur_pic->sao_chroma[lcu.y * cur_pic->width_in_lcu + lcu.x]);
|
||||
}
|
||||
|
||||
encode_coding_tree(encoder_state, lcu.x << MAX_DEPTH, lcu.y << MAX_DEPTH, 0);
|
||||
|
||||
cabac_encode_bin_trm(&encoder_state->cabac, ((lcu_id == lcu_count - 1) && !end_of_sub_stream) ? 1 : 0); // end_of_slice_segment_flag
|
||||
}
|
||||
if (end_of_sub_stream) {
|
||||
cabac_encode_bin_trm(&encoder_state->cabac, 1); // end_of_sub_stream_one_bit == 1
|
||||
cabac_flush(&encoder_state->cabac);
|
||||
} else {
|
||||
cabac_flush(&encoder_state->cabac);
|
||||
bitstream_align(&encoder_state->stream);
|
||||
}
|
||||
}
|
||||
|
||||
static void substream_encode(encoder_state * const encoder_state) {
|
||||
static void encoder_state_encode_tile(encoder_state * const encoder_state) {
|
||||
const encoder_control * const encoder = encoder_state->encoder_control;
|
||||
#ifndef NDEBUG
|
||||
const unsigned long long int debug_bitstream_position = bitstream_tell(&(encoder_state->stream));
|
||||
|
@ -1129,57 +1151,79 @@ static void substream_encode(encoder_state * const encoder_state) {
|
|||
yuv_t_free(ver_buf);
|
||||
}
|
||||
|
||||
static void subencoder_blit_pixels(const encoder_state * const target_enc, pixel * const target, const encoder_state * const source_enc, const pixel * const source, const int is_y_channel) {
|
||||
const int source_offset_x = source_enc->tile->lcu_offset_x * LCU_WIDTH;
|
||||
const int source_offset_y = source_enc->tile->lcu_offset_y * LCU_WIDTH;
|
||||
static void encoder_state_encode(encoder_state * const main_state) {
|
||||
//If we have children, encode at child level
|
||||
if (main_state->children[0].encoder_control) {
|
||||
int i=0;
|
||||
for (i=0; main_state->children[i].encoder_control; ++i) {
|
||||
encoder_state *sub_state = &(main_state->children[i]);
|
||||
|
||||
const int target_offset_x = target_enc->tile->lcu_offset_x * LCU_WIDTH;
|
||||
const int target_offset_y = target_enc->tile->lcu_offset_y * LCU_WIDTH;
|
||||
if (sub_state->tile != main_state->tile) {
|
||||
//FIXME: remove this once these are in slice
|
||||
sub_state->tile->cur_pic->slicetype = main_state->tile->cur_pic->slicetype;
|
||||
sub_state->tile->cur_pic->type = main_state->tile->cur_pic->type;
|
||||
|
||||
int source_stride = source_enc->tile->cur_pic->width;
|
||||
int target_stride = target_enc->tile->cur_pic->width;
|
||||
encoder_state_blit_pixels(sub_state, sub_state->tile->cur_pic->y_data, main_state, main_state->tile->cur_pic->y_data, 1);
|
||||
encoder_state_blit_pixels(sub_state, sub_state->tile->cur_pic->u_data, main_state, main_state->tile->cur_pic->u_data, 0);
|
||||
encoder_state_blit_pixels(sub_state, sub_state->tile->cur_pic->v_data, main_state, main_state->tile->cur_pic->v_data, 0);
|
||||
}
|
||||
encoder_state_encode(&main_state->children[i]);
|
||||
//FIXME: substream_write_bitstream(subencoder, (main_state->children[i+1].encoder_control) != NULL);
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
int source_offset;
|
||||
int target_offset;
|
||||
|
||||
//One of them has to be the main encoder
|
||||
assert(target_enc->children || source_enc->children);
|
||||
|
||||
if (is_y_channel) {
|
||||
target_offset = source_offset_x + source_offset_y * target_enc->tile->cur_pic->width;
|
||||
source_offset = target_offset_x + target_offset_y * source_enc->tile->cur_pic->width;
|
||||
if (sub_state->tile != main_state->tile) {
|
||||
encoder_state_blit_pixels(main_state, main_state->tile->cur_pic->y_recdata, sub_state, sub_state->tile->cur_pic->y_recdata, 1);
|
||||
encoder_state_blit_pixels(main_state, main_state->tile->cur_pic->u_recdata, sub_state, sub_state->tile->cur_pic->u_recdata, 0);
|
||||
encoder_state_blit_pixels(main_state, main_state->tile->cur_pic->v_recdata, sub_state, sub_state->tile->cur_pic->v_recdata, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
target_offset = source_offset_x/2 + source_offset_y/2 * target_enc->tile->cur_pic->width/2;
|
||||
source_offset = target_offset_x/2 + target_offset_y/2 * source_enc->tile->cur_pic->width/2;
|
||||
switch (main_state->type) {
|
||||
case ENCODER_STATE_TYPE_TILE:
|
||||
encoder_state_encode_tile(main_state);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported leaf type %c!\n", main_state->type);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (target_enc->children) {
|
||||
//Use information from the source
|
||||
width = MIN(source_enc->tile->cur_pic->width_in_lcu * LCU_WIDTH, target_enc->tile->cur_pic->width - source_offset_x);
|
||||
height = MIN(source_enc->tile->cur_pic->height_in_lcu * LCU_WIDTH, target_enc->tile->cur_pic->height - source_offset_y);
|
||||
} else {
|
||||
//Use information from the target
|
||||
width = MIN(target_enc->tile->cur_pic->width_in_lcu * LCU_WIDTH, source_enc->tile->cur_pic->width - target_offset_x);
|
||||
height = MIN(target_enc->tile->cur_pic->height_in_lcu * LCU_WIDTH, source_enc->tile->cur_pic->height - target_offset_y);
|
||||
}
|
||||
|
||||
if (!is_y_channel) {
|
||||
width /= 2;
|
||||
height /= 2;
|
||||
|
||||
source_stride /= 2;
|
||||
target_stride /= 2;
|
||||
}
|
||||
|
||||
//picture_blit_pixels(source + source_offset, target + target_offset, width, height, source_enc->cur_pic->width, target_enc->cur_pic->width);
|
||||
picture_blit_pixels(source + source_offset, target + target_offset, width, height, source_stride, target_stride);
|
||||
}
|
||||
|
||||
void encode_one_frame(encoder_state * const main_state)
|
||||
{
|
||||
static void encoder_state_new_frame(encoder_state * const main_state) {
|
||||
int i;
|
||||
//FIXME Move this somewhere else!
|
||||
if (main_state->type == ENCODER_STATE_TYPE_MAIN) {
|
||||
const encoder_control * const encoder = main_state->encoder_control;
|
||||
|
||||
const int is_first_frame = (main_state->global->frame == 0);
|
||||
const int is_i_radl = (encoder->cfg->intra_period == 1 && main_state->global->frame % 2 == 0);
|
||||
const int is_p_radl = (encoder->cfg->intra_period > 1 && (main_state->global->frame % encoder->cfg->intra_period) == 0);
|
||||
const int is_radl_frame = is_first_frame || is_i_radl || is_p_radl;
|
||||
|
||||
if (is_radl_frame) {
|
||||
// Clear the reference list
|
||||
encoder_state_clear_refs(main_state);
|
||||
|
||||
main_state->tile->cur_pic->slicetype = SLICE_I;
|
||||
main_state->tile->cur_pic->type = NAL_IDR_W_RADL;
|
||||
} else {
|
||||
main_state->tile->cur_pic->slicetype = encoder->cfg->intra_period==1 ? SLICE_I : SLICE_P;
|
||||
main_state->tile->cur_pic->type = NAL_TRAIL_R;
|
||||
}
|
||||
} else {
|
||||
//Clear the bitstream if it's not the main encoder
|
||||
bitstream_clear(&main_state->stream);
|
||||
}
|
||||
|
||||
init_contexts(main_state, main_state->global->QP, main_state->tile->cur_pic->slicetype);
|
||||
|
||||
for (i = 0; main_state->children[i].encoder_control; ++i) {
|
||||
encoder_state_new_frame(&main_state->children[i]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void encoder_state_write_bitstream_main(encoder_state * const main_state) {
|
||||
const encoder_control * const encoder = main_state->encoder_control;
|
||||
bitstream * const stream = &main_state->stream;
|
||||
|
||||
|
@ -1188,6 +1232,8 @@ void encode_one_frame(encoder_state * const main_state)
|
|||
const int is_p_radl = (encoder->cfg->intra_period > 1 && (main_state->global->frame % encoder->cfg->intra_period) == 0);
|
||||
const int is_radl_frame = is_first_frame || is_i_radl || is_p_radl;
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
/** IDR picture when: period == 0 and frame == 0
|
||||
* period == 1 && frame%2 == 0
|
||||
|
@ -1244,50 +1290,13 @@ void encode_one_frame(encoder_state * const main_state)
|
|||
is_radl_frame ? NAL_IDR_W_RADL : NAL_TRAIL_R, 0, long_start_code);
|
||||
}
|
||||
|
||||
encode_slice_header(main_state);
|
||||
bitstream_align(&main_state->stream);
|
||||
|
||||
|
||||
if (main_state->children) {
|
||||
int i;
|
||||
//FIXME!
|
||||
//This can be parallelized, we don't use a do...while loop because we use OpenMP
|
||||
#pragma omp parallel for
|
||||
for (i = 0; i < encoder->tiles_num_tile_rows * encoder->tiles_num_tile_columns; ++i) {
|
||||
encoder_state *subencoder = &(main_state->children[i]);
|
||||
|
||||
subencoder_blit_pixels(subencoder, subencoder->tile->cur_pic->y_data, main_state, main_state->tile->cur_pic->y_data, 1);
|
||||
subencoder_blit_pixels(subencoder, subencoder->tile->cur_pic->u_data, main_state, main_state->tile->cur_pic->u_data, 0);
|
||||
subencoder_blit_pixels(subencoder, subencoder->tile->cur_pic->v_data, main_state, main_state->tile->cur_pic->v_data, 0);
|
||||
|
||||
//FIXME: remove this once these are in slice
|
||||
subencoder->tile->cur_pic->slicetype = main_state->tile->cur_pic->slicetype;
|
||||
subencoder->tile->cur_pic->type = main_state->tile->cur_pic->type;
|
||||
|
||||
substream_encode(subencoder);
|
||||
substream_write_bitstream(subencoder, (main_state->children[i+1].encoder_control) != NULL);
|
||||
|
||||
subencoder_blit_pixels(main_state, main_state->tile->cur_pic->y_recdata, subencoder, subencoder->tile->cur_pic->y_recdata, 1);
|
||||
subencoder_blit_pixels(main_state, main_state->tile->cur_pic->u_recdata, subencoder, subencoder->tile->cur_pic->u_recdata, 0);
|
||||
subencoder_blit_pixels(main_state, main_state->tile->cur_pic->v_recdata, subencoder, subencoder->tile->cur_pic->v_recdata, 0);
|
||||
}
|
||||
|
||||
//We should do the slice header here, because we can have the entry points
|
||||
|
||||
//This has to be serial
|
||||
i = 0;
|
||||
for (i = 0; main_state->children[i].encoder_control; ++i) {
|
||||
//Append bitstream to main stream
|
||||
bitstream_append(&main_state->stream, &main_state->children[i].stream);
|
||||
//FIXME: Move this...
|
||||
bitstream_clear(&main_state->children[i].stream);
|
||||
}
|
||||
|
||||
} else {
|
||||
//Encode the whole thing as one stream
|
||||
substream_encode(main_state);
|
||||
substream_write_bitstream(main_state, 0);
|
||||
}
|
||||
|
||||
// Calculate checksum
|
||||
add_checksum(main_state);
|
||||
|
||||
|
@ -1295,6 +1304,81 @@ void encode_one_frame(encoder_state * const main_state)
|
|||
main_state->tile->cur_pic->poc = main_state->global->poc;
|
||||
}
|
||||
|
||||
static void encoder_state_write_bitstream_tile(encoder_state * const encoder_state) {
|
||||
const encoder_control * const encoder = encoder_state->encoder_control;
|
||||
const picture* const cur_pic = encoder_state->tile->cur_pic;
|
||||
const int lcu_count = cur_pic->width_in_lcu * cur_pic->height_in_lcu;
|
||||
int lcu_id;
|
||||
vector2d lcu;
|
||||
|
||||
for (lcu_id = 0; lcu_id < lcu_count; ++lcu_id) {
|
||||
lcu.x = lcu_id % cur_pic->width_in_lcu;
|
||||
lcu.y = lcu_id / cur_pic->width_in_lcu;
|
||||
|
||||
//Write bitstream
|
||||
if (encoder->sao_enable) {
|
||||
encode_sao(encoder_state, lcu.x, lcu.y, &cur_pic->sao_luma[lcu.y * cur_pic->width_in_lcu + lcu.x], &cur_pic->sao_chroma[lcu.y * cur_pic->width_in_lcu + lcu.x]);
|
||||
}
|
||||
|
||||
encode_coding_tree(encoder_state, lcu.x << MAX_DEPTH, lcu.y << MAX_DEPTH, 0);
|
||||
|
||||
cabac_encode_bin_trm(&encoder_state->cabac, ((lcu_id == lcu_count - 1) && lcu_at_slice_end(encoder, lcu_id + encoder_state->tile->lcu_offset_in_ts)) ? 1 : 0); // end_of_slice_segment_flag
|
||||
}
|
||||
if (!lcu_at_slice_end(encoder, encoder_state->tile->lcu_offset_in_ts + cur_pic->width_in_lcu * cur_pic->height_in_lcu - 1)) {
|
||||
cabac_encode_bin_trm(&encoder_state->cabac, 1); // end_of_sub_stream_one_bit == 1
|
||||
cabac_flush(&encoder_state->cabac);
|
||||
} else {
|
||||
cabac_flush(&encoder_state->cabac);
|
||||
bitstream_align(&encoder_state->stream);
|
||||
}
|
||||
//We do not handle tiles containing something for now
|
||||
assert(!encoder_state->children[0].encoder_control);
|
||||
}
|
||||
|
||||
static void encoder_state_write_bitstream_slice(encoder_state * const main_state) {
|
||||
int i;
|
||||
encode_slice_header(main_state);
|
||||
bitstream_align(&main_state->stream);
|
||||
|
||||
for (i = 0; main_state->children[i].encoder_control; ++i) {
|
||||
//Append bitstream to main stream
|
||||
bitstream_append(&main_state->stream, &main_state->children[i].stream);
|
||||
//FIXME: Move this...
|
||||
bitstream_clear(&main_state->children[i].stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void encoder_state_write_bitstream(encoder_state * const main_state) {
|
||||
int i;
|
||||
for (i=0; main_state->children[i].encoder_control; ++i) {
|
||||
encoder_state *sub_state = &(main_state->children[i]);
|
||||
encoder_state_write_bitstream(sub_state);
|
||||
}
|
||||
|
||||
switch (main_state->type) {
|
||||
case ENCODER_STATE_TYPE_MAIN:
|
||||
encoder_state_write_bitstream_main(main_state);
|
||||
break;
|
||||
case ENCODER_STATE_TYPE_TILE:
|
||||
encoder_state_write_bitstream_tile(main_state);
|
||||
break;
|
||||
case ENCODER_STATE_TYPE_SLICE:
|
||||
encoder_state_write_bitstream_slice(main_state);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported leaf type %c!\n", main_state->type);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void encode_one_frame(encoder_state * const main_state)
|
||||
{
|
||||
encoder_state_new_frame(main_state);
|
||||
encoder_state_encode(main_state);
|
||||
encoder_state_write_bitstream(main_state);
|
||||
}
|
||||
|
||||
static void fill_after_frame(unsigned height, unsigned array_width,
|
||||
unsigned array_height, pixel *data)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue