mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-30 20:54:07 +00:00
Replace deblock filter with a simple loop.
- Adds function is_pu_boundary. - Moves code for filtering an edge of a single PU or TU to a new function filter_deblock_unit. - Replaces recursive CU tree traversal in filter_deblock_cu with a simple loop and renames it to filter_deblock_lcu_inside.
This commit is contained in:
parent
7516fda970
commit
21ca74fe86
242
src/filter.c
242
src/filter.c
|
@ -172,7 +172,7 @@ static INLINE void kvz_filter_deblock_chroma(const encoder_control_t * const enc
|
|||
|
||||
|
||||
/**
|
||||
* \brief Check wheter an edge is a TU boundary.
|
||||
* \brief Check whether an edge is a TU boundary.
|
||||
*
|
||||
* \param state encoder state
|
||||
* \param x x-coordinate of the scu in pixels
|
||||
|
@ -199,7 +199,48 @@ static bool is_tu_boundary(const encoder_state_t *const state,
|
|||
|
||||
|
||||
/**
|
||||
* \brief Check wheter an edge is aligned on a 8x8 grid.
|
||||
* \brief Check whether an edge is a PU boundary.
|
||||
*
|
||||
* \param state encoder state
|
||||
* \param x x-coordinate of the scu in pixels
|
||||
* \param y y-coordinate of the scu in pixels
|
||||
* \param dir direction of the edge to check
|
||||
* \return true, if the edge is a TU boundary, otherwise false
|
||||
*/
|
||||
static bool is_pu_boundary(const encoder_state_t *const state,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
edge_dir dir)
|
||||
{
|
||||
const cu_info_t *const scu = kvz_videoframe_get_cu(state->tile->frame,
|
||||
x >> MIN_SIZE,
|
||||
y >> MIN_SIZE);
|
||||
// Get the containing CU.
|
||||
const int32_t cu_width = LCU_WIDTH >> scu->depth;
|
||||
const int32_t x_cu = x & ~(cu_width - 1);
|
||||
const int32_t y_cu = y & ~(cu_width - 1);
|
||||
const cu_info_t *const cu = kvz_videoframe_get_cu(state->tile->frame,
|
||||
x_cu >> MIN_SIZE,
|
||||
y_cu >> MIN_SIZE);
|
||||
|
||||
const int num_pu = kvz_part_mode_num_parts[cu->part_size];
|
||||
for (int i = 0; i < num_pu; i++) {
|
||||
if (dir == EDGE_HOR) {
|
||||
int y_pu = PU_GET_Y(cu->part_size, cu_width, y_cu, i);
|
||||
if (y_pu == y) return true;
|
||||
|
||||
} else {
|
||||
int x_pu = PU_GET_X(cu->part_size, cu_width, x_cu, i);
|
||||
if (x_pu == x) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Check whether an edge is aligned on a 8x8 grid.
|
||||
*
|
||||
* \param x x-coordinate of the edge
|
||||
* \param y y-coordinate of the edge
|
||||
|
@ -238,12 +279,14 @@ static bool is_on_8x8_grid(int x, int y, edge_dir dir)
|
|||
* \param y y-coordinate in pixels (see above)
|
||||
* \param length length of the edge in pixels
|
||||
* \param dir direction of the edge to filter
|
||||
* \param tu_boundary whether the edge is a TU boundary
|
||||
*/
|
||||
static void filter_deblock_edge_luma(encoder_state_t * const state,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t length,
|
||||
edge_dir dir)
|
||||
edge_dir dir,
|
||||
bool tu_boundary)
|
||||
{
|
||||
videoframe_t * const frame = state->tile->frame;
|
||||
const encoder_control_t * const encoder = state->encoder_control;
|
||||
|
@ -286,11 +329,14 @@ static void filter_deblock_edge_luma(encoder_state_t * const state,
|
|||
// CU in the side we are filtering, update every 8-pixels
|
||||
cu_p = kvz_videoframe_get_cu(frame, x_cu - (dir == EDGE_VER) + (dir == EDGE_HOR ? block_idx>>1 : 0), y_cu - (dir == EDGE_HOR) + (dir == EDGE_VER ? block_idx>>1 : 0));
|
||||
|
||||
bool nonzero_coeffs = cbf_is_set(cu_q->cbf.y, cu_q->tr_depth)
|
||||
|| cbf_is_set(cu_p->cbf.y, cu_p->tr_depth);
|
||||
|
||||
// Filter strength
|
||||
strength = 0;
|
||||
if(cu_q->type == CU_INTRA || cu_p->type == CU_INTRA) {
|
||||
if (cu_q->type == CU_INTRA || cu_p->type == CU_INTRA) {
|
||||
strength = 2;
|
||||
} else if(cbf_is_set(cu_q->cbf.y, cu_q->tr_depth) || cbf_is_set(cu_p->cbf.y, cu_p->tr_depth)) {
|
||||
} else if (tu_boundary && nonzero_coeffs) {
|
||||
// Non-zero residual/coeffs and transform boundary
|
||||
// Neither CU is intra so tr_depth <= MAX_DEPTH.
|
||||
strength = 1;
|
||||
|
@ -423,17 +469,19 @@ static void filter_deblock_edge_luma(encoder_state_t * const state,
|
|||
|
||||
\endverbatim
|
||||
*
|
||||
* \param state encoder state
|
||||
* \param x x-coordinate in chroma pixels (see above)
|
||||
* \param y y-coordinate in chroma pixels (see above)
|
||||
* \param length length of the edge in chroma pixels
|
||||
* \param dir direction of the edge to filter
|
||||
* \param state encoder state
|
||||
* \param x x-coordinate in chroma pixels (see above)
|
||||
* \param y y-coordinate in chroma pixels (see above)
|
||||
* \param length length of the edge in chroma pixels
|
||||
* \param dir direction of the edge to filter
|
||||
* \param tu_boundary whether the edge is a TU boundary
|
||||
*/
|
||||
static void filter_deblock_edge_chroma(encoder_state_t * const state,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t length,
|
||||
edge_dir dir)
|
||||
edge_dir dir,
|
||||
bool tu_boundary)
|
||||
{
|
||||
const encoder_control_t * const encoder = state->encoder_control;
|
||||
const videoframe_t * const frame = state->tile->frame;
|
||||
|
@ -479,92 +527,91 @@ static void filter_deblock_edge_chroma(encoder_state_t * const state,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief function to split LCU into smaller CU blocks
|
||||
* \brief Filter edge of a single PU or TU
|
||||
*
|
||||
* \param encoder the encoder info structure
|
||||
* \param state encoder state
|
||||
* \param x block x-position in pixels
|
||||
* \param y block y-position in pixels
|
||||
* \param width block width in pixels
|
||||
* \param height block height in pixels
|
||||
* \param dir direction of the edges to filter
|
||||
* \param tu_boundary whether the edge is a TU boundary
|
||||
*/
|
||||
static void filter_deblock_unit(encoder_state_t * const state,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
edge_dir dir,
|
||||
bool tu_boundary)
|
||||
{
|
||||
// no filtering on borders (where filter would use pixels outside the picture)
|
||||
if (x == 0 && dir == EDGE_VER) return;
|
||||
if (y == 0 && dir == EDGE_HOR) return;
|
||||
|
||||
// Length of luma and chroma edges.
|
||||
int32_t length;
|
||||
int32_t length_c;
|
||||
|
||||
if (dir == EDGE_HOR) {
|
||||
const videoframe_t * const frame = state->tile->frame;
|
||||
const int32_t x_right = x + width;
|
||||
const bool rightmost_4px_of_lcu = x_right % LCU_WIDTH == 0;
|
||||
const bool rightmost_4px_of_frame = x_right == frame->width;
|
||||
|
||||
if (rightmost_4px_of_lcu && !rightmost_4px_of_frame) {
|
||||
// The last 4 pixels will be deblocked when processing the next LCU.
|
||||
length = width - 4;
|
||||
length_c = (width >> 1) - 4;
|
||||
|
||||
} else {
|
||||
length = width;
|
||||
length_c = width >> 1;
|
||||
}
|
||||
} else {
|
||||
length = height;
|
||||
length_c = height >> 1;
|
||||
}
|
||||
|
||||
filter_deblock_edge_luma(state, x, y, length, dir, tu_boundary);
|
||||
|
||||
// Chroma pixel coordinates.
|
||||
const int32_t x_c = x >> 1;
|
||||
const int32_t y_c = y >> 1;
|
||||
if (is_on_8x8_grid(x_c, y_c, dir)) {
|
||||
filter_deblock_edge_chroma(state, x_c, y_c, length_c, dir, tu_boundary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Deblock PU and TU boundaries inside an LCU.
|
||||
*
|
||||
* \param state encoder state
|
||||
* \param x_px block x-position in pixels
|
||||
* \param y_px block y-position in pixels
|
||||
* \param depth block depth
|
||||
* \param dir direction of the edges to filter
|
||||
*
|
||||
* Recursively traverse the CU/TU quadtree. At the lowest level, apply the
|
||||
* deblocking filter to the left edge (when dir == EDGE_VER) or the top edge
|
||||
* (when dir == EDGE_HOR) as needed. Both luma and chroma are filtered.
|
||||
*/
|
||||
static void filter_deblock_cu(encoder_state_t * const state,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int8_t depth,
|
||||
edge_dir dir)
|
||||
static void filter_deblock_lcu_inside(encoder_state_t * const state,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
edge_dir dir)
|
||||
{
|
||||
const videoframe_t * const frame = state->tile->frame;
|
||||
const cu_info_t *cur_cu = kvz_videoframe_get_cu_const(frame,
|
||||
x >> MAX_DEPTH,
|
||||
y >> MAX_DEPTH);
|
||||
const int end_x = MIN(x + LCU_WIDTH, state->tile->frame->width);
|
||||
const int end_y = MIN(y + LCU_WIDTH, state->tile->frame->height);
|
||||
|
||||
const int cu_width = LCU_WIDTH >> depth;
|
||||
const int half_cu_width = cu_width >> 1;
|
||||
const int scu_width = LCU_WIDTH >> MAX_DEPTH;
|
||||
const bool split_flag = cur_cu->depth > depth;
|
||||
const bool tr_split = cur_cu->tr_depth > depth;
|
||||
const bool border_x = frame->width < x + cu_width;
|
||||
const bool border_y = frame->height < y + cu_width;
|
||||
const bool border_split_x = frame->width >= x + scu_width + half_cu_width;
|
||||
const bool border_split_y = frame->height >= y + scu_width + half_cu_width;
|
||||
const bool border = border_x || border_y; // are we in any border CU?
|
||||
|
||||
// split 64x64, on split flag and on border
|
||||
if (depth < MAX_DEPTH && (depth == 0 || split_flag || border || tr_split)) {
|
||||
// Split the four sub-blocks of this block recursively.
|
||||
const int32_t x2 = x + half_cu_width;
|
||||
const int32_t y2 = y + half_cu_width;
|
||||
|
||||
filter_deblock_cu(state, x, y, depth + 1, dir);
|
||||
if (!border_x || border_split_x) {
|
||||
filter_deblock_cu(state, x2, y, depth + 1, dir);
|
||||
}
|
||||
if (!border_y || border_split_y) {
|
||||
filter_deblock_cu(state, x, y2, depth + 1, dir);
|
||||
}
|
||||
if (!border || (border_split_x && border_split_y)) {
|
||||
filter_deblock_cu(state, x2, y2, depth + 1, dir);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// no filtering on borders (where filter would use pixels outside the picture)
|
||||
if ((x == 0 && dir == EDGE_VER) || (y == 0 && dir == EDGE_HOR)) return;
|
||||
|
||||
// do the filtering for block edge
|
||||
if (is_tu_boundary(state, x, y, dir)) {
|
||||
// Length of luma and chroma edges.
|
||||
int32_t length;
|
||||
int32_t length_c;
|
||||
|
||||
const int32_t x_right = x + cu_width;
|
||||
const bool rightmost_4px_of_lcu = x_right % LCU_WIDTH == 0;
|
||||
const bool rightmost_4px_of_frame = x_right == frame->width;
|
||||
|
||||
if (dir == EDGE_HOR &&
|
||||
rightmost_4px_of_lcu &&
|
||||
!rightmost_4px_of_frame) {
|
||||
// The last 4 pixels will be deblocked when processing the next LCU.
|
||||
length = cu_width - 4;
|
||||
length_c = half_cu_width - 4;
|
||||
|
||||
} else {
|
||||
length = cu_width;
|
||||
length_c = half_cu_width;
|
||||
}
|
||||
|
||||
filter_deblock_edge_luma(state, x, y, length, dir);
|
||||
|
||||
// Chroma pixel coordinates.
|
||||
const int32_t x_c = x >> 1;
|
||||
const int32_t y_c = y >> 1;
|
||||
if (is_on_8x8_grid(x_c, y_c, dir)) {
|
||||
filter_deblock_edge_chroma(state, x_c, y_c, length_c, dir);
|
||||
for (int edge_y = y; edge_y < end_y; edge_y += 8) {
|
||||
for (int edge_x = x; edge_x < end_x; edge_x += 8) {
|
||||
bool tu_boundary = is_tu_boundary(state, edge_x, edge_y, dir);
|
||||
if (tu_boundary || is_pu_boundary(state, edge_x, edge_y, dir)) {
|
||||
filter_deblock_unit(state, edge_x, edge_y, 8, 8, dir, tu_boundary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -597,23 +644,17 @@ static void filter_deblock_cu(encoder_state_t * const state,
|
|||
*/
|
||||
void kvz_filter_deblock_lcu(encoder_state_t * const state, int x_px, int y_px)
|
||||
{
|
||||
const vector2d_t lcu = { x_px / LCU_WIDTH, y_px / LCU_WIDTH };
|
||||
|
||||
filter_deblock_cu(state, x_px, y_px, 0, EDGE_VER);
|
||||
|
||||
assert(x_px == lcu.x * LCU_WIDTH);
|
||||
assert(y_px == lcu.y * LCU_WIDTH);
|
||||
|
||||
// Filter rightmost 4 pixels from last LCU now that they have been
|
||||
// finally deblocked vertically.
|
||||
filter_deblock_lcu_inside(state, x_px, y_px, EDGE_VER);
|
||||
if (x_px > 0) {
|
||||
// Luma
|
||||
const int x = x_px - 4;
|
||||
const int end = MIN(y_px + LCU_WIDTH, state->tile->frame->height);
|
||||
for (int y = y_px; y < end; y += 8) {
|
||||
// The top edge of the whole frame is not filtered.
|
||||
if (y > 0 && is_tu_boundary(state, x, y, EDGE_HOR)) {
|
||||
filter_deblock_edge_luma(state, x, y, 4, EDGE_HOR);
|
||||
bool tu_boundary = is_tu_boundary(state, x, y, EDGE_HOR);
|
||||
bool pu_boundary = is_pu_boundary(state, x, y, EDGE_HOR);
|
||||
if (y > 0 && (tu_boundary || pu_boundary)) {
|
||||
filter_deblock_edge_luma(state, x, y, 4, EDGE_HOR, tu_boundary);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -624,11 +665,12 @@ void kvz_filter_deblock_lcu(encoder_state_t * const state, int x_px, int y_px)
|
|||
const int end_c = MIN(y_px_c + LCU_WIDTH_C, state->tile->frame->height >> 1);
|
||||
for (int y_c = y_px_c; y_c < end_c; y_c += 8) {
|
||||
// The top edge of the whole frame is not filtered.
|
||||
if (y_c > 0 && is_tu_boundary(state, x_c << 1, y_c << 1, EDGE_HOR)) {
|
||||
filter_deblock_edge_chroma(state, x_c, y_c, 4, EDGE_HOR);
|
||||
bool tu_boundary = is_tu_boundary(state, x_c << 1, y_c << 1, EDGE_HOR);
|
||||
bool pu_boundary = is_pu_boundary(state, x_c << 1, y_c << 1, EDGE_HOR);
|
||||
if (y_c > 0 && (tu_boundary || pu_boundary)) {
|
||||
filter_deblock_edge_chroma(state, x_c, y_c, 4, EDGE_HOR, tu_boundary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filter_deblock_cu(state, x_px, y_px, 0, EDGE_HOR);
|
||||
filter_deblock_lcu_inside(state, x_px, y_px, EDGE_HOR);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue