Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * HEVC video decoder
  3.  *
  4.  * Copyright (C) 2012 - 2013 Guillaume Martres
  5.  * Copyright (C) 2013 Seppo Tomperi
  6.  * Copyright (C) 2013 Wassim Hamidouche
  7.  *
  8.  * This file is part of FFmpeg.
  9.  *
  10.  * FFmpeg is free software; you can redistribute it and/or
  11.  * modify it under the terms of the GNU Lesser General Public
  12.  * License as published by the Free Software Foundation; either
  13.  * version 2.1 of the License, or (at your option) any later version.
  14.  *
  15.  * FFmpeg is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18.  * Lesser General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU Lesser General Public
  21.  * License along with FFmpeg; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23.  */
  24.  
  25. #include "libavutil/common.h"
  26. #include "libavutil/internal.h"
  27.  
  28. #include "cabac_functions.h"
  29. #include "golomb.h"
  30. #include "hevc.h"
  31.  
  32. #include "bit_depth_template.c"
  33.  
  34. #define LUMA 0
  35. #define CB 1
  36. #define CR 2
  37.  
  38. static const uint8_t tctable[54] = {
  39.     0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0, 1, // QP  0...18
  40.     1, 1, 1, 1, 1, 1, 1,  1,  2,  2,  2,  2,  3,  3,  3,  3, 4, 4, 4, // QP 19...37
  41.     5, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 24           // QP 38...53
  42. };
  43.  
  44. static const uint8_t betatable[52] = {
  45.      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  7,  8, // QP 0...18
  46.      9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, // QP 19...37
  47.     38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64                      // QP 38...51
  48. };
  49.  
  50. static int chroma_tc(HEVCContext *s, int qp_y, int c_idx, int tc_offset)
  51. {
  52.     static const int qp_c[] = {
  53.         29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37
  54.     };
  55.     int qp, qp_i, offset, idxt;
  56.  
  57.     // slice qp offset is not used for deblocking
  58.     if (c_idx == 1)
  59.         offset = s->ps.pps->cb_qp_offset;
  60.     else
  61.         offset = s->ps.pps->cr_qp_offset;
  62.  
  63.     qp_i = av_clip(qp_y + offset, 0, 57);
  64.     if (s->ps.sps->chroma_format_idc == 1) {
  65.         if (qp_i < 30)
  66.             qp = qp_i;
  67.         else if (qp_i > 43)
  68.             qp = qp_i - 6;
  69.         else
  70.             qp = qp_c[qp_i - 30];
  71.     } else {
  72.         qp = av_clip(qp_i, 0, 51);
  73.     }
  74.  
  75.     idxt = av_clip(qp + DEFAULT_INTRA_TC_OFFSET + tc_offset, 0, 53);
  76.     return tctable[idxt];
  77. }
  78.  
  79. static int get_qPy_pred(HEVCContext *s, int xBase, int yBase, int log2_cb_size)
  80. {
  81.     HEVCLocalContext *lc     = s->HEVClc;
  82.     int ctb_size_mask        = (1 << s->ps.sps->log2_ctb_size) - 1;
  83.     int MinCuQpDeltaSizeMask = (1 << (s->ps.sps->log2_ctb_size -
  84.                                       s->ps.pps->diff_cu_qp_delta_depth)) - 1;
  85.     int xQgBase              = xBase - (xBase & MinCuQpDeltaSizeMask);
  86.     int yQgBase              = yBase - (yBase & MinCuQpDeltaSizeMask);
  87.     int min_cb_width         = s->ps.sps->min_cb_width;
  88.     int x_cb                 = xQgBase >> s->ps.sps->log2_min_cb_size;
  89.     int y_cb                 = yQgBase >> s->ps.sps->log2_min_cb_size;
  90.     int availableA           = (xBase   & ctb_size_mask) &&
  91.                                (xQgBase & ctb_size_mask);
  92.     int availableB           = (yBase   & ctb_size_mask) &&
  93.                                (yQgBase & ctb_size_mask);
  94.     int qPy_pred, qPy_a, qPy_b;
  95.  
  96.     // qPy_pred
  97.     if (lc->first_qp_group || (!xQgBase && !yQgBase)) {
  98.         lc->first_qp_group = !lc->tu.is_cu_qp_delta_coded;
  99.         qPy_pred = s->sh.slice_qp;
  100.     } else {
  101.         qPy_pred = lc->qPy_pred;
  102.     }
  103.  
  104.     // qPy_a
  105.     if (availableA == 0)
  106.         qPy_a = qPy_pred;
  107.     else
  108.         qPy_a = s->qp_y_tab[(x_cb - 1) + y_cb * min_cb_width];
  109.  
  110.     // qPy_b
  111.     if (availableB == 0)
  112.         qPy_b = qPy_pred;
  113.     else
  114.         qPy_b = s->qp_y_tab[x_cb + (y_cb - 1) * min_cb_width];
  115.  
  116.     av_assert2(qPy_a >= -s->ps.sps->qp_bd_offset && qPy_a < 52);
  117.     av_assert2(qPy_b >= -s->ps.sps->qp_bd_offset && qPy_b < 52);
  118.  
  119.     return (qPy_a + qPy_b + 1) >> 1;
  120. }
  121.  
  122. void ff_hevc_set_qPy(HEVCContext *s, int xBase, int yBase, int log2_cb_size)
  123. {
  124.     int qp_y = get_qPy_pred(s, xBase, yBase, log2_cb_size);
  125.  
  126.     if (s->HEVClc->tu.cu_qp_delta != 0) {
  127.         int off = s->ps.sps->qp_bd_offset;
  128.         s->HEVClc->qp_y = FFUMOD(qp_y + s->HEVClc->tu.cu_qp_delta + 52 + 2 * off,
  129.                                  52 + off) - off;
  130.     } else
  131.         s->HEVClc->qp_y = qp_y;
  132. }
  133.  
  134. static int get_qPy(HEVCContext *s, int xC, int yC)
  135. {
  136.     int log2_min_cb_size  = s->ps.sps->log2_min_cb_size;
  137.     int x                 = xC >> log2_min_cb_size;
  138.     int y                 = yC >> log2_min_cb_size;
  139.     return s->qp_y_tab[x + y * s->ps.sps->min_cb_width];
  140. }
  141.  
  142. static void copy_CTB(uint8_t *dst, const uint8_t *src, int width, int height,
  143.                      intptr_t stride_dst, intptr_t stride_src)
  144. {
  145. int i, j;
  146.  
  147.     if (((intptr_t)dst | (intptr_t)src | stride_dst | stride_src) & 15) {
  148.         for (i = 0; i < height; i++) {
  149.             for (j = 0; j < width; j+=8)
  150.                 AV_COPY64U(dst+j, src+j);
  151.             dst += stride_dst;
  152.             src += stride_src;
  153.         }
  154.     } else {
  155.         for (i = 0; i < height; i++) {
  156.             for (j = 0; j < width; j+=16)
  157.                 AV_COPY128(dst+j, src+j);
  158.             dst += stride_dst;
  159.             src += stride_src;
  160.         }
  161.     }
  162. }
  163.  
  164. static void copy_pixel(uint8_t *dst, const uint8_t *src, int pixel_shift)
  165. {
  166.     if (pixel_shift)
  167.         *(uint16_t *)dst = *(uint16_t *)src;
  168.     else
  169.         *dst = *src;
  170. }
  171.  
  172. static void copy_vert(uint8_t *dst, const uint8_t *src,
  173.                       int pixel_shift, int height,
  174.                       int stride_dst, int stride_src)
  175. {
  176.     int i;
  177.     if (pixel_shift == 0) {
  178.         for (i = 0; i < height; i++) {
  179.             *dst = *src;
  180.             dst += stride_dst;
  181.             src += stride_src;
  182.         }
  183.     } else {
  184.         for (i = 0; i < height; i++) {
  185.             *(uint16_t *)dst = *(uint16_t *)src;
  186.             dst += stride_dst;
  187.             src += stride_src;
  188.         }
  189.     }
  190. }
  191.  
  192. static void copy_CTB_to_hv(HEVCContext *s, const uint8_t *src,
  193.                            int stride_src, int x, int y, int width, int height,
  194.                            int c_idx, int x_ctb, int y_ctb)
  195. {
  196.     int sh = s->ps.sps->pixel_shift;
  197.     int w = s->ps.sps->width >> s->ps.sps->hshift[c_idx];
  198.     int h = s->ps.sps->height >> s->ps.sps->vshift[c_idx];
  199.  
  200.     /* copy horizontal edges */
  201.     memcpy(s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb) * w + x) << sh),
  202.         src, width << sh);
  203.     memcpy(s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 1) * w + x) << sh),
  204.         src + stride_src * (height - 1), width << sh);
  205.  
  206.     /* copy vertical edges */
  207.     copy_vert(s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb) * h + y) << sh), src, sh, height, 1 << sh, stride_src);
  208.  
  209.     copy_vert(s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 1) * h + y) << sh), src + ((width - 1) << sh), sh, height, 1 << sh, stride_src);
  210. }
  211.  
  212. static void restore_tqb_pixels(HEVCContext *s,
  213.                                uint8_t *src1, const uint8_t *dst1,
  214.                                ptrdiff_t stride_src, ptrdiff_t stride_dst,
  215.                                int x0, int y0, int width, int height, int c_idx)
  216. {
  217.     if ( s->ps.pps->transquant_bypass_enable_flag ||
  218.             (s->ps.sps->pcm.loop_filter_disable_flag && s->ps.sps->pcm_enabled_flag)) {
  219.         int x, y;
  220.         int min_pu_size  = 1 << s->ps.sps->log2_min_pu_size;
  221.         int hshift       = s->ps.sps->hshift[c_idx];
  222.         int vshift       = s->ps.sps->vshift[c_idx];
  223.         int x_min        = ((x0         ) >> s->ps.sps->log2_min_pu_size);
  224.         int y_min        = ((y0         ) >> s->ps.sps->log2_min_pu_size);
  225.         int x_max        = ((x0 + width ) >> s->ps.sps->log2_min_pu_size);
  226.         int y_max        = ((y0 + height) >> s->ps.sps->log2_min_pu_size);
  227.         int len          = (min_pu_size >> hshift) << s->ps.sps->pixel_shift;
  228.         for (y = y_min; y < y_max; y++) {
  229.             for (x = x_min; x < x_max; x++) {
  230.                 if (s->is_pcm[y * s->ps.sps->min_pu_width + x]) {
  231.                     int n;
  232.                     uint8_t *src = src1 + (((y << s->ps.sps->log2_min_pu_size) - y0) >> vshift) * stride_src + ((((x << s->ps.sps->log2_min_pu_size) - x0) >> hshift) << s->ps.sps->pixel_shift);
  233.                     const uint8_t *dst = dst1 + (((y << s->ps.sps->log2_min_pu_size) - y0) >> vshift) * stride_dst + ((((x << s->ps.sps->log2_min_pu_size) - x0) >> hshift) << s->ps.sps->pixel_shift);
  234.                     for (n = 0; n < (min_pu_size >> vshift); n++) {
  235.                         memcpy(src, dst, len);
  236.                         src += stride_src;
  237.                         dst += stride_dst;
  238.                     }
  239.                 }
  240.             }
  241.         }
  242.     }
  243. }
  244.  
  245. #define CTB(tab, x, y) ((tab)[(y) * s->ps.sps->ctb_width + (x)])
  246.  
  247. static void sao_filter_CTB(HEVCContext *s, int x, int y)
  248. {
  249.     static const uint8_t sao_tab[8] = { 0, 1, 2, 2, 3, 3, 4, 4 };
  250.     HEVCLocalContext *lc = s->HEVClc;
  251.     int c_idx;
  252.     int edges[4];  // 0 left 1 top 2 right 3 bottom
  253.     int x_ctb                = x >> s->ps.sps->log2_ctb_size;
  254.     int y_ctb                = y >> s->ps.sps->log2_ctb_size;
  255.     int ctb_addr_rs          = y_ctb * s->ps.sps->ctb_width + x_ctb;
  256.     int ctb_addr_ts          = s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs];
  257.     SAOParams *sao           = &CTB(s->sao, x_ctb, y_ctb);
  258.     // flags indicating unfilterable edges
  259.     uint8_t vert_edge[]      = { 0, 0 };
  260.     uint8_t horiz_edge[]     = { 0, 0 };
  261.     uint8_t diag_edge[]      = { 0, 0, 0, 0 };
  262.     uint8_t lfase            = CTB(s->filter_slice_edges, x_ctb, y_ctb);
  263.     uint8_t no_tile_filter   = s->ps.pps->tiles_enabled_flag &&
  264.                                !s->ps.pps->loop_filter_across_tiles_enabled_flag;
  265.     uint8_t restore          = no_tile_filter || !lfase;
  266.     uint8_t left_tile_edge   = 0;
  267.     uint8_t right_tile_edge  = 0;
  268.     uint8_t up_tile_edge     = 0;
  269.     uint8_t bottom_tile_edge = 0;
  270.  
  271.     edges[0]   = x_ctb == 0;
  272.     edges[1]   = y_ctb == 0;
  273.     edges[2]   = x_ctb == s->ps.sps->ctb_width  - 1;
  274.     edges[3]   = y_ctb == s->ps.sps->ctb_height - 1;
  275.  
  276.     if (restore) {
  277.         if (!edges[0]) {
  278.             left_tile_edge  = no_tile_filter && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs-1]];
  279.             vert_edge[0]    = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb)) || left_tile_edge;
  280.         }
  281.         if (!edges[2]) {
  282.             right_tile_edge = no_tile_filter && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs+1]];
  283.             vert_edge[1]    = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb)) || right_tile_edge;
  284.         }
  285.         if (!edges[1]) {
  286.             up_tile_edge     = no_tile_filter && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs - s->ps.sps->ctb_width]];
  287.             horiz_edge[0]    = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) || up_tile_edge;
  288.         }
  289.         if (!edges[3]) {
  290.             bottom_tile_edge = no_tile_filter && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs + s->ps.sps->ctb_width]];
  291.             horiz_edge[1]    = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb, y_ctb + 1)) || bottom_tile_edge;
  292.         }
  293.         if (!edges[0] && !edges[1]) {
  294.             diag_edge[0] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb - 1)) || left_tile_edge || up_tile_edge;
  295.         }
  296.         if (!edges[1] && !edges[2]) {
  297.             diag_edge[1] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb - 1)) || right_tile_edge || up_tile_edge;
  298.         }
  299.         if (!edges[2] && !edges[3]) {
  300.             diag_edge[2] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb + 1)) || right_tile_edge || bottom_tile_edge;
  301.         }
  302.         if (!edges[0] && !edges[3]) {
  303.             diag_edge[3] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb + 1)) || left_tile_edge || bottom_tile_edge;
  304.         }
  305.     }
  306.  
  307.     for (c_idx = 0; c_idx < (s->ps.sps->chroma_format_idc ? 3 : 1); c_idx++) {
  308.         int x0       = x >> s->ps.sps->hshift[c_idx];
  309.         int y0       = y >> s->ps.sps->vshift[c_idx];
  310.         int stride_src = s->frame->linesize[c_idx];
  311.         int ctb_size_h = (1 << (s->ps.sps->log2_ctb_size)) >> s->ps.sps->hshift[c_idx];
  312.         int ctb_size_v = (1 << (s->ps.sps->log2_ctb_size)) >> s->ps.sps->vshift[c_idx];
  313.         int width    = FFMIN(ctb_size_h, (s->ps.sps->width  >> s->ps.sps->hshift[c_idx]) - x0);
  314.         int height   = FFMIN(ctb_size_v, (s->ps.sps->height >> s->ps.sps->vshift[c_idx]) - y0);
  315.         int tab      = sao_tab[(FFALIGN(width, 8) >> 3) - 1];
  316.         uint8_t *src = &s->frame->data[c_idx][y0 * stride_src + (x0 << s->ps.sps->pixel_shift)];
  317.         int stride_dst;
  318.         uint8_t *dst;
  319.  
  320.         switch (sao->type_idx[c_idx]) {
  321.         case SAO_BAND:
  322.             copy_CTB_to_hv(s, src, stride_src, x0, y0, width, height, c_idx,
  323.                            x_ctb, y_ctb);
  324.             if (s->ps.pps->transquant_bypass_enable_flag ||
  325.                 (s->ps.sps->pcm.loop_filter_disable_flag && s->ps.sps->pcm_enabled_flag)) {
  326.             dst = lc->edge_emu_buffer;
  327.             stride_dst = 2*MAX_PB_SIZE;
  328.             copy_CTB(dst, src, width << s->ps.sps->pixel_shift, height, stride_dst, stride_src);
  329.             s->hevcdsp.sao_band_filter[tab](src, dst, stride_src, stride_dst,
  330.                                             sao->offset_val[c_idx], sao->band_position[c_idx],
  331.                                             width, height);
  332.             restore_tqb_pixels(s, src, dst, stride_src, stride_dst,
  333.                                x, y, width, height, c_idx);
  334.             } else {
  335.             s->hevcdsp.sao_band_filter[tab](src, src, stride_src, stride_src,
  336.                                             sao->offset_val[c_idx], sao->band_position[c_idx],
  337.                                             width, height);
  338.             }
  339.             sao->type_idx[c_idx] = SAO_APPLIED;
  340.             break;
  341.         case SAO_EDGE:
  342.         {
  343.             int w = s->ps.sps->width >> s->ps.sps->hshift[c_idx];
  344.             int h = s->ps.sps->height >> s->ps.sps->vshift[c_idx];
  345.             int left_edge = edges[0];
  346.             int top_edge = edges[1];
  347.             int right_edge = edges[2];
  348.             int bottom_edge = edges[3];
  349.             int sh = s->ps.sps->pixel_shift;
  350.             int left_pixels, right_pixels;
  351.  
  352.             stride_dst = 2*MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE;
  353.             dst = lc->edge_emu_buffer + stride_dst + AV_INPUT_BUFFER_PADDING_SIZE;
  354.  
  355.             if (!top_edge) {
  356.                 int left = 1 - left_edge;
  357.                 int right = 1 - right_edge;
  358.                 const uint8_t *src1[2];
  359.                 uint8_t *dst1;
  360.                 int src_idx, pos;
  361.  
  362.                 dst1 = dst - stride_dst - (left << sh);
  363.                 src1[0] = src - stride_src - (left << sh);
  364.                 src1[1] = s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb - 1) * w + x0 - left) << sh);
  365.                 pos = 0;
  366.                 if (left) {
  367.                     src_idx = (CTB(s->sao, x_ctb-1, y_ctb-1).type_idx[c_idx] ==
  368.                                SAO_APPLIED);
  369.                     copy_pixel(dst1, src1[src_idx], sh);
  370.                     pos += (1 << sh);
  371.                 }
  372.                 src_idx = (CTB(s->sao, x_ctb, y_ctb-1).type_idx[c_idx] ==
  373.                            SAO_APPLIED);
  374.                 memcpy(dst1 + pos, src1[src_idx] + pos, width << sh);
  375.                 if (right) {
  376.                     pos += width << sh;
  377.                     src_idx = (CTB(s->sao, x_ctb+1, y_ctb-1).type_idx[c_idx] ==
  378.                                SAO_APPLIED);
  379.                     copy_pixel(dst1 + pos, src1[src_idx] + pos, sh);
  380.                 }
  381.             }
  382.             if (!bottom_edge) {
  383.                 int left = 1 - left_edge;
  384.                 int right = 1 - right_edge;
  385.                 const uint8_t *src1[2];
  386.                 uint8_t *dst1;
  387.                 int src_idx, pos;
  388.  
  389.                 dst1 = dst + height * stride_dst - (left << sh);
  390.                 src1[0] = src + height * stride_src - (left << sh);
  391.                 src1[1] = s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 2) * w + x0 - left) << sh);
  392.                 pos = 0;
  393.                 if (left) {
  394.                     src_idx = (CTB(s->sao, x_ctb-1, y_ctb+1).type_idx[c_idx] ==
  395.                                SAO_APPLIED);
  396.                     copy_pixel(dst1, src1[src_idx], sh);
  397.                     pos += (1 << sh);
  398.                 }
  399.                 src_idx = (CTB(s->sao, x_ctb, y_ctb+1).type_idx[c_idx] ==
  400.                            SAO_APPLIED);
  401.                 memcpy(dst1 + pos, src1[src_idx] + pos, width << sh);
  402.                 if (right) {
  403.                     pos += width << sh;
  404.                     src_idx = (CTB(s->sao, x_ctb+1, y_ctb+1).type_idx[c_idx] ==
  405.                                SAO_APPLIED);
  406.                     copy_pixel(dst1 + pos, src1[src_idx] + pos, sh);
  407.                 }
  408.             }
  409.             left_pixels = 0;
  410.             if (!left_edge) {
  411.                 if (CTB(s->sao, x_ctb-1, y_ctb).type_idx[c_idx] == SAO_APPLIED) {
  412.                     copy_vert(dst - (1 << sh),
  413.                               s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb - 1) * h + y0) << sh),
  414.                               sh, height, stride_dst, 1 << sh);
  415.                 } else {
  416.                     left_pixels = 1;
  417.                 }
  418.             }
  419.             right_pixels = 0;
  420.             if (!right_edge) {
  421.                 if (CTB(s->sao, x_ctb+1, y_ctb).type_idx[c_idx] == SAO_APPLIED) {
  422.                     copy_vert(dst + (width << sh),
  423.                               s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 2) * h + y0) << sh),
  424.                               sh, height, stride_dst, 1 << sh);
  425.                 } else {
  426.                     right_pixels = 1;
  427.                 }
  428.             }
  429.  
  430.             copy_CTB(dst - (left_pixels << sh),
  431.                      src - (left_pixels << sh),
  432.                      (width + left_pixels + right_pixels) << sh,
  433.                      height, stride_dst, stride_src);
  434.  
  435.             copy_CTB_to_hv(s, src, stride_src, x0, y0, width, height, c_idx,
  436.                            x_ctb, y_ctb);
  437.             s->hevcdsp.sao_edge_filter[tab](src, dst, stride_src, sao->offset_val[c_idx],
  438.                                             sao->eo_class[c_idx], width, height);
  439.             s->hevcdsp.sao_edge_restore[restore](src, dst,
  440.                                                 stride_src, stride_dst,
  441.                                                 sao,
  442.                                                 edges, width,
  443.                                                 height, c_idx,
  444.                                                 vert_edge,
  445.                                                 horiz_edge,
  446.                                                 diag_edge);
  447.             restore_tqb_pixels(s, src, dst, stride_src, stride_dst,
  448.                                x, y, width, height, c_idx);
  449.             sao->type_idx[c_idx] = SAO_APPLIED;
  450.             break;
  451.         }
  452.         }
  453.     }
  454. }
  455.  
  456. static int get_pcm(HEVCContext *s, int x, int y)
  457. {
  458.     int log2_min_pu_size = s->ps.sps->log2_min_pu_size;
  459.     int x_pu, y_pu;
  460.  
  461.     if (x < 0 || y < 0)
  462.         return 2;
  463.  
  464.     x_pu = x >> log2_min_pu_size;
  465.     y_pu = y >> log2_min_pu_size;
  466.  
  467.     if (x_pu >= s->ps.sps->min_pu_width || y_pu >= s->ps.sps->min_pu_height)
  468.         return 2;
  469.     return s->is_pcm[y_pu * s->ps.sps->min_pu_width + x_pu];
  470. }
  471.  
  472. #define TC_CALC(qp, bs)                                                 \
  473.     tctable[av_clip((qp) + DEFAULT_INTRA_TC_OFFSET * ((bs) - 1) +       \
  474.                     (tc_offset >> 1 << 1),                              \
  475.                     0, MAX_QP + DEFAULT_INTRA_TC_OFFSET)]
  476.  
  477. static void deblocking_filter_CTB(HEVCContext *s, int x0, int y0)
  478. {
  479.     uint8_t *src;
  480.     int x, y;
  481.     int chroma, beta;
  482.     int32_t c_tc[2], tc[2];
  483.     uint8_t no_p[2] = { 0 };
  484.     uint8_t no_q[2] = { 0 };
  485.  
  486.     int log2_ctb_size = s->ps.sps->log2_ctb_size;
  487.     int x_end, x_end2, y_end;
  488.     int ctb_size        = 1 << log2_ctb_size;
  489.     int ctb             = (x0 >> log2_ctb_size) +
  490.                           (y0 >> log2_ctb_size) * s->ps.sps->ctb_width;
  491.     int cur_tc_offset   = s->deblock[ctb].tc_offset;
  492.     int cur_beta_offset = s->deblock[ctb].beta_offset;
  493.     int left_tc_offset, left_beta_offset;
  494.     int tc_offset, beta_offset;
  495.     int pcmf = (s->ps.sps->pcm_enabled_flag &&
  496.                 s->ps.sps->pcm.loop_filter_disable_flag) ||
  497.                s->ps.pps->transquant_bypass_enable_flag;
  498.  
  499.     if (x0) {
  500.         left_tc_offset   = s->deblock[ctb - 1].tc_offset;
  501.         left_beta_offset = s->deblock[ctb - 1].beta_offset;
  502.     } else {
  503.         left_tc_offset   = 0;
  504.         left_beta_offset = 0;
  505.     }
  506.  
  507.     x_end = x0 + ctb_size;
  508.     if (x_end > s->ps.sps->width)
  509.         x_end = s->ps.sps->width;
  510.     y_end = y0 + ctb_size;
  511.     if (y_end > s->ps.sps->height)
  512.         y_end = s->ps.sps->height;
  513.  
  514.     tc_offset   = cur_tc_offset;
  515.     beta_offset = cur_beta_offset;
  516.  
  517.     x_end2 = x_end;
  518.     if (x_end2 != s->ps.sps->width)
  519.         x_end2 -= 8;
  520.     for (y = y0; y < y_end; y += 8) {
  521.         // vertical filtering luma
  522.         for (x = x0 ? x0 : 8; x < x_end; x += 8) {
  523.             const int bs0 = s->vertical_bs[(x +  y      * s->bs_width) >> 2];
  524.             const int bs1 = s->vertical_bs[(x + (y + 4) * s->bs_width) >> 2];
  525.             if (bs0 || bs1) {
  526.                 const int qp = (get_qPy(s, x - 1, y)     + get_qPy(s, x, y)     + 1) >> 1;
  527.  
  528.                 beta = betatable[av_clip(qp + beta_offset, 0, MAX_QP)];
  529.  
  530.                 tc[0]   = bs0 ? TC_CALC(qp, bs0) : 0;
  531.                 tc[1]   = bs1 ? TC_CALC(qp, bs1) : 0;
  532.                 src     = &s->frame->data[LUMA][y * s->frame->linesize[LUMA] + (x << s->ps.sps->pixel_shift)];
  533.                 if (pcmf) {
  534.                     no_p[0] = get_pcm(s, x - 1, y);
  535.                     no_p[1] = get_pcm(s, x - 1, y + 4);
  536.                     no_q[0] = get_pcm(s, x, y);
  537.                     no_q[1] = get_pcm(s, x, y + 4);
  538.                     s->hevcdsp.hevc_v_loop_filter_luma_c(src,
  539.                                                          s->frame->linesize[LUMA],
  540.                                                          beta, tc, no_p, no_q);
  541.                 } else
  542.                     s->hevcdsp.hevc_v_loop_filter_luma(src,
  543.                                                        s->frame->linesize[LUMA],
  544.                                                        beta, tc, no_p, no_q);
  545.             }
  546.         }
  547.  
  548.         if(!y)
  549.              continue;
  550.  
  551.         // horizontal filtering luma
  552.         for (x = x0 ? x0 - 8 : 0; x < x_end2; x += 8) {
  553.             const int bs0 = s->horizontal_bs[( x      + y * s->bs_width) >> 2];
  554.             const int bs1 = s->horizontal_bs[((x + 4) + y * s->bs_width) >> 2];
  555.             if (bs0 || bs1) {
  556.                 const int qp = (get_qPy(s, x, y - 1)     + get_qPy(s, x, y)     + 1) >> 1;
  557.  
  558.                 tc_offset   = x >= x0 ? cur_tc_offset : left_tc_offset;
  559.                 beta_offset = x >= x0 ? cur_beta_offset : left_beta_offset;
  560.  
  561.                 beta = betatable[av_clip(qp + beta_offset, 0, MAX_QP)];
  562.                 tc[0]   = bs0 ? TC_CALC(qp, bs0) : 0;
  563.                 tc[1]   = bs1 ? TC_CALC(qp, bs1) : 0;
  564.                 src     = &s->frame->data[LUMA][y * s->frame->linesize[LUMA] + (x << s->ps.sps->pixel_shift)];
  565.                 if (pcmf) {
  566.                     no_p[0] = get_pcm(s, x, y - 1);
  567.                     no_p[1] = get_pcm(s, x + 4, y - 1);
  568.                     no_q[0] = get_pcm(s, x, y);
  569.                     no_q[1] = get_pcm(s, x + 4, y);
  570.                     s->hevcdsp.hevc_h_loop_filter_luma_c(src,
  571.                                                          s->frame->linesize[LUMA],
  572.                                                          beta, tc, no_p, no_q);
  573.                 } else
  574.                     s->hevcdsp.hevc_h_loop_filter_luma(src,
  575.                                                        s->frame->linesize[LUMA],
  576.                                                        beta, tc, no_p, no_q);
  577.             }
  578.         }
  579.     }
  580.  
  581.     if (s->ps.sps->chroma_format_idc) {
  582.         for (chroma = 1; chroma <= 2; chroma++) {
  583.             int h = 1 << s->ps.sps->hshift[chroma];
  584.             int v = 1 << s->ps.sps->vshift[chroma];
  585.  
  586.             // vertical filtering chroma
  587.             for (y = y0; y < y_end; y += (8 * v)) {
  588.                 for (x = x0 ? x0 : 8 * h; x < x_end; x += (8 * h)) {
  589.                     const int bs0 = s->vertical_bs[(x +  y            * s->bs_width) >> 2];
  590.                     const int bs1 = s->vertical_bs[(x + (y + (4 * v)) * s->bs_width) >> 2];
  591.  
  592.                     if ((bs0 == 2) || (bs1 == 2)) {
  593.                         const int qp0 = (get_qPy(s, x - 1, y)           + get_qPy(s, x, y)           + 1) >> 1;
  594.                         const int qp1 = (get_qPy(s, x - 1, y + (4 * v)) + get_qPy(s, x, y + (4 * v)) + 1) >> 1;
  595.  
  596.                         c_tc[0] = (bs0 == 2) ? chroma_tc(s, qp0, chroma, tc_offset) : 0;
  597.                         c_tc[1] = (bs1 == 2) ? chroma_tc(s, qp1, chroma, tc_offset) : 0;
  598.                         src       = &s->frame->data[chroma][(y >> s->ps.sps->vshift[chroma]) * s->frame->linesize[chroma] + ((x >> s->ps.sps->hshift[chroma]) << s->ps.sps->pixel_shift)];
  599.                         if (pcmf) {
  600.                             no_p[0] = get_pcm(s, x - 1, y);
  601.                             no_p[1] = get_pcm(s, x - 1, y + (4 * v));
  602.                             no_q[0] = get_pcm(s, x, y);
  603.                             no_q[1] = get_pcm(s, x, y + (4 * v));
  604.                             s->hevcdsp.hevc_v_loop_filter_chroma_c(src,
  605.                                                                    s->frame->linesize[chroma],
  606.                                                                    c_tc, no_p, no_q);
  607.                         } else
  608.                             s->hevcdsp.hevc_v_loop_filter_chroma(src,
  609.                                                                  s->frame->linesize[chroma],
  610.                                                                  c_tc, no_p, no_q);
  611.                     }
  612.                 }
  613.  
  614.                 if(!y)
  615.                     continue;
  616.  
  617.                 // horizontal filtering chroma
  618.                 tc_offset = x0 ? left_tc_offset : cur_tc_offset;
  619.                 x_end2 = x_end;
  620.                 if (x_end != s->ps.sps->width)
  621.                     x_end2 = x_end - 8 * h;
  622.                 for (x = x0 ? x0 - 8 * h : 0; x < x_end2; x += (8 * h)) {
  623.                     const int bs0 = s->horizontal_bs[( x          + y * s->bs_width) >> 2];
  624.                     const int bs1 = s->horizontal_bs[((x + 4 * h) + y * s->bs_width) >> 2];
  625.                     if ((bs0 == 2) || (bs1 == 2)) {
  626.                         const int qp0 = bs0 == 2 ? (get_qPy(s, x,           y - 1) + get_qPy(s, x,           y) + 1) >> 1 : 0;
  627.                         const int qp1 = bs1 == 2 ? (get_qPy(s, x + (4 * h), y - 1) + get_qPy(s, x + (4 * h), y) + 1) >> 1 : 0;
  628.  
  629.                         c_tc[0]   = bs0 == 2 ? chroma_tc(s, qp0, chroma, tc_offset)     : 0;
  630.                         c_tc[1]   = bs1 == 2 ? chroma_tc(s, qp1, chroma, cur_tc_offset) : 0;
  631.                         src       = &s->frame->data[chroma][(y >> s->ps.sps->vshift[1]) * s->frame->linesize[chroma] + ((x >> s->ps.sps->hshift[1]) << s->ps.sps->pixel_shift)];
  632.                         if (pcmf) {
  633.                             no_p[0] = get_pcm(s, x,           y - 1);
  634.                             no_p[1] = get_pcm(s, x + (4 * h), y - 1);
  635.                             no_q[0] = get_pcm(s, x,           y);
  636.                             no_q[1] = get_pcm(s, x + (4 * h), y);
  637.                             s->hevcdsp.hevc_h_loop_filter_chroma_c(src,
  638.                                                                    s->frame->linesize[chroma],
  639.                                                                    c_tc, no_p, no_q);
  640.                         } else
  641.                             s->hevcdsp.hevc_h_loop_filter_chroma(src,
  642.                                                                  s->frame->linesize[chroma],
  643.                                                                  c_tc, no_p, no_q);
  644.                     }
  645.                 }
  646.             }
  647.         }
  648.     }
  649. }
  650.  
  651. static int boundary_strength(HEVCContext *s, MvField *curr, MvField *neigh,
  652.                              RefPicList *neigh_refPicList)
  653. {
  654.     if (curr->pred_flag == PF_BI &&  neigh->pred_flag == PF_BI) {
  655.         // same L0 and L1
  656.         if (s->ref->refPicList[0].list[curr->ref_idx[0]] == neigh_refPicList[0].list[neigh->ref_idx[0]]  &&
  657.             s->ref->refPicList[0].list[curr->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]] &&
  658.             neigh_refPicList[0].list[neigh->ref_idx[0]] == neigh_refPicList[1].list[neigh->ref_idx[1]]) {
  659.             if ((FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
  660.                  FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 4) &&
  661.                 (FFABS(neigh->mv[1].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 4 ||
  662.                  FFABS(neigh->mv[0].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[1].y) >= 4))
  663.                 return 1;
  664.             else
  665.                 return 0;
  666.         } else if (neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[0].list[curr->ref_idx[0]] &&
  667.                    neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) {
  668.             if (FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
  669.                 FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 4)
  670.                 return 1;
  671.             else
  672.                 return 0;
  673.         } else if (neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[0].list[curr->ref_idx[0]] &&
  674.                    neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) {
  675.             if (FFABS(neigh->mv[1].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 4 ||
  676.                 FFABS(neigh->mv[0].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[1].y) >= 4)
  677.                 return 1;
  678.             else
  679.                 return 0;
  680.         } else {
  681.             return 1;
  682.         }
  683.     } else if ((curr->pred_flag != PF_BI) && (neigh->pred_flag != PF_BI)){ // 1 MV
  684.         Mv A, B;
  685.         int ref_A, ref_B;
  686.  
  687.         if (curr->pred_flag & 1) {
  688.             A     = curr->mv[0];
  689.             ref_A = s->ref->refPicList[0].list[curr->ref_idx[0]];
  690.         } else {
  691.             A     = curr->mv[1];
  692.             ref_A = s->ref->refPicList[1].list[curr->ref_idx[1]];
  693.         }
  694.  
  695.         if (neigh->pred_flag & 1) {
  696.             B     = neigh->mv[0];
  697.             ref_B = neigh_refPicList[0].list[neigh->ref_idx[0]];
  698.         } else {
  699.             B     = neigh->mv[1];
  700.             ref_B = neigh_refPicList[1].list[neigh->ref_idx[1]];
  701.         }
  702.  
  703.         if (ref_A == ref_B) {
  704.             if (FFABS(A.x - B.x) >= 4 || FFABS(A.y - B.y) >= 4)
  705.                 return 1;
  706.             else
  707.                 return 0;
  708.         } else
  709.             return 1;
  710.     }
  711.  
  712.     return 1;
  713. }
  714.  
  715. void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0,
  716.                                            int log2_trafo_size)
  717. {
  718.     HEVCLocalContext *lc = s->HEVClc;
  719.     MvField *tab_mvf     = s->ref->tab_mvf;
  720.     int log2_min_pu_size = s->ps.sps->log2_min_pu_size;
  721.     int log2_min_tu_size = s->ps.sps->log2_min_tb_size;
  722.     int min_pu_width     = s->ps.sps->min_pu_width;
  723.     int min_tu_width     = s->ps.sps->min_tb_width;
  724.     int is_intra = tab_mvf[(y0 >> log2_min_pu_size) * min_pu_width +
  725.                            (x0 >> log2_min_pu_size)].pred_flag == PF_INTRA;
  726.     int boundary_upper, boundary_left;
  727.     int i, j, bs;
  728.  
  729.     boundary_upper = y0 > 0 && !(y0 & 7);
  730.     if (boundary_upper &&
  731.         ((!s->sh.slice_loop_filter_across_slices_enabled_flag &&
  732.           lc->boundary_flags & BOUNDARY_UPPER_SLICE &&
  733.           (y0 % (1 << s->ps.sps->log2_ctb_size)) == 0) ||
  734.          (!s->ps.pps->loop_filter_across_tiles_enabled_flag &&
  735.           lc->boundary_flags & BOUNDARY_UPPER_TILE &&
  736.           (y0 % (1 << s->ps.sps->log2_ctb_size)) == 0)))
  737.         boundary_upper = 0;
  738.  
  739.     if (boundary_upper) {
  740.         RefPicList *rpl_top = (lc->boundary_flags & BOUNDARY_UPPER_SLICE) ?
  741.                               ff_hevc_get_ref_list(s, s->ref, x0, y0 - 1) :
  742.                               s->ref->refPicList;
  743.         int yp_pu = (y0 - 1) >> log2_min_pu_size;
  744.         int yq_pu =  y0      >> log2_min_pu_size;
  745.         int yp_tu = (y0 - 1) >> log2_min_tu_size;
  746.         int yq_tu =  y0      >> log2_min_tu_size;
  747.  
  748.             for (i = 0; i < (1 << log2_trafo_size); i += 4) {
  749.                 int x_pu = (x0 + i) >> log2_min_pu_size;
  750.                 int x_tu = (x0 + i) >> log2_min_tu_size;
  751.                 MvField *top  = &tab_mvf[yp_pu * min_pu_width + x_pu];
  752.                 MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu];
  753.                 uint8_t top_cbf_luma  = s->cbf_luma[yp_tu * min_tu_width + x_tu];
  754.                 uint8_t curr_cbf_luma = s->cbf_luma[yq_tu * min_tu_width + x_tu];
  755.  
  756.                 if (curr->pred_flag == PF_INTRA || top->pred_flag == PF_INTRA)
  757.                     bs = 2;
  758.                 else if (curr_cbf_luma || top_cbf_luma)
  759.                     bs = 1;
  760.                 else
  761.                     bs = boundary_strength(s, curr, top, rpl_top);
  762.                 s->horizontal_bs[((x0 + i) + y0 * s->bs_width) >> 2] = bs;
  763.             }
  764.     }
  765.  
  766.     // bs for vertical TU boundaries
  767.     boundary_left = x0 > 0 && !(x0 & 7);
  768.     if (boundary_left &&
  769.         ((!s->sh.slice_loop_filter_across_slices_enabled_flag &&
  770.           lc->boundary_flags & BOUNDARY_LEFT_SLICE &&
  771.           (x0 % (1 << s->ps.sps->log2_ctb_size)) == 0) ||
  772.          (!s->ps.pps->loop_filter_across_tiles_enabled_flag &&
  773.           lc->boundary_flags & BOUNDARY_LEFT_TILE &&
  774.           (x0 % (1 << s->ps.sps->log2_ctb_size)) == 0)))
  775.         boundary_left = 0;
  776.  
  777.     if (boundary_left) {
  778.         RefPicList *rpl_left = (lc->boundary_flags & BOUNDARY_LEFT_SLICE) ?
  779.                                ff_hevc_get_ref_list(s, s->ref, x0 - 1, y0) :
  780.                                s->ref->refPicList;
  781.         int xp_pu = (x0 - 1) >> log2_min_pu_size;
  782.         int xq_pu =  x0      >> log2_min_pu_size;
  783.         int xp_tu = (x0 - 1) >> log2_min_tu_size;
  784.         int xq_tu =  x0      >> log2_min_tu_size;
  785.  
  786.             for (i = 0; i < (1 << log2_trafo_size); i += 4) {
  787.                 int y_pu      = (y0 + i) >> log2_min_pu_size;
  788.                 int y_tu      = (y0 + i) >> log2_min_tu_size;
  789.                 MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu];
  790.                 MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu];
  791.                 uint8_t left_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xp_tu];
  792.                 uint8_t curr_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xq_tu];
  793.  
  794.                 if (curr->pred_flag == PF_INTRA || left->pred_flag == PF_INTRA)
  795.                     bs = 2;
  796.                 else if (curr_cbf_luma || left_cbf_luma)
  797.                     bs = 1;
  798.                 else
  799.                     bs = boundary_strength(s, curr, left, rpl_left);
  800.                 s->vertical_bs[(x0 + (y0 + i) * s->bs_width) >> 2] = bs;
  801.             }
  802.     }
  803.  
  804.     if (log2_trafo_size > log2_min_pu_size && !is_intra) {
  805.         RefPicList *rpl = s->ref->refPicList;
  806.  
  807.         // bs for TU internal horizontal PU boundaries
  808.         for (j = 8; j < (1 << log2_trafo_size); j += 8) {
  809.             int yp_pu = (y0 + j - 1) >> log2_min_pu_size;
  810.             int yq_pu = (y0 + j)     >> log2_min_pu_size;
  811.  
  812.             for (i = 0; i < (1 << log2_trafo_size); i += 4) {
  813.                 int x_pu = (x0 + i) >> log2_min_pu_size;
  814.                 MvField *top  = &tab_mvf[yp_pu * min_pu_width + x_pu];
  815.                 MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu];
  816.  
  817.                 bs = boundary_strength(s, curr, top, rpl);
  818.                 s->horizontal_bs[((x0 + i) + (y0 + j) * s->bs_width) >> 2] = bs;
  819.             }
  820.         }
  821.  
  822.         // bs for TU internal vertical PU boundaries
  823.         for (j = 0; j < (1 << log2_trafo_size); j += 4) {
  824.             int y_pu = (y0 + j) >> log2_min_pu_size;
  825.  
  826.             for (i = 8; i < (1 << log2_trafo_size); i += 8) {
  827.                 int xp_pu = (x0 + i - 1) >> log2_min_pu_size;
  828.                 int xq_pu = (x0 + i)     >> log2_min_pu_size;
  829.                 MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu];
  830.                 MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu];
  831.  
  832.                 bs = boundary_strength(s, curr, left, rpl);
  833.                 s->vertical_bs[((x0 + i) + (y0 + j) * s->bs_width) >> 2] = bs;
  834.             }
  835.         }
  836.     }
  837. }
  838.  
  839. #undef LUMA
  840. #undef CB
  841. #undef CR
  842.  
  843. void ff_hevc_hls_filter(HEVCContext *s, int x, int y, int ctb_size)
  844. {
  845.     int x_end = x >= s->ps.sps->width  - ctb_size;
  846.     if (s->avctx->skip_loop_filter < AVDISCARD_ALL)
  847.         deblocking_filter_CTB(s, x, y);
  848.     if (s->ps.sps->sao_enabled) {
  849.         int y_end = y >= s->ps.sps->height - ctb_size;
  850.         if (y && x)
  851.             sao_filter_CTB(s, x - ctb_size, y - ctb_size);
  852.         if (x && y_end)
  853.             sao_filter_CTB(s, x - ctb_size, y);
  854.         if (y && x_end) {
  855.             sao_filter_CTB(s, x, y - ctb_size);
  856.             if (s->threads_type & FF_THREAD_FRAME )
  857.                 ff_thread_report_progress(&s->ref->tf, y, 0);
  858.         }
  859.         if (x_end && y_end) {
  860.             sao_filter_CTB(s, x , y);
  861.             if (s->threads_type & FF_THREAD_FRAME )
  862.                 ff_thread_report_progress(&s->ref->tf, y + ctb_size, 0);
  863.         }
  864.     } else if (s->threads_type & FF_THREAD_FRAME && x_end)
  865.         ff_thread_report_progress(&s->ref->tf, y + ctb_size - 4, 0);
  866. }
  867.  
  868. void ff_hevc_hls_filters(HEVCContext *s, int x_ctb, int y_ctb, int ctb_size)
  869. {
  870.     int x_end = x_ctb >= s->ps.sps->width  - ctb_size;
  871.     int y_end = y_ctb >= s->ps.sps->height - ctb_size;
  872.     if (y_ctb && x_ctb)
  873.         ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb - ctb_size, ctb_size);
  874.     if (y_ctb && x_end)
  875.         ff_hevc_hls_filter(s, x_ctb, y_ctb - ctb_size, ctb_size);
  876.     if (x_ctb && y_end)
  877.         ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb, ctb_size);
  878. }
  879.