From 31e1b614f683940ffe6c1fd0f33f658b3e7c845f Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sat, 12 Nov 2022 23:44:01 +0100 Subject: avcodec/rpzaenc: stop assuming prev and current frame linesize match --- libavcodec/rpzaenc.c | 53 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/libavcodec/rpzaenc.c b/libavcodec/rpzaenc.c index 4ced9523e2..880f6f71dc 100644 --- a/libavcodec/rpzaenc.c +++ b/libavcodec/rpzaenc.c @@ -80,6 +80,7 @@ typedef struct BlockInfo { int block_index; uint16_t start; int rowstride; + int prev_rowstride; int blocks_per_row; int total_blocks; } BlockInfo; @@ -113,7 +114,7 @@ static void get_colors(const uint8_t *min, const uint8_t *max, uint8_t color4[4] } /* Fill BlockInfo struct with information about a 4x4 block of the image */ -static int get_block_info(BlockInfo *bi, int block) +static int get_block_info(BlockInfo *bi, int block, int prev_frame) { bi->row = block / bi->blocks_per_row; bi->col = block % bi->blocks_per_row; @@ -132,7 +133,7 @@ static int get_block_info(BlockInfo *bi, int block) bi->block_height = 4; } - return block ? (bi->col * 4) + (bi->row * bi->rowstride * 4) : 0; + return block ? (bi->col * 4) + (bi->row * (prev_frame ? bi->prev_rowstride : bi->rowstride) * 4) : 0; } static uint16_t rgb24_to_rgb555(const uint8_t *rgb24) @@ -253,7 +254,7 @@ static int compare_blocks(const uint16_t *block1, const uint16_t *block2, return -1; } } - block1 += bi->rowstride; + block1 += bi->prev_rowstride; block2 += bi->rowstride; } return 0; @@ -387,9 +388,11 @@ static int match_color(const uint16_t *color, uint8_t colors[4][3]) static int encode_four_color_block(const uint8_t *min_color, const uint8_t *max_color, PutBitContext *pb, const uint16_t *block_ptr, const BlockInfo *bi) { - int x, y, idx; + const int y_size = FFMIN(4, bi->image_height - bi->row * 4); + const int x_size = FFMIN(4, bi->image_width - bi->col * 4); uint8_t color4[4][3]; uint16_t rounded_max, rounded_min; + int idx; // round min and max wider rounded_min = rgb24_to_rgb555(min_color); @@ -403,13 +406,21 @@ static int encode_four_color_block(const uint8_t *min_color, const uint8_t *max_ get_colors(min_color, max_color, color4); - for (y = 0; y < 4; y++) { - for (x = 0; x < 4; x++) { + for (int y = 0; y < y_size; y++) { + for (int x = 0; x < x_size; x++) { idx = match_color(&block_ptr[x], color4); put_bits(pb, 2, idx); } + + for (int x = x_size; x < 4; x++) + put_bits(pb, 2, idx); block_ptr += bi->rowstride; } + + for (int y = y_size; y < 4; y++) { + for (int x = 0; x < 4; x++) + put_bits(pb, 2, 0); + } return 1; // num blocks encoded } @@ -421,10 +432,11 @@ static void update_block_in_prev_frame(const uint16_t *src_pixels, const BlockInfo *bi, int block_counter) { const int y_size = FFMIN(4, bi->image_height - bi->row * 4); + const int x_size = FFMIN(4, bi->image_width - bi->col * 4) * 2; for (int y = 0; y < y_size; y++) { - memcpy(dest_pixels, src_pixels, 8); - dest_pixels += bi->rowstride; + memcpy(dest_pixels, src_pixels, x_size); + dest_pixels += bi->prev_rowstride; src_pixels += bi->rowstride; } } @@ -556,6 +568,7 @@ static void rpza_encode_stream(RpzaContext *s, const AVFrame *pict) int total_blocks; int prev_block_offset; int block_offset = 0; + int pblock_offset = 0; uint8_t min = 0, max = 0; channel_offset chan; int i; @@ -574,6 +587,7 @@ static void rpza_encode_stream(RpzaContext *s, const AVFrame *pict) bi.image_width = s->frame_width; bi.image_height = s->frame_height; bi.rowstride = pict->linesize[0] / 2; + bi.prev_rowstride = s->prev_frame->linesize[0] / 2; bi.blocks_per_row = (s->frame_width + 3) / 4; @@ -586,8 +600,8 @@ static void rpza_encode_stream(RpzaContext *s, const AVFrame *pict) prev_block_offset = 0; while (n_blocks < 32 && block_counter + n_blocks < total_blocks) { - - block_offset = get_block_info(&bi, block_counter + n_blocks); + block_offset = get_block_info(&bi, block_counter + n_blocks, 0); + pblock_offset = get_block_info(&bi, block_counter + n_blocks, 1); // multi-block opcodes cannot span multiple rows. // If we're starting a new row, break out and write the opcode @@ -602,7 +616,7 @@ static void rpza_encode_stream(RpzaContext *s, const AVFrame *pict) prev_block_offset = block_offset; - if (compare_blocks(&prev_pixels[block_offset], + if (compare_blocks(&prev_pixels[pblock_offset], &src_pixels[block_offset], &bi, s->skip_frame_thresh) != 0) { // write out skipable blocks if (n_blocks) { @@ -623,7 +637,7 @@ static void rpza_encode_stream(RpzaContext *s, const AVFrame *pict) */ // update_block_in_prev_frame(&src_pixels[block_offset], - // &prev_pixels[block_offset], &bi, block_counter + n_blocks); + // &prev_pixels[pblock_offset], &bi, block_counter + n_blocks); n_blocks++; } @@ -639,7 +653,8 @@ static void rpza_encode_stream(RpzaContext *s, const AVFrame *pict) } } else { - block_offset = get_block_info(&bi, block_counter); + block_offset = get_block_info(&bi, block_counter, 0); + pblock_offset = get_block_info(&bi, block_counter, 1); } post_skip : @@ -653,11 +668,12 @@ post_skip : /* update this block in the previous frame buffer */ update_block_in_prev_frame(&src_pixels[block_offset], - &prev_pixels[block_offset], &bi, block_counter + n_blocks); + &prev_pixels[pblock_offset], &bi, block_counter + n_blocks); // check for subsequent blocks with the same color while (n_blocks < 32 && block_counter + n_blocks < total_blocks) { - block_offset = get_block_info(&bi, block_counter + n_blocks); + block_offset = get_block_info(&bi, block_counter + n_blocks, 0); + pblock_offset = get_block_info(&bi, block_counter + n_blocks, 1); // multi-block opcodes cannot span multiple rows. // If we've hit end of a row, break out and write the opcode @@ -675,7 +691,7 @@ post_skip : /* update this block in the previous frame buffer */ update_block_in_prev_frame(&src_pixels[block_offset], - &prev_pixels[block_offset], &bi, block_counter + n_blocks); + &prev_pixels[pblock_offset], &bi, block_counter + n_blocks); n_blocks++; } @@ -734,7 +750,8 @@ post_skip : const uint16_t *row_ptr; int y_size, rgb555; - block_offset = get_block_info(&bi, block_counter); + block_offset = get_block_info(&bi, block_counter, 0); + pblock_offset = get_block_info(&bi, block_counter, 1); row_ptr = &src_pixels[block_offset]; y_size = FFMIN(4, bi.image_height - bi.row * 4); @@ -761,7 +778,7 @@ post_skip : /* update this block in the previous frame buffer */ update_block_in_prev_frame(&src_pixels[block_offset], - &prev_pixels[block_offset], &bi, block_counter); + &prev_pixels[pblock_offset], &bi, block_counter); } } } -- cgit v1.2.3