mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-24 02:24:07 +00:00
Moved reference list sorting and parsing to encoder_state_new_frame()
* fixed a bug in reference verification and added an error state
This commit is contained in:
parent
c40ca49b6c
commit
5071b5c990
|
@ -21,6 +21,7 @@
|
||||||
#include "encoder_state-bitstream.h"
|
#include "encoder_state-bitstream.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "checkpoint.h"
|
#include "checkpoint.h"
|
||||||
#include "encoderstate.h"
|
#include "encoderstate.h"
|
||||||
|
@ -611,13 +612,17 @@ void encoder_state_write_bitstream_slice_header(encoder_state_t * const state)
|
||||||
int8_t found = 0;
|
int8_t found = 0;
|
||||||
do {
|
do {
|
||||||
delta_poc = state->encoder_control->cfg->gop[state->global->gop_offset].ref_neg[j + poc_shift];
|
delta_poc = state->encoder_control->cfg->gop[state->global->gop_offset].ref_neg[j + poc_shift];
|
||||||
for (j = 0; j < state->global->ref->used_size; j++) {
|
for (int i = 0; i < state->global->ref->used_size; i++) {
|
||||||
if (state->global->ref->images[j]->poc == state->global->poc - delta_poc) {
|
if (state->global->ref->images[i]->poc == state->global->poc - delta_poc) {
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
poc_shift++;
|
if (!found) poc_shift++;
|
||||||
|
if (j + poc_shift == ref_negative) {
|
||||||
|
fprintf(stderr, "Failure, reference not found!");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
} while (!found);
|
} while (!found);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,13 +641,17 @@ void encoder_state_write_bitstream_slice_header(encoder_state_t * const state)
|
||||||
int8_t found = 0;
|
int8_t found = 0;
|
||||||
do {
|
do {
|
||||||
delta_poc = state->encoder_control->cfg->gop[state->global->gop_offset].ref_pos[j + poc_shift];
|
delta_poc = state->encoder_control->cfg->gop[state->global->gop_offset].ref_pos[j + poc_shift];
|
||||||
for (j = 0; j < state->global->ref->used_size; j++) {
|
for (int i = 0; i < state->global->ref->used_size; i++) {
|
||||||
if (state->global->ref->images[j]->poc == state->global->poc + delta_poc) {
|
if (state->global->ref->images[i]->poc == state->global->poc + delta_poc) {
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
poc_shift++;
|
if (!found) poc_shift++;
|
||||||
|
if (j + poc_shift == ref_positive) {
|
||||||
|
fprintf(stderr, "Failure, reference not found!");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
} while (!found);
|
} while (!found);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -659,6 +659,95 @@ static void encoder_state_encode(encoder_state_t * const main_state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void encoder_ref_insertion_sort(int reflist[16], int length) {
|
||||||
|
|
||||||
|
for (uint8_t i = 1; i < length; ++i) {
|
||||||
|
const int16_t cur_poc = reflist[i];
|
||||||
|
int16_t j = i;
|
||||||
|
while (j > 0 && cur_poc < reflist[j - 1]) {
|
||||||
|
reflist[j] = reflist[j - 1];
|
||||||
|
--j;
|
||||||
|
}
|
||||||
|
reflist[j] = cur_poc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void encoder_state_ref_sort(encoder_state_t *state) {
|
||||||
|
int j, ref_list[2] = { 0, 0 }, ref_list_poc[2][16];
|
||||||
|
|
||||||
|
// List all pocs of lists
|
||||||
|
for (j = 0; j < state->global->ref->used_size; j++) {
|
||||||
|
if (state->global->ref->images[j]->poc < state->global->poc) {
|
||||||
|
ref_list_poc[0][ref_list[0]] = state->global->ref->images[j]->poc;
|
||||||
|
ref_list[0]++;
|
||||||
|
} else {
|
||||||
|
ref_list_poc[1][ref_list[1]] = state->global->ref->images[j]->poc;
|
||||||
|
ref_list[1]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder_ref_insertion_sort(ref_list_poc[0], ref_list[0]);
|
||||||
|
encoder_ref_insertion_sort(ref_list_poc[1], ref_list[1]);
|
||||||
|
|
||||||
|
for (j = 0; j < state->global->ref->used_size; j++) {
|
||||||
|
if (state->global->ref->images[j]->poc < state->global->poc) {
|
||||||
|
int idx = ref_list[0];
|
||||||
|
for (int ref_idx = 0; ref_idx < ref_list[0]; ref_idx++) {
|
||||||
|
if (ref_list_poc[0][ref_idx] == state->global->ref->images[j]->poc) {
|
||||||
|
state->global->refmap[j].idx = ref_list[0] - ref_idx - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state->global->refmap[j].list = 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
int idx = ref_list[1];
|
||||||
|
for (int ref_idx = 0; ref_idx < ref_list[1]; ref_idx++) {
|
||||||
|
if (ref_list_poc[1][ref_idx] == state->global->ref->images[j]->poc) {
|
||||||
|
state->global->refmap[j].idx = ref_idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state->global->refmap[j].list = 2;
|
||||||
|
}
|
||||||
|
state->global->refmap[j].poc = state->global->ref->images[j]->poc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void encoder_state_remove_refs(encoder_state_t *state) {
|
||||||
|
const encoder_control_t * const encoder = state->encoder_control;
|
||||||
|
int8_t refnumber = encoder->cfg->ref_frames;
|
||||||
|
if (encoder->cfg->gop_len) {
|
||||||
|
refnumber = encoder->cfg->gop[state->global->gop_offset].ref_neg_count + encoder->cfg->gop[state->global->gop_offset].ref_pos_count;
|
||||||
|
}
|
||||||
|
// Remove the ref pic (if present)
|
||||||
|
while (state->global->ref->used_size > (uint32_t)refnumber) {
|
||||||
|
int8_t ref_to_remove = state->global->ref->used_size - 1;
|
||||||
|
if (encoder->cfg->gop_len) {
|
||||||
|
for (int ref = 0; ref < state->global->ref->used_size; ref++) {
|
||||||
|
uint8_t found = 0;
|
||||||
|
for (int i = 0; i < encoder->cfg->gop[state->global->gop_offset].ref_neg_count; i++) {
|
||||||
|
if (state->global->ref->images[ref]->poc == state->global->poc - encoder->cfg->gop[state->global->gop_offset].ref_neg[i]) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) continue;
|
||||||
|
for (int i = 0; i < encoder->cfg->gop[state->global->gop_offset].ref_pos_count; i++) {
|
||||||
|
if (state->global->ref->images[ref]->poc == state->global->poc + encoder->cfg->gop[state->global->gop_offset].ref_pos[i]) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
image_list_rem(state->global->ref, ref);
|
||||||
|
ref--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else image_list_rem(state->global->ref, ref_to_remove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void encoder_state_clear_refs(encoder_state_t *state) {
|
static void encoder_state_clear_refs(encoder_state_t *state) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -681,7 +770,14 @@ static void encoder_state_new_frame(encoder_state_t * const state) {
|
||||||
const int is_i_radl = (encoder->cfg->intra_period == 1 && state->global->frame % 2 == 0);
|
const int is_i_radl = (encoder->cfg->intra_period == 1 && state->global->frame % 2 == 0);
|
||||||
const int is_p_radl = (encoder->cfg->intra_period > 1 && (state->global->frame % encoder->cfg->intra_period) == 0);
|
const int is_p_radl = (encoder->cfg->intra_period > 1 && (state->global->frame % encoder->cfg->intra_period) == 0);
|
||||||
state->global->is_radl_frame = is_first_frame || is_i_radl || is_p_radl;
|
state->global->is_radl_frame = is_first_frame || is_i_radl || is_p_radl;
|
||||||
|
|
||||||
|
if (state->global->frame && encoder->cfg->gop_len) {
|
||||||
|
// Calculate POC according to the global frame counter and GOP structure
|
||||||
|
state->global->poc = (state->global->frame - 1) - (state->global->frame - 1) % encoder->cfg->gop_len +
|
||||||
|
encoder->cfg->gop[state->global->gop_offset].poc_offset;
|
||||||
|
videoframe_set_poc(state->tile->frame, state->global->poc);
|
||||||
|
}
|
||||||
|
|
||||||
if (state->global->is_radl_frame) {
|
if (state->global->is_radl_frame) {
|
||||||
// Clear the reference list
|
// Clear the reference list
|
||||||
encoder_state_clear_refs(state);
|
encoder_state_clear_refs(state);
|
||||||
|
@ -689,6 +785,8 @@ static void encoder_state_new_frame(encoder_state_t * const state) {
|
||||||
state->global->slicetype = SLICE_I;
|
state->global->slicetype = SLICE_I;
|
||||||
state->global->pictype = NAL_IDR_W_RADL;
|
state->global->pictype = NAL_IDR_W_RADL;
|
||||||
} else {
|
} else {
|
||||||
|
encoder_state_remove_refs(state);
|
||||||
|
encoder_state_ref_sort(state);
|
||||||
state->global->slicetype = encoder->cfg->intra_period==1 ? SLICE_I : (state->encoder_control->cfg->gop_len?SLICE_B:SLICE_P);
|
state->global->slicetype = encoder->cfg->intra_period==1 ? SLICE_I : (state->encoder_control->cfg->gop_len?SLICE_B:SLICE_P);
|
||||||
state->global->pictype = NAL_TRAIL_R;
|
state->global->pictype = NAL_TRAIL_R;
|
||||||
}
|
}
|
||||||
|
@ -827,16 +925,20 @@ int read_one_frame(FILE* file, const encoder_state_t * const state)
|
||||||
unsigned array_height = state->tile->frame->height;
|
unsigned array_height = state->tile->frame->height;
|
||||||
|
|
||||||
// storing GOP pictures
|
// storing GOP pictures
|
||||||
|
static int8_t gop_init = 0;
|
||||||
static int8_t gop_pictures_available = 0;
|
static int8_t gop_pictures_available = 0;
|
||||||
static videoframe_t gop_pictures[MAX_GOP];
|
static videoframe_t gop_pictures[MAX_GOP];
|
||||||
static int8_t gop_skip_frames = 0;
|
static int8_t gop_skip_frames = 0;
|
||||||
|
static int8_t gop_skipped = 0;
|
||||||
|
|
||||||
// On first frame, init structures
|
// Initialize GOP structure when gop is enabled and not initialized
|
||||||
if (!state->global->frame) {
|
if (state->encoder_control->cfg->gop_len && !gop_init) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < state->encoder_control->cfg->gop_len; i++) {
|
for (i = 0; i < state->encoder_control->cfg->gop_len; i++) {
|
||||||
gop_pictures[i].source = image_alloc(array_width, array_height, 0);
|
gop_pictures[i].source = image_alloc(array_width, array_height, 0);
|
||||||
}
|
}
|
||||||
|
state->global->gop_offset = 0;
|
||||||
|
gop_init = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If GOP is present but no pictures found
|
// If GOP is present but no pictures found
|
||||||
|
@ -883,13 +985,16 @@ int read_one_frame(FILE* file, const encoder_state_t * const state)
|
||||||
|
|
||||||
// If GOP is present, fetch the data from our GOP picture buffer
|
// If GOP is present, fetch the data from our GOP picture buffer
|
||||||
if (state->global->frame && state->encoder_control->cfg->gop_len) {
|
if (state->global->frame && state->encoder_control->cfg->gop_len) {
|
||||||
int cur_gop_idx = state->encoder_control->cfg->gop_len - (gop_pictures_available + gop_skip_frames);
|
int cur_gop_idx = state->encoder_control->cfg->gop_len - (gop_pictures_available + gop_skip_frames) + gop_skipped;
|
||||||
int cur_gop = state->encoder_control->cfg->gop[cur_gop_idx].poc_offset - 1;
|
int cur_gop = state->encoder_control->cfg->gop[cur_gop_idx].poc_offset - 1;
|
||||||
// Special case when end of the sequence and not all pictures are available
|
// Special case when end of the sequence and not all pictures are available
|
||||||
if (gop_skip_frames) {
|
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++) {
|
for (; cur_gop >= state->encoder_control->cfg->gop_len - gop_skip_frames; cur_gop_idx++) {
|
||||||
cur_gop = state->encoder_control->cfg->gop[cur_gop_idx].poc_offset - 1;
|
cur_gop = state->encoder_control->cfg->gop[cur_gop_idx].poc_offset - 1;
|
||||||
|
gop_skipped++;
|
||||||
}
|
}
|
||||||
|
cur_gop_idx--;
|
||||||
|
gop_skipped--;
|
||||||
}
|
}
|
||||||
state->global->gop_offset = cur_gop_idx;
|
state->global->gop_offset = cur_gop_idx;
|
||||||
memcpy(state->tile->frame->source->y, gop_pictures[cur_gop].source->y, width * height);
|
memcpy(state->tile->frame->source->y, gop_pictures[cur_gop].source->y, width * height);
|
||||||
|
@ -985,95 +1090,6 @@ void encoder_compute_stats(encoder_state_t *state, FILE * const recout, uint32_t
|
||||||
*bitstream_length += state->stats_bitstream_length;
|
*bitstream_length += state->stats_bitstream_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void encoder_ref_insertion_sort(int reflist[16], int length) {
|
|
||||||
|
|
||||||
for (uint8_t i = 1; i < length; ++i) {
|
|
||||||
const int16_t cur_poc = reflist[i];
|
|
||||||
int16_t j = i;
|
|
||||||
while (j > 0 && cur_poc < reflist[j - 1]) {
|
|
||||||
reflist[j] = reflist[j - 1];
|
|
||||||
--j;
|
|
||||||
}
|
|
||||||
reflist[j] = cur_poc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static void encoder_state_ref_sort(encoder_state_t *state) {
|
|
||||||
int j, ref_list[2] = { 0, 0 },ref_list_poc[2][16];
|
|
||||||
|
|
||||||
// List all pocs of lists
|
|
||||||
for (j = 0; j < state->global->ref->used_size; j++) {
|
|
||||||
if (state->global->ref->images[j]->poc < state->global->poc) {
|
|
||||||
ref_list_poc[0][ref_list[0]] = state->global->ref->images[j]->poc;
|
|
||||||
ref_list[0]++;
|
|
||||||
} else {
|
|
||||||
ref_list_poc[1][ref_list[1]] = state->global->ref->images[j]->poc;
|
|
||||||
ref_list[1]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder_ref_insertion_sort(ref_list_poc[0], ref_list[0]);
|
|
||||||
encoder_ref_insertion_sort(ref_list_poc[1], ref_list[1]);
|
|
||||||
|
|
||||||
for (j = 0; j < state->global->ref->used_size; j++) {
|
|
||||||
if (state->global->ref->images[j]->poc < state->global->poc) {
|
|
||||||
int idx = ref_list[0];
|
|
||||||
for (int ref_idx = 0; ref_idx < ref_list[0]; ref_idx++) {
|
|
||||||
if (ref_list_poc[0][ref_idx] == state->global->ref->images[j]->poc) {
|
|
||||||
state->global->refmap[j].idx = ref_list[0] - ref_idx - 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state->global->refmap[j].list = 1;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
int idx = ref_list[1];
|
|
||||||
for (int ref_idx = 0; ref_idx < ref_list[1]; ref_idx++) {
|
|
||||||
if (ref_list_poc[1][ref_idx] == state->global->ref->images[j]->poc) {
|
|
||||||
state->global->refmap[j].idx = ref_idx;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state->global->refmap[j].list = 2;
|
|
||||||
}
|
|
||||||
state->global->refmap[j].poc = state->global->ref->images[j]->poc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void encoder_state_remove_refs(encoder_state_t *state) {
|
|
||||||
const encoder_control_t * const encoder = state->encoder_control;
|
|
||||||
int8_t refnumber = encoder->cfg->ref_frames;
|
|
||||||
if (encoder->cfg->gop_len) {
|
|
||||||
refnumber = encoder->cfg->gop[state->global->gop_offset].ref_neg_count + encoder->cfg->gop[state->global->gop_offset].ref_pos_count;
|
|
||||||
}
|
|
||||||
// Remove the ref pic (if present)
|
|
||||||
while (state->global->ref->used_size > (uint32_t)refnumber) {
|
|
||||||
int8_t ref_to_remove = state->global->ref->used_size - 1;
|
|
||||||
if (encoder->cfg->gop_len) {
|
|
||||||
for (int ref = 0; ref < state->global->ref->used_size; ref++) {
|
|
||||||
uint8_t found = 0;
|
|
||||||
for (int i = 0; i < encoder->cfg->gop[state->global->gop_offset].ref_neg_count; i++) {
|
|
||||||
if (state->global->ref->images[ref]->poc == state->global->poc - encoder->cfg->gop[state->global->gop_offset].ref_neg[i]) {
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found) continue;
|
|
||||||
for (int i = 0; i < encoder->cfg->gop[state->global->gop_offset].ref_pos_count; i++) {
|
|
||||||
if (state->global->ref->images[ref]->poc == state->global->poc + encoder->cfg->gop[state->global->gop_offset].ref_pos[i]) {
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
image_list_rem(state->global->ref, ref);
|
|
||||||
ref--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else image_list_rem(state->global->ref, ref_to_remove);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void encoder_next_frame(encoder_state_t *state) {
|
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;
|
||||||
int8_t use_as_ref[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
|
int8_t use_as_ref[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
|
||||||
|
@ -1097,12 +1113,6 @@ void encoder_next_frame(encoder_state_t *state) {
|
||||||
//We have a "real" previous encoder
|
//We have a "real" previous encoder
|
||||||
state->global->frame = state->previous_encoder_state->global->frame + 1;
|
state->global->frame = state->previous_encoder_state->global->frame + 1;
|
||||||
state->global->poc = state->previous_encoder_state->global->poc + 1;
|
state->global->poc = state->previous_encoder_state->global->poc + 1;
|
||||||
if (encoder->cfg->gop_len) {
|
|
||||||
// Calculate POC according to the global frame counter and GOP structure
|
|
||||||
state->global->poc = state->previous_encoder_state->global->frame -
|
|
||||||
state->global->gop_offset +
|
|
||||||
encoder->cfg->gop[state->global->gop_offset].poc_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
image_free(state->tile->frame->rec);
|
image_free(state->tile->frame->rec);
|
||||||
cu_array_free(state->tile->frame->cu_array);
|
cu_array_free(state->tile->frame->cu_array);
|
||||||
|
@ -1116,31 +1126,20 @@ void encoder_next_frame(encoder_state_t *state) {
|
||||||
}
|
}
|
||||||
videoframe_set_poc(state->tile->frame, state->global->poc);
|
videoframe_set_poc(state->tile->frame, state->global->poc);
|
||||||
image_list_copy_contents(state->global->ref, state->previous_encoder_state->global->ref);
|
image_list_copy_contents(state->global->ref, state->previous_encoder_state->global->ref);
|
||||||
|
|
||||||
if (!encoder->cfg->gop_len || !state->previous_encoder_state->global->poc || encoder->cfg->gop[state->global->gop_offset].is_ref) {
|
if (!encoder->cfg->gop_len || !state->previous_encoder_state->global->poc || encoder->cfg->gop[state->global->gop_offset].is_ref) {
|
||||||
image_list_add(state->global->ref, state->previous_encoder_state->tile->frame->rec, state->previous_encoder_state->tile->frame->cu_array);
|
image_list_add(state->global->ref, state->previous_encoder_state->tile->frame->rec, state->previous_encoder_state->tile->frame->cu_array);
|
||||||
}
|
}
|
||||||
encoder_state_remove_refs(state);
|
|
||||||
encoder_state_ref_sort(state);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->global->frame++;
|
state->global->frame++;
|
||||||
state->global->poc++;
|
state->global->poc++;
|
||||||
if (encoder->cfg->gop_len) {
|
|
||||||
// Calculate POC according to the global frame counter and GOP structure
|
|
||||||
state->global->poc = state->global->frame - 1 -
|
|
||||||
(state->global->gop_offset) +
|
|
||||||
encoder->cfg->gop[state->global->gop_offset].poc_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!encoder->cfg->gop_len || !lastpoc || encoder->cfg->gop[state->global->gop_offset].is_ref) {
|
if (!encoder->cfg->gop_len || !state->previous_encoder_state->global->poc || encoder->cfg->gop[state->global->gop_offset].is_ref) {
|
||||||
// Add current reconstructed picture as reference
|
// Add current reconstructed picture as reference
|
||||||
image_list_add(state->global->ref, state->tile->frame->rec, state->tile->frame->cu_array);
|
image_list_add(state->global->ref, state->tile->frame->rec, state->tile->frame->cu_array);
|
||||||
}
|
}
|
||||||
encoder_state_remove_refs(state);
|
|
||||||
encoder_state_ref_sort(state);
|
|
||||||
|
|
||||||
//Remove current reconstructed picture, and alloc a new one
|
//Remove current reconstructed picture, and alloc a new one
|
||||||
image_free(state->tile->frame->rec);
|
image_free(state->tile->frame->rec);
|
||||||
|
|
Loading…
Reference in a new issue