Merge commit 'b11acd57326db6c2cc1475dd0bea2a06fbc85aa2'
authorMichael Niedermayer <michael@niedermayer.cc>
Sun, 12 Jul 2015 20:06:21 +0000 (22:06 +0200)
committerMichael Niedermayer <michael@niedermayer.cc>
Sun, 12 Jul 2015 20:28:54 +0000 (22:28 +0200)
* commit 'b11acd57326db6c2cc1475dd0bea2a06fbc85aa2':
  hevc: remove HEVCContext usage from hevc_ps

Conflicts:
libavcodec/hevc.c
libavcodec/hevc_cabac.c
libavcodec/hevc_filter.c
libavcodec/hevc_mvs.c
libavcodec/hevc_ps.c
libavcodec/hevc_refs.c
libavcodec/hevcpred_template.c

Merged-by: Michael Niedermayer <michael@niedermayer.cc>
1  2 
libavcodec/hevc.c
libavcodec/hevc.h
libavcodec/hevc_cabac.c
libavcodec/hevc_filter.c
libavcodec/hevc_mvs.c
libavcodec/hevc_parser.c
libavcodec/hevc_ps.c
libavcodec/hevc_refs.c
libavcodec/hevc_sei.c
libavcodec/hevcpred_template.c

@@@ -143,15 -250,11 +143,15 @@@ static void pred_weight_table(HEVCConte
      uint8_t chroma_weight_l0_flag[16];
      uint8_t luma_weight_l1_flag[16];
      uint8_t chroma_weight_l1_flag[16];
 +    int luma_log2_weight_denom;
  
 -    s->sh.luma_log2_weight_denom = av_clip(get_ue_golomb_long(gb), 0, 7);
 +    luma_log2_weight_denom = get_ue_golomb_long(gb);
 +    if (luma_log2_weight_denom < 0 || luma_log2_weight_denom > 7)
 +        av_log(s->avctx, AV_LOG_ERROR, "luma_log2_weight_denom %d is invalid\n", luma_log2_weight_denom);
 +    s->sh.luma_log2_weight_denom = av_clip_uintp2(luma_log2_weight_denom, 3);
-     if (s->sps->chroma_format_idc != 0) {
+     if (s->ps.sps->chroma_format_idc != 0) {
          int delta = get_se_golomb(gb);
 -        s->sh.chroma_log2_weight_denom = av_clip(s->sh.luma_log2_weight_denom + delta, 0, 7);
 +        s->sh.chroma_log2_weight_denom = av_clip_uintp2(s->sh.luma_log2_weight_denom + delta, 3);
      }
  
      for (i = 0; i < s->sh.nb_refs[L0]; i++) {
              s->sh.luma_offset_l0[i] = 0;
          }
      }
-     if (s->sps->chroma_format_idc != 0) {
 -    if (s->ps.sps->chroma_format_idc != 0) { // FIXME: invert "if" and "for"
++    if (s->ps.sps->chroma_format_idc != 0) {
          for (i = 0; i < s->sh.nb_refs[L0]; i++)
              chroma_weight_l0_flag[i] = get_bits1(gb);
      } else {
@@@ -368,29 -463,16 +368,29 @@@ static int set_sps(HEVCContext *s, cons
      ff_hevc_dsp_init (&s->hevcdsp, sps->bit_depth);
      ff_videodsp_init (&s->vdsp,    sps->bit_depth);
  
 +    for (i = 0; i < 3; i++) {
 +        av_freep(&s->sao_pixel_buffer_h[i]);
 +        av_freep(&s->sao_pixel_buffer_v[i]);
 +    }
 +
      if (sps->sao_enabled && !s->avctx->hwaccel) {
 -        av_frame_unref(s->tmp_frame);
 -        ret = ff_get_buffer(s->avctx, s->tmp_frame, AV_GET_BUFFER_FLAG_REF);
 -        if (ret < 0)
 -            goto fail;
 -        s->frame = s->tmp_frame;
 +        int c_count = (sps->chroma_format_idc != 0) ? 3 : 1;
 +        int c_idx;
 +
 +        for(c_idx = 0; c_idx < c_count; c_idx++) {
 +            int w = sps->width >> sps->hshift[c_idx];
 +            int h = sps->height >> sps->vshift[c_idx];
 +            s->sao_pixel_buffer_h[c_idx] =
 +                av_malloc((w * 2 * sps->ctb_height) <<
 +                          sps->pixel_shift);
 +            s->sao_pixel_buffer_v[c_idx] =
 +                av_malloc((h * 2 * sps->ctb_width) <<
 +                          sps->pixel_shift);
 +        }
      }
  
-     s->sps = sps;
-     s->vps = (HEVCVPS*) s->vps_list[s->sps->vps_id]->data;
+     s->ps.sps = sps;
+     s->ps.vps = (HEVCVPS*) s->ps.vps_list[s->ps.sps->vps_id]->data;
  
      return 0;
  
@@@ -428,21 -509,13 +428,21 @@@ static int hls_slice_header(HEVCContex
          av_log(s->avctx, AV_LOG_ERROR, "PPS changed between slices.\n");
          return AVERROR_INVALIDDATA;
      }
-     s->pps = (HEVCPPS*)s->pps_list[sh->pps_id]->data;
+     s->ps.pps = (HEVCPPS*)s->ps.pps_list[sh->pps_id]->data;
 +    if (s->nal_unit_type == NAL_CRA_NUT && s->last_eos == 1)
 +        sh->no_output_of_prior_pics_flag = 1;
  
-     if (s->sps != (HEVCSPS*)s->sps_list[s->pps->sps_id]->data) {
-         const HEVCSPS* last_sps = s->sps;
-         s->sps = (HEVCSPS*)s->sps_list[s->pps->sps_id]->data;
+     if (s->ps.sps != (HEVCSPS*)s->ps.sps_list[s->ps.pps->sps_id]->data) {
++        const HEVCSPS* last_sps = s->ps.sps;
+         s->ps.sps = (HEVCSPS*)s->ps.sps_list[s->ps.pps->sps_id]->data;
 -
 +        if (last_sps && IS_IRAP(s) && s->nal_unit_type != NAL_CRA_NUT) {
-             if (s->sps->width !=  last_sps->width || s->sps->height != last_sps->height ||
-                 s->sps->temporal_layer[s->sps->max_sub_layers - 1].max_dec_pic_buffering !=
++            if (s->ps.sps->width !=  last_sps->width || s->ps.sps->height != last_sps->height ||
++                s->ps.sps->temporal_layer[s->ps.sps->max_sub_layers - 1].max_dec_pic_buffering !=
 +                last_sps->temporal_layer[last_sps->max_sub_layers - 1].max_dec_pic_buffering)
 +                sh->no_output_of_prior_pics_flag = 0;
 +        }
          ff_hevc_clear_refs(s);
-         ret = set_sps(s, s->sps, AV_PIX_FMT_NONE);
 -        ret = set_sps(s, s->ps.sps);
++        ret = set_sps(s, s->ps.sps, AV_PIX_FMT_NONE);
          if (ret < 0)
              return ret;
  
              sh->colour_plane_id = get_bits(gb, 2);
  
          if (!IS_IDR(s)) {
 -            int poc;
 +            int poc, pos;
  
-             sh->pic_order_cnt_lsb = get_bits(gb, s->sps->log2_max_poc_lsb);
+             sh->pic_order_cnt_lsb = get_bits(gb, s->ps.sps->log2_max_poc_lsb);
              poc = ff_hevc_compute_poc(s, sh->pic_order_cnt_lsb);
              if (!sh->first_slice_in_pic_flag && poc != s->poc) {
                  av_log(s->avctx, AV_LOG_WARNING,
              s->poc = poc;
  
              sh->short_term_ref_pic_set_sps_flag = get_bits1(gb);
 +            pos = get_bits_left(gb);
              if (!sh->short_term_ref_pic_set_sps_flag) {
-                 ret = ff_hevc_decode_short_term_rps(gb, s->avctx, &sh->slice_rps, s->sps, 1);
 -                int pos = get_bits_left(gb);
+                 ret = ff_hevc_decode_short_term_rps(gb, s->avctx, &sh->slice_rps, s->ps.sps, 1);
                  if (ret < 0)
                      return ret;
  
                      return AVERROR_INVALIDDATA;
                  }
  
-                 numbits = av_ceil_log2(s->sps->nb_st_rps);
+                 numbits = av_ceil_log2(s->ps.sps->nb_st_rps);
                  rps_idx = numbits > 0 ? get_bits(gb, numbits) : 0;
-                 sh->short_term_rps = &s->sps->st_rps[rps_idx];
+                 sh->short_term_rps = &s->ps.sps->st_rps[rps_idx];
              }
 +            sh->short_term_ref_pic_set_size = pos - get_bits_left(gb);
  
 +            pos = get_bits_left(gb);
              ret = decode_lt_rps(s, &sh->long_term_rps, gb);
              if (ret < 0) {
                  av_log(s->avctx, AV_LOG_WARNING, "Invalid long term RPS.\n");
                  if (s->avctx->err_recognition & AV_EF_EXPLODE)
                      return AVERROR_INVALIDDATA;
              }
 +            sh->long_term_ref_pic_set_size = pos - get_bits_left(gb);
  
-             if (s->sps->sps_temporal_mvp_enabled_flag)
+             if (s->ps.sps->sps_temporal_mvp_enabled_flag)
                  sh->slice_temporal_mvp_enabled_flag = get_bits1(gb);
              else
                  sh->slice_temporal_mvp_enabled_flag = 0;
              s->nal_unit_type != NAL_RASL_R)
              s->pocTid0 = s->poc;
  
-         if (s->sps->sao_enabled) {
+         if (s->ps.sps->sao_enabled) {
              sh->slice_sample_adaptive_offset_flag[0] = get_bits1(gb);
-             if (s->sps->chroma_format_idc) {
 -            sh->slice_sample_adaptive_offset_flag[1] =
 -            sh->slice_sample_adaptive_offset_flag[2] = get_bits1(gb);
++            if (s->ps.sps->chroma_format_idc) {
 +                sh->slice_sample_adaptive_offset_flag[1] =
 +                sh->slice_sample_adaptive_offset_flag[2] = get_bits1(gb);
 +            }
          } else {
              sh->slice_sample_adaptive_offset_flag[0] = 0;
              sh->slice_sample_adaptive_offset_flag[1] = 0;
              sh->slice_cr_qp_offset = 0;
          }
  
-         if (s->pps->chroma_qp_offset_list_enabled_flag)
++        if (s->ps.pps->chroma_qp_offset_list_enabled_flag)
 +            sh->cu_chroma_qp_offset_enabled_flag = get_bits1(gb);
 +        else
 +            sh->cu_chroma_qp_offset_enabled_flag = 0;
 +
-         if (s->pps->deblocking_filter_control_present_flag) {
+         if (s->ps.pps->deblocking_filter_control_present_flag) {
              int deblocking_filter_override_flag = 0;
  
-             if (s->pps->deblocking_filter_override_enabled_flag)
+             if (s->ps.pps->deblocking_filter_override_enabled_flag)
                  deblocking_filter_override_flag = get_bits1(gb);
  
              if (deblocking_filter_override_flag) {
      }
  
      sh->num_entry_point_offsets = 0;
-     if (s->pps->tiles_enabled_flag || s->pps->entropy_coding_sync_enabled_flag) {
+     if (s->ps.pps->tiles_enabled_flag || s->ps.pps->entropy_coding_sync_enabled_flag) {
 -        sh->num_entry_point_offsets = get_ue_golomb_long(gb);
 +        unsigned num_entry_point_offsets = get_ue_golomb_long(gb);
 +        // It would be possible to bound this tighter but this here is simpler
 +        if (num_entry_point_offsets > get_bits_left(gb)) {
 +            av_log(s->avctx, AV_LOG_ERROR, "num_entry_point_offsets %d is invalid\n", num_entry_point_offsets);
 +            return AVERROR_INVALIDDATA;
 +        }
 +
 +        sh->num_entry_point_offsets = num_entry_point_offsets;
          if (sh->num_entry_point_offsets > 0) {
              int offset_len = get_ue_golomb_long(gb) + 1;
  
 -            for (i = 0; i < sh->num_entry_point_offsets; i++)
 -                skip_bits(gb, offset_len);
 -        }
 +            if (offset_len < 1 || offset_len > 32) {
 +                sh->num_entry_point_offsets = 0;
 +                av_log(s->avctx, AV_LOG_ERROR, "offset_len %d is invalid\n", offset_len);
 +                return AVERROR_INVALIDDATA;
 +            }
 +
 +            av_freep(&sh->entry_point_offset);
 +            av_freep(&sh->offset);
 +            av_freep(&sh->size);
 +            sh->entry_point_offset = av_malloc_array(sh->num_entry_point_offsets, sizeof(int));
 +            sh->offset = av_malloc_array(sh->num_entry_point_offsets, sizeof(int));
 +            sh->size = av_malloc_array(sh->num_entry_point_offsets, sizeof(int));
 +            if (!sh->entry_point_offset || !sh->offset || !sh->size) {
 +                sh->num_entry_point_offsets = 0;
 +                av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate memory\n");
 +                return AVERROR(ENOMEM);
 +            }
 +            for (i = 0; i < sh->num_entry_point_offsets; i++) {
 +                unsigned val = get_bits_long(gb, offset_len);
 +                sh->entry_point_offset[i] = val + 1; // +1; // +1 to get the size
 +            }
-             if (s->threads_number > 1 && (s->pps->num_tile_rows > 1 || s->pps->num_tile_columns > 1)) {
++            if (s->threads_number > 1 && (s->ps.pps->num_tile_rows > 1 || s->ps.pps->num_tile_columns > 1)) {
 +                s->enable_parallel_tiles = 0; // TODO: you can enable tiles in parallel here
 +                s->threads_number = 1;
 +            } else
 +                s->enable_parallel_tiles = 0;
 +        } else
 +            s->enable_parallel_tiles = 0;
      }
  
-     if (s->pps->slice_header_extension_present_flag) {
+     if (s->ps.pps->slice_header_extension_present_flag) {
          unsigned int length = get_ue_golomb_long(gb);
 +        if (length*8LL > get_bits_left(gb)) {
 +            av_log(s->avctx, AV_LOG_ERROR, "too many slice_header_extension_data_bytes\n");
 +            return AVERROR_INVALIDDATA;
 +        }
          for (i = 0; i < length; i++)
              skip_bits(gb, 8);  // slice_header_extension_data_byte
      }
  
      // Inferred parameters
-     sh->slice_qp = 26U + s->pps->pic_init_qp_minus26 + sh->slice_qp_delta;
 -    sh->slice_qp = 26 + s->ps.pps->pic_init_qp_minus26 + sh->slice_qp_delta;
++    sh->slice_qp = 26U + s->ps.pps->pic_init_qp_minus26 + sh->slice_qp_delta;
      if (sh->slice_qp > 51 ||
-         sh->slice_qp < -s->sps->qp_bd_offset) {
+         sh->slice_qp < -s->ps.sps->qp_bd_offset) {
          av_log(s->avctx, AV_LOG_ERROR,
                 "The slice_qp %d is outside the valid range "
                 "[%d, 51].\n",
          return AVERROR_INVALIDDATA;
      }
  
 -    s->HEVClc.first_qp_group = !s->sh.dependent_slice_segment_flag;
 +    if (get_bits_left(gb) < 0) {
 +        av_log(s->avctx, AV_LOG_ERROR,
 +               "Overread slice header by %d bits\n", -get_bits_left(gb));
 +        return AVERROR_INVALIDDATA;
 +    }
 +
 +    s->HEVClc->first_qp_group = !s->sh.dependent_slice_segment_flag;
  
-     if (!s->pps->cu_qp_delta_enabled_flag)
+     if (!s->ps.pps->cu_qp_delta_enabled_flag)
 -        s->HEVClc.qp_y = FFUMOD(s->sh.slice_qp + 52 + 2 * s->ps.sps->qp_bd_offset,
 -                                52 + s->ps.sps->qp_bd_offset) - s->ps.sps->qp_bd_offset;
 +        s->HEVClc->qp_y = s->sh.slice_qp;
  
      s->slice_initialized = 1;
 +    s->HEVClc->tu.cu_qp_offset_cb = 0;
 +    s->HEVClc->tu.cu_qp_offset_cr = 0;
  
      return 0;
  }
@@@ -837,10 -859,7 +837,10 @@@ static void hls_sao_param(HEVCContext *
          }
      }
  
-     for (c_idx = 0; c_idx < (s->sps->chroma_format_idc ? 3 : 1); c_idx++) {
-         int log2_sao_offset_scale = c_idx == 0 ? s->pps->log2_sao_offset_scale_luma :
-                                                  s->pps->log2_sao_offset_scale_chroma;
 -    for (c_idx = 0; c_idx < 3; c_idx++) {
++    for (c_idx = 0; c_idx < (s->ps.sps->chroma_format_idc ? 3 : 1); c_idx++) {
++        int log2_sao_offset_scale = c_idx == 0 ? s->ps.pps->log2_sao_offset_scale_luma :
++                                                 s->ps.pps->log2_sao_offset_scale_chroma;
 +
          if (!s->sh.slice_sample_adaptive_offset_flag[c_idx]) {
              sao->type_idx[c_idx] = SAO_NOT_APPLIED;
              continue;
@@@ -910,28 -1261,34 +910,28 @@@ static int hls_cross_component_pred(HEV
  static int hls_transform_unit(HEVCContext *s, int x0, int y0,
                                int xBase, int yBase, int cb_xBase, int cb_yBase,
                                int log2_cb_size, int log2_trafo_size,
 -                              int blk_idx, int cbf_luma, int cbf_cb, int cbf_cr)
 +                              int blk_idx, int cbf_luma, int *cbf_cb, int *cbf_cr)
  {
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
-     const int log2_trafo_size_c = log2_trafo_size - s->sps->hshift[1];
++    const int log2_trafo_size_c = log2_trafo_size - s->ps.sps->hshift[1];
 +    int i;
  
      if (lc->cu.pred_mode == MODE_INTRA) {
          int trafo_size = 1 << log2_trafo_size;
          ff_hevc_set_neighbour_available(s, x0, y0, trafo_size, trafo_size);
  
          s->hpc.intra_pred[log2_trafo_size - 2](s, x0, y0, 0);
 -        if (log2_trafo_size > 2) {
 -            trafo_size = trafo_size << (s->ps.sps->hshift[1] - 1);
 -            ff_hevc_set_neighbour_available(s, x0, y0, trafo_size, trafo_size);
 -            s->hpc.intra_pred[log2_trafo_size - 3](s, x0, y0, 1);
 -            s->hpc.intra_pred[log2_trafo_size - 3](s, x0, y0, 2);
 -        } else if (blk_idx == 3) {
 -            trafo_size = trafo_size << s->ps.sps->hshift[1];
 -            ff_hevc_set_neighbour_available(s, xBase, yBase,
 -                                            trafo_size, trafo_size);
 -            s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase, 1);
 -            s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase, 2);
 -        }
      }
  
 -    if (cbf_luma || cbf_cb || cbf_cr) {
 +    if (cbf_luma || cbf_cb[0] || cbf_cr[0] ||
-         (s->sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) {
++        (s->ps.sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) {
          int scan_idx   = SCAN_DIAG;
          int scan_idx_c = SCAN_DIAG;
-                          (s->sps->chroma_format_idc == 2 &&
 +        int cbf_chroma = cbf_cb[0] || cbf_cr[0] ||
++                         (s->ps.sps->chroma_format_idc == 2 &&
 +                         (cbf_cb[1] || cbf_cr[1]));
  
-         if (s->pps->cu_qp_delta_enabled_flag && !lc->tu.is_cu_qp_delta_coded) {
+         if (s->ps.pps->cu_qp_delta_enabled_flag && !lc->tu.is_cu_qp_delta_coded) {
              lc->tu.cu_qp_delta = ff_hevc_cu_qp_delta_abs(s);
              if (lc->tu.cu_qp_delta != 0)
                  if (ff_hevc_cu_qp_delta_sign_flag(s) == 1)
                  return AVERROR_INVALIDDATA;
              }
  
 -            ff_hevc_set_qPy(s, x0, y0, cb_xBase, cb_yBase, log2_cb_size);
 +            ff_hevc_set_qPy(s, cb_xBase, cb_yBase, log2_cb_size);
 +        }
 +
 +        if (s->sh.cu_chroma_qp_offset_enabled_flag && cbf_chroma &&
 +            !lc->cu.cu_transquant_bypass_flag  &&  !lc->tu.is_cu_chroma_qp_offset_coded) {
 +            int cu_chroma_qp_offset_flag = ff_hevc_cu_chroma_qp_offset_flag(s);
 +            if (cu_chroma_qp_offset_flag) {
 +                int cu_chroma_qp_offset_idx  = 0;
-                 if (s->pps->chroma_qp_offset_list_len_minus1 > 0) {
++                if (s->ps.pps->chroma_qp_offset_list_len_minus1 > 0) {
 +                    cu_chroma_qp_offset_idx = ff_hevc_cu_chroma_qp_offset_idx(s);
 +                    av_log(s->avctx, AV_LOG_ERROR,
 +                        "cu_chroma_qp_offset_idx not yet tested.\n");
 +                }
-                 lc->tu.cu_qp_offset_cb = s->pps->cb_qp_offset_list[cu_chroma_qp_offset_idx];
-                 lc->tu.cu_qp_offset_cr = s->pps->cr_qp_offset_list[cu_chroma_qp_offset_idx];
++                lc->tu.cu_qp_offset_cb = s->ps.pps->cb_qp_offset_list[cu_chroma_qp_offset_idx];
++                lc->tu.cu_qp_offset_cr = s->ps.pps->cr_qp_offset_list[cu_chroma_qp_offset_idx];
 +            } else {
 +                lc->tu.cu_qp_offset_cb = 0;
 +                lc->tu.cu_qp_offset_cr = 0;
 +            }
 +            lc->tu.is_cu_chroma_qp_offset_coded = 1;
          }
  
          if (lc->cu.pred_mode == MODE_INTRA && log2_trafo_size < 4) {
              }
          }
  
 +        lc->tu.cross_pf = 0;
 +
          if (cbf_luma)
 -            hls_residual_coding(s, x0, y0, log2_trafo_size, scan_idx, 0);
 -        if (log2_trafo_size > 2) {
 -            if (cbf_cb)
 -                hls_residual_coding(s, x0, y0, log2_trafo_size - 1, scan_idx_c, 1);
 -            if (cbf_cr)
 -                hls_residual_coding(s, x0, y0, log2_trafo_size - 1, scan_idx_c, 2);
 +            ff_hevc_hls_residual_coding(s, x0, y0, log2_trafo_size, scan_idx, 0);
-         if (s->sps->chroma_format_idc && (log2_trafo_size > 2 || s->sps->chroma_format_idc == 3)) {
-             int trafo_size_h = 1 << (log2_trafo_size_c + s->sps->hshift[1]);
-             int trafo_size_v = 1 << (log2_trafo_size_c + s->sps->vshift[1]);
-             lc->tu.cross_pf  = (s->pps->cross_component_prediction_enabled_flag && cbf_luma &&
++        if (s->ps.sps->chroma_format_idc && (log2_trafo_size > 2 || s->ps.sps->chroma_format_idc == 3)) {
++            int trafo_size_h = 1 << (log2_trafo_size_c + s->ps.sps->hshift[1]);
++            int trafo_size_v = 1 << (log2_trafo_size_c + s->ps.sps->vshift[1]);
++            lc->tu.cross_pf  = (s->ps.pps->cross_component_prediction_enabled_flag && cbf_luma &&
 +                                (lc->cu.pred_mode == MODE_INTER ||
 +                                 (lc->tu.chroma_mode_c ==  4)));
 +
 +            if (lc->tu.cross_pf) {
 +                hls_cross_component_pred(s, 0);
 +            }
-             for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) {
++            for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) {
 +                if (lc->cu.pred_mode == MODE_INTRA) {
 +                    ff_hevc_set_neighbour_available(s, x0, y0 + (i << log2_trafo_size_c), trafo_size_h, trafo_size_v);
 +                    s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0 + (i << log2_trafo_size_c), 1);
 +                }
 +                if (cbf_cb[i])
 +                    ff_hevc_hls_residual_coding(s, x0, y0 + (i << log2_trafo_size_c),
 +                                                log2_trafo_size_c, scan_idx_c, 1);
 +                else
 +                    if (lc->tu.cross_pf) {
 +                        ptrdiff_t stride = s->frame->linesize[1];
-                         int hshift = s->sps->hshift[1];
-                         int vshift = s->sps->vshift[1];
++                        int hshift = s->ps.sps->hshift[1];
++                        int vshift = s->ps.sps->vshift[1];
 +                        int16_t *coeffs_y = (int16_t*)lc->edge_emu_buffer;
 +                        int16_t *coeffs   = (int16_t*)lc->edge_emu_buffer2;
 +                        int size = 1 << log2_trafo_size_c;
 +
 +                        uint8_t *dst = &s->frame->data[1][(y0 >> vshift) * stride +
-                                                               ((x0 >> hshift) << s->sps->pixel_shift)];
++                                                              ((x0 >> hshift) << s->ps.sps->pixel_shift)];
 +                        for (i = 0; i < (size * size); i++) {
 +                            coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3);
 +                        }
 +                        s->hevcdsp.transform_add[log2_trafo_size_c-2](dst, coeffs, stride);
 +                    }
 +            }
 +
 +            if (lc->tu.cross_pf) {
 +                hls_cross_component_pred(s, 1);
 +            }
-             for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) {
++            for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) {
 +                if (lc->cu.pred_mode == MODE_INTRA) {
 +                    ff_hevc_set_neighbour_available(s, x0, y0 + (i << log2_trafo_size_c), trafo_size_h, trafo_size_v);
 +                    s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0 + (i << log2_trafo_size_c), 2);
 +                }
 +                if (cbf_cr[i])
 +                    ff_hevc_hls_residual_coding(s, x0, y0 + (i << log2_trafo_size_c),
 +                                                log2_trafo_size_c, scan_idx_c, 2);
 +                else
 +                    if (lc->tu.cross_pf) {
 +                        ptrdiff_t stride = s->frame->linesize[2];
-                         int hshift = s->sps->hshift[2];
-                         int vshift = s->sps->vshift[2];
++                        int hshift = s->ps.sps->hshift[2];
++                        int vshift = s->ps.sps->vshift[2];
 +                        int16_t *coeffs_y = (int16_t*)lc->edge_emu_buffer;
 +                        int16_t *coeffs   = (int16_t*)lc->edge_emu_buffer2;
 +                        int size = 1 << log2_trafo_size_c;
 +
 +                        uint8_t *dst = &s->frame->data[2][(y0 >> vshift) * stride +
-                                                           ((x0 >> hshift) << s->sps->pixel_shift)];
++                                                          ((x0 >> hshift) << s->ps.sps->pixel_shift)];
 +                        for (i = 0; i < (size * size); i++) {
 +                            coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3);
 +                        }
 +                        s->hevcdsp.transform_add[log2_trafo_size_c-2](dst, coeffs, stride);
 +                    }
 +            }
-         } else if (s->sps->chroma_format_idc && blk_idx == 3) {
++        } else if (s->ps.sps->chroma_format_idc && blk_idx == 3) {
 +            int trafo_size_h = 1 << (log2_trafo_size + 1);
-             int trafo_size_v = 1 << (log2_trafo_size + s->sps->vshift[1]);
-             for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) {
++            int trafo_size_v = 1 << (log2_trafo_size + s->ps.sps->vshift[1]);
++            for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) {
 +                if (lc->cu.pred_mode == MODE_INTRA) {
 +                    ff_hevc_set_neighbour_available(s, xBase, yBase + (i << log2_trafo_size),
 +                                                    trafo_size_h, trafo_size_v);
 +                    s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase + (i << log2_trafo_size), 1);
 +                }
 +                if (cbf_cb[i])
 +                    ff_hevc_hls_residual_coding(s, xBase, yBase + (i << log2_trafo_size),
 +                                                log2_trafo_size, scan_idx_c, 1);
 +            }
-             for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) {
++            for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) {
 +                if (lc->cu.pred_mode == MODE_INTRA) {
 +                    ff_hevc_set_neighbour_available(s, xBase, yBase + (i << log2_trafo_size),
 +                                                trafo_size_h, trafo_size_v);
 +                    s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase + (i << log2_trafo_size), 2);
 +                }
 +                if (cbf_cr[i])
 +                    ff_hevc_hls_residual_coding(s, xBase, yBase + (i << log2_trafo_size),
 +                                                log2_trafo_size, scan_idx_c, 2);
 +            }
 +        }
-     } else if (s->sps->chroma_format_idc && lc->cu.pred_mode == MODE_INTRA) {
-         if (log2_trafo_size > 2 || s->sps->chroma_format_idc == 3) {
-             int trafo_size_h = 1 << (log2_trafo_size_c + s->sps->hshift[1]);
-             int trafo_size_v = 1 << (log2_trafo_size_c + s->sps->vshift[1]);
++    } else if (s->ps.sps->chroma_format_idc && lc->cu.pred_mode == MODE_INTRA) {
++        if (log2_trafo_size > 2 || s->ps.sps->chroma_format_idc == 3) {
++            int trafo_size_h = 1 << (log2_trafo_size_c + s->ps.sps->hshift[1]);
++            int trafo_size_v = 1 << (log2_trafo_size_c + s->ps.sps->vshift[1]);
 +            ff_hevc_set_neighbour_available(s, x0, y0, trafo_size_h, trafo_size_v);
 +            s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0, 1);
 +            s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0, 2);
-             if (s->sps->chroma_format_idc == 2) {
++            if (s->ps.sps->chroma_format_idc == 2) {
 +                ff_hevc_set_neighbour_available(s, x0, y0 + (1 << log2_trafo_size_c),
 +                                                trafo_size_h, trafo_size_v);
 +                s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0 + (1 << log2_trafo_size_c), 1);
 +                s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0 + (1 << log2_trafo_size_c), 2);
 +            }
          } else if (blk_idx == 3) {
 -            if (cbf_cb)
 -                hls_residual_coding(s, xBase, yBase, log2_trafo_size, scan_idx_c, 1);
 -            if (cbf_cr)
 -                hls_residual_coding(s, xBase, yBase, log2_trafo_size, scan_idx_c, 2);
 +            int trafo_size_h = 1 << (log2_trafo_size + 1);
-             int trafo_size_v = 1 << (log2_trafo_size + s->sps->vshift[1]);
++            int trafo_size_v = 1 << (log2_trafo_size + s->ps.sps->vshift[1]);
 +            ff_hevc_set_neighbour_available(s, xBase, yBase,
 +                                            trafo_size_h, trafo_size_v);
 +            s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase, 1);
 +            s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase, 2);
-             if (s->sps->chroma_format_idc == 2) {
++            if (s->ps.sps->chroma_format_idc == 2) {
 +                ff_hevc_set_neighbour_available(s, xBase, yBase + (1 << (log2_trafo_size)),
 +                                                trafo_size_h, trafo_size_v);
 +                s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase + (1 << (log2_trafo_size)), 1);
 +                s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase + (1 << (log2_trafo_size)), 2);
 +            }
          }
      }
 +
      return 0;
  }
  
@@@ -1132,38 -1363,21 +1132,38 @@@ static int hls_transform_tree(HEVCConte
                                int xBase, int yBase, int cb_xBase, int cb_yBase,
                                int log2_cb_size, int log2_trafo_size,
                                int trafo_depth, int blk_idx,
 -                              int cbf_cb, int cbf_cr)
 +                              const int *base_cbf_cb, const int *base_cbf_cr)
  {
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
      uint8_t split_transform_flag;
 +    int cbf_cb[2];
 +    int cbf_cr[2];
      int ret;
  
 +    cbf_cb[0] = base_cbf_cb[0];
 +    cbf_cb[1] = base_cbf_cb[1];
 +    cbf_cr[0] = base_cbf_cr[0];
 +    cbf_cr[1] = base_cbf_cr[1];
 +
      if (lc->cu.intra_split_flag) {
 -        if (trafo_depth == 1)
 -            lc->tu.cur_intra_pred_mode = lc->pu.intra_pred_mode[blk_idx];
 +        if (trafo_depth == 1) {
 +            lc->tu.intra_pred_mode   = lc->pu.intra_pred_mode[blk_idx];
-             if (s->sps->chroma_format_idc == 3) {
++            if (s->ps.sps->chroma_format_idc == 3) {
 +                lc->tu.intra_pred_mode_c = lc->pu.intra_pred_mode_c[blk_idx];
 +                lc->tu.chroma_mode_c     = lc->pu.chroma_mode_c[blk_idx];
 +            } else {
 +                lc->tu.intra_pred_mode_c = lc->pu.intra_pred_mode_c[0];
 +                lc->tu.chroma_mode_c     = lc->pu.chroma_mode_c[0];
 +            }
 +        }
      } else {
 -        lc->tu.cur_intra_pred_mode = lc->pu.intra_pred_mode[0];
 +        lc->tu.intra_pred_mode   = lc->pu.intra_pred_mode[0];
 +        lc->tu.intra_pred_mode_c = lc->pu.intra_pred_mode_c[0];
 +        lc->tu.chroma_mode_c     = lc->pu.chroma_mode_c[0];
      }
  
-     if (log2_trafo_size <= s->sps->log2_max_trafo_size &&
-         log2_trafo_size >  s->sps->log2_min_tb_size    &&
+     if (log2_trafo_size <= s->ps.sps->log2_max_trafo_size &&
+         log2_trafo_size >  s->ps.sps->log2_min_tb_size    &&
          trafo_depth     < lc->cu.max_trafo_depth       &&
          !(lc->cu.intra_split_flag && trafo_depth == 0)) {
          split_transform_flag = ff_hevc_split_transform_flag_decode(s, log2_trafo_size);
                                 inter_split;
      }
  
-     if (s->sps->chroma_format_idc && (log2_trafo_size > 2 || s->sps->chroma_format_idc == 3)) {
 -    if (log2_trafo_size > 2 && (trafo_depth == 0 || cbf_cb))
 -        cbf_cb = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
 -    else if (log2_trafo_size > 2 || trafo_depth == 0)
 -        cbf_cb = 0;
 -    if (log2_trafo_size > 2 && (trafo_depth == 0 || cbf_cr))
 -        cbf_cr = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
 -    else if (log2_trafo_size > 2 || trafo_depth == 0)
 -        cbf_cr = 0;
++    if (s->ps.sps->chroma_format_idc && (log2_trafo_size > 2 || s->ps.sps->chroma_format_idc == 3)) {
 +        if (trafo_depth == 0 || cbf_cb[0]) {
 +            cbf_cb[0] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
-             if (s->sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) {
++            if (s->ps.sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) {
 +                cbf_cb[1] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
 +            }
 +        }
 +
 +        if (trafo_depth == 0 || cbf_cr[0]) {
 +            cbf_cr[0] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
-             if (s->sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) {
++            if (s->ps.sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) {
 +                cbf_cr[1] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
 +            }
 +        }
 +    }
  
      if (split_transform_flag) {
          const int trafo_size_split = 1 << (log2_trafo_size - 1);
@@@ -1221,10 -1428,8 +1221,10 @@@ do 
          int cbf_luma         = 1;
  
          if (lc->cu.pred_mode == MODE_INTRA || trafo_depth != 0 ||
 -            cbf_cb || cbf_cr)
 +            cbf_cb[0] || cbf_cr[0] ||
-             (s->sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) {
++            (s->ps.sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) {
              cbf_luma = ff_hevc_cbf_luma_decode(s, trafo_depth);
 +        }
  
          ret = hls_transform_unit(s, x0, y0, xBase, yBase, cb_xBase, cb_yBase,
                                   log2_cb_size, log2_trafo_size,
@@@ -1257,16 -1463,13 +1257,16 @@@ static int hls_pcm_sample(HEVCContext *
      GetBitContext gb;
      int cb_size   = 1 << log2_cb_size;
      int stride0   = s->frame->linesize[0];
-     uint8_t *dst0 = &s->frame->data[0][y0 * stride0 + (x0 << s->sps->pixel_shift)];
+     uint8_t *dst0 = &s->frame->data[0][y0 * stride0 + (x0 << s->ps.sps->pixel_shift)];
      int   stride1 = s->frame->linesize[1];
-     uint8_t *dst1 = &s->frame->data[1][(y0 >> s->sps->vshift[1]) * stride1 + ((x0 >> s->sps->hshift[1]) << s->sps->pixel_shift)];
+     uint8_t *dst1 = &s->frame->data[1][(y0 >> s->ps.sps->vshift[1]) * stride1 + ((x0 >> s->ps.sps->hshift[1]) << s->ps.sps->pixel_shift)];
      int   stride2 = s->frame->linesize[2];
-     uint8_t *dst2 = &s->frame->data[2][(y0 >> s->sps->vshift[2]) * stride2 + ((x0 >> s->sps->hshift[2]) << s->sps->pixel_shift)];
+     uint8_t *dst2 = &s->frame->data[2][(y0 >> s->ps.sps->vshift[2]) * stride2 + ((x0 >> s->ps.sps->hshift[2]) << s->ps.sps->pixel_shift)];
  
-     int length         = cb_size * cb_size * s->sps->pcm.bit_depth +
-                          (((cb_size >> s->sps->hshift[1]) * (cb_size >> s->sps->vshift[1])) +
-                           ((cb_size >> s->sps->hshift[2]) * (cb_size >> s->sps->vshift[2]))) *
-                           s->sps->pcm.bit_depth_chroma;
 -    int length         = cb_size * cb_size * s->ps.sps->pcm.bit_depth + ((cb_size * cb_size) >> 1) * s->ps.sps->pcm.bit_depth_chroma;
++    int length         = cb_size * cb_size * s->ps.sps->pcm.bit_depth +
++                         (((cb_size >> s->ps.sps->hshift[1]) * (cb_size >> s->ps.sps->vshift[1])) +
++                          ((cb_size >> s->ps.sps->hshift[2]) * (cb_size >> s->ps.sps->vshift[2]))) *
++                          s->ps.sps->pcm.bit_depth_chroma;
      const uint8_t *pcm = skip_bytes(&lc->cc, (length + 7) >> 3);
      int ret;
  
      if (ret < 0)
          return ret;
  
-     s->hevcdsp.put_pcm(dst0, stride0, cb_size, cb_size,     &gb, s->sps->pcm.bit_depth);
-     if (s->sps->chroma_format_idc) {
 -    s->hevcdsp.put_pcm(dst0, stride0, cb_size,     &gb, s->ps.sps->pcm.bit_depth);
 -    s->hevcdsp.put_pcm(dst1, stride1, cb_size / 2, &gb, s->ps.sps->pcm.bit_depth_chroma);
 -    s->hevcdsp.put_pcm(dst2, stride2, cb_size / 2, &gb, s->ps.sps->pcm.bit_depth_chroma);
 -    return 0;
 -}
 -
 -static void hls_mvd_coding(HEVCContext *s, int x0, int y0, int log2_cb_size)
 -{
 -    HEVCLocalContext *lc = &s->HEVClc;
 -    int x = ff_hevc_abs_mvd_greater0_flag_decode(s);
 -    int y = ff_hevc_abs_mvd_greater0_flag_decode(s);
 -
 -    if (x)
 -        x += ff_hevc_abs_mvd_greater1_flag_decode(s);
 -    if (y)
 -        y += ff_hevc_abs_mvd_greater1_flag_decode(s);
 -
 -    switch (x) {
 -    case 2: lc->pu.mvd.x = ff_hevc_mvd_decode(s);           break;
 -    case 1: lc->pu.mvd.x = ff_hevc_mvd_sign_flag_decode(s); break;
 -    case 0: lc->pu.mvd.x = 0;                               break;
++    s->hevcdsp.put_pcm(dst0, stride0, cb_size, cb_size,     &gb, s->ps.sps->pcm.bit_depth);
++    if (s->ps.sps->chroma_format_idc) {
 +        s->hevcdsp.put_pcm(dst1, stride1,
-                            cb_size >> s->sps->hshift[1],
-                            cb_size >> s->sps->vshift[1],
-                            &gb, s->sps->pcm.bit_depth_chroma);
++                           cb_size >> s->ps.sps->hshift[1],
++                           cb_size >> s->ps.sps->vshift[1],
++                           &gb, s->ps.sps->pcm.bit_depth_chroma);
 +        s->hevcdsp.put_pcm(dst2, stride2,
-                            cb_size >> s->sps->hshift[2],
-                            cb_size >> s->sps->vshift[2],
-                            &gb, s->sps->pcm.bit_depth_chroma);
++                           cb_size >> s->ps.sps->hshift[2],
++                           cb_size >> s->ps.sps->vshift[2],
++                           &gb, s->ps.sps->pcm.bit_depth_chroma);
      }
  
 -    switch (y) {
 -    case 2: lc->pu.mvd.y = ff_hevc_mvd_decode(s);           break;
 -    case 1: lc->pu.mvd.y = ff_hevc_mvd_sign_flag_decode(s); break;
 -    case 0: lc->pu.mvd.y = 0;                               break;
 -    }
 +    return 0;
  }
  
  /**
   * @param y_off vertical position of block from origin (0, 0)
   * @param block_w width of block
   * @param block_h height of block
 + * @param luma_weight weighting factor applied to the luma prediction
 + * @param luma_offset additive offset applied to the luma prediction value
   */
 -static void luma_mc(HEVCContext *s, int16_t *dst, ptrdiff_t dststride,
 -                    AVFrame *ref, const Mv *mv, int x_off, int y_off,
 -                    int block_w, int block_h)
 +
 +static void luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
 +                        AVFrame *ref, const Mv *mv, int x_off, int y_off,
 +                        int block_w, int block_h, int luma_weight, int luma_offset)
  {
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
      uint8_t *src         = ref->data[0];
      ptrdiff_t srcstride  = ref->linesize[0];
-     int pic_width        = s->sps->width;
-     int pic_height       = s->sps->height;
+     int pic_width        = s->ps.sps->width;
+     int pic_height       = s->ps.sps->height;
 -
 -    int mx         = mv->x & 3;
 -    int my         = mv->y & 3;
 -    int extra_left = ff_hevc_qpel_extra_before[mx];
 -    int extra_top  = ff_hevc_qpel_extra_before[my];
 +    int mx               = mv->x & 3;
 +    int my               = mv->y & 3;
-     int weight_flag      = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
-                            (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag);
++    int weight_flag      = (s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
++                           (s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag);
 +    int idx              = ff_hevc_pel_weight[block_w];
  
      x_off += mv->x >> 2;
      y_off += mv->y >> 2;
-     src   += y_off * srcstride + x_off * (1 << s->sps->pixel_shift);
 -    src   += y_off * srcstride + (x_off << s->ps.sps->pixel_shift);
++    src   += y_off * srcstride + x_off * (1 << s->ps.sps->pixel_shift);
  
 -    if (x_off < extra_left || y_off < extra_top ||
 -        x_off >= pic_width - block_w - ff_hevc_qpel_extra_after[mx] ||
 -        y_off >= pic_height - block_h - ff_hevc_qpel_extra_after[my]) {
 +    if (x_off < QPEL_EXTRA_BEFORE || y_off < QPEL_EXTRA_AFTER ||
 +        x_off >= pic_width - block_w - QPEL_EXTRA_AFTER ||
 +        y_off >= pic_height - block_h - QPEL_EXTRA_AFTER) {
-         const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
-         int offset     = QPEL_EXTRA_BEFORE * srcstride       + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
-         int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
+         const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift;
 -        int offset = extra_top * srcstride + (extra_left << s->ps.sps->pixel_shift);
 -        int buf_offset = extra_top *
 -                         edge_emu_stride + (extra_left << s->ps.sps->pixel_shift);
++        int offset     = QPEL_EXTRA_BEFORE * srcstride       + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift);
++        int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift);
  
          s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src - offset,
                                   edge_emu_stride, srcstride,
          src = lc->edge_emu_buffer + buf_offset;
          srcstride = edge_emu_stride;
      }
 -    s->hevcdsp.put_hevc_qpel[my][mx](dst, dststride, src, srcstride, block_w,
 -                                     block_h, lc->mc_buffer);
 +
 +    if (!weight_flag)
 +        s->hevcdsp.put_hevc_qpel_uni[idx][!!my][!!mx](dst, dststride, src, srcstride,
 +                                                      block_h, mx, my, block_w);
 +    else
 +        s->hevcdsp.put_hevc_qpel_uni_w[idx][!!my][!!mx](dst, dststride, src, srcstride,
 +                                                        block_h, s->sh.luma_log2_weight_denom,
 +                                                        luma_weight, luma_offset, mx, my, block_w);
 +}
 +
 +/**
 + * 8.5.3.2.2.1 Luma sample bidirectional interpolation process
 + *
 + * @param s HEVC decoding context
 + * @param dst target buffer for block data at block position
 + * @param dststride stride of the dst buffer
 + * @param ref0 reference picture0 buffer at origin (0, 0)
 + * @param mv0 motion vector0 (relative to block position) to get pixel data from
 + * @param x_off horizontal position of block from origin (0, 0)
 + * @param y_off vertical position of block from origin (0, 0)
 + * @param block_w width of block
 + * @param block_h height of block
 + * @param ref1 reference picture1 buffer at origin (0, 0)
 + * @param mv1 motion vector1 (relative to block position) to get pixel data from
 + * @param current_mv current motion vector structure
 + */
 + static void luma_mc_bi(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
 +                       AVFrame *ref0, const Mv *mv0, int x_off, int y_off,
 +                       int block_w, int block_h, AVFrame *ref1, const Mv *mv1, struct MvField *current_mv)
 +{
 +    HEVCLocalContext *lc = s->HEVClc;
 +    ptrdiff_t src0stride  = ref0->linesize[0];
 +    ptrdiff_t src1stride  = ref1->linesize[0];
-     int pic_width        = s->sps->width;
-     int pic_height       = s->sps->height;
++    int pic_width        = s->ps.sps->width;
++    int pic_height       = s->ps.sps->height;
 +    int mx0              = mv0->x & 3;
 +    int my0              = mv0->y & 3;
 +    int mx1              = mv1->x & 3;
 +    int my1              = mv1->y & 3;
-     int weight_flag      = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
-                            (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag);
++    int weight_flag      = (s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
++                           (s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag);
 +    int x_off0           = x_off + (mv0->x >> 2);
 +    int y_off0           = y_off + (mv0->y >> 2);
 +    int x_off1           = x_off + (mv1->x >> 2);
 +    int y_off1           = y_off + (mv1->y >> 2);
 +    int idx              = ff_hevc_pel_weight[block_w];
 +
-     uint8_t *src0  = ref0->data[0] + y_off0 * src0stride + (int)((unsigned)x_off0 << s->sps->pixel_shift);
-     uint8_t *src1  = ref1->data[0] + y_off1 * src1stride + (int)((unsigned)x_off1 << s->sps->pixel_shift);
++    uint8_t *src0  = ref0->data[0] + y_off0 * src0stride + (int)((unsigned)x_off0 << s->ps.sps->pixel_shift);
++    uint8_t *src1  = ref1->data[0] + y_off1 * src1stride + (int)((unsigned)x_off1 << s->ps.sps->pixel_shift);
 +
 +    if (x_off0 < QPEL_EXTRA_BEFORE || y_off0 < QPEL_EXTRA_AFTER ||
 +        x_off0 >= pic_width - block_w - QPEL_EXTRA_AFTER ||
 +        y_off0 >= pic_height - block_h - QPEL_EXTRA_AFTER) {
-         const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
-         int offset     = QPEL_EXTRA_BEFORE * src0stride       + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
-         int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
++        const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift;
++        int offset     = QPEL_EXTRA_BEFORE * src0stride       + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift);
++        int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift);
 +
 +        s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src0 - offset,
 +                                 edge_emu_stride, src0stride,
 +                                 block_w + QPEL_EXTRA,
 +                                 block_h + QPEL_EXTRA,
 +                                 x_off0 - QPEL_EXTRA_BEFORE, y_off0 - QPEL_EXTRA_BEFORE,
 +                                 pic_width, pic_height);
 +        src0 = lc->edge_emu_buffer + buf_offset;
 +        src0stride = edge_emu_stride;
 +    }
 +
 +    if (x_off1 < QPEL_EXTRA_BEFORE || y_off1 < QPEL_EXTRA_AFTER ||
 +        x_off1 >= pic_width - block_w - QPEL_EXTRA_AFTER ||
 +        y_off1 >= pic_height - block_h - QPEL_EXTRA_AFTER) {
-         const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
-         int offset     = QPEL_EXTRA_BEFORE * src1stride       + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
-         int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
++        const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift;
++        int offset     = QPEL_EXTRA_BEFORE * src1stride       + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift);
++        int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift);
 +
 +        s->vdsp.emulated_edge_mc(lc->edge_emu_buffer2, src1 - offset,
 +                                 edge_emu_stride, src1stride,
 +                                 block_w + QPEL_EXTRA,
 +                                 block_h + QPEL_EXTRA,
 +                                 x_off1 - QPEL_EXTRA_BEFORE, y_off1 - QPEL_EXTRA_BEFORE,
 +                                 pic_width, pic_height);
 +        src1 = lc->edge_emu_buffer2 + buf_offset;
 +        src1stride = edge_emu_stride;
 +    }
 +
 +    s->hevcdsp.put_hevc_qpel[idx][!!my0][!!mx0](lc->tmp, src0, src0stride,
 +                                                block_h, mx0, my0, block_w);
 +    if (!weight_flag)
 +        s->hevcdsp.put_hevc_qpel_bi[idx][!!my1][!!mx1](dst, dststride, src1, src1stride, lc->tmp,
 +                                                       block_h, mx1, my1, block_w);
 +    else
 +        s->hevcdsp.put_hevc_qpel_bi_w[idx][!!my1][!!mx1](dst, dststride, src1, src1stride, lc->tmp,
 +                                                         block_h, s->sh.luma_log2_weight_denom,
 +                                                         s->sh.luma_weight_l0[current_mv->ref_idx[0]],
 +                                                         s->sh.luma_weight_l1[current_mv->ref_idx[1]],
 +                                                         s->sh.luma_offset_l0[current_mv->ref_idx[0]],
 +                                                         s->sh.luma_offset_l1[current_mv->ref_idx[1]],
 +                                                         mx1, my1, block_w);
 +
  }
  
  /**
   * @param y_off vertical position of block from origin (0, 0)
   * @param block_w width of block
   * @param block_h height of block
 + * @param chroma_weight weighting factor applied to the chroma prediction
 + * @param chroma_offset additive offset applied to the chroma prediction value
   */
 -static void chroma_mc(HEVCContext *s, int16_t *dst1, int16_t *dst2,
 -                      ptrdiff_t dststride, AVFrame *ref, const Mv *mv,
 -                      int x_off, int y_off, int block_w, int block_h)
 +
 +static void chroma_mc_uni(HEVCContext *s, uint8_t *dst0,
 +                          ptrdiff_t dststride, uint8_t *src0, ptrdiff_t srcstride, int reflist,
 +                          int x_off, int y_off, int block_w, int block_h, struct MvField *current_mv, int chroma_weight, int chroma_offset)
  {
 -    HEVCLocalContext *lc = &s->HEVClc;
 -    uint8_t *src1        = ref->data[1];
 -    uint8_t *src2        = ref->data[2];
 -    ptrdiff_t src1stride = ref->linesize[1];
 -    ptrdiff_t src2stride = ref->linesize[2];
 -    int pic_width        = s->ps.sps->width >> 1;
 -    int pic_height       = s->ps.sps->height >> 1;
 -
 -    int mx = mv->x & 7;
 -    int my = mv->y & 7;
 -
 -    x_off += mv->x >> 3;
 -    y_off += mv->y >> 3;
 -    src1  += y_off * src1stride + (x_off << s->ps.sps->pixel_shift);
 -    src2  += y_off * src2stride + (x_off << s->ps.sps->pixel_shift);
 +    HEVCLocalContext *lc = s->HEVClc;
-     int pic_width        = s->sps->width >> s->sps->hshift[1];
-     int pic_height       = s->sps->height >> s->sps->vshift[1];
++    int pic_width        = s->ps.sps->width >> s->ps.sps->hshift[1];
++    int pic_height       = s->ps.sps->height >> s->ps.sps->vshift[1];
 +    const Mv *mv         = &current_mv->mv[reflist];
-     int weight_flag      = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
-                            (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag);
++    int weight_flag      = (s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
++                           (s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag);
 +    int idx              = ff_hevc_pel_weight[block_w];
-     int hshift           = s->sps->hshift[1];
-     int vshift           = s->sps->vshift[1];
++    int hshift           = s->ps.sps->hshift[1];
++    int vshift           = s->ps.sps->vshift[1];
 +    intptr_t mx          = av_mod_uintp2(mv->x, 2 + hshift);
 +    intptr_t my          = av_mod_uintp2(mv->y, 2 + vshift);
 +    intptr_t _mx         = mx << (1 - hshift);
 +    intptr_t _my         = my << (1 - vshift);
 +
 +    x_off += mv->x >> (2 + hshift);
 +    y_off += mv->y >> (2 + vshift);
-     src0  += y_off * srcstride + x_off * (1 << s->sps->pixel_shift);
++    src0  += y_off * srcstride + x_off * (1 << s->ps.sps->pixel_shift);
  
      if (x_off < EPEL_EXTRA_BEFORE || y_off < EPEL_EXTRA_AFTER ||
          x_off >= pic_width - block_w - EPEL_EXTRA_AFTER ||
          y_off >= pic_height - block_h - EPEL_EXTRA_AFTER) {
-         const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
-         int offset0 = EPEL_EXTRA_BEFORE * (srcstride + (1 << s->sps->pixel_shift));
+         const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift;
++        int offset0 = EPEL_EXTRA_BEFORE * (srcstride + (1 << s->ps.sps->pixel_shift));
 +        int buf_offset0 = EPEL_EXTRA_BEFORE *
-                           (edge_emu_stride + (1 << s->sps->pixel_shift));
++                          (edge_emu_stride + (1 << s->ps.sps->pixel_shift));
 +        s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src0 - offset0,
 +                                 edge_emu_stride, srcstride,
 +                                 block_w + EPEL_EXTRA, block_h + EPEL_EXTRA,
 +                                 x_off - EPEL_EXTRA_BEFORE,
 +                                 y_off - EPEL_EXTRA_BEFORE,
 +                                 pic_width, pic_height);
 +
 +        src0 = lc->edge_emu_buffer + buf_offset0;
 +        srcstride = edge_emu_stride;
 +    }
 +    if (!weight_flag)
 +        s->hevcdsp.put_hevc_epel_uni[idx][!!my][!!mx](dst0, dststride, src0, srcstride,
 +                                                  block_h, _mx, _my, block_w);
 +    else
 +        s->hevcdsp.put_hevc_epel_uni_w[idx][!!my][!!mx](dst0, dststride, src0, srcstride,
 +                                                        block_h, s->sh.chroma_log2_weight_denom,
 +                                                        chroma_weight, chroma_offset, _mx, _my, block_w);
 +}
 +
 +/**
 + * 8.5.3.2.2.2 Chroma sample bidirectional interpolation process
 + *
 + * @param s HEVC decoding context
 + * @param dst target buffer for block data at block position
 + * @param dststride stride of the dst buffer
 + * @param ref0 reference picture0 buffer at origin (0, 0)
 + * @param mv0 motion vector0 (relative to block position) to get pixel data from
 + * @param x_off horizontal position of block from origin (0, 0)
 + * @param y_off vertical position of block from origin (0, 0)
 + * @param block_w width of block
 + * @param block_h height of block
 + * @param ref1 reference picture1 buffer at origin (0, 0)
 + * @param mv1 motion vector1 (relative to block position) to get pixel data from
 + * @param current_mv current motion vector structure
 + * @param cidx chroma component(cb, cr)
 + */
 +static void chroma_mc_bi(HEVCContext *s, uint8_t *dst0, ptrdiff_t dststride, AVFrame *ref0, AVFrame *ref1,
 +                         int x_off, int y_off, int block_w, int block_h, struct MvField *current_mv, int cidx)
 +{
 +    HEVCLocalContext *lc = s->HEVClc;
 +    uint8_t *src1        = ref0->data[cidx+1];
 +    uint8_t *src2        = ref1->data[cidx+1];
 +    ptrdiff_t src1stride = ref0->linesize[cidx+1];
 +    ptrdiff_t src2stride = ref1->linesize[cidx+1];
-     int weight_flag      = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
-                            (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag);
-     int pic_width        = s->sps->width >> s->sps->hshift[1];
-     int pic_height       = s->sps->height >> s->sps->vshift[1];
++    int weight_flag      = (s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
++                           (s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag);
++    int pic_width        = s->ps.sps->width >> s->ps.sps->hshift[1];
++    int pic_height       = s->ps.sps->height >> s->ps.sps->vshift[1];
 +    Mv *mv0              = &current_mv->mv[0];
 +    Mv *mv1              = &current_mv->mv[1];
-     int hshift = s->sps->hshift[1];
-     int vshift = s->sps->vshift[1];
++    int hshift = s->ps.sps->hshift[1];
++    int vshift = s->ps.sps->vshift[1];
 +
 +    intptr_t mx0 = av_mod_uintp2(mv0->x, 2 + hshift);
 +    intptr_t my0 = av_mod_uintp2(mv0->y, 2 + vshift);
 +    intptr_t mx1 = av_mod_uintp2(mv1->x, 2 + hshift);
 +    intptr_t my1 = av_mod_uintp2(mv1->y, 2 + vshift);
 +    intptr_t _mx0 = mx0 << (1 - hshift);
 +    intptr_t _my0 = my0 << (1 - vshift);
 +    intptr_t _mx1 = mx1 << (1 - hshift);
 +    intptr_t _my1 = my1 << (1 - vshift);
 +
 +    int x_off0 = x_off + (mv0->x >> (2 + hshift));
 +    int y_off0 = y_off + (mv0->y >> (2 + vshift));
 +    int x_off1 = x_off + (mv1->x >> (2 + hshift));
 +    int y_off1 = y_off + (mv1->y >> (2 + vshift));
 +    int idx = ff_hevc_pel_weight[block_w];
-     src1  += y_off0 * src1stride + (int)((unsigned)x_off0 << s->sps->pixel_shift);
-     src2  += y_off1 * src2stride + (int)((unsigned)x_off1 << s->sps->pixel_shift);
++    src1  += y_off0 * src1stride + (int)((unsigned)x_off0 << s->ps.sps->pixel_shift);
++    src2  += y_off1 * src2stride + (int)((unsigned)x_off1 << s->ps.sps->pixel_shift);
 +
 +    if (x_off0 < EPEL_EXTRA_BEFORE || y_off0 < EPEL_EXTRA_AFTER ||
 +        x_off0 >= pic_width - block_w - EPEL_EXTRA_AFTER ||
 +        y_off0 >= pic_height - block_h - EPEL_EXTRA_AFTER) {
-         const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
-         int offset1 = EPEL_EXTRA_BEFORE * (src1stride + (1 << s->sps->pixel_shift));
++        const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift;
+         int offset1 = EPEL_EXTRA_BEFORE * (src1stride + (1 << s->ps.sps->pixel_shift));
          int buf_offset1 = EPEL_EXTRA_BEFORE *
-                           (edge_emu_stride + (1 << s->sps->pixel_shift));
+                           (edge_emu_stride + (1 << s->ps.sps->pixel_shift));
 -        int offset2 = EPEL_EXTRA_BEFORE * (src2stride + (1 << s->ps.sps->pixel_shift));
 -        int buf_offset2 = EPEL_EXTRA_BEFORE *
 -                          (edge_emu_stride + (1 << s->ps.sps->pixel_shift));
  
          s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src1 - offset1,
                                   edge_emu_stride, src1stride,
  
          src1 = lc->edge_emu_buffer + buf_offset1;
          src1stride = edge_emu_stride;
 -        s->hevcdsp.put_hevc_epel[!!my][!!mx](dst1, dststride, src1, src1stride,
 -                                             block_w, block_h, mx, my, lc->mc_buffer);
 +    }
  
 -        s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src2 - offset2,
 +    if (x_off1 < EPEL_EXTRA_BEFORE || y_off1 < EPEL_EXTRA_AFTER ||
 +        x_off1 >= pic_width - block_w - EPEL_EXTRA_AFTER ||
 +        y_off1 >= pic_height - block_h - EPEL_EXTRA_AFTER) {
-         const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
-         int offset1 = EPEL_EXTRA_BEFORE * (src2stride + (1 << s->sps->pixel_shift));
++        const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift;
++        int offset1 = EPEL_EXTRA_BEFORE * (src2stride + (1 << s->ps.sps->pixel_shift));
 +        int buf_offset1 = EPEL_EXTRA_BEFORE *
-                           (edge_emu_stride + (1 << s->sps->pixel_shift));
++                          (edge_emu_stride + (1 << s->ps.sps->pixel_shift));
 +
 +        s->vdsp.emulated_edge_mc(lc->edge_emu_buffer2, src2 - offset1,
                                   edge_emu_stride, src2stride,
                                   block_w + EPEL_EXTRA, block_h + EPEL_EXTRA,
 -                                 x_off - EPEL_EXTRA_BEFORE,
 -                                 y_off - EPEL_EXTRA_BEFORE,
 +                                 x_off1 - EPEL_EXTRA_BEFORE,
 +                                 y_off1 - EPEL_EXTRA_BEFORE,
                                   pic_width, pic_height);
 -        src2 = lc->edge_emu_buffer + buf_offset2;
 -        src2stride = edge_emu_stride;
  
 -        s->hevcdsp.put_hevc_epel[!!my][!!mx](dst2, dststride, src2, src2stride,
 -                                             block_w, block_h, mx, my,
 -                                             lc->mc_buffer);
 -    } else {
 -        s->hevcdsp.put_hevc_epel[!!my][!!mx](dst1, dststride, src1, src1stride,
 -                                             block_w, block_h, mx, my,
 -                                             lc->mc_buffer);
 -        s->hevcdsp.put_hevc_epel[!!my][!!mx](dst2, dststride, src2, src2stride,
 -                                             block_w, block_h, mx, my,
 -                                             lc->mc_buffer);
 +        src2 = lc->edge_emu_buffer2 + buf_offset1;
 +        src2stride = edge_emu_stride;
      }
 +
 +    s->hevcdsp.put_hevc_epel[idx][!!my0][!!mx0](lc->tmp, src1, src1stride,
 +                                                block_h, _mx0, _my0, block_w);
 +    if (!weight_flag)
 +        s->hevcdsp.put_hevc_epel_bi[idx][!!my1][!!mx1](dst0, s->frame->linesize[cidx+1],
 +                                                       src2, src2stride, lc->tmp,
 +                                                       block_h, _mx1, _my1, block_w);
 +    else
 +        s->hevcdsp.put_hevc_epel_bi_w[idx][!!my1][!!mx1](dst0, s->frame->linesize[cidx+1],
 +                                                         src2, src2stride, lc->tmp,
 +                                                         block_h,
 +                                                         s->sh.chroma_log2_weight_denom,
 +                                                         s->sh.chroma_weight_l0[current_mv->ref_idx[0]][cidx],
 +                                                         s->sh.chroma_weight_l1[current_mv->ref_idx[1]][cidx],
 +                                                         s->sh.chroma_offset_l0[current_mv->ref_idx[0]][cidx],
 +                                                         s->sh.chroma_offset_l1[current_mv->ref_idx[1]][cidx],
 +                                                         _mx1, _my1, block_w);
  }
  
  static void hevc_await_progress(HEVCContext *s, HEVCFrame *ref,
@@@ -1671,12 -1695,12 +1671,12 @@@ static void hevc_luma_mv_mvp_mode(HEVCC
  
  static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
                                  int nPbW, int nPbH,
 -                                int log2_cb_size, int partIdx)
 +                                int log2_cb_size, int partIdx, int idx)
  {
  #define POS(c_idx, x, y)                                                              \
-     &s->frame->data[c_idx][((y) >> s->sps->vshift[c_idx]) * s->frame->linesize[c_idx] + \
-                            (((x) >> s->sps->hshift[c_idx]) << s->sps->pixel_shift)]
+     &s->frame->data[c_idx][((y) >> s->ps.sps->vshift[c_idx]) * s->frame->linesize[c_idx] + \
+                            (((x) >> s->ps.sps->hshift[c_idx]) << s->ps.sps->pixel_shift)]
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
      int merge_idx = 0;
      struct MvField current_mv = {{{ 0 }}};
  
                                partIdx, merge_idx, &current_mv);
      }
  
-     x_pu = x0 >> s->sps->log2_min_pu_size;
-     y_pu = y0 >> s->sps->log2_min_pu_size;
+     x_pu = x0 >> s->ps.sps->log2_min_pu_size;
+     y_pu = y0 >> s->ps.sps->log2_min_pu_size;
  
-     for (j = 0; j < nPbH >> s->sps->log2_min_pu_size; j++)
-         for (i = 0; i < nPbW >> s->sps->log2_min_pu_size; i++)
+     for (j = 0; j < nPbH >> s->ps.sps->log2_min_pu_size; j++)
+         for (i = 0; i < nPbW >> s->ps.sps->log2_min_pu_size; i++)
              tab_mvf[(y_pu + j) * min_pu_width + x_pu + i] = current_mv;
  
 -    if (current_mv.pred_flag[0]) {
 +    if (current_mv.pred_flag & PF_L0) {
          ref0 = refPicList[0].ref[current_mv.ref_idx[0]];
          if (!ref0)
              return;
          hevc_await_progress(s, ref1, &current_mv.mv[1], y0, nPbH);
      }
  
 -    if (current_mv.pred_flag[0] && !current_mv.pred_flag[1]) {
 -        DECLARE_ALIGNED(16, int16_t,  tmp[MAX_PB_SIZE * MAX_PB_SIZE]);
 -        DECLARE_ALIGNED(16, int16_t, tmp2[MAX_PB_SIZE * MAX_PB_SIZE]);
 +    if (current_mv.pred_flag == PF_L0) {
-         int x0_c = x0 >> s->sps->hshift[1];
-         int y0_c = y0 >> s->sps->vshift[1];
-         int nPbW_c = nPbW >> s->sps->hshift[1];
-         int nPbH_c = nPbH >> s->sps->vshift[1];
++        int x0_c = x0 >> s->ps.sps->hshift[1];
++        int y0_c = y0 >> s->ps.sps->vshift[1];
++        int nPbW_c = nPbW >> s->ps.sps->hshift[1];
++        int nPbH_c = nPbH >> s->ps.sps->vshift[1];
  
 -        luma_mc(s, tmp, tmpstride, ref0->frame,
 -                &current_mv.mv[0], x0, y0, nPbW, nPbH);
 +        luma_mc_uni(s, dst0, s->frame->linesize[0], ref0->frame,
 +                    &current_mv.mv[0], x0, y0, nPbW, nPbH,
 +                    s->sh.luma_weight_l0[current_mv.ref_idx[0]],
 +                    s->sh.luma_offset_l0[current_mv.ref_idx[0]]);
  
-         if (s->sps->chroma_format_idc) {
 -        if ((s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
 -            (s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag)) {
 -            s->hevcdsp.weighted_pred(s->sh.luma_log2_weight_denom,
 -                                     s->sh.luma_weight_l0[current_mv.ref_idx[0]],
 -                                     s->sh.luma_offset_l0[current_mv.ref_idx[0]],
 -                                     dst0, s->frame->linesize[0], tmp,
 -                                     tmpstride, nPbW, nPbH);
 -        } else {
 -            s->hevcdsp.put_unweighted_pred(dst0, s->frame->linesize[0], tmp, tmpstride, nPbW, nPbH);
 -        }
 -        chroma_mc(s, tmp, tmp2, tmpstride, ref0->frame,
 -                  &current_mv.mv[0], x0 / 2, y0 / 2, nPbW / 2, nPbH / 2);
 -
 -        if ((s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
 -            (s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag)) {
 -            s->hevcdsp.weighted_pred(s->sh.chroma_log2_weight_denom,
 -                                     s->sh.chroma_weight_l0[current_mv.ref_idx[0]][0],
 -                                     s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0],
 -                                     dst1, s->frame->linesize[1], tmp, tmpstride,
 -                                     nPbW / 2, nPbH / 2);
 -            s->hevcdsp.weighted_pred(s->sh.chroma_log2_weight_denom,
 -                                     s->sh.chroma_weight_l0[current_mv.ref_idx[0]][1],
 -                                     s->sh.chroma_offset_l0[current_mv.ref_idx[0]][1],
 -                                     dst2, s->frame->linesize[2], tmp2, tmpstride,
 -                                     nPbW / 2, nPbH / 2);
 -        } else {
 -            s->hevcdsp.put_unweighted_pred(dst1, s->frame->linesize[1], tmp, tmpstride, nPbW/2, nPbH/2);
 -            s->hevcdsp.put_unweighted_pred(dst2, s->frame->linesize[2], tmp2, tmpstride, nPbW/2, nPbH/2);
 -        }
 -    } else if (!current_mv.pred_flag[0] && current_mv.pred_flag[1]) {
 -        DECLARE_ALIGNED(16, int16_t, tmp [MAX_PB_SIZE * MAX_PB_SIZE]);
 -        DECLARE_ALIGNED(16, int16_t, tmp2[MAX_PB_SIZE * MAX_PB_SIZE]);
 -
 -        luma_mc(s, tmp, tmpstride, ref1->frame,
 -                &current_mv.mv[1], x0, y0, nPbW, nPbH);
 -
 -        if ((s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
 -            (s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag)) {
 -            s->hevcdsp.weighted_pred(s->sh.luma_log2_weight_denom,
 -                                      s->sh.luma_weight_l1[current_mv.ref_idx[1]],
 -                                      s->sh.luma_offset_l1[current_mv.ref_idx[1]],
 -                                      dst0, s->frame->linesize[0], tmp, tmpstride,
 -                                      nPbW, nPbH);
 -        } else {
 -            s->hevcdsp.put_unweighted_pred(dst0, s->frame->linesize[0], tmp, tmpstride, nPbW, nPbH);
 -        }
 -
 -        chroma_mc(s, tmp, tmp2, tmpstride, ref1->frame,
 -                  &current_mv.mv[1], x0/2, y0/2, nPbW/2, nPbH/2);
 -
 -        if ((s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
 -            (s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag)) {
 -            s->hevcdsp.weighted_pred(s->sh.chroma_log2_weight_denom,
 -                                     s->sh.chroma_weight_l1[current_mv.ref_idx[1]][0],
 -                                     s->sh.chroma_offset_l1[current_mv.ref_idx[1]][0],
 -                                     dst1, s->frame->linesize[1], tmp, tmpstride, nPbW/2, nPbH/2);
 -            s->hevcdsp.weighted_pred(s->sh.chroma_log2_weight_denom,
 -                                     s->sh.chroma_weight_l1[current_mv.ref_idx[1]][1],
 -                                     s->sh.chroma_offset_l1[current_mv.ref_idx[1]][1],
 -                                     dst2, s->frame->linesize[2], tmp2, tmpstride, nPbW/2, nPbH/2);
 -        } else {
 -            s->hevcdsp.put_unweighted_pred(dst1, s->frame->linesize[1], tmp, tmpstride, nPbW/2, nPbH/2);
 -            s->hevcdsp.put_unweighted_pred(dst2, s->frame->linesize[2], tmp2, tmpstride, nPbW/2, nPbH/2);
 -        }
 -    } else if (current_mv.pred_flag[0] && current_mv.pred_flag[1]) {
 -        DECLARE_ALIGNED(16, int16_t, tmp [MAX_PB_SIZE * MAX_PB_SIZE]);
 -        DECLARE_ALIGNED(16, int16_t, tmp2[MAX_PB_SIZE * MAX_PB_SIZE]);
 -        DECLARE_ALIGNED(16, int16_t, tmp3[MAX_PB_SIZE * MAX_PB_SIZE]);
 -        DECLARE_ALIGNED(16, int16_t, tmp4[MAX_PB_SIZE * MAX_PB_SIZE]);
 -
 -        luma_mc(s, tmp, tmpstride, ref0->frame,
 -                &current_mv.mv[0], x0, y0, nPbW, nPbH);
 -        luma_mc(s, tmp2, tmpstride, ref1->frame,
 -                &current_mv.mv[1], x0, y0, nPbW, nPbH);
 -
 -        if ((s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
 -            (s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag)) {
 -            s->hevcdsp.weighted_pred_avg(s->sh.luma_log2_weight_denom,
 -                                         s->sh.luma_weight_l0[current_mv.ref_idx[0]],
 -                                         s->sh.luma_weight_l1[current_mv.ref_idx[1]],
 -                                         s->sh.luma_offset_l0[current_mv.ref_idx[0]],
 -                                         s->sh.luma_offset_l1[current_mv.ref_idx[1]],
 -                                         dst0, s->frame->linesize[0],
 -                                         tmp, tmp2, tmpstride, nPbW, nPbH);
 -        } else {
 -            s->hevcdsp.put_weighted_pred_avg(dst0, s->frame->linesize[0],
 -                                             tmp, tmp2, tmpstride, nPbW, nPbH);
 -        }
 -
 -        chroma_mc(s, tmp, tmp2, tmpstride, ref0->frame,
 -                  &current_mv.mv[0], x0 / 2, y0 / 2, nPbW / 2, nPbH / 2);
 -        chroma_mc(s, tmp3, tmp4, tmpstride, ref1->frame,
 -                  &current_mv.mv[1], x0 / 2, y0 / 2, nPbW / 2, nPbH / 2);
 -
 -        if ((s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
 -            (s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag)) {
 -            s->hevcdsp.weighted_pred_avg(s->sh.chroma_log2_weight_denom,
 -                                         s->sh.chroma_weight_l0[current_mv.ref_idx[0]][0],
 -                                         s->sh.chroma_weight_l1[current_mv.ref_idx[1]][0],
 -                                         s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0],
 -                                         s->sh.chroma_offset_l1[current_mv.ref_idx[1]][0],
 -                                         dst1, s->frame->linesize[1], tmp, tmp3,
 -                                         tmpstride, nPbW / 2, nPbH / 2);
 -            s->hevcdsp.weighted_pred_avg(s->sh.chroma_log2_weight_denom,
 -                                         s->sh.chroma_weight_l0[current_mv.ref_idx[0]][1],
 -                                         s->sh.chroma_weight_l1[current_mv.ref_idx[1]][1],
 -                                         s->sh.chroma_offset_l0[current_mv.ref_idx[0]][1],
 -                                         s->sh.chroma_offset_l1[current_mv.ref_idx[1]][1],
 -                                         dst2, s->frame->linesize[2], tmp2, tmp4,
 -                                         tmpstride, nPbW / 2, nPbH / 2);
 -        } else {
 -            s->hevcdsp.put_weighted_pred_avg(dst1, s->frame->linesize[1], tmp, tmp3, tmpstride, nPbW/2, nPbH/2);
 -            s->hevcdsp.put_weighted_pred_avg(dst2, s->frame->linesize[2], tmp2, tmp4, tmpstride, nPbW/2, nPbH/2);
++        if (s->ps.sps->chroma_format_idc) {
 +            chroma_mc_uni(s, dst1, s->frame->linesize[1], ref0->frame->data[1], ref0->frame->linesize[1],
 +                          0, x0_c, y0_c, nPbW_c, nPbH_c, &current_mv,
 +                          s->sh.chroma_weight_l0[current_mv.ref_idx[0]][0], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0]);
 +            chroma_mc_uni(s, dst2, s->frame->linesize[2], ref0->frame->data[2], ref0->frame->linesize[2],
 +                          0, x0_c, y0_c, nPbW_c, nPbH_c, &current_mv,
 +                          s->sh.chroma_weight_l0[current_mv.ref_idx[0]][1], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][1]);
 +        }
 +    } else if (current_mv.pred_flag == PF_L1) {
-         int x0_c = x0 >> s->sps->hshift[1];
-         int y0_c = y0 >> s->sps->vshift[1];
-         int nPbW_c = nPbW >> s->sps->hshift[1];
-         int nPbH_c = nPbH >> s->sps->vshift[1];
++        int x0_c = x0 >> s->ps.sps->hshift[1];
++        int y0_c = y0 >> s->ps.sps->vshift[1];
++        int nPbW_c = nPbW >> s->ps.sps->hshift[1];
++        int nPbH_c = nPbH >> s->ps.sps->vshift[1];
 +
 +        luma_mc_uni(s, dst0, s->frame->linesize[0], ref1->frame,
 +                    &current_mv.mv[1], x0, y0, nPbW, nPbH,
 +                    s->sh.luma_weight_l1[current_mv.ref_idx[1]],
 +                    s->sh.luma_offset_l1[current_mv.ref_idx[1]]);
 +
-         if (s->sps->chroma_format_idc) {
++        if (s->ps.sps->chroma_format_idc) {
 +            chroma_mc_uni(s, dst1, s->frame->linesize[1], ref1->frame->data[1], ref1->frame->linesize[1],
 +                          1, x0_c, y0_c, nPbW_c, nPbH_c, &current_mv,
 +                          s->sh.chroma_weight_l1[current_mv.ref_idx[1]][0], s->sh.chroma_offset_l1[current_mv.ref_idx[1]][0]);
 +
 +            chroma_mc_uni(s, dst2, s->frame->linesize[2], ref1->frame->data[2], ref1->frame->linesize[2],
 +                          1, x0_c, y0_c, nPbW_c, nPbH_c, &current_mv,
 +                          s->sh.chroma_weight_l1[current_mv.ref_idx[1]][1], s->sh.chroma_offset_l1[current_mv.ref_idx[1]][1]);
 +        }
 +    } else if (current_mv.pred_flag == PF_BI) {
-         int x0_c = x0 >> s->sps->hshift[1];
-         int y0_c = y0 >> s->sps->vshift[1];
-         int nPbW_c = nPbW >> s->sps->hshift[1];
-         int nPbH_c = nPbH >> s->sps->vshift[1];
++        int x0_c = x0 >> s->ps.sps->hshift[1];
++        int y0_c = y0 >> s->ps.sps->vshift[1];
++        int nPbW_c = nPbW >> s->ps.sps->hshift[1];
++        int nPbH_c = nPbH >> s->ps.sps->vshift[1];
 +
 +        luma_mc_bi(s, dst0, s->frame->linesize[0], ref0->frame,
 +                   &current_mv.mv[0], x0, y0, nPbW, nPbH,
 +                   ref1->frame, &current_mv.mv[1], &current_mv);
 +
-         if (s->sps->chroma_format_idc) {
++        if (s->ps.sps->chroma_format_idc) {
 +            chroma_mc_bi(s, dst1, s->frame->linesize[1], ref0->frame, ref1->frame,
 +                         x0_c, y0_c, nPbW_c, nPbH_c, &current_mv, 0);
 +
 +            chroma_mc_bi(s, dst2, s->frame->linesize[2], ref0->frame, ref1->frame,
 +                         x0_c, y0_c, nPbW_c, nPbH_c, &current_mv, 1);
          }
      }
  }
  static int luma_intra_pred_mode(HEVCContext *s, int x0, int y0, int pu_size,
                                  int prev_intra_luma_pred_flag)
  {
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
-     int x_pu             = x0 >> s->sps->log2_min_pu_size;
-     int y_pu             = y0 >> s->sps->log2_min_pu_size;
-     int min_pu_width     = s->sps->min_pu_width;
-     int size_in_pus      = pu_size >> s->sps->log2_min_pu_size;
-     int x0b              = av_mod_uintp2(x0, s->sps->log2_ctb_size);
-     int y0b              = av_mod_uintp2(y0, s->sps->log2_ctb_size);
+     int x_pu             = x0 >> s->ps.sps->log2_min_pu_size;
+     int y_pu             = y0 >> s->ps.sps->log2_min_pu_size;
+     int min_pu_width     = s->ps.sps->min_pu_width;
+     int size_in_pus      = pu_size >> s->ps.sps->log2_min_pu_size;
 -    int x0b              = x0 & ((1 << s->ps.sps->log2_ctb_size) - 1);
 -    int y0b              = y0 & ((1 << s->ps.sps->log2_ctb_size) - 1);
++    int x0b              = av_mod_uintp2(x0, s->ps.sps->log2_ctb_size);
++    int y0b              = av_mod_uintp2(y0, s->ps.sps->log2_ctb_size);
  
      int cand_up   = (lc->ctb_up_flag || y0b) ?
                      s->tab_ipm[(y_pu - 1) * min_pu_width + x_pu] : INTRA_DC;
@@@ -1921,42 -2017,14 +1921,42 @@@ static void intra_prediction_unit(HEVCC
          }
      }
  
-     if (s->sps->chroma_format_idc == 3) {
 -    chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(s);
 -    if (chroma_mode != 4) {
 -        if (lc->pu.intra_pred_mode[0] == intra_chroma_table[chroma_mode])
 -            lc->pu.intra_pred_mode_c = 34;
 -        else
 -            lc->pu.intra_pred_mode_c = intra_chroma_table[chroma_mode];
 -    } else {
 -        lc->pu.intra_pred_mode_c = lc->pu.intra_pred_mode[0];
++    if (s->ps.sps->chroma_format_idc == 3) {
 +        for (i = 0; i < side; i++) {
 +            for (j = 0; j < side; j++) {
 +                lc->pu.chroma_mode_c[2 * i + j] = chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(s);
 +                if (chroma_mode != 4) {
 +                    if (lc->pu.intra_pred_mode[2 * i + j] == intra_chroma_table[chroma_mode])
 +                        lc->pu.intra_pred_mode_c[2 * i + j] = 34;
 +                    else
 +                        lc->pu.intra_pred_mode_c[2 * i + j] = intra_chroma_table[chroma_mode];
 +                } else {
 +                    lc->pu.intra_pred_mode_c[2 * i + j] = lc->pu.intra_pred_mode[2 * i + j];
 +                }
 +            }
 +        }
-     } else if (s->sps->chroma_format_idc == 2) {
++    } else if (s->ps.sps->chroma_format_idc == 2) {
 +        int mode_idx;
 +        lc->pu.chroma_mode_c[0] = chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(s);
 +        if (chroma_mode != 4) {
 +            if (lc->pu.intra_pred_mode[0] == intra_chroma_table[chroma_mode])
 +                mode_idx = 34;
 +            else
 +                mode_idx = intra_chroma_table[chroma_mode];
 +        } else {
 +            mode_idx = lc->pu.intra_pred_mode[0];
 +        }
 +        lc->pu.intra_pred_mode_c[0] = tab_mode_idx[mode_idx];
-     } else if (s->sps->chroma_format_idc != 0) {
++    } else if (s->ps.sps->chroma_format_idc != 0) {
 +        chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(s);
 +        if (chroma_mode != 4) {
 +            if (lc->pu.intra_pred_mode[0] == intra_chroma_table[chroma_mode])
 +                lc->pu.intra_pred_mode_c[0] = 34;
 +            else
 +                lc->pu.intra_pred_mode_c[0] = intra_chroma_table[chroma_mode];
 +        } else {
 +            lc->pu.intra_pred_mode_c[0] = lc->pu.intra_pred_mode[0];
 +        }
      }
  }
  
@@@ -1964,13 -2032,13 +1964,13 @@@ static void intra_prediction_unit_defau
                                                  int x0, int y0,
                                                  int log2_cb_size)
  {
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
      int pb_size          = 1 << log2_cb_size;
-     int size_in_pus      = pb_size >> s->sps->log2_min_pu_size;
-     int min_pu_width     = s->sps->min_pu_width;
+     int size_in_pus      = pb_size >> s->ps.sps->log2_min_pu_size;
+     int min_pu_width     = s->ps.sps->min_pu_width;
      MvField *tab_mvf     = s->ref->tab_mvf;
-     int x_pu             = x0 >> s->sps->log2_min_pu_size;
-     int y_pu             = y0 >> s->sps->log2_min_pu_size;
+     int x_pu             = x0 >> s->ps.sps->log2_min_pu_size;
+     int y_pu             = y0 >> s->ps.sps->log2_min_pu_size;
      int j, k;
  
      if (size_in_pus == 0)
  static int hls_coding_unit(HEVCContext *s, int x0, int y0, int log2_cb_size)
  {
      int cb_size          = 1 << log2_cb_size;
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
-     int log2_min_cb_size = s->sps->log2_min_cb_size;
+     int log2_min_cb_size = s->ps.sps->log2_min_cb_size;
      int length           = cb_size >> log2_min_cb_size;
-     int min_cb_width     = s->sps->min_cb_width;
+     int min_cb_width     = s->ps.sps->min_cb_width;
      int x_cb             = x0 >> log2_min_cb_size;
      int y_cb             = y0 >> log2_min_cb_size;
-     int qp_block_mask    = (1<<(s->sps->log2_ctb_size - s->pps->diff_cu_qp_delta_depth)) - 1;
 +    int idx              = log2_cb_size - 2;
++    int qp_block_mask    = (1<<(s->ps.sps->log2_ctb_size - s->ps.pps->diff_cu_qp_delta_depth)) - 1;
      int x, y, ret;
  
      lc->cu.x                = x0;
                  rqt_root_cbf = ff_hevc_no_residual_syntax_flag_decode(s);
              }
              if (rqt_root_cbf) {
 +                const static int cbf[2] = { 0 };
                  lc->cu.max_trafo_depth = lc->cu.pred_mode == MODE_INTRA ?
-                                          s->sps->max_transform_hierarchy_depth_intra + lc->cu.intra_split_flag :
-                                          s->sps->max_transform_hierarchy_depth_inter;
+                                          s->ps.sps->max_transform_hierarchy_depth_intra + lc->cu.intra_split_flag :
+                                          s->ps.sps->max_transform_hierarchy_depth_inter;
                  ret = hls_transform_tree(s, x0, y0, x0, y0, x0, y0,
                                           log2_cb_size,
 -                                         log2_cb_size, 0, 0, 0, 0);
 +                                         log2_cb_size, 0, 0, cbf, cbf);
                  if (ret < 0)
                      return ret;
              } else {
          }
      }
  
-     if (s->pps->cu_qp_delta_enabled_flag && lc->tu.is_cu_qp_delta_coded == 0)
+     if (s->ps.pps->cu_qp_delta_enabled_flag && lc->tu.is_cu_qp_delta_coded == 0)
 -        ff_hevc_set_qPy(s, x0, y0, x0, y0, log2_cb_size);
 +        ff_hevc_set_qPy(s, x0, y0, log2_cb_size);
  
      x = y_cb * min_cb_width + x_cb;
      for (y = 0; y < length; y++) {
  static int hls_coding_quadtree(HEVCContext *s, int x0, int y0,
                                 int log2_cb_size, int cb_depth)
  {
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
      const int cb_size    = 1 << log2_cb_size;
 +    int ret;
      int split_cu;
  
 -    lc->ct.depth = cb_depth;
 +    lc->ct_depth = cb_depth;
-     if (x0 + cb_size <= s->sps->width  &&
-         y0 + cb_size <= s->sps->height &&
-         log2_cb_size > s->sps->log2_min_cb_size) {
+     if (x0 + cb_size <= s->ps.sps->width  &&
+         y0 + cb_size <= s->ps.sps->height &&
+         log2_cb_size > s->ps.sps->log2_min_cb_size) {
          split_cu = ff_hevc_split_coding_unit_flag_decode(s, cb_depth, x0, y0);
      } else {
-         split_cu = (log2_cb_size > s->sps->log2_min_cb_size);
+         split_cu = (log2_cb_size > s->ps.sps->log2_min_cb_size);
      }
-     if (s->pps->cu_qp_delta_enabled_flag &&
-         log2_cb_size >= s->sps->log2_ctb_size - s->pps->diff_cu_qp_delta_depth) {
+     if (s->ps.pps->cu_qp_delta_enabled_flag &&
+         log2_cb_size >= s->ps.sps->log2_ctb_size - s->ps.pps->diff_cu_qp_delta_depth) {
          lc->tu.is_cu_qp_delta_coded = 0;
          lc->tu.cu_qp_delta          = 0;
      }
  
-         log2_cb_size >= s->sps->log2_ctb_size - s->pps->diff_cu_chroma_qp_offset_depth) {
 +    if (s->sh.cu_chroma_qp_offset_enabled_flag &&
++        log2_cb_size >= s->ps.sps->log2_ctb_size - s->ps.pps->diff_cu_chroma_qp_offset_depth) {
 +        lc->tu.is_cu_chroma_qp_offset_coded = 0;
 +    }
 +
      if (split_cu) {
-         int qp_block_mask = (1<<(s->sps->log2_ctb_size - s->pps->diff_cu_qp_delta_depth)) - 1;
++        int qp_block_mask = (1<<(s->ps.sps->log2_ctb_size - s->ps.pps->diff_cu_qp_delta_depth)) - 1;
          const int cb_size_split = cb_size >> 1;
          const int x1 = x0 + cb_size_split;
          const int y1 = y0 + cb_size_split;
  
 -        log2_cb_size--;
 -        cb_depth++;
 +        int more_data = 0;
  
 -#define SUBDIVIDE(x, y)                                                \
 -do {                                                                   \
 -    if (x < s->ps.sps->width && y < s->ps.sps->height) {                     \
 -        int ret = hls_coding_quadtree(s, x, y, log2_cb_size, cb_depth);\
 -        if (ret < 0)                                                   \
 -            return ret;                                                \
 -    }                                                                  \
 -} while (0)
 +        more_data = hls_coding_quadtree(s, x0, y0, log2_cb_size - 1, cb_depth + 1);
 +        if (more_data < 0)
 +            return more_data;
  
-         if (more_data && x1 < s->sps->width) {
 -        SUBDIVIDE(x0, y0);
 -        SUBDIVIDE(x1, y0);
 -        SUBDIVIDE(x0, y1);
 -        SUBDIVIDE(x1, y1);
++        if (more_data && x1 < s->ps.sps->width) {
 +            more_data = hls_coding_quadtree(s, x1, y0, log2_cb_size - 1, cb_depth + 1);
 +            if (more_data < 0)
 +                return more_data;
 +        }
-         if (more_data && y1 < s->sps->height) {
++        if (more_data && y1 < s->ps.sps->height) {
 +            more_data = hls_coding_quadtree(s, x0, y1, log2_cb_size - 1, cb_depth + 1);
 +            if (more_data < 0)
 +                return more_data;
 +        }
-         if (more_data && x1 < s->sps->width &&
-             y1 < s->sps->height) {
++        if (more_data && x1 < s->ps.sps->width &&
++            y1 < s->ps.sps->height) {
 +            more_data = hls_coding_quadtree(s, x1, y1, log2_cb_size - 1, cb_depth + 1);
 +            if (more_data < 0)
 +                return more_data;
 +        }
 +
 +        if(((x0 + (1<<log2_cb_size)) & qp_block_mask) == 0 &&
 +            ((y0 + (1<<log2_cb_size)) & qp_block_mask) == 0)
 +            lc->qPy_pred = lc->qp_y;
 +
 +        if (more_data)
-             return ((x1 + cb_size_split) < s->sps->width ||
-                     (y1 + cb_size_split) < s->sps->height);
++            return ((x1 + cb_size_split) < s->ps.sps->width ||
++                    (y1 + cb_size_split) < s->ps.sps->height);
 +        else
 +            return 0;
      } else {
 -        int ret = hls_coding_unit(s, x0, y0, log2_cb_size);
 +        ret = hls_coding_unit(s, x0, y0, log2_cb_size);
          if (ret < 0)
              return ret;
-                (1 << (s->sps->log2_ctb_size))) ||
-              (x0 + cb_size >= s->sps->width)) &&
 +        if ((!((x0 + cb_size) %
-                (1 << (s->sps->log2_ctb_size))) ||
-              (y0 + cb_size >= s->sps->height))) {
++               (1 << (s->ps.sps->log2_ctb_size))) ||
++             (x0 + cb_size >= s->ps.sps->width)) &&
 +            (!((y0 + cb_size) %
++               (1 << (s->ps.sps->log2_ctb_size))) ||
++             (y0 + cb_size >= s->ps.sps->height))) {
 +            int end_of_slice_flag = ff_hevc_end_of_slice_flag_decode(s);
 +            return !end_of_slice_flag;
 +        } else {
 +            return 1;
 +        }
      }
  
      return 0;
  static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
                                   int ctb_addr_ts)
  {
 -    HEVCLocalContext *lc  = &s->HEVClc;
 +    HEVCLocalContext *lc  = s->HEVClc;
-     int ctb_size          = 1 << s->sps->log2_ctb_size;
-     int ctb_addr_rs       = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts];
+     int ctb_size          = 1 << s->ps.sps->log2_ctb_size;
+     int ctb_addr_rs       = s->ps.pps->ctb_addr_ts_to_rs[ctb_addr_ts];
      int ctb_addr_in_slice = ctb_addr_rs - s->sh.slice_addr;
  
      s->tab_slice_address[ctb_addr_rs] = s->sh.slice_addr;
  
-     if (s->pps->entropy_coding_sync_enabled_flag) {
+     if (s->ps.pps->entropy_coding_sync_enabled_flag) {
          if (x_ctb == 0 && (y_ctb & (ctb_size - 1)) == 0)
              lc->first_qp_group = 1;
-         lc->end_of_tiles_x = s->sps->width;
-     } else if (s->pps->tiles_enabled_flag) {
-         if (ctb_addr_ts && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[ctb_addr_ts - 1]) {
-             int idxX = s->pps->col_idxX[x_ctb >> s->sps->log2_ctb_size];
-             lc->end_of_tiles_x   = x_ctb + (s->pps->column_width[idxX] << s->sps->log2_ctb_size);
+         lc->end_of_tiles_x = s->ps.sps->width;
+     } else if (s->ps.pps->tiles_enabled_flag) {
+         if (ctb_addr_ts && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[ctb_addr_ts - 1]) {
+             int idxX = s->ps.pps->col_idxX[x_ctb >> s->ps.sps->log2_ctb_size];
 -            lc->start_of_tiles_x = x_ctb;
+             lc->end_of_tiles_x   = x_ctb + (s->ps.pps->column_width[idxX] << s->ps.sps->log2_ctb_size);
              lc->first_qp_group   = 1;
          }
      } else {
              lc->boundary_flags |= BOUNDARY_LEFT_TILE;
          if (x_ctb > 0 && s->tab_slice_address[ctb_addr_rs] != s->tab_slice_address[ctb_addr_rs - 1])
              lc->boundary_flags |= BOUNDARY_LEFT_SLICE;
-         if (y_ctb > 0 && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs - s->sps->ctb_width]])
+         if (y_ctb > 0 && 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]])
              lc->boundary_flags |= BOUNDARY_UPPER_TILE;
-         if (y_ctb > 0 && s->tab_slice_address[ctb_addr_rs] != s->tab_slice_address[ctb_addr_rs - s->sps->ctb_width])
+         if (y_ctb > 0 && s->tab_slice_address[ctb_addr_rs] != s->tab_slice_address[ctb_addr_rs - s->ps.sps->ctb_width])
              lc->boundary_flags |= BOUNDARY_UPPER_SLICE;
      } else {
 -        if (!ctb_addr_in_slice > 0)
 +        if (ctb_addr_in_slice <= 0)
              lc->boundary_flags |= BOUNDARY_LEFT_SLICE;
-         if (ctb_addr_in_slice < s->sps->ctb_width)
+         if (ctb_addr_in_slice < s->ps.sps->ctb_width)
              lc->boundary_flags |= BOUNDARY_UPPER_SLICE;
      }
  
      lc->ctb_left_flag = ((x_ctb > 0) && (ctb_addr_in_slice > 0) && !(lc->boundary_flags & BOUNDARY_LEFT_TILE));
-     lc->ctb_up_flag   = ((y_ctb > 0) && (ctb_addr_in_slice >= s->sps->ctb_width) && !(lc->boundary_flags & BOUNDARY_UPPER_TILE));
-     lc->ctb_up_right_flag = ((y_ctb > 0)  && (ctb_addr_in_slice+1 >= s->sps->ctb_width) && (s->pps->tile_id[ctb_addr_ts] == s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs+1 - s->sps->ctb_width]]));
-     lc->ctb_up_left_flag = ((x_ctb > 0) && (y_ctb > 0)  && (ctb_addr_in_slice-1 >= s->sps->ctb_width) && (s->pps->tile_id[ctb_addr_ts] == s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs-1 - s->sps->ctb_width]]));
+     lc->ctb_up_flag   = ((y_ctb > 0) && (ctb_addr_in_slice >= s->ps.sps->ctb_width) && !(lc->boundary_flags & BOUNDARY_UPPER_TILE));
+     lc->ctb_up_right_flag = ((y_ctb > 0)  && (ctb_addr_in_slice+1 >= s->ps.sps->ctb_width) && (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 - s->ps.sps->ctb_width]]));
+     lc->ctb_up_left_flag = ((x_ctb > 0) && (y_ctb > 0)  && (ctb_addr_in_slice-1 >= s->ps.sps->ctb_width) && (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 - s->ps.sps->ctb_width]]));
  }
  
 -static int hls_slice_data(HEVCContext *s)
 +static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
  {
-     int ctb_size    = 1 << s->sps->log2_ctb_size;
 +    HEVCContext *s  = avctxt->priv_data;
+     int ctb_size    = 1 << s->ps.sps->log2_ctb_size;
      int more_data   = 1;
      int x_ctb       = 0;
      int y_ctb       = 0;
-     int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs];
+     int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs];
 -    int ret;
 +
 +    if (!ctb_addr_ts && s->sh.dependent_slice_segment_flag) {
 +        av_log(s->avctx, AV_LOG_ERROR, "Impossible initial tile.\n");
 +        return AVERROR_INVALIDDATA;
 +    }
 +
 +    if (s->sh.dependent_slice_segment_flag) {
-         int prev_rs = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts - 1];
++        int prev_rs = s->ps.pps->ctb_addr_ts_to_rs[ctb_addr_ts - 1];
 +        if (s->tab_slice_address[prev_rs] != s->sh.slice_addr) {
 +            av_log(s->avctx, AV_LOG_ERROR, "Previous slice segment missing\n");
 +            return AVERROR_INVALIDDATA;
 +        }
 +    }
  
-     while (more_data && ctb_addr_ts < s->sps->ctb_size) {
-         int ctb_addr_rs = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts];
+     while (more_data && ctb_addr_ts < s->ps.sps->ctb_size) {
+         int ctb_addr_rs = s->ps.pps->ctb_addr_ts_to_rs[ctb_addr_ts];
  
-         x_ctb = (ctb_addr_rs % ((s->sps->width + ctb_size - 1) >> s->sps->log2_ctb_size)) << s->sps->log2_ctb_size;
-         y_ctb = (ctb_addr_rs / ((s->sps->width + ctb_size - 1) >> s->sps->log2_ctb_size)) << s->sps->log2_ctb_size;
+         x_ctb = (ctb_addr_rs % ((s->ps.sps->width + ctb_size - 1) >> s->ps.sps->log2_ctb_size)) << s->ps.sps->log2_ctb_size;
+         y_ctb = (ctb_addr_rs / ((s->ps.sps->width + ctb_size - 1) >> s->ps.sps->log2_ctb_size)) << s->ps.sps->log2_ctb_size;
          hls_decode_neighbour(s, x_ctb, y_ctb, ctb_addr_ts);
  
          ff_hevc_cabac_init(s, ctb_addr_ts);
          s->deblock[ctb_addr_rs].tc_offset   = s->sh.tc_offset;
          s->filter_slice_edges[ctb_addr_rs]  = s->sh.slice_loop_filter_across_slices_enabled_flag;
  
-         more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->sps->log2_ctb_size, 0);
 -        ret = hls_coding_quadtree(s, x_ctb, y_ctb, s->ps.sps->log2_ctb_size, 0);
 -        if (ret < 0)
 -            return ret;
 -        more_data = !ff_hevc_end_of_slice_flag_decode(s);
++        more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->ps.sps->log2_ctb_size, 0);
 +        if (more_data < 0) {
 +            s->tab_slice_address[ctb_addr_rs] = -1;
 +            return more_data;
 +        }
 +
  
          ctb_addr_ts++;
          ff_hevc_save_states(s, ctb_addr_ts);
          ff_hevc_hls_filters(s, x_ctb, y_ctb, ctb_size);
      }
  
-     if (x_ctb + ctb_size >= s->sps->width &&
-         y_ctb + ctb_size >= s->sps->height)
+     if (x_ctb + ctb_size >= s->ps.sps->width &&
+         y_ctb + ctb_size >= s->ps.sps->height)
 -        ff_hevc_hls_filter(s, x_ctb, y_ctb);
 +        ff_hevc_hls_filter(s, x_ctb, y_ctb, ctb_size);
  
      return ctb_addr_ts;
  }
  
-     int ctb_size    = 1<< s1->sps->log2_ctb_size;
 +static int hls_slice_data(HEVCContext *s)
 +{
 +    int arg[2];
 +    int ret[2];
 +
 +    arg[0] = 0;
 +    arg[1] = 1;
 +
 +    s->avctx->execute(s->avctx, hls_decode_entry, arg, ret , 1, sizeof(int));
 +    return ret[0];
 +}
 +static int hls_decode_entry_wpp(AVCodecContext *avctxt, void *input_ctb_row, int job, int self_id)
 +{
 +    HEVCContext *s1  = avctxt->priv_data, *s;
 +    HEVCLocalContext *lc;
-     int ctb_addr_rs = s1->sh.slice_ctb_addr_rs + ctb_row * ((s1->sps->width + ctb_size - 1) >> s1->sps->log2_ctb_size);
-     int ctb_addr_ts = s1->pps->ctb_addr_rs_to_ts[ctb_addr_rs];
++    int ctb_size    = 1<< s1->ps.sps->log2_ctb_size;
 +    int more_data   = 1;
 +    int *ctb_row_p    = input_ctb_row;
 +    int ctb_row = ctb_row_p[job];
-     while(more_data && ctb_addr_ts < s->sps->ctb_size) {
-         int x_ctb = (ctb_addr_rs % s->sps->ctb_width) << s->sps->log2_ctb_size;
-         int y_ctb = (ctb_addr_rs / s->sps->ctb_width) << s->sps->log2_ctb_size;
++    int ctb_addr_rs = s1->sh.slice_ctb_addr_rs + ctb_row * ((s1->ps.sps->width + ctb_size - 1) >> s1->ps.sps->log2_ctb_size);
++    int ctb_addr_ts = s1->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs];
 +    int thread = ctb_row % s1->threads_number;
 +    int ret;
 +
 +    s = s1->sList[self_id];
 +    lc = s->HEVClc;
 +
 +    if(ctb_row) {
 +        ret = init_get_bits8(&lc->gb, s->data + s->sh.offset[ctb_row - 1], s->sh.size[ctb_row - 1]);
 +
 +        if (ret < 0)
 +            return ret;
 +        ff_init_cabac_decoder(&lc->cc, s->data + s->sh.offset[(ctb_row)-1], s->sh.size[ctb_row - 1]);
 +    }
 +
-         hls_sao_param(s, x_ctb >> s->sps->log2_ctb_size, y_ctb >> s->sps->log2_ctb_size);
-         more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->sps->log2_ctb_size, 0);
++    while(more_data && ctb_addr_ts < s->ps.sps->ctb_size) {
++        int x_ctb = (ctb_addr_rs % s->ps.sps->ctb_width) << s->ps.sps->log2_ctb_size;
++        int y_ctb = (ctb_addr_rs / s->ps.sps->ctb_width) << s->ps.sps->log2_ctb_size;
 +
 +        hls_decode_neighbour(s, x_ctb, y_ctb, ctb_addr_ts);
 +
 +        ff_thread_await_progress2(s->avctx, ctb_row, thread, SHIFT_CTB_WPP);
 +
 +        if (avpriv_atomic_int_get(&s1->wpp_err)){
 +            ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP);
 +            return 0;
 +        }
 +
 +        ff_hevc_cabac_init(s, ctb_addr_ts);
-         if (!more_data && (x_ctb+ctb_size) < s->sps->width && ctb_row != s->sh.num_entry_point_offsets) {
++        hls_sao_param(s, x_ctb >> s->ps.sps->log2_ctb_size, y_ctb >> s->ps.sps->log2_ctb_size);
++        more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->ps.sps->log2_ctb_size, 0);
 +
 +        if (more_data < 0) {
 +            s->tab_slice_address[ctb_addr_rs] = -1;
 +            return more_data;
 +        }
 +
 +        ctb_addr_ts++;
 +
 +        ff_hevc_save_states(s, ctb_addr_ts);
 +        ff_thread_report_progress2(s->avctx, ctb_row, thread, 1);
 +        ff_hevc_hls_filters(s, x_ctb, y_ctb, ctb_size);
 +
-         if ((x_ctb+ctb_size) >= s->sps->width && (y_ctb+ctb_size) >= s->sps->height ) {
++        if (!more_data && (x_ctb+ctb_size) < s->ps.sps->width && ctb_row != s->sh.num_entry_point_offsets) {
 +            avpriv_atomic_int_set(&s1->wpp_err,  1);
 +            ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP);
 +            return 0;
 +        }
 +
-         ctb_addr_rs       = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts];
++        if ((x_ctb+ctb_size) >= s->ps.sps->width && (y_ctb+ctb_size) >= s->ps.sps->height ) {
 +            ff_hevc_hls_filter(s, x_ctb, y_ctb, ctb_size);
 +            ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP);
 +            return ctb_addr_ts;
 +        }
-         if(x_ctb >= s->sps->width) {
++        ctb_addr_rs       = s->ps.pps->ctb_addr_ts_to_rs[ctb_addr_ts];
 +        x_ctb+=ctb_size;
 +
-     if (s->pps->entropy_coding_sync_enabled_flag)
++        if(x_ctb >= s->ps.sps->width) {
 +            break;
 +        }
 +    }
 +    ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP);
 +
 +    return 0;
 +}
 +
 +static int hls_slice_data_wpp(HEVCContext *s, const uint8_t *nal, int length)
 +{
 +    HEVCLocalContext *lc = s->HEVClc;
 +    int *ret = av_malloc_array(s->sh.num_entry_point_offsets + 1, sizeof(int));
 +    int *arg = av_malloc_array(s->sh.num_entry_point_offsets + 1, sizeof(int));
 +    int offset;
 +    int startheader, cmpt = 0;
 +    int i, j, res = 0;
 +
 +    if (!ret || !arg) {
 +        av_free(ret);
 +        av_free(arg);
 +        return AVERROR(ENOMEM);
 +    }
 +
 +
 +    if (!s->sList[1]) {
 +        ff_alloc_entries(s->avctx, s->sh.num_entry_point_offsets + 1);
 +
 +
 +        for (i = 1; i < s->threads_number; i++) {
 +            s->sList[i] = av_malloc(sizeof(HEVCContext));
 +            memcpy(s->sList[i], s, sizeof(HEVCContext));
 +            s->HEVClcList[i] = av_mallocz(sizeof(HEVCLocalContext));
 +            s->sList[i]->HEVClc = s->HEVClcList[i];
 +        }
 +    }
 +
 +    offset = (lc->gb.index >> 3);
 +
 +    for (j = 0, cmpt = 0, startheader = offset + s->sh.entry_point_offset[0]; j < s->skipped_bytes; j++) {
 +        if (s->skipped_bytes_pos[j] >= offset && s->skipped_bytes_pos[j] < startheader) {
 +            startheader--;
 +            cmpt++;
 +        }
 +    }
 +
 +    for (i = 1; i < s->sh.num_entry_point_offsets; i++) {
 +        offset += (s->sh.entry_point_offset[i - 1] - cmpt);
 +        for (j = 0, cmpt = 0, startheader = offset
 +             + s->sh.entry_point_offset[i]; j < s->skipped_bytes; j++) {
 +            if (s->skipped_bytes_pos[j] >= offset && s->skipped_bytes_pos[j] < startheader) {
 +                startheader--;
 +                cmpt++;
 +            }
 +        }
 +        s->sh.size[i - 1] = s->sh.entry_point_offset[i] - cmpt;
 +        s->sh.offset[i - 1] = offset;
 +
 +    }
 +    if (s->sh.num_entry_point_offsets != 0) {
 +        offset += s->sh.entry_point_offset[s->sh.num_entry_point_offsets - 1] - cmpt;
 +        s->sh.size[s->sh.num_entry_point_offsets - 1] = length - offset;
 +        s->sh.offset[s->sh.num_entry_point_offsets - 1] = offset;
 +
 +    }
 +    s->data = nal;
 +
 +    for (i = 1; i < s->threads_number; i++) {
 +        s->sList[i]->HEVClc->first_qp_group = 1;
 +        s->sList[i]->HEVClc->qp_y = s->sList[0]->HEVClc->qp_y;
 +        memcpy(s->sList[i], s, sizeof(HEVCContext));
 +        s->sList[i]->HEVClc = s->HEVClcList[i];
 +    }
 +
 +    avpriv_atomic_int_set(&s->wpp_err, 0);
 +    ff_reset_entries(s->avctx);
 +
 +    for (i = 0; i <= s->sh.num_entry_point_offsets; i++) {
 +        arg[i] = i;
 +        ret[i] = 0;
 +    }
 +
++    if (s->ps.pps->entropy_coding_sync_enabled_flag)
 +        s->avctx->execute2(s->avctx, (void *) hls_decode_entry_wpp, arg, ret, s->sh.num_entry_point_offsets + 1);
 +
 +    for (i = 0; i <= s->sh.num_entry_point_offsets; i++)
 +        res += ret[i];
 +    av_free(ret);
 +    av_free(arg);
 +    return res;
 +}
 +
  /**
   * @return AVERROR_INVALIDDATA if the packet is not a valid NAL unit,
   * 0 if the unit should be skipped, 1 otherwise
@@@ -2582,24 -2445,23 +2582,24 @@@ static int set_side_data(HEVCContext *s
  
  static int hevc_frame_start(HEVCContext *s)
  {
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
-     int pic_size_in_ctb  = ((s->sps->width  >> s->sps->log2_min_cb_size) + 1) *
-                            ((s->sps->height >> s->sps->log2_min_cb_size) + 1);
++    int pic_size_in_ctb  = ((s->ps.sps->width  >> s->ps.sps->log2_min_cb_size) + 1) *
++                           ((s->ps.sps->height >> s->ps.sps->log2_min_cb_size) + 1);
      int ret;
  
 -    memset(s->horizontal_bs, 0, 2 * s->bs_width * (s->bs_height + 1));
 -    memset(s->vertical_bs,   0, 2 * s->bs_width * (s->bs_height + 1));
 +    memset(s->horizontal_bs, 0, s->bs_width * s->bs_height);
 +    memset(s->vertical_bs,   0, s->bs_width * s->bs_height);
-     memset(s->cbf_luma,      0, s->sps->min_tb_width * s->sps->min_tb_height);
-     memset(s->is_pcm,        0, (s->sps->min_pu_width + 1) * (s->sps->min_pu_height + 1));
+     memset(s->cbf_luma,      0, s->ps.sps->min_tb_width * s->ps.sps->min_tb_height);
 -    memset(s->is_pcm,        0, s->ps.sps->min_pu_width * s->ps.sps->min_pu_height);
++    memset(s->is_pcm,        0, (s->ps.sps->min_pu_width + 1) * (s->ps.sps->min_pu_height + 1));
 +    memset(s->tab_slice_address, -1, pic_size_in_ctb * sizeof(*s->tab_slice_address));
  
 -    lc->start_of_tiles_x = 0;
      s->is_decoded        = 0;
      s->first_nal_type    = s->nal_unit_type;
  
-     if (s->pps->tiles_enabled_flag)
-         lc->end_of_tiles_x = s->pps->column_width[0] << s->sps->log2_ctb_size;
+     if (s->ps.pps->tiles_enabled_flag)
+         lc->end_of_tiles_x = s->ps.pps->column_width[0] << s->ps.sps->log2_ctb_size;
  
 -    ret = ff_hevc_set_new_ref(s, s->ps.sps->sao_enabled ? &s->sao_frame : &s->frame,
 -                              s->poc);
 +    ret = ff_hevc_set_new_ref(s, &s->frame, s->poc);
      if (ret < 0)
          goto fail;
  
@@@ -2752,12 -2609,13 +2753,12 @@@ static int decode_nal_unit(HEVCContext 
              if (ret < 0)
                  goto fail;
          } else {
 -            ctb_addr_ts = hls_slice_data(s);
 +            if (s->threads_number > 1 && s->sh.num_entry_point_offsets > 0)
 +                ctb_addr_ts = hls_slice_data_wpp(s, nal->data, nal->size);
 +            else
 +                ctb_addr_ts = hls_slice_data(s);
-             if (ctb_addr_ts >= (s->sps->ctb_width * s->sps->ctb_height)) {
+             if (ctb_addr_ts >= (s->ps.sps->ctb_width * s->ps.sps->ctb_height)) {
                  s->is_decoded = 1;
 -                if ((s->ps.pps->transquant_bypass_enable_flag ||
 -                     (s->ps.sps->pcm.loop_filter_disable_flag && s->ps.sps->pcm_enabled_flag)) &&
 -                    s->ps.sps->sao_enabled)
 -                    restore_tqb_pixels(s);
              }
  
              if (ctb_addr_ts < 0) {
@@@ -3104,30 -2915,12 +3105,30 @@@ static av_cold int hevc_decode_free(AVC
          av_frame_free(&s->DPB[i].frame);
      }
  
-     for (i = 0; i < FF_ARRAY_ELEMS(s->vps_list); i++)
-         av_buffer_unref(&s->vps_list[i]);
-     for (i = 0; i < FF_ARRAY_ELEMS(s->sps_list); i++)
-         av_buffer_unref(&s->sps_list[i]);
-     for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++)
-         av_buffer_unref(&s->pps_list[i]);
-     s->sps = NULL;
-     s->pps = NULL;
-     s->vps = NULL;
+     for (i = 0; i < FF_ARRAY_ELEMS(s->ps.vps_list); i++)
+         av_buffer_unref(&s->ps.vps_list[i]);
+     for (i = 0; i < FF_ARRAY_ELEMS(s->ps.sps_list); i++)
+         av_buffer_unref(&s->ps.sps_list[i]);
+     for (i = 0; i < FF_ARRAY_ELEMS(s->ps.pps_list); i++)
+         av_buffer_unref(&s->ps.pps_list[i]);
++    s->ps.sps = NULL;
++    s->ps.pps = NULL;
++    s->ps.vps = NULL;
 +
 +    av_freep(&s->sh.entry_point_offset);
 +    av_freep(&s->sh.offset);
 +    av_freep(&s->sh.size);
 +
 +    for (i = 1; i < s->threads_number; i++) {
 +        HEVCLocalContext *lc = s->HEVClcList[i];
 +        if (lc) {
 +            av_freep(&s->HEVClcList[i]);
 +            av_freep(&s->sList[i]);
 +        }
 +    }
 +    if (s->HEVClc == s->HEVClcList[0])
 +        s->HEVClc = NULL;
 +    av_freep(&s->HEVClcList[0]);
  
      for (i = 0; i < s->nals_allocated; i++)
          av_freep(&s->nals[i].rbsp_buffer);
@@@ -3205,13 -2991,11 +3206,13 @@@ static int hevc_update_thread_context(A
          }
      }
  
-     if (s->sps != s0->sps)
-         s->sps = NULL;
-     for (i = 0; i < FF_ARRAY_ELEMS(s->vps_list); i++) {
-         av_buffer_unref(&s->vps_list[i]);
-         if (s0->vps_list[i]) {
-             s->vps_list[i] = av_buffer_ref(s0->vps_list[i]);
-             if (!s->vps_list[i])
++    if (s->ps.sps != s0->ps.sps)
++        s->ps.sps = NULL;
+     for (i = 0; i < FF_ARRAY_ELEMS(s->ps.vps_list); i++) {
+         av_buffer_unref(&s->ps.vps_list[i]);
+         if (s0->ps.vps_list[i]) {
+             s->ps.vps_list[i] = av_buffer_ref(s0->ps.vps_list[i]);
+             if (!s->ps.vps_list[i])
                  return AVERROR(ENOMEM);
          }
      }
          }
      }
  
-     if (s->sps != s0->sps)
-         if ((ret = set_sps(s, s0->sps, src->pix_fmt)) < 0)
+     if (s->ps.sps != s0->ps.sps)
 -        ret = set_sps(s, s0->ps.sps);
++        if ((ret = set_sps(s, s0->ps.sps, src->pix_fmt)) < 0)
 +            return ret;
  
      s->seq_decode = s0->seq_decode;
      s->seq_output = s0->seq_output;
@@@ -554,9 -523,19 +554,20 @@@ typedef struct HEVCPPS 
      int *tile_id;           ///< TileId
      int *tile_pos_rs;       ///< TilePosRS
      int *min_tb_addr_zs;    ///< MinTbAddrZS
 +    int *min_tb_addr_zs_tab;///< MinTbAddrZS
  } HEVCPPS;
  
+ typedef struct HEVCParamSets {
+     AVBufferRef *vps_list[MAX_VPS_COUNT];
+     AVBufferRef *sps_list[MAX_SPS_COUNT];
+     AVBufferRef *pps_list[MAX_PPS_COUNT];
+     /* currently active parameter sets */
+     const HEVCVPS *vps;
+     const HEVCSPS *sps;
+     const HEVCPPS *pps;
+ } HEVCParamSets;
  typedef struct SliceHeader {
      unsigned int pps_id;
  
@@@ -809,16 -776,11 +820,11 @@@ typedef struct HEVCContext 
      uint8_t slice_initialized;
  
      AVFrame *frame;
 -    AVFrame *sao_frame;
 -    AVFrame *tmp_frame;
      AVFrame *output_frame;
 +    uint8_t *sao_pixel_buffer_h[3];
 +    uint8_t *sao_pixel_buffer_v[3];
  
-     const HEVCVPS *vps;
-     const HEVCSPS *sps;
-     const HEVCPPS *pps;
-     AVBufferRef *vps_list[MAX_VPS_COUNT];
-     AVBufferRef *sps_list[MAX_SPS_COUNT];
-     AVBufferRef *pps_list[MAX_PPS_COUNT];
+     HEVCParamSets ps;
  
      AVBufferPool *tab_mvf_pool;
      AVBufferPool *rpl_tab_pool;
@@@ -499,11 -325,11 +499,11 @@@ static const uint8_t diag_scan8x8_inv[8
  
  void ff_hevc_save_states(HEVCContext *s, int ctb_addr_ts)
  {
-     if (s->pps->entropy_coding_sync_enabled_flag &&
-         (ctb_addr_ts % s->sps->ctb_width == 2 ||
-          (s->sps->ctb_width == 2 &&
-           ctb_addr_ts % s->sps->ctb_width == 0))) {
+     if (s->ps.pps->entropy_coding_sync_enabled_flag &&
+         (ctb_addr_ts % s->ps.sps->ctb_width == 2 ||
+          (s->ps.sps->ctb_width == 2 &&
+           ctb_addr_ts % s->ps.sps->ctb_width == 0))) {
 -        memcpy(s->cabac_state, s->HEVClc.cabac_state, HEVC_CONTEXTS);
 +        memcpy(s->cabac_state, s->HEVClc->cabac_state, HEVC_CONTEXTS);
      }
  }
  
@@@ -570,23 -393,17 +570,23 @@@ void ff_hevc_cabac_init(HEVCContext *s
              }
          }
      } else {
-         if (s->pps->tiles_enabled_flag &&
-             s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[ctb_addr_ts - 1]) {
+         if (s->ps.pps->tiles_enabled_flag &&
+             s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[ctb_addr_ts - 1]) {
 -            cabac_reinit(&s->HEVClc);
 +            if (s->threads_number == 1)
 +                cabac_reinit(s->HEVClc);
 +            else
 +                cabac_init_decoder(s);
              cabac_init_state(s);
          }
-         if (s->pps->entropy_coding_sync_enabled_flag) {
-             if (ctb_addr_ts % s->sps->ctb_width == 0) {
+         if (s->ps.pps->entropy_coding_sync_enabled_flag) {
+             if (ctb_addr_ts % s->ps.sps->ctb_width == 0) {
 -                get_cabac_terminate(&s->HEVClc.cc);
 -                cabac_reinit(&s->HEVClc);
 +                get_cabac_terminate(&s->HEVClc->cc);
 +                if (s->threads_number == 1)
 +                    cabac_reinit(s->HEVClc);
 +                else
 +                    cabac_init_decoder(s);
  
-                 if (s->sps->ctb_width == 1)
+                 if (s->ps.sps->ctb_width == 1)
                      cabac_init_state(s);
                  else
                      load_states(s);
@@@ -625,9 -442,9 +625,9 @@@ int ff_hevc_sao_band_position_decode(HE
  int ff_hevc_sao_offset_abs_decode(HEVCContext *s)
  {
      int i = 0;
-     int length = (1 << (FFMIN(s->sps->bit_depth, 10) - 5)) - 1;
+     int length = (1 << (FFMIN(s->ps.sps->bit_depth, 10) - 5)) - 1;
  
 -    while (i < length && get_cabac_bypass(&s->HEVClc.cc))
 +    while (i < length && get_cabac_bypass(&s->HEVClc->cc))
          i++;
      return i;
  }
@@@ -656,14 -473,14 +656,14 @@@ int ff_hevc_cu_transquant_bypass_flag_d
  
  int ff_hevc_skip_flag_decode(HEVCContext *s, int x0, int y0, int x_cb, int y_cb)
  {
-     int min_cb_width = s->sps->min_cb_width;
+     int min_cb_width = s->ps.sps->min_cb_width;
      int inc = 0;
-     int x0b = av_mod_uintp2(x0, s->sps->log2_ctb_size);
-     int y0b = av_mod_uintp2(y0, s->sps->log2_ctb_size);
 -    int x0b = x0 & ((1 << s->ps.sps->log2_ctb_size) - 1);
 -    int y0b = y0 & ((1 << s->ps.sps->log2_ctb_size) - 1);
++    int x0b = av_mod_uintp2(x0, s->ps.sps->log2_ctb_size);
++    int y0b = av_mod_uintp2(y0, s->ps.sps->log2_ctb_size);
  
 -    if (s->HEVClc.ctb_left_flag || x0b)
 +    if (s->HEVClc->ctb_left_flag || x0b)
          inc = !!SAMPLE_CTB(s->skip_flag, x_cb - 1, y_cb);
 -    if (s->HEVClc.ctb_up_flag || y0b)
 +    if (s->HEVClc->ctb_up_flag || y0b)
          inc += !!SAMPLE_CTB(s->skip_flag, x_cb, y_cb - 1);
  
      return GET_CABAC(elem_offset[SKIP_FLAG] + inc);
@@@ -696,23 -513,7 +696,23 @@@ int ff_hevc_cu_qp_delta_abs(HEVCContex
  
  int ff_hevc_cu_qp_delta_sign_flag(HEVCContext *s)
  {
 -    return get_cabac_bypass(&s->HEVClc.cc);
 +    return get_cabac_bypass(&s->HEVClc->cc);
 +}
 +
 +int ff_hevc_cu_chroma_qp_offset_flag(HEVCContext *s)
 +{
 +    return GET_CABAC(elem_offset[CU_CHROMA_QP_OFFSET_FLAG]);
 +}
 +
 +int ff_hevc_cu_chroma_qp_offset_idx(HEVCContext *s)
 +{
-     int c_max= FFMAX(5, s->pps->chroma_qp_offset_list_len_minus1);
++    int c_max= FFMAX(5, s->ps.pps->chroma_qp_offset_list_len_minus1);
 +    int i = 0;
 +
 +    while (i < c_max && GET_CABAC(elem_offset[CU_CHROMA_QP_OFFSET_IDX]))
 +        i++;
 +
 +    return i;
  }
  
  int ff_hevc_pred_mode_decode(HEVCContext *s)
  int ff_hevc_split_coding_unit_flag_decode(HEVCContext *s, int ct_depth, int x0, int y0)
  {
      int inc = 0, depth_left = 0, depth_top = 0;
-     int x0b  = av_mod_uintp2(x0, s->sps->log2_ctb_size);
-     int y0b  = av_mod_uintp2(y0, s->sps->log2_ctb_size);
-     int x_cb = x0 >> s->sps->log2_min_cb_size;
-     int y_cb = y0 >> s->sps->log2_min_cb_size;
 -    int x0b  = x0 & ((1 << s->ps.sps->log2_ctb_size) - 1);
 -    int y0b  = y0 & ((1 << s->ps.sps->log2_ctb_size) - 1);
++    int x0b  = av_mod_uintp2(x0, s->ps.sps->log2_ctb_size);
++    int y0b  = av_mod_uintp2(y0, s->ps.sps->log2_ctb_size);
+     int x_cb = x0 >> s->ps.sps->log2_min_cb_size;
+     int y_cb = y0 >> s->ps.sps->log2_min_cb_size;
  
 -    if (s->HEVClc.ctb_left_flag || x0b)
 +    if (s->HEVClc->ctb_left_flag || x0b)
-         depth_left = s->tab_ct_depth[(y_cb) * s->sps->min_cb_width + x_cb - 1];
+         depth_left = s->tab_ct_depth[(y_cb) * s->ps.sps->min_cb_width + x_cb - 1];
 -    if (s->HEVClc.ctb_up_flag || y0b)
 +    if (s->HEVClc->ctb_up_flag || y0b)
-         depth_top = s->tab_ct_depth[(y_cb - 1) * s->sps->min_cb_width + x_cb];
+         depth_top = s->tab_ct_depth[(y_cb - 1) * s->ps.sps->min_cb_width + x_cb];
  
      inc += (depth_left > ct_depth);
      inc += (depth_top  > ct_depth);
@@@ -743,8 -544,8 +743,8 @@@ int ff_hevc_part_mode_decode(HEVCContex
  {
      if (GET_CABAC(elem_offset[PART_MODE])) // 1
          return PART_2Nx2N;
-     if (log2_cb_size == s->sps->log2_min_cb_size) {
+     if (log2_cb_size == s->ps.sps->log2_min_cb_size) {
 -        if (s->HEVClc.cu.pred_mode == MODE_INTRA) // 0
 +        if (s->HEVClc->cu.pred_mode == MODE_INTRA) // 0
              return PART_NxN;
          if (GET_CABAC(elem_offset[PART_MODE] + 1)) // 01
              return PART_2NxN;
@@@ -1047,541 -867,6 +1047,541 @@@ static av_always_inline int coeff_sign_
      int ret = 0;
  
      for (i = 0; i < nb; i++)
 -        ret = (ret << 1) | get_cabac_bypass(&s->HEVClc.cc);
 +        ret = (ret << 1) | get_cabac_bypass(&s->HEVClc->cc);
      return ret;
  }
-     int hshift = s->sps->hshift[c_idx];
-     int vshift = s->sps->vshift[c_idx];
 +
 +void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
 +                                int log2_trafo_size, enum ScanType scan_idx,
 +                                int c_idx)
 +{
 +#define GET_COORD(offset, n)                                    \
 +    do {                                                        \
 +        x_c = (x_cg << 2) + scan_x_off[n];                      \
 +        y_c = (y_cg << 2) + scan_y_off[n];                      \
 +    } while (0)
 +    HEVCLocalContext *lc = s->HEVClc;
 +    int transform_skip_flag = 0;
 +
 +    int last_significant_coeff_x, last_significant_coeff_y;
 +    int last_scan_pos;
 +    int n_end;
 +    int num_coeff = 0;
 +    int greater1_ctx = 1;
 +
 +    int num_last_subset;
 +    int x_cg_last_sig, y_cg_last_sig;
 +
 +    const uint8_t *scan_x_cg, *scan_y_cg, *scan_x_off, *scan_y_off;
 +
 +    ptrdiff_t stride = s->frame->linesize[c_idx];
-                                           ((x0 >> hshift) << s->sps->pixel_shift)];
++    int hshift = s->ps.sps->hshift[c_idx];
++    int vshift = s->ps.sps->vshift[c_idx];
 +    uint8_t *dst = &s->frame->data[c_idx][(y0 >> vshift) * stride +
-         if (s->pps->transform_skip_enabled_flag &&
-             log2_trafo_size <= s->pps->log2_max_transform_skip_block_size) {
++                                          ((x0 >> hshift) << s->ps.sps->pixel_shift)];
 +    int16_t *coeffs = (int16_t*)(c_idx ? lc->edge_emu_buffer2 : lc->edge_emu_buffer);
 +    uint8_t significant_coeff_group_flag[8][8] = {{0}};
 +    int explicit_rdpcm_flag = 0;
 +    int explicit_rdpcm_dir_flag;
 +
 +    int trafo_size = 1 << log2_trafo_size;
 +    int i;
 +    int qp,shift,add,scale,scale_m;
 +    const uint8_t level_scale[] = { 40, 45, 51, 57, 64, 72 };
 +    const uint8_t *scale_matrix = NULL;
 +    uint8_t dc_scale;
 +    int pred_mode_intra = (c_idx == 0) ? lc->tu.intra_pred_mode :
 +                                         lc->tu.intra_pred_mode_c;
 +
 +    memset(coeffs, 0, trafo_size * trafo_size * sizeof(int16_t));
 +
 +    // Derive QP for dequant
 +    if (!lc->cu.cu_transquant_bypass_flag) {
 +        static const int qp_c[] = { 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 };
 +        static const uint8_t rem6[51 + 4 * 6 + 1] = {
 +            0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2,
 +            3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5,
 +            0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3,
 +            4, 5, 0, 1, 2, 3, 4, 5, 0, 1
 +        };
 +
 +        static const uint8_t div6[51 + 4 * 6 + 1] = {
 +            0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3,  3,  3,
 +            3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6,  6,  6,
 +            7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10,
 +            10, 10, 11, 11, 11, 11, 11, 11, 12, 12
 +        };
 +        int qp_y = lc->qp_y;
 +
-             qp = qp_y + s->sps->qp_bd_offset;
++        if (s->ps.pps->transform_skip_enabled_flag &&
++            log2_trafo_size <= s->ps.pps->log2_max_transform_skip_block_size) {
 +            transform_skip_flag = hevc_transform_skip_flag_decode(s, c_idx);
 +        }
 +
 +        if (c_idx == 0) {
-                 offset = s->pps->cb_qp_offset + s->sh.slice_cb_qp_offset +
++            qp = qp_y + s->ps.sps->qp_bd_offset;
 +        } else {
 +            int qp_i, offset;
 +
 +            if (c_idx == 1)
-                 offset = s->pps->cr_qp_offset + s->sh.slice_cr_qp_offset +
++                offset = s->ps.pps->cb_qp_offset + s->sh.slice_cb_qp_offset +
 +                         lc->tu.cu_qp_offset_cb;
 +            else
-             qp_i = av_clip(qp_y + offset, - s->sps->qp_bd_offset, 57);
-             if (s->sps->chroma_format_idc == 1) {
++                offset = s->ps.pps->cr_qp_offset + s->sh.slice_cr_qp_offset +
 +                         lc->tu.cu_qp_offset_cr;
 +
-             qp += s->sps->qp_bd_offset;
++            qp_i = av_clip(qp_y + offset, - s->ps.sps->qp_bd_offset, 57);
++            if (s->ps.sps->chroma_format_idc == 1) {
 +                if (qp_i < 30)
 +                    qp = qp_i;
 +                else if (qp_i > 43)
 +                    qp = qp_i - 6;
 +                else
 +                    qp = qp_c[qp_i - 30];
 +            } else {
 +                if (qp_i > 51)
 +                    qp = 51;
 +                else
 +                    qp = qp_i;
 +            }
 +
-         shift    = s->sps->bit_depth + log2_trafo_size - 5;
++            qp += s->ps.sps->qp_bd_offset;
 +        }
 +
-         if (s->sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) {
-             const ScalingList *sl = s->pps->scaling_list_data_present_flag ?
-             &s->pps->scaling_list : &s->sps->scaling_list;
++        shift    = s->ps.sps->bit_depth + log2_trafo_size - 5;
 +        add      = 1 << (shift-1);
 +        scale    = level_scale[rem6[qp]] << (div6[qp]);
 +        scale_m  = 16; // default when no custom scaling lists.
 +        dc_scale = 16;
 +
-     if (lc->cu.pred_mode == MODE_INTER && s->sps->explicit_rdpcm_enabled_flag &&
++        if (s->ps.sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) {
++            const ScalingList *sl = s->ps.pps->scaling_list_data_present_flag ?
++            &s->ps.pps->scaling_list : &s->ps.sps->scaling_list;
 +            int matrix_id = lc->cu.pred_mode != MODE_INTRA;
 +
 +            matrix_id = 3 * matrix_id + c_idx;
 +
 +            scale_matrix = sl->sl[log2_trafo_size - 2][matrix_id];
 +            if (log2_trafo_size >= 4)
 +                dc_scale = sl->sl_dc[log2_trafo_size - 4][matrix_id];
 +        }
 +    } else {
 +        shift        = 0;
 +        add          = 0;
 +        scale        = 0;
 +        dc_scale     = 0;
 +    }
 +
-             if (s->sps->transform_skip_context_enabled_flag &&
++    if (lc->cu.pred_mode == MODE_INTER && s->ps.sps->explicit_rdpcm_enabled_flag &&
 +        (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
 +        explicit_rdpcm_flag = explicit_rdpcm_flag_decode(s, c_idx);
 +        if (explicit_rdpcm_flag) {
 +            explicit_rdpcm_dir_flag = explicit_rdpcm_dir_flag_decode(s, c_idx);
 +        }
 +    }
 +
 +    last_significant_coeff_xy_prefix_decode(s, c_idx, log2_trafo_size,
 +                                           &last_significant_coeff_x, &last_significant_coeff_y);
 +
 +    if (last_significant_coeff_x > 3) {
 +        int suffix = last_significant_coeff_suffix_decode(s, last_significant_coeff_x);
 +        last_significant_coeff_x = (1 << ((last_significant_coeff_x >> 1) - 1)) *
 +        (2 + (last_significant_coeff_x & 1)) +
 +        suffix;
 +    }
 +
 +    if (last_significant_coeff_y > 3) {
 +        int suffix = last_significant_coeff_suffix_decode(s, last_significant_coeff_y);
 +        last_significant_coeff_y = (1 << ((last_significant_coeff_y >> 1) - 1)) *
 +        (2 + (last_significant_coeff_y & 1)) +
 +        suffix;
 +    }
 +
 +    if (scan_idx == SCAN_VERT)
 +        FFSWAP(int, last_significant_coeff_x, last_significant_coeff_y);
 +
 +    x_cg_last_sig = last_significant_coeff_x >> 2;
 +    y_cg_last_sig = last_significant_coeff_y >> 2;
 +
 +    switch (scan_idx) {
 +    case SCAN_DIAG: {
 +        int last_x_c = last_significant_coeff_x & 3;
 +        int last_y_c = last_significant_coeff_y & 3;
 +
 +        scan_x_off = ff_hevc_diag_scan4x4_x;
 +        scan_y_off = ff_hevc_diag_scan4x4_y;
 +        num_coeff = diag_scan4x4_inv[last_y_c][last_x_c];
 +        if (trafo_size == 4) {
 +            scan_x_cg = scan_1x1;
 +            scan_y_cg = scan_1x1;
 +        } else if (trafo_size == 8) {
 +            num_coeff += diag_scan2x2_inv[y_cg_last_sig][x_cg_last_sig] << 4;
 +            scan_x_cg = diag_scan2x2_x;
 +            scan_y_cg = diag_scan2x2_y;
 +        } else if (trafo_size == 16) {
 +            num_coeff += diag_scan4x4_inv[y_cg_last_sig][x_cg_last_sig] << 4;
 +            scan_x_cg = ff_hevc_diag_scan4x4_x;
 +            scan_y_cg = ff_hevc_diag_scan4x4_y;
 +        } else { // trafo_size == 32
 +            num_coeff += diag_scan8x8_inv[y_cg_last_sig][x_cg_last_sig] << 4;
 +            scan_x_cg = ff_hevc_diag_scan8x8_x;
 +            scan_y_cg = ff_hevc_diag_scan8x8_y;
 +        }
 +        break;
 +    }
 +    case SCAN_HORIZ:
 +        scan_x_cg = horiz_scan2x2_x;
 +        scan_y_cg = horiz_scan2x2_y;
 +        scan_x_off = horiz_scan4x4_x;
 +        scan_y_off = horiz_scan4x4_y;
 +        num_coeff = horiz_scan8x8_inv[last_significant_coeff_y][last_significant_coeff_x];
 +        break;
 +    default: //SCAN_VERT
 +        scan_x_cg = horiz_scan2x2_y;
 +        scan_y_cg = horiz_scan2x2_x;
 +        scan_x_off = horiz_scan4x4_y;
 +        scan_y_off = horiz_scan4x4_x;
 +        num_coeff = horiz_scan8x8_inv[last_significant_coeff_x][last_significant_coeff_y];
 +        break;
 +    }
 +    num_coeff++;
 +    num_last_subset = (num_coeff - 1) >> 4;
 +
 +    for (i = num_last_subset; i >= 0; i--) {
 +        int n, m;
 +        int x_cg, y_cg, x_c, y_c, pos;
 +        int implicit_non_zero_coeff = 0;
 +        int64_t trans_coeff_level;
 +        int prev_sig = 0;
 +        int offset = i << 4;
 +        int rice_init = 0;
 +
 +        uint8_t significant_coeff_flag_idx[16];
 +        uint8_t nb_significant_coeff_flag = 0;
 +
 +        x_cg = scan_x_cg[i];
 +        y_cg = scan_y_cg[i];
 +
 +        if ((i < num_last_subset) && (i > 0)) {
 +            int ctx_cg = 0;
 +            if (x_cg < (1 << (log2_trafo_size - 2)) - 1)
 +                ctx_cg += significant_coeff_group_flag[x_cg + 1][y_cg];
 +            if (y_cg < (1 << (log2_trafo_size - 2)) - 1)
 +                ctx_cg += significant_coeff_group_flag[x_cg][y_cg + 1];
 +
 +            significant_coeff_group_flag[x_cg][y_cg] =
 +                significant_coeff_group_flag_decode(s, c_idx, ctx_cg);
 +            implicit_non_zero_coeff = 1;
 +        } else {
 +            significant_coeff_group_flag[x_cg][y_cg] =
 +            ((x_cg == x_cg_last_sig && y_cg == y_cg_last_sig) ||
 +             (x_cg == 0 && y_cg == 0));
 +        }
 +
 +        last_scan_pos = num_coeff - offset - 1;
 +
 +        if (i == num_last_subset) {
 +            n_end = last_scan_pos - 1;
 +            significant_coeff_flag_idx[0] = last_scan_pos;
 +            nb_significant_coeff_flag = 1;
 +        } else {
 +            n_end = 15;
 +        }
 +
 +        if (x_cg < ((1 << log2_trafo_size) - 1) >> 2)
 +            prev_sig = !!significant_coeff_group_flag[x_cg + 1][y_cg];
 +        if (y_cg < ((1 << log2_trafo_size) - 1) >> 2)
 +            prev_sig += (!!significant_coeff_group_flag[x_cg][y_cg + 1] << 1);
 +
 +        if (significant_coeff_group_flag[x_cg][y_cg] && n_end >= 0) {
 +            static const uint8_t ctx_idx_map[] = {
 +                0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8, // log2_trafo_size == 2
 +                1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 0
 +                2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 1
 +                2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, // prev_sig == 2
 +                2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2  // default
 +            };
 +            const uint8_t *ctx_idx_map_p;
 +            int scf_offset = 0;
-                 if (s->sps->transform_skip_context_enabled_flag &&
++            if (s->ps.sps->transform_skip_context_enabled_flag &&
 +                (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
 +                ctx_idx_map_p = (uint8_t*) &ctx_idx_map[4 * 16];
 +                if (c_idx == 0) {
 +                    scf_offset = 40;
 +                } else {
 +                    scf_offset = 14 + 27;
 +                }
 +            } else {
 +                if (c_idx != 0)
 +                    scf_offset = 27;
 +                if (log2_trafo_size == 2) {
 +                    ctx_idx_map_p = (uint8_t*) &ctx_idx_map[0];
 +                } else {
 +                    ctx_idx_map_p = (uint8_t*) &ctx_idx_map[(prev_sig + 1) << 4];
 +                    if (c_idx == 0) {
 +                        if ((x_cg > 0 || y_cg > 0))
 +                            scf_offset += 3;
 +                        if (log2_trafo_size == 3) {
 +                            scf_offset += (scan_idx == SCAN_DIAG) ? 9 : 15;
 +                        } else {
 +                            scf_offset += 21;
 +                        }
 +                    } else {
 +                        if (log2_trafo_size == 3)
 +                            scf_offset += 9;
 +                        else
 +                            scf_offset += 12;
 +                    }
 +                }
 +            }
 +            for (n = n_end; n > 0; n--) {
 +                x_c = scan_x_off[n];
 +                y_c = scan_y_off[n];
 +                if (significant_coeff_flag_decode(s, x_c, y_c, scf_offset, ctx_idx_map_p)) {
 +                    significant_coeff_flag_idx[nb_significant_coeff_flag] = n;
 +                    nb_significant_coeff_flag++;
 +                    implicit_non_zero_coeff = 0;
 +                }
 +            }
 +            if (implicit_non_zero_coeff == 0) {
-             if (s->sps->persistent_rice_adaptation_enabled_flag) {
++                if (s->ps.sps->transform_skip_context_enabled_flag &&
 +                    (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
 +                    if (c_idx == 0) {
 +                        scf_offset = 42;
 +                    } else {
 +                        scf_offset = 16 + 27;
 +                    }
 +                } else {
 +                    if (i == 0) {
 +                        if (c_idx == 0)
 +                            scf_offset = 0;
 +                        else
 +                            scf_offset = 27;
 +                    } else {
 +                        scf_offset = 2 + scf_offset;
 +                    }
 +                }
 +                if (significant_coeff_flag_decode_0(s, c_idx, scf_offset) == 1) {
 +                    significant_coeff_flag_idx[nb_significant_coeff_flag] = 0;
 +                    nb_significant_coeff_flag++;
 +                }
 +            } else {
 +                significant_coeff_flag_idx[nb_significant_coeff_flag] = 0;
 +                nb_significant_coeff_flag++;
 +            }
 +        }
 +
 +        n_end = nb_significant_coeff_flag;
 +
 +
 +        if (n_end) {
 +            int first_nz_pos_in_cg;
 +            int last_nz_pos_in_cg;
 +            int c_rice_param = 0;
 +            int first_greater1_coeff_idx = -1;
 +            uint8_t coeff_abs_level_greater1_flag[8];
 +            uint16_t coeff_sign_flag;
 +            int sum_abs = 0;
 +            int sign_hidden;
 +            int sb_type;
 +
 +
 +            // initialize first elem of coeff_bas_level_greater1_flag
 +            int ctx_set = (i > 0 && c_idx == 0) ? 2 : 0;
 +
-                  s->sps->implicit_rdpcm_enabled_flag  &&  transform_skip_flag  &&
++            if (s->ps.sps->persistent_rice_adaptation_enabled_flag) {
 +                if (!transform_skip_flag && !lc->cu.cu_transquant_bypass_flag)
 +                    sb_type = 2 * (c_idx == 0 ? 1 : 0);
 +                else
 +                    sb_type = 2 * (c_idx == 0 ? 1 : 0) + 1;
 +                c_rice_param = lc->stat_coeff[sb_type] / 4;
 +            }
 +
 +            if (!(i == num_last_subset) && greater1_ctx == 0)
 +                ctx_set++;
 +            greater1_ctx = 1;
 +            last_nz_pos_in_cg = significant_coeff_flag_idx[0];
 +
 +            for (m = 0; m < (n_end > 8 ? 8 : n_end); m++) {
 +                int inc = (ctx_set << 2) + greater1_ctx;
 +                coeff_abs_level_greater1_flag[m] =
 +                    coeff_abs_level_greater1_flag_decode(s, c_idx, inc);
 +                if (coeff_abs_level_greater1_flag[m]) {
 +                    greater1_ctx = 0;
 +                    if (first_greater1_coeff_idx == -1)
 +                        first_greater1_coeff_idx = m;
 +                } else if (greater1_ctx > 0 && greater1_ctx < 3) {
 +                    greater1_ctx++;
 +                }
 +            }
 +            first_nz_pos_in_cg = significant_coeff_flag_idx[n_end - 1];
 +
 +            if (lc->cu.cu_transquant_bypass_flag ||
 +                (lc->cu.pred_mode ==  MODE_INTRA  &&
-             if (!s->pps->sign_data_hiding_flag || !sign_hidden ) {
++                 s->ps.sps->implicit_rdpcm_enabled_flag  &&  transform_skip_flag  &&
 +                 (pred_mode_intra == 10 || pred_mode_intra  ==  26 )) ||
 +                 explicit_rdpcm_flag)
 +                sign_hidden = 0;
 +            else
 +                sign_hidden = (last_nz_pos_in_cg - first_nz_pos_in_cg >= 4);
 +
 +            if (first_greater1_coeff_idx != -1) {
 +                coeff_abs_level_greater1_flag[first_greater1_coeff_idx] += coeff_abs_level_greater2_flag_decode(s, c_idx, ctx_set);
 +            }
-                             c_rice_param = s->sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4);
-                         if (s->sps->persistent_rice_adaptation_enabled_flag && !rice_init) {
++            if (!s->ps.pps->sign_data_hiding_flag || !sign_hidden ) {
 +                coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag) << (16 - nb_significant_coeff_flag);
 +            } else {
 +                coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag - 1) << (16 - (nb_significant_coeff_flag - 1));
 +            }
 +
 +            for (m = 0; m < n_end; m++) {
 +                n = significant_coeff_flag_idx[m];
 +                GET_COORD(offset, n);
 +                if (m < 8) {
 +                    trans_coeff_level = 1 + coeff_abs_level_greater1_flag[m];
 +                    if (trans_coeff_level == ((m == first_greater1_coeff_idx) ? 3 : 2)) {
 +                        int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param);
 +
 +                        trans_coeff_level += last_coeff_abs_level_remaining;
 +                        if (trans_coeff_level > (3 << c_rice_param))
-                         c_rice_param = s->sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4);
-                     if (s->sps->persistent_rice_adaptation_enabled_flag && !rice_init) {
++                            c_rice_param = s->ps.sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4);
++                        if (s->ps.sps->persistent_rice_adaptation_enabled_flag && !rice_init) {
 +                            int c_rice_p_init = lc->stat_coeff[sb_type] / 4;
 +                            if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init))
 +                                lc->stat_coeff[sb_type]++;
 +                            else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init))
 +                                if (lc->stat_coeff[sb_type] > 0)
 +                                    lc->stat_coeff[sb_type]--;
 +                            rice_init = 1;
 +                        }
 +                    }
 +                } else {
 +                    int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param);
 +
 +                    trans_coeff_level = 1 + last_coeff_abs_level_remaining;
 +                    if (trans_coeff_level > (3 << c_rice_param))
-                 if (s->pps->sign_data_hiding_flag && sign_hidden) {
++                        c_rice_param = s->ps.sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4);
++                    if (s->ps.sps->persistent_rice_adaptation_enabled_flag && !rice_init) {
 +                        int c_rice_p_init = lc->stat_coeff[sb_type] / 4;
 +                        if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init))
 +                            lc->stat_coeff[sb_type]++;
 +                        else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init))
 +                            if (lc->stat_coeff[sb_type] > 0)
 +                                lc->stat_coeff[sb_type]--;
 +                        rice_init = 1;
 +                    }
 +                }
-                     if (s->sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) {
++                if (s->ps.pps->sign_data_hiding_flag && sign_hidden) {
 +                    sum_abs += trans_coeff_level;
 +                    if (n == first_nz_pos_in_cg && (sum_abs&1))
 +                        trans_coeff_level = -trans_coeff_level;
 +                }
 +                if (coeff_sign_flag >> 15)
 +                    trans_coeff_level = -trans_coeff_level;
 +                coeff_sign_flag <<= 1;
 +                if(!lc->cu.cu_transquant_bypass_flag) {
-         if (explicit_rdpcm_flag || (s->sps->implicit_rdpcm_enabled_flag &&
++                    if (s->ps.sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) {
 +                        if(y_c || x_c || log2_trafo_size < 4) {
 +                            switch(log2_trafo_size) {
 +                                case 3: pos = (y_c << 3) + x_c; break;
 +                                case 4: pos = ((y_c >> 1) << 3) + (x_c >> 1); break;
 +                                case 5: pos = ((y_c >> 2) << 3) + (x_c >> 2); break;
 +                                default: pos = (y_c << 2) + x_c; break;
 +                            }
 +                            scale_m = scale_matrix[pos];
 +                        } else {
 +                            scale_m = dc_scale;
 +                        }
 +                    }
 +                    trans_coeff_level = (trans_coeff_level * (int64_t)scale * (int64_t)scale_m + add) >> shift;
 +                    if(trans_coeff_level < 0) {
 +                        if((~trans_coeff_level) & 0xFffffffffff8000)
 +                            trans_coeff_level = -32768;
 +                    } else {
 +                        if(trans_coeff_level & 0xffffffffffff8000)
 +                            trans_coeff_level = 32767;
 +                    }
 +                }
 +                coeffs[y_c * trafo_size + x_c] = trans_coeff_level;
 +            }
 +        }
 +    }
 +
 +    if (lc->cu.cu_transquant_bypass_flag) {
-             int mode = s->sps->implicit_rdpcm_enabled_flag ? (pred_mode_intra == 26) : explicit_rdpcm_dir_flag;
++        if (explicit_rdpcm_flag || (s->ps.sps->implicit_rdpcm_enabled_flag &&
 +                                    (pred_mode_intra == 10 || pred_mode_intra == 26))) {
-             int rot = s->sps->transform_skip_rotation_enabled_flag &&
++            int mode = s->ps.sps->implicit_rdpcm_enabled_flag ? (pred_mode_intra == 26) : explicit_rdpcm_dir_flag;
 +
 +            s->hevcdsp.transform_rdpcm(coeffs, log2_trafo_size, mode);
 +        }
 +    } else {
 +        if (transform_skip_flag) {
-             if (explicit_rdpcm_flag || (s->sps->implicit_rdpcm_enabled_flag &&
++            int rot = s->ps.sps->transform_skip_rotation_enabled_flag &&
 +                      log2_trafo_size == 2 &&
 +                      lc->cu.pred_mode == MODE_INTRA;
 +            if (rot) {
 +                for (i = 0; i < 8; i++)
 +                    FFSWAP(int16_t, coeffs[i], coeffs[16 - i - 1]);
 +            }
 +
 +            s->hevcdsp.transform_skip(coeffs, log2_trafo_size);
 +
++            if (explicit_rdpcm_flag || (s->ps.sps->implicit_rdpcm_enabled_flag &&
 +                                        lc->cu.pred_mode == MODE_INTRA &&
 +                                        (pred_mode_intra == 10 || pred_mode_intra == 26))) {
 +                int mode = explicit_rdpcm_flag ? explicit_rdpcm_dir_flag : (pred_mode_intra == 26);
 +
 +                s->hevcdsp.transform_rdpcm(coeffs, log2_trafo_size, mode);
 +            }
 +        } else if (lc->cu.pred_mode == MODE_INTRA && c_idx == 0 && log2_trafo_size == 2) {
 +            s->hevcdsp.idct_4x4_luma(coeffs);
 +        } else {
 +            int max_xy = FFMAX(last_significant_coeff_x, last_significant_coeff_y);
 +            if (max_xy == 0)
 +                s->hevcdsp.idct_dc[log2_trafo_size-2](coeffs);
 +            else {
 +                int col_limit = last_significant_coeff_x + last_significant_coeff_y + 4;
 +                if (max_xy < 4)
 +                    col_limit = FFMIN(4, col_limit);
 +                else if (max_xy < 8)
 +                    col_limit = FFMIN(8, col_limit);
 +                else if (max_xy < 12)
 +                    col_limit = FFMIN(24, col_limit);
 +                s->hevcdsp.idct[log2_trafo_size-2](coeffs, col_limit);
 +            }
 +        }
 +    }
 +    if (lc->tu.cross_pf) {
 +        int16_t *coeffs_y = (int16_t*)lc->edge_emu_buffer;
 +
 +        for (i = 0; i < (trafo_size * trafo_size); i++) {
 +            coeffs[i] = coeffs[i] + ((lc->tu.res_scale_val * coeffs_y[i]) >> 3);
 +        }
 +    }
 +    s->hevcdsp.transform_add[log2_trafo_size-2](dst, coeffs, stride);
 +}
 +
 +void ff_hevc_hls_mvd_coding(HEVCContext *s, int x0, int y0, int log2_cb_size)
 +{
 +    HEVCLocalContext *lc = s->HEVClc;
 +    int x = abs_mvd_greater0_flag_decode(s);
 +    int y = abs_mvd_greater0_flag_decode(s);
 +
 +    if (x)
 +        x += abs_mvd_greater1_flag_decode(s);
 +    if (y)
 +        y += abs_mvd_greater1_flag_decode(s);
 +
 +    switch (x) {
 +    case 2: lc->pu.mvd.x = mvd_decode(s);           break;
 +    case 1: lc->pu.mvd.x = mvd_sign_flag_decode(s); break;
 +    case 0: lc->pu.mvd.x = 0;                       break;
 +    }
 +
 +    switch (y) {
 +    case 2: lc->pu.mvd.y = mvd_decode(s);           break;
 +    case 1: lc->pu.mvd.y = mvd_sign_flag_decode(s); break;
 +    case 0: lc->pu.mvd.y = 0;                       break;
 +    }
 +}
 +
@@@ -56,37 -54,35 +56,37 @@@ static int chroma_tc(HEVCContext *s, in
  
      // slice qp offset is not used for deblocking
      if (c_idx == 1)
-         offset = s->pps->cb_qp_offset;
+         offset = s->ps.pps->cb_qp_offset;
      else
-         offset = s->pps->cr_qp_offset;
+         offset = s->ps.pps->cr_qp_offset;
  
      qp_i = av_clip(qp_y + offset, 0, 57);
-     if (s->sps->chroma_format_idc == 1) {
 -    if (qp_i < 30)
 -        qp = qp_i;
 -    else if (qp_i > 43)
 -        qp = qp_i - 6;
 -    else
 -        qp = qp_c[qp_i - 30];
++    if (s->ps.sps->chroma_format_idc == 1) {
 +        if (qp_i < 30)
 +            qp = qp_i;
 +        else if (qp_i > 43)
 +            qp = qp_i - 6;
 +        else
 +            qp = qp_c[qp_i - 30];
 +    } else {
 +        qp = av_clip(qp_i, 0, 51);
 +    }
  
      idxt = av_clip(qp + DEFAULT_INTRA_TC_OFFSET + tc_offset, 0, 53);
      return tctable[idxt];
  }
  
 -static int get_qPy_pred(HEVCContext *s, int xC, int yC,
 -                        int xBase, int yBase, int log2_cb_size)
 +static int get_qPy_pred(HEVCContext *s, int xBase, int yBase, int log2_cb_size)
  {
 -    HEVCLocalContext *lc     = &s->HEVClc;
 +    HEVCLocalContext *lc     = s->HEVClc;
-     int ctb_size_mask        = (1 << s->sps->log2_ctb_size) - 1;
-     int MinCuQpDeltaSizeMask = (1 << (s->sps->log2_ctb_size -
-                                       s->pps->diff_cu_qp_delta_depth)) - 1;
+     int ctb_size_mask        = (1 << s->ps.sps->log2_ctb_size) - 1;
+     int MinCuQpDeltaSizeMask = (1 << (s->ps.sps->log2_ctb_size -
+                                       s->ps.pps->diff_cu_qp_delta_depth)) - 1;
      int xQgBase              = xBase - (xBase & MinCuQpDeltaSizeMask);
      int yQgBase              = yBase - (yBase & MinCuQpDeltaSizeMask);
-     int min_cb_width         = s->sps->min_cb_width;
-     int x_cb                 = xQgBase >> s->sps->log2_min_cb_size;
-     int y_cb                 = yQgBase >> s->sps->log2_min_cb_size;
+     int min_cb_width         = s->ps.sps->min_cb_width;
 -    int min_cb_height        = s->ps.sps->min_cb_height;
+     int x_cb                 = xQgBase >> s->ps.sps->log2_min_cb_size;
+     int y_cb                 = yQgBase >> s->ps.sps->log2_min_cb_size;
      int availableA           = (xBase   & ctb_size_mask) &&
                                 (xQgBase & ctb_size_mask);
      int availableB           = (yBase   & ctb_size_mask) &&
      else
          qPy_b = s->qp_y_tab[x_cb + (y_cb - 1) * min_cb_width];
  
-     av_assert2(qPy_a >= -s->sps->qp_bd_offset && qPy_a < 52);
-     av_assert2(qPy_b >= -s->sps->qp_bd_offset && qPy_b < 52);
++    av_assert2(qPy_a >= -s->ps.sps->qp_bd_offset && qPy_a < 52);
++    av_assert2(qPy_b >= -s->ps.sps->qp_bd_offset && qPy_b < 52);
 +
      return (qPy_a + qPy_b + 1) >> 1;
  }
  
 -void ff_hevc_set_qPy(HEVCContext *s, int xC, int yC,
 -                     int xBase, int yBase, int log2_cb_size)
 +void ff_hevc_set_qPy(HEVCContext *s, int xBase, int yBase, int log2_cb_size)
  {
 -    int qp_y = get_qPy_pred(s, xC, yC, xBase, yBase, log2_cb_size);
 +    int qp_y = get_qPy_pred(s, xBase, yBase, log2_cb_size);
  
 -    if (s->HEVClc.tu.cu_qp_delta != 0) {
 +    if (s->HEVClc->tu.cu_qp_delta != 0) {
-         int off = s->sps->qp_bd_offset;
+         int off = s->ps.sps->qp_bd_offset;
 -        s->HEVClc.qp_y = FFUMOD(qp_y + s->HEVClc.tu.cu_qp_delta + 52 + 2 * off,
 -                                52 + off) - off;
 +        s->HEVClc->qp_y = FFUMOD(qp_y + s->HEVClc->tu.cu_qp_delta + 52 + 2 * off,
 +                                 52 + off) - off;
      } else
 -        s->HEVClc.qp_y = qp_y;
 +        s->HEVClc->qp_y = qp_y;
  }
  
  static int get_qPy(HEVCContext *s, int xC, int yC)
  {
-     int log2_min_cb_size  = s->sps->log2_min_cb_size;
+     int log2_min_cb_size  = s->ps.sps->log2_min_cb_size;
      int x                 = xC >> log2_min_cb_size;
      int y                 = yC >> log2_min_cb_size;
-     return s->qp_y_tab[x + y * s->sps->min_cb_width];
+     return s->qp_y_tab[x + y * s->ps.sps->min_cb_width];
  }
  
 -static void copy_CTB(uint8_t *dst, uint8_t *src,
 -                     int width, int height, int stride)
 +static void copy_CTB(uint8_t *dst, const uint8_t *src, int width, int height,
 +                     intptr_t stride_dst, intptr_t stride_src)
 +{
 +int i, j;
 +
 +    if (((intptr_t)dst | (intptr_t)src | stride_dst | stride_src) & 15) {
 +        for (i = 0; i < height; i++) {
 +            for (j = 0; j < width; j+=8)
 +                AV_COPY64U(dst+j, src+j);
 +            dst += stride_dst;
 +            src += stride_src;
 +        }
 +    } else {
 +        for (i = 0; i < height; i++) {
 +            for (j = 0; j < width; j+=16)
 +                AV_COPY128(dst+j, src+j);
 +            dst += stride_dst;
 +            src += stride_src;
 +        }
 +    }
 +}
 +
 +static void copy_pixel(uint8_t *dst, const uint8_t *src, int pixel_shift)
 +{
 +    if (pixel_shift)
 +        *(uint16_t *)dst = *(uint16_t *)src;
 +    else
 +        *dst = *src;
 +}
 +
 +static void copy_vert(uint8_t *dst, const uint8_t *src,
 +                      int pixel_shift, int height,
 +                      int stride_dst, int stride_src)
  {
      int i;
-     int sh = s->sps->pixel_shift;
-     int w = s->sps->width >> s->sps->hshift[c_idx];
-     int h = s->sps->height >> s->sps->vshift[c_idx];
 +    if (pixel_shift == 0) {
 +        for (i = 0; i < height; i++) {
 +            *dst = *src;
 +            dst += stride_dst;
 +            src += stride_src;
 +        }
 +    } else {
 +        for (i = 0; i < height; i++) {
 +            *(uint16_t *)dst = *(uint16_t *)src;
 +            dst += stride_dst;
 +            src += stride_src;
 +        }
 +    }
 +}
 +
 +static void copy_CTB_to_hv(HEVCContext *s, const uint8_t *src,
 +                           int stride_src, int x, int y, int width, int height,
 +                           int c_idx, int x_ctb, int y_ctb)
 +{
++    int sh = s->ps.sps->pixel_shift;
++    int w = s->ps.sps->width >> s->ps.sps->hshift[c_idx];
++    int h = s->ps.sps->height >> s->ps.sps->vshift[c_idx];
  
 -    for (i = 0; i < height; i++) {
 -        memcpy(dst, src, width);
 -        dst += stride;
 -        src += stride;
 +    /* copy horizontal edges */
 +    memcpy(s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb) * w + x) << sh),
 +        src, width << sh);
 +    memcpy(s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 1) * w + x) << sh),
 +        src + stride_src * (height - 1), width << sh);
 +
 +    /* copy vertical edges */
 +    copy_vert(s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb) * h + y) << sh), src, sh, height, 1 << sh, stride_src);
 +
 +    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);
 +}
 +
 +static void restore_tqb_pixels(HEVCContext *s,
 +                               uint8_t *src1, const uint8_t *dst1,
 +                               ptrdiff_t stride_src, ptrdiff_t stride_dst,
 +                               int x0, int y0, int width, int height, int c_idx)
 +{
-     if ( s->pps->transquant_bypass_enable_flag ||
-             (s->sps->pcm.loop_filter_disable_flag && s->sps->pcm_enabled_flag)) {
++    if ( s->ps.pps->transquant_bypass_enable_flag ||
++            (s->ps.sps->pcm.loop_filter_disable_flag && s->ps.sps->pcm_enabled_flag)) {
 +        int x, y;
-         int min_pu_size  = 1 << s->sps->log2_min_pu_size;
-         int hshift       = s->sps->hshift[c_idx];
-         int vshift       = s->sps->vshift[c_idx];
-         int x_min        = ((x0         ) >> s->sps->log2_min_pu_size);
-         int y_min        = ((y0         ) >> s->sps->log2_min_pu_size);
-         int x_max        = ((x0 + width ) >> s->sps->log2_min_pu_size);
-         int y_max        = ((y0 + height) >> s->sps->log2_min_pu_size);
-         int len          = (min_pu_size >> hshift) << s->sps->pixel_shift;
++        int min_pu_size  = 1 << s->ps.sps->log2_min_pu_size;
++        int hshift       = s->ps.sps->hshift[c_idx];
++        int vshift       = s->ps.sps->vshift[c_idx];
++        int x_min        = ((x0         ) >> s->ps.sps->log2_min_pu_size);
++        int y_min        = ((y0         ) >> s->ps.sps->log2_min_pu_size);
++        int x_max        = ((x0 + width ) >> s->ps.sps->log2_min_pu_size);
++        int y_max        = ((y0 + height) >> s->ps.sps->log2_min_pu_size);
++        int len          = (min_pu_size >> hshift) << s->ps.sps->pixel_shift;
 +        for (y = y_min; y < y_max; y++) {
 +            for (x = x_min; x < x_max; x++) {
-                 if (s->is_pcm[y * s->sps->min_pu_width + x]) {
++                if (s->is_pcm[y * s->ps.sps->min_pu_width + x]) {
 +                    int n;
-                     uint8_t *src = src1 + (((y << s->sps->log2_min_pu_size) - y0) >> vshift) * stride_src + ((((x << s->sps->log2_min_pu_size) - x0) >> hshift) << s->sps->pixel_shift);
-                     const uint8_t *dst = dst1 + (((y << s->sps->log2_min_pu_size) - y0) >> vshift) * stride_dst + ((((x << s->sps->log2_min_pu_size) - x0) >> hshift) << s->sps->pixel_shift);
++                    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);
++                    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);
 +                    for (n = 0; n < (min_pu_size >> vshift); n++) {
 +                        memcpy(src, dst, len);
 +                        src += stride_src;
 +                        dst += stride_dst;
 +                    }
 +                }
 +            }
 +        }
      }
  }
  
  
  static void sao_filter_CTB(HEVCContext *s, int x, int y)
  {
 -    //  TODO: This should be easily parallelizable
 -    //  TODO: skip CBs when (cu_transquant_bypass_flag || (pcm_loop_filter_disable_flag && pcm_flag))
 -    int c_idx = 0;
 -    int class = 1, class_index;
 +    static const uint8_t sao_tab[8] = { 0, 1, 2, 2, 3, 3, 4, 4 };
 +    HEVCLocalContext *lc = s->HEVClc;
 +    int c_idx;
      int edges[4];  // 0 left 1 top 2 right 3 bottom
-     int x_ctb                = x >> s->sps->log2_ctb_size;
-     int y_ctb                = y >> s->sps->log2_ctb_size;
-     int ctb_addr_rs          = y_ctb * s->sps->ctb_width + x_ctb;
-     int ctb_addr_ts          = s->pps->ctb_addr_rs_to_ts[ctb_addr_rs];
 -    SAOParams *sao[4];
 -    int classes[4];
 -    int x_shift = 0, y_shift = 0;
 -    int x_ctb = x >> s->ps.sps->log2_ctb_size;
 -    int y_ctb = y >> s->ps.sps->log2_ctb_size;
 -    int ctb_addr_rs = y_ctb * s->ps.sps->ctb_width + x_ctb;
 -    int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs];
 -
++    int x_ctb                = x >> s->ps.sps->log2_ctb_size;
++    int y_ctb                = y >> s->ps.sps->log2_ctb_size;
++    int ctb_addr_rs          = y_ctb * s->ps.sps->ctb_width + x_ctb;
++    int ctb_addr_ts          = s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs];
 +    SAOParams *sao           = &CTB(s->sao, x_ctb, y_ctb);
      // flags indicating unfilterable edges
 -    uint8_t vert_edge[]  = { 0, 0, 0, 0 };
 -    uint8_t horiz_edge[] = { 0, 0, 0, 0 };
 -    uint8_t diag_edge[]  = { 0, 0, 0, 0 };
 -    uint8_t lfase[3]; // current, above, left
 -    uint8_t no_tile_filter = s->ps.pps->tiles_enabled_flag &&
 -                             !s->ps.pps->loop_filter_across_tiles_enabled_flag;
 -    uint8_t left_tile_edge = 0, up_tile_edge = 0;
 -
 -    sao[0]     = &CTB(s->sao, x_ctb, y_ctb);
 +    uint8_t vert_edge[]      = { 0, 0 };
 +    uint8_t horiz_edge[]     = { 0, 0 };
 +    uint8_t diag_edge[]      = { 0, 0, 0, 0 };
 +    uint8_t lfase            = CTB(s->filter_slice_edges, x_ctb, y_ctb);
-     uint8_t no_tile_filter   = s->pps->tiles_enabled_flag &&
-                                !s->pps->loop_filter_across_tiles_enabled_flag;
++    uint8_t no_tile_filter   = s->ps.pps->tiles_enabled_flag &&
++                               !s->ps.pps->loop_filter_across_tiles_enabled_flag;
 +    uint8_t restore          = no_tile_filter || !lfase;
 +    uint8_t left_tile_edge   = 0;
 +    uint8_t right_tile_edge  = 0;
 +    uint8_t up_tile_edge     = 0;
 +    uint8_t bottom_tile_edge = 0;
 +
      edges[0]   = x_ctb == 0;
      edges[1]   = y_ctb == 0;
-     edges[2]   = x_ctb == s->sps->ctb_width  - 1;
-     edges[3]   = y_ctb == s->sps->ctb_height - 1;
+     edges[2]   = x_ctb == s->ps.sps->ctb_width  - 1;
+     edges[3]   = y_ctb == s->ps.sps->ctb_height - 1;
 -    lfase[0]   = CTB(s->filter_slice_edges, x_ctb, y_ctb);
 -    classes[0] = 0;
 -
 -    if (!edges[0]) {
 -        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]];
 -        sao[class] = &CTB(s->sao, x_ctb - 1, y_ctb);
 -        vert_edge[0] = (!lfase[0] && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb)) || left_tile_edge;
 -        vert_edge[2] = vert_edge[0];
 -        lfase[2]     = CTB(s->filter_slice_edges, x_ctb - 1, y_ctb);
 -        classes[class] = 2;
 -        class++;
 -        x_shift = 8;
 -    }
 -
 -    if (!edges[1]) {
 -        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]];
 -        sao[class] = &CTB(s->sao, x_ctb, y_ctb - 1);
 -        horiz_edge[0] = (!lfase[0] && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) || up_tile_edge;
 -        horiz_edge[1] = horiz_edge[0];
 -        lfase[1] = CTB(s->filter_slice_edges, x_ctb, y_ctb - 1);
 -        classes[class] = 1;
 -        class++;
 -        y_shift = 4;
  
 +    if (restore) {
          if (!edges[0]) {
-             left_tile_edge  = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs-1]];
 -            classes[class] = 3;
 -            sao[class] = &CTB(s->sao, x_ctb - 1, y_ctb - 1);
 -            class++;
 -
 -            // Tile check here is done current CTB row/col, not above/left like you'd expect,
 -            //but that is because the tile boundary always extends through the whole pic
 -            vert_edge[1] = (!lfase[1] && CTB(s->tab_slice_address, x_ctb, y_ctb - 1) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb - 1)) || left_tile_edge;
 -            vert_edge[3] = vert_edge[1];
 -            horiz_edge[2] = (!lfase[2] && CTB(s->tab_slice_address, x_ctb - 1, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb - 1)) || up_tile_edge;
 -            horiz_edge[3] = horiz_edge[2];
 -            diag_edge[0] = (!lfase[0] && 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;
 -            diag_edge[3] = diag_edge[0];
 -
 -            // Does left CTB comes after above CTB?
 -            if (CTB(s->tab_slice_address, x_ctb - 1, y_ctb) >
 -                CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) {
 -                diag_edge[2] = !lfase[2] || left_tile_edge || up_tile_edge;
 -                diag_edge[1] = diag_edge[2];
 -            } else if (CTB(s->tab_slice_address, x_ctb - 1, y_ctb) <
 -                       CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) {
 -                diag_edge[1] = !lfase[1] || left_tile_edge || up_tile_edge;
 -                diag_edge[2] = diag_edge[1];
 -            } else {
 -                // Same slice, only consider tiles
 -                diag_edge[2] = left_tile_edge || up_tile_edge;
 -                diag_edge[1] = diag_edge[2];
 -            }
++            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]];
 +            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;
 +        }
 +        if (!edges[2]) {
-             right_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs+1]];
++            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]];
 +            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;
 +        }
 +        if (!edges[1]) {
-             up_tile_edge     = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs - s->sps->ctb_width]];
++            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]];
 +            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;
 +        }
 +        if (!edges[3]) {
-             bottom_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs + s->sps->ctb_width]];
++            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]];
 +            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;
 +        }
 +        if (!edges[0] && !edges[1]) {
 +            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;
 +        }
 +        if (!edges[1] && !edges[2]) {
 +            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;
 +        }
 +        if (!edges[2] && !edges[3]) {
 +            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;
 +        }
 +        if (!edges[0] && !edges[3]) {
 +            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;
          }
      }
  
-     for (c_idx = 0; c_idx < (s->sps->chroma_format_idc ? 3 : 1); c_idx++) {
-         int x0       = x >> s->sps->hshift[c_idx];
-         int y0       = y >> s->sps->vshift[c_idx];
 -    for (c_idx = 0; c_idx < 3; c_idx++) {
 -        int chroma = c_idx ? 1 : 0;
 -        int x0 = x >> chroma;
 -        int y0 = y >> chroma;
 -        int stride = s->frame->linesize[c_idx];
 -        int ctb_size = (1 << (s->ps.sps->log2_ctb_size)) >> s->ps.sps->hshift[c_idx];
 -        int width = FFMIN(ctb_size,
 -                          (s->ps.sps->width >> s->ps.sps->hshift[c_idx]) - x0);
 -        int height = FFMIN(ctb_size,
 -                           (s->ps.sps->height >> s->ps.sps->vshift[c_idx]) - y0);
 -
 -        uint8_t *src = &s->frame->data[c_idx][y0 * stride + (x0 << s->ps.sps->pixel_shift)];
 -        uint8_t *dst = &s->sao_frame->data[c_idx][y0 * stride + (x0 << s->ps.sps->pixel_shift)];
 -        int offset = (y_shift >> chroma) * stride + ((x_shift >> chroma) << s->ps.sps->pixel_shift);
 -
 -        copy_CTB(dst - offset, src - offset,
 -                 (edges[2] ? width  + (x_shift >> chroma) : width)  << s->ps.sps->pixel_shift,
 -                 (edges[3] ? height + (y_shift >> chroma) : height), stride);
 -
 -        for (class_index = 0; class_index < class; class_index++) {
 -
 -            switch (sao[class_index]->type_idx[c_idx]) {
 -            case SAO_BAND:
 -                s->hevcdsp.sao_band_filter[classes[class_index]](dst, src,
 -                                                                 stride,
 -                                                                 sao[class_index],
 -                                                                 edges, width,
 -                                                                 height, c_idx);
 -                break;
 -            case SAO_EDGE:
 -                s->hevcdsp.sao_edge_filter[classes[class_index]](dst, src,
 -                                                                 stride,
 -                                                                 sao[class_index],
 -                                                                 edges, width,
 -                                                                 height, c_idx,
 -                                                                 vert_edge[classes[class_index]],
 -                                                                 horiz_edge[classes[class_index]],
 -                                                                 diag_edge[classes[class_index]]);
 -                break;
++    for (c_idx = 0; c_idx < (s->ps.sps->chroma_format_idc ? 3 : 1); c_idx++) {
++        int x0       = x >> s->ps.sps->hshift[c_idx];
++        int y0       = y >> s->ps.sps->vshift[c_idx];
 +        int stride_src = s->frame->linesize[c_idx];
-         int ctb_size_h = (1 << (s->sps->log2_ctb_size)) >> s->sps->hshift[c_idx];
-         int ctb_size_v = (1 << (s->sps->log2_ctb_size)) >> s->sps->vshift[c_idx];
-         int width    = FFMIN(ctb_size_h, (s->sps->width  >> s->sps->hshift[c_idx]) - x0);
-         int height   = FFMIN(ctb_size_v, (s->sps->height >> s->sps->vshift[c_idx]) - y0);
++        int ctb_size_h = (1 << (s->ps.sps->log2_ctb_size)) >> s->ps.sps->hshift[c_idx];
++        int ctb_size_v = (1 << (s->ps.sps->log2_ctb_size)) >> s->ps.sps->vshift[c_idx];
++        int width    = FFMIN(ctb_size_h, (s->ps.sps->width  >> s->ps.sps->hshift[c_idx]) - x0);
++        int height   = FFMIN(ctb_size_v, (s->ps.sps->height >> s->ps.sps->vshift[c_idx]) - y0);
 +        int tab      = sao_tab[(FFALIGN(width, 8) >> 3) - 1];
-         uint8_t *src = &s->frame->data[c_idx][y0 * stride_src + (x0 << s->sps->pixel_shift)];
++        uint8_t *src = &s->frame->data[c_idx][y0 * stride_src + (x0 << s->ps.sps->pixel_shift)];
 +        int stride_dst;
 +        uint8_t *dst;
 +
 +        switch (sao->type_idx[c_idx]) {
 +        case SAO_BAND:
 +            copy_CTB_to_hv(s, src, stride_src, x0, y0, width, height, c_idx,
 +                           x_ctb, y_ctb);
-             if (s->pps->transquant_bypass_enable_flag ||
-                 (s->sps->pcm.loop_filter_disable_flag && s->sps->pcm_enabled_flag)) {
++            if (s->ps.pps->transquant_bypass_enable_flag ||
++                (s->ps.sps->pcm.loop_filter_disable_flag && s->ps.sps->pcm_enabled_flag)) {
 +            dst = lc->edge_emu_buffer;
 +            stride_dst = 2*MAX_PB_SIZE;
-             copy_CTB(dst, src, width << s->sps->pixel_shift, height, stride_dst, stride_src);
++            copy_CTB(dst, src, width << s->ps.sps->pixel_shift, height, stride_dst, stride_src);
 +            s->hevcdsp.sao_band_filter[tab](src, dst, stride_src, stride_dst,
 +                                            sao->offset_val[c_idx], sao->band_position[c_idx],
 +                                            width, height);
 +            restore_tqb_pixels(s, src, dst, stride_src, stride_dst,
 +                               x, y, width, height, c_idx);
 +            } else {
 +            s->hevcdsp.sao_band_filter[tab](src, src, stride_src, stride_src,
 +                                            sao->offset_val[c_idx], sao->band_position[c_idx],
 +                                            width, height);
 +            }
 +            sao->type_idx[c_idx] = SAO_APPLIED;
 +            break;
 +        case SAO_EDGE:
 +        {
-             int w = s->sps->width >> s->sps->hshift[c_idx];
-             int h = s->sps->height >> s->sps->vshift[c_idx];
++            int w = s->ps.sps->width >> s->ps.sps->hshift[c_idx];
++            int h = s->ps.sps->height >> s->ps.sps->vshift[c_idx];
 +            int left_edge = edges[0];
 +            int top_edge = edges[1];
 +            int right_edge = edges[2];
 +            int bottom_edge = edges[3];
-             int sh = s->sps->pixel_shift;
++            int sh = s->ps.sps->pixel_shift;
 +            int left_pixels, right_pixels;
 +
 +            stride_dst = 2*MAX_PB_SIZE + FF_INPUT_BUFFER_PADDING_SIZE;
 +            dst = lc->edge_emu_buffer + stride_dst + FF_INPUT_BUFFER_PADDING_SIZE;
 +
 +            if (!top_edge) {
 +                int left = 1 - left_edge;
 +                int right = 1 - right_edge;
 +                const uint8_t *src1[2];
 +                uint8_t *dst1;
 +                int src_idx, pos;
 +
 +                dst1 = dst - stride_dst - (left << sh);
 +                src1[0] = src - stride_src - (left << sh);
 +                src1[1] = s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb - 1) * w + x0 - left) << sh);
 +                pos = 0;
 +                if (left) {
 +                    src_idx = (CTB(s->sao, x_ctb-1, y_ctb-1).type_idx[c_idx] ==
 +                               SAO_APPLIED);
 +                    copy_pixel(dst1, src1[src_idx], sh);
 +                    pos += (1 << sh);
 +                }
 +                src_idx = (CTB(s->sao, x_ctb, y_ctb-1).type_idx[c_idx] ==
 +                           SAO_APPLIED);
 +                memcpy(dst1 + pos, src1[src_idx] + pos, width << sh);
 +                if (right) {
 +                    pos += width << sh;
 +                    src_idx = (CTB(s->sao, x_ctb+1, y_ctb-1).type_idx[c_idx] ==
 +                               SAO_APPLIED);
 +                    copy_pixel(dst1 + pos, src1[src_idx] + pos, sh);
 +                }
              }
 +            if (!bottom_edge) {
 +                int left = 1 - left_edge;
 +                int right = 1 - right_edge;
 +                const uint8_t *src1[2];
 +                uint8_t *dst1;
 +                int src_idx, pos;
 +
 +                dst1 = dst + height * stride_dst - (left << sh);
 +                src1[0] = src + height * stride_src - (left << sh);
 +                src1[1] = s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 2) * w + x0 - left) << sh);
 +                pos = 0;
 +                if (left) {
 +                    src_idx = (CTB(s->sao, x_ctb-1, y_ctb+1).type_idx[c_idx] ==
 +                               SAO_APPLIED);
 +                    copy_pixel(dst1, src1[src_idx], sh);
 +                    pos += (1 << sh);
 +                }
 +                src_idx = (CTB(s->sao, x_ctb, y_ctb+1).type_idx[c_idx] ==
 +                           SAO_APPLIED);
 +                memcpy(dst1 + pos, src1[src_idx] + pos, width << sh);
 +                if (right) {
 +                    pos += width << sh;
 +                    src_idx = (CTB(s->sao, x_ctb+1, y_ctb+1).type_idx[c_idx] ==
 +                               SAO_APPLIED);
 +                    copy_pixel(dst1 + pos, src1[src_idx] + pos, sh);
 +                }
 +            }
 +            left_pixels = 0;
 +            if (!left_edge) {
 +                if (CTB(s->sao, x_ctb-1, y_ctb).type_idx[c_idx] == SAO_APPLIED) {
 +                    copy_vert(dst - (1 << sh),
 +                              s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb - 1) * h + y0) << sh),
 +                              sh, height, stride_dst, 1 << sh);
 +                } else {
 +                    left_pixels = 1;
 +                }
 +            }
 +            right_pixels = 0;
 +            if (!right_edge) {
 +                if (CTB(s->sao, x_ctb+1, y_ctb).type_idx[c_idx] == SAO_APPLIED) {
 +                    copy_vert(dst + (width << sh),
 +                              s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 2) * h + y0) << sh),
 +                              sh, height, stride_dst, 1 << sh);
 +                } else {
 +                    right_pixels = 1;
 +                }
 +            }
 +
 +            copy_CTB(dst - (left_pixels << sh),
 +                     src - (left_pixels << sh),
 +                     (width + left_pixels + right_pixels) << sh,
 +                     height, stride_dst, stride_src);
 +
 +            copy_CTB_to_hv(s, src, stride_src, x0, y0, width, height, c_idx,
 +                           x_ctb, y_ctb);
 +            s->hevcdsp.sao_edge_filter[tab](src, dst, stride_src, sao->offset_val[c_idx],
 +                                            sao->eo_class[c_idx], width, height);
 +            s->hevcdsp.sao_edge_restore[restore](src, dst,
 +                                                stride_src, stride_dst,
 +                                                sao,
 +                                                edges, width,
 +                                                height, c_idx,
 +                                                vert_edge,
 +                                                horiz_edge,
 +                                                diag_edge);
 +            restore_tqb_pixels(s, src, dst, stride_src, stride_dst,
 +                               x, y, width, height, c_idx);
 +            sao->type_idx[c_idx] = SAO_APPLIED;
 +            break;
 +        }
          }
      }
  }
@@@ -483,18 -343,16 +483,18 @@@ static void deblocking_filter_CTB(HEVCC
      uint8_t no_p[2] = { 0 };
      uint8_t no_q[2] = { 0 };
  
-     int log2_ctb_size = s->sps->log2_ctb_size;
+     int log2_ctb_size = s->ps.sps->log2_ctb_size;
 +    int x_end, x_end2, y_end;
      int ctb_size        = 1 << log2_ctb_size;
      int ctb             = (x0 >> log2_ctb_size) +
-                           (y0 >> log2_ctb_size) * s->sps->ctb_width;
+                           (y0 >> log2_ctb_size) * s->ps.sps->ctb_width;
      int cur_tc_offset   = s->deblock[ctb].tc_offset;
      int cur_beta_offset = s->deblock[ctb].beta_offset;
 -    int tc_offset, left_tc_offset, beta_offset, left_beta_offset;
 +    int left_tc_offset, left_beta_offset;
 +    int tc_offset, beta_offset;
-     int pcmf = (s->sps->pcm_enabled_flag &&
-                 s->sps->pcm.loop_filter_disable_flag) ||
-                s->pps->transquant_bypass_enable_flag;
+     int pcmf = (s->ps.sps->pcm_enabled_flag &&
+                 s->ps.sps->pcm.loop_filter_disable_flag) ||
+                s->ps.pps->transquant_bypass_enable_flag;
  
      if (x0) {
          left_tc_offset   = s->deblock[ctb - 1].tc_offset;
      tc_offset   = cur_tc_offset;
      beta_offset = cur_beta_offset;
  
 -    // vertical filtering luma
 +    x_end2 = x_end;
-     if (x_end2 != s->sps->width)
++    if (x_end2 != s->ps.sps->width)
 +        x_end2 -= 8;
      for (y = y0; y < y_end; y += 8) {
 +        // vertical filtering luma
          for (x = x0 ? x0 : 8; x < x_end; x += 8) {
 -            const int bs0 = s->vertical_bs[(x >> 3) + (y       >> 2) * s->bs_width];
 -            const int bs1 = s->vertical_bs[(x >> 3) + ((y + 4) >> 2) * s->bs_width];
 +            const int bs0 = s->vertical_bs[(x +  y      * s->bs_width) >> 2];
 +            const int bs1 = s->vertical_bs[(x + (y + 4) * s->bs_width) >> 2];
              if (bs0 || bs1) {
                  const int qp = (get_qPy(s, x - 1, y)     + get_qPy(s, x, y)     + 1) >> 1;
  
          }
      }
  
-     if (s->sps->chroma_format_idc) {
 -    // horizontal filtering chroma
 -    for (chroma = 1; chroma <= 2; chroma++) {
 -        for (y = y0 ? y0 : 16; y < y_end; y += 16) {
 -            for (x = x0 - 8; x < x_end; x += 16) {
 -                int bs0, bs1;
 -                // to make sure no memory access over boundary when x = -8
 -                // TODO: simplify with row based deblocking
 -                if (x < 0) {
 -                    bs0 = 0;
 -                    bs1 = s->horizontal_bs[(x + 8 + y * s->bs_width) >> 2];
 -                } else if (x >= x_end - 8) {
 -                    bs0 = s->horizontal_bs[(x +     y * s->bs_width) >> 2];
 -                    bs1 = 0;
 -                } else {
 -                    bs0 = s->horizontal_bs[(x + y     * s->bs_width) >> 2];
 -                    bs1 = s->horizontal_bs[(x + 8 + y * s->bs_width) >> 2];
++    if (s->ps.sps->chroma_format_idc) {
 +        for (chroma = 1; chroma <= 2; chroma++) {
-             int h = 1 << s->sps->hshift[chroma];
-             int v = 1 << s->sps->vshift[chroma];
++            int h = 1 << s->ps.sps->hshift[chroma];
++            int v = 1 << s->ps.sps->vshift[chroma];
 +
 +            // vertical filtering chroma
 +            for (y = y0; y < y_end; y += (8 * v)) {
 +                for (x = x0 ? x0 : 8 * h; x < x_end; x += (8 * h)) {
 +                    const int bs0 = s->vertical_bs[(x +  y            * s->bs_width) >> 2];
 +                    const int bs1 = s->vertical_bs[(x + (y + (4 * v)) * s->bs_width) >> 2];
 +
 +                    if ((bs0 == 2) || (bs1 == 2)) {
 +                        const int qp0 = (get_qPy(s, x - 1, y)           + get_qPy(s, x, y)           + 1) >> 1;
 +                        const int qp1 = (get_qPy(s, x - 1, y + (4 * v)) + get_qPy(s, x, y + (4 * v)) + 1) >> 1;
 +
 +                        c_tc[0] = (bs0 == 2) ? chroma_tc(s, qp0, chroma, tc_offset) : 0;
 +                        c_tc[1] = (bs1 == 2) ? chroma_tc(s, qp1, chroma, tc_offset) : 0;
-                         src       = &s->frame->data[chroma][(y >> s->sps->vshift[chroma]) * s->frame->linesize[chroma] + ((x >> s->sps->hshift[chroma]) << s->sps->pixel_shift)];
++                        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)];
 +                        if (pcmf) {
 +                            no_p[0] = get_pcm(s, x - 1, y);
 +                            no_p[1] = get_pcm(s, x - 1, y + (4 * v));
 +                            no_q[0] = get_pcm(s, x, y);
 +                            no_q[1] = get_pcm(s, x, y + (4 * v));
 +                            s->hevcdsp.hevc_v_loop_filter_chroma_c(src,
 +                                                                   s->frame->linesize[chroma],
 +                                                                   c_tc, no_p, no_q);
 +                        } else
 +                            s->hevcdsp.hevc_v_loop_filter_chroma(src,
 +                                                                 s->frame->linesize[chroma],
 +                                                                 c_tc, no_p, no_q);
 +                    }
                  }
  
 -                if ((bs0 == 2) || (bs1 == 2)) {
 -                    const int qp0 = bs0 == 2 ? (get_qPy(s, x,     y - 1) + get_qPy(s, x,     y) + 1) >> 1 : 0;
 -                    const int qp1 = bs1 == 2 ? (get_qPy(s, x + 8, y - 1) + get_qPy(s, x + 8, y) + 1) >> 1 : 0;
 -
 -                    tc_offset = x >= x0 ? cur_tc_offset : left_tc_offset;
 -                    c_tc[0]   = bs0 == 2 ? chroma_tc(s, qp0, chroma, tc_offset)     : 0;
 -                    c_tc[1]   = bs1 == 2 ? chroma_tc(s, qp1, chroma, cur_tc_offset) : 0;
 -                    src       = &s->frame->data[chroma][y / 2 * s->frame->linesize[chroma] + ((x / 2) << s->ps.sps->pixel_shift)];
 -                    if (pcmf) {
 -                        no_p[0] = get_pcm(s, x, y - 1);
 -                        no_p[1] = get_pcm(s, x + 8, y - 1);
 -                        no_q[0] = get_pcm(s, x, y);
 -                        no_q[1] = get_pcm(s, x + 8, y);
 -                        s->hevcdsp.hevc_h_loop_filter_chroma_c(src,
 -                                                               s->frame->linesize[chroma],
 -                                                               c_tc, no_p, no_q);
 -                    } else
 -                        s->hevcdsp.hevc_h_loop_filter_chroma(src,
 -                                                             s->frame->linesize[chroma],
 -                                                             c_tc, no_p, no_q);
 +                if(!y)
 +                    continue;
 +
 +                // horizontal filtering chroma
 +                tc_offset = x0 ? left_tc_offset : cur_tc_offset;
 +                x_end2 = x_end;
-                 if (x_end != s->sps->width)
++                if (x_end != s->ps.sps->width)
 +                    x_end2 = x_end - 8 * h;
 +                for (x = x0 ? x0 - 8 * h : 0; x < x_end2; x += (8 * h)) {
 +                    const int bs0 = s->horizontal_bs[( x          + y * s->bs_width) >> 2];
 +                    const int bs1 = s->horizontal_bs[((x + 4 * h) + y * s->bs_width) >> 2];
 +                    if ((bs0 == 2) || (bs1 == 2)) {
 +                        const int qp0 = bs0 == 2 ? (get_qPy(s, x,           y - 1) + get_qPy(s, x,           y) + 1) >> 1 : 0;
 +                        const int qp1 = bs1 == 2 ? (get_qPy(s, x + (4 * h), y - 1) + get_qPy(s, x + (4 * h), y) + 1) >> 1 : 0;
 +
 +                        c_tc[0]   = bs0 == 2 ? chroma_tc(s, qp0, chroma, tc_offset)     : 0;
 +                        c_tc[1]   = bs1 == 2 ? chroma_tc(s, qp1, chroma, cur_tc_offset) : 0;
-                         src       = &s->frame->data[chroma][(y >> s->sps->vshift[1]) * s->frame->linesize[chroma] + ((x >> s->sps->hshift[1]) << s->sps->pixel_shift)];
++                        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)];
 +                        if (pcmf) {
 +                            no_p[0] = get_pcm(s, x,           y - 1);
 +                            no_p[1] = get_pcm(s, x + (4 * h), y - 1);
 +                            no_q[0] = get_pcm(s, x,           y);
 +                            no_q[1] = get_pcm(s, x + (4 * h), y);
 +                            s->hevcdsp.hevc_h_loop_filter_chroma_c(src,
 +                                                                   s->frame->linesize[chroma],
 +                                                                   c_tc, no_p, no_q);
 +                        } else
 +                            s->hevcdsp.hevc_h_loop_filter_chroma(src,
 +                                                                 s->frame->linesize[chroma],
 +                                                                 c_tc, no_p, no_q);
 +                    }
                  }
              }
          }
@@@ -715,14 -586,14 +715,14 @@@ static int boundary_strength(HEVCContex
  void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0,
                                             int log2_trafo_size)
  {
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
      MvField *tab_mvf     = s->ref->tab_mvf;
-     int log2_min_pu_size = s->sps->log2_min_pu_size;
-     int log2_min_tu_size = s->sps->log2_min_tb_size;
-     int min_pu_width     = s->sps->min_pu_width;
-     int min_tu_width     = s->sps->min_tb_width;
+     int log2_min_pu_size = s->ps.sps->log2_min_pu_size;
+     int log2_min_tu_size = s->ps.sps->log2_min_tb_size;
+     int min_pu_width     = s->ps.sps->min_pu_width;
+     int min_tu_width     = s->ps.sps->min_tb_width;
      int is_intra = tab_mvf[(y0 >> log2_min_pu_size) * min_pu_width +
 -                           (x0 >> log2_min_pu_size)].is_intra;
 +                           (x0 >> log2_min_pu_size)].pred_flag == PF_INTRA;
      int boundary_upper, boundary_left;
      int i, j, bs;
  
  #undef CB
  #undef CR
  
 -void ff_hevc_hls_filter(HEVCContext *s, int x, int y)
 +void ff_hevc_hls_filter(HEVCContext *s, int x, int y, int ctb_size)
  {
-     int x_end = x >= s->sps->width  - ctb_size;
++    int x_end = x >= s->ps.sps->width  - ctb_size;
      deblocking_filter_CTB(s, x, y);
-     if (s->sps->sao_enabled) {
-         int y_end = y >= s->sps->height - ctb_size;
 -    if (s->ps.sps->sao_enabled)
 -        sao_filter_CTB(s, x, y);
++    if (s->ps.sps->sao_enabled) {
++        int y_end = y >= s->ps.sps->height - ctb_size;
 +        if (y && x)
 +            sao_filter_CTB(s, x - ctb_size, y - ctb_size);
 +        if (x && y_end)
 +            sao_filter_CTB(s, x - ctb_size, y);
 +        if (y && x_end) {
 +            sao_filter_CTB(s, x, y - ctb_size);
 +            if (s->threads_type & FF_THREAD_FRAME )
 +                ff_thread_report_progress(&s->ref->tf, y, 0);
 +        }
 +        if (x_end && y_end) {
 +            sao_filter_CTB(s, x , y);
 +            if (s->threads_type & FF_THREAD_FRAME )
 +                ff_thread_report_progress(&s->ref->tf, y + ctb_size, 0);
 +        }
 +    } else if (s->threads_type & FF_THREAD_FRAME && x_end)
 +        ff_thread_report_progress(&s->ref->tf, y + ctb_size - 4, 0);
  }
  
  void ff_hevc_hls_filters(HEVCContext *s, int x_ctb, int y_ctb, int ctb_size)
  {
-     int x_end = x_ctb >= s->sps->width  - ctb_size;
-     int y_end = y_ctb >= s->sps->height - ctb_size;
++    int x_end = x_ctb >= s->ps.sps->width  - ctb_size;
++    int y_end = y_ctb >= s->ps.sps->height - ctb_size;
      if (y_ctb && x_ctb)
 -        ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb - ctb_size);
 -    if (y_ctb && x_ctb >= s->ps.sps->width - ctb_size) {
 -        ff_hevc_hls_filter(s, x_ctb, y_ctb - ctb_size);
 -        ff_thread_report_progress(&s->ref->tf, y_ctb - ctb_size, 0);
 -    }
 -    if (x_ctb && y_ctb >= s->ps.sps->height - ctb_size)
 -        ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb);
 +        ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb - ctb_size, ctb_size);
 +    if (y_ctb && x_end)
 +        ff_hevc_hls_filter(s, x_ctb, y_ctb - ctb_size, ctb_size);
 +    if (x_ctb && y_end)
 +        ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb, ctb_size);
  }
@@@ -41,18 -41,19 +41,18 @@@ static const uint8_t l0_l1_cand_idx[12]
  void ff_hevc_set_neighbour_available(HEVCContext *s, int x0, int y0,
                                       int nPbW, int nPbH)
  {
 -    HEVCLocalContext *lc = &s->HEVClc;
 -    int x0b = x0 & ((1 << s->ps.sps->log2_ctb_size) - 1);
 -    int y0b = y0 & ((1 << s->ps.sps->log2_ctb_size) - 1);
 +    HEVCLocalContext *lc = s->HEVClc;
-     int x0b = av_mod_uintp2(x0, s->sps->log2_ctb_size);
-     int y0b = av_mod_uintp2(y0, s->sps->log2_ctb_size);
++    int x0b = av_mod_uintp2(x0, s->ps.sps->log2_ctb_size);
++    int y0b = av_mod_uintp2(y0, s->ps.sps->log2_ctb_size);
  
      lc->na.cand_up       = (lc->ctb_up_flag   || y0b);
      lc->na.cand_left     = (lc->ctb_left_flag || x0b);
      lc->na.cand_up_left  = (!x0b && !y0b) ? lc->ctb_up_left_flag : lc->na.cand_left && lc->na.cand_up;
      lc->na.cand_up_right_sap =
-             ((x0b + nPbW) == (1 << s->sps->log2_ctb_size)) ?
+             ((x0b + nPbW) == (1 << s->ps.sps->log2_ctb_size)) ?
                      lc->ctb_up_right_flag && !y0b : lc->na.cand_up;
      lc->na.cand_up_right =
 -            ((x0b + nPbW) == (1 << s->ps.sps->log2_ctb_size) ?
 -                    lc->ctb_up_right_flag && !y0b : lc->na.cand_up )
 +            lc->na.cand_up_right_sap
                       && (x0 + nPbW) < lc->end_of_tiles_x;
      lc->na.cand_bottom_left = ((y0 + nPbH) >= lc->end_of_tiles_y) ? 0 : lc->na.cand_left;
  }
@@@ -64,27 -65,54 +64,27 @@@ static av_always_inline int z_scan_bloc
                                int xN, int yN)
  {
  #define MIN_TB_ADDR_ZS(x, y)                                            \
-     s->pps->min_tb_addr_zs[(y) * (s->sps->tb_mask+2) + (x)]
 -    s->ps.pps->min_tb_addr_zs[(y) * s->ps.sps->min_tb_width + (x)]
 -    int Curr = MIN_TB_ADDR_ZS(xCurr >> s->ps.sps->log2_min_tb_size,
 -                              yCurr >> s->ps.sps->log2_min_tb_size);
 -    int N;
 -
 -    if (xN < 0 || yN < 0 ||
 -        xN >= s->ps.sps->width ||
 -        yN >= s->ps.sps->height)
 -        return 0;
 -
 -    N = MIN_TB_ADDR_ZS(xN >> s->ps.sps->log2_min_tb_size,
 -                       yN >> s->ps.sps->log2_min_tb_size);
 -
 -    return N <= Curr;
 -}
 -
 -static int same_prediction_block(HEVCLocalContext *lc, int log2_cb_size,
 -                                 int x0, int y0, int nPbW, int nPbH,
 -                                 int xA1, int yA1, int partIdx)
 -{
 -    return !(nPbW << 1 == 1 << log2_cb_size &&
 -             nPbH << 1 == 1 << log2_cb_size && partIdx == 1 &&
 -             lc->cu.x + nPbW > xA1 &&
 -             lc->cu.y + nPbH <= yA1);
 -}
++    s->ps.pps->min_tb_addr_zs[(y) * (s->ps.sps->tb_mask+2) + (x)]
  
-     int xCurr_ctb = xCurr >> s->sps->log2_ctb_size;
-     int yCurr_ctb = yCurr >> s->sps->log2_ctb_size;
-     int xN_ctb    = xN    >> s->sps->log2_ctb_size;
-     int yN_ctb    = yN    >> s->sps->log2_ctb_size;
 -/*
 - * 6.4.2 Derivation process for prediction block availability
 - */
 -static int check_prediction_block_available(HEVCContext *s, int log2_cb_size,
 -                                            int x0, int y0, int nPbW, int nPbH,
 -                                            int xA1, int yA1, int partIdx)
 -{
 -    HEVCLocalContext *lc = &s->HEVClc;
 -
 -    if (lc->cu.x < xA1 && lc->cu.y < yA1 &&
 -        (lc->cu.x + (1 << log2_cb_size)) > xA1 &&
 -        (lc->cu.y + (1 << log2_cb_size)) > yA1)
 -        return same_prediction_block(lc, log2_cb_size, x0, y0,
 -                                     nPbW, nPbH, xA1, yA1, partIdx);
 -    else
 -        return z_scan_block_avail(s, x0, y0, xA1, yA1);
++    int xCurr_ctb = xCurr >> s->ps.sps->log2_ctb_size;
++    int yCurr_ctb = yCurr >> s->ps.sps->log2_ctb_size;
++    int xN_ctb    = xN    >> s->ps.sps->log2_ctb_size;
++    int yN_ctb    = yN    >> s->ps.sps->log2_ctb_size;
 +    if( yN_ctb < yCurr_ctb || xN_ctb < xCurr_ctb )
 +        return 1;
 +    else {
-         int Curr = MIN_TB_ADDR_ZS((xCurr >> s->sps->log2_min_tb_size) & s->sps->tb_mask,
-                 (yCurr >> s->sps->log2_min_tb_size) & s->sps->tb_mask);
-         int N    = MIN_TB_ADDR_ZS((xN >> s->sps->log2_min_tb_size) & s->sps->tb_mask,
-                 (yN >> s->sps->log2_min_tb_size) & s->sps->tb_mask);
++        int Curr = MIN_TB_ADDR_ZS((xCurr >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask,
++                (yCurr >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask);
++        int N    = MIN_TB_ADDR_ZS((xN >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask,
++                (yN >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask);
 +        return N <= Curr;
 +    }
  }
  
  //check if the two luma locations belong to the same mostion estimation region
 -static int isDiffMER(HEVCContext *s, int xN, int yN, int xP, int yP)
 +static av_always_inline int is_diff_mer(HEVCContext *s, int xN, int yN, int xP, int yP)
  {
-     uint8_t plevel = s->pps->log2_parallel_merge_level;
+     uint8_t plevel = s->ps.pps->log2_parallel_merge_level;
  
      return xN >> plevel == xP >> plevel &&
             yN >> plevel == yP >> plevel;
@@@ -203,8 -234,7 +203,8 @@@ static int derive_temporal_colocated_mv
      tab_mvf[(y) * min_pu_width + x]
  
  #define TAB_MVF_PU(v)                                                   \
-     TAB_MVF(((x ## v) >> s->sps->log2_min_pu_size),                     \
-             ((y ## v) >> s->sps->log2_min_pu_size))
 -    TAB_MVF(x ## v ## _pu, y ## v ## _pu)
++    TAB_MVF(((x ## v) >> s->ps.sps->log2_min_pu_size),                     \
++            ((y ## v) >> s->ps.sps->log2_min_pu_size))
  
  #define DERIVE_TEMPORAL_COLOCATED_MVS                                   \
      derive_temporal_colocated_mvs(s, temp_col,                          \
@@@ -240,15 -270,14 +240,15 @@@ static int temporal_luma_motion_vector(
      y = y0 + nPbH;
  
      if (tab_mvf &&
-         (y0 >> s->sps->log2_ctb_size) == (y >> s->sps->log2_ctb_size) &&
-         y < s->sps->height &&
-         x < s->sps->width) {
+         (y0 >> s->ps.sps->log2_ctb_size) == (y >> s->ps.sps->log2_ctb_size) &&
+         y < s->ps.sps->height &&
+         x < s->ps.sps->width) {
          x                 &= ~15;
          y                 &= ~15;
 -        ff_thread_await_progress(&ref->tf, y, 0);
 +        if (s->threads_type == FF_THREAD_FRAME)
 +            ff_thread_await_progress(&ref->tf, y, 0);
-         x_pu               = x >> s->sps->log2_min_pu_size;
-         y_pu               = y >> s->sps->log2_min_pu_size;
+         x_pu               = x >> s->ps.sps->log2_min_pu_size;
+         y_pu               = y >> s->ps.sps->log2_min_pu_size;
          temp_col           = TAB_MVF(x_pu, y_pu);
          availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS;
      }
          y                  = y0 + (nPbH >> 1);
          x                 &= ~15;
          y                 &= ~15;
 -        ff_thread_await_progress(&ref->tf, y, 0);
 +        if (s->threads_type == FF_THREAD_FRAME)
 +            ff_thread_await_progress(&ref->tf, y, 0);
-         x_pu               = x >> s->sps->log2_min_pu_size;
-         y_pu               = y >> s->sps->log2_min_pu_size;
+         x_pu               = x >> s->ps.sps->log2_min_pu_size;
+         y_pu               = y >> s->ps.sps->log2_min_pu_size;
          temp_col           = TAB_MVF(x_pu, y_pu);
          availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS;
      }
@@@ -350,27 -398,29 +350,27 @@@ static void derive_spatial_merge_candid
          (lc->cu.part_mode == PART_2NxN ||
           lc->cu.part_mode == PART_2NxnU ||
           lc->cu.part_mode == PART_2NxnD) ||
 -        isDiffMER(s, xB1, yB1, x0, y0)) {
 +        is_diff_mer(s, xB1, yB1, x0, y0)) {
          is_available_b1 = 0;
 +    } else {
 +        is_available_b1 = AVAILABLE(cand_up, B1);
 +        if (is_available_b1 &&
 +            !(is_available_a1 && COMPARE_MV_REFIDX(B1, A1))) {
 +            mergecandlist[nb_merge_cand] = TAB_MVF_PU(B1);
 +            if (merge_idx == nb_merge_cand)
 +                return;
 +            nb_merge_cand++;
 +        }
      }
  
 -    if (is_available_a1 && is_available_b1)
 -        check_MER = !COMPARE_MV_REFIDX(B1, A1);
 -
 -    if (is_available_b1 && check_MER)
 -        mergecandlist[nb_merge_cand++] = TAB_MVF_PU(B1);
 -
      // above right spatial merge candidate
 -    check_MER = 1;
 -    check_B0  = PRED_BLOCK_AVAILABLE(B0);
 -
 -    is_available_b0 = check_B0 && AVAILABLE(cand_up_right, B0);
 +    is_available_b0 = AVAILABLE(cand_up_right, B0) &&
-                       xB0 < s->sps->width &&
++                      xB0 < s->ps.sps->width &&
 +                      PRED_BLOCK_AVAILABLE(B0) &&
 +                      !is_diff_mer(s, xB0, yB0, x0, y0);
  
 -    if (isDiffMER(s, xB0, yB0, x0, y0))
 -        is_available_b0 = 0;
 -
 -    if (is_available_b1 && is_available_b0)
 -        check_MER = !COMPARE_MV_REFIDX(B0, B1);
 -
 -    if (is_available_b0 && check_MER) {
 +    if (is_available_b0 &&
 +        !(is_available_b1 && COMPARE_MV_REFIDX(B0, B1))) {
          mergecandlist[nb_merge_cand] = TAB_MVF_PU(B0);
          if (merge_idx == nb_merge_cand)
              return;
      }
  
      // left bottom spatial merge candidate
 -    check_MER = 1;
 -    check_A0  = PRED_BLOCK_AVAILABLE(A0);
 -
 -    is_available_a0 = check_A0 && AVAILABLE(cand_bottom_left, A0);
 +    is_available_a0 = AVAILABLE(cand_bottom_left, A0) &&
-                       yA0 < s->sps->height &&
++                      yA0 < s->ps.sps->height &&
 +                      PRED_BLOCK_AVAILABLE(A0) &&
 +                      !is_diff_mer(s, xA0, yA0, x0, y0);
  
 -    if (isDiffMER(s, xA0, yA0, x0, y0))
 -        is_available_a0 = 0;
 -
 -    if (is_available_a1 && is_available_a0)
 -        check_MER = !COMPARE_MV_REFIDX(A0, A1);
 -
 -    if (is_available_a0 && check_MER) {
 +    if (is_available_a0 &&
 +        !(is_available_a1 && COMPARE_MV_REFIDX(A0, A1))) {
          mergecandlist[nb_merge_cand] = TAB_MVF_PU(A0);
          if (merge_idx == nb_merge_cand)
              return;
@@@ -484,9 -552,9 +484,9 @@@ void ff_hevc_luma_mv_merge_mode(HEVCCon
      LOCAL_ALIGNED(4, MvField, mergecand_list, [MRG_MAX_NUM_CANDS]);
      int nPbW2 = nPbW;
      int nPbH2 = nPbH;
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
  
-     if (s->pps->log2_parallel_merge_level > 2 && nCS == 8) {
+     if (s->ps.pps->log2_parallel_merge_level > 2 && nCS == 8) {
          singleMCLFlag = 1;
          x0            = lc->cu.x;
          y0            = lc->cu.y;
@@@ -545,67 -615,69 +545,67 @@@ static int mv_mp_mode_mx_lt(HEVCContex
                              Mv *mv, int ref_idx_curr, int ref_idx)
  {
      MvField *tab_mvf = s->ref->tab_mvf;
-     int min_pu_width = s->sps->min_pu_width;
+     int min_pu_width = s->ps.sps->min_pu_width;
  
      RefPicList *refPicList = s->ref->refPicList;
 -    int currIsLongTerm     = refPicList[ref_idx_curr].isLongTerm[ref_idx];
  
 -    int colIsLongTerm =
 -        refPicList[pred_flag_index].isLongTerm[(TAB_MVF(x, y).ref_idx[pred_flag_index])];
 +    if ((TAB_MVF(x, y).pred_flag) & (1 << pred_flag_index)) {
 +        int currIsLongTerm     = refPicList[ref_idx_curr].isLongTerm[ref_idx];
  
 -    if (TAB_MVF(x, y).pred_flag[pred_flag_index] &&
 -        colIsLongTerm == currIsLongTerm) {
 -        *mv = TAB_MVF(x, y).mv[pred_flag_index];
 -        if (!currIsLongTerm)
 -            dist_scale(s, mv, min_pu_width, x, y,
 -                       pred_flag_index, ref_idx_curr, ref_idx);
 -        return 1;
 +        int colIsLongTerm =
 +            refPicList[pred_flag_index].isLongTerm[(TAB_MVF(x, y).ref_idx[pred_flag_index])];
 +
 +        if (colIsLongTerm == currIsLongTerm) {
 +            *mv = TAB_MVF(x, y).mv[pred_flag_index];
 +            if (!currIsLongTerm)
 +                dist_scale(s, mv, min_pu_width, x, y,
 +                           pred_flag_index, ref_idx_curr, ref_idx);
 +            return 1;
 +        }
      }
      return 0;
  }
  
  #define MP_MX(v, pred, mx)                                      \
 -    mv_mp_mode_mx(s, x ## v ## _pu, y ## v ## _pu, pred,        \
 -                  &mx, ref_idx_curr, ref_idx)
 +    mv_mp_mode_mx(s,                                            \
-                   (x ## v) >> s->sps->log2_min_pu_size,         \
-                   (y ## v) >> s->sps->log2_min_pu_size,         \
++                  (x ## v) >> s->ps.sps->log2_min_pu_size,         \
++                  (y ## v) >> s->ps.sps->log2_min_pu_size,         \
 +                  pred, &mx, ref_idx_curr, ref_idx)
  
  #define MP_MX_LT(v, pred, mx)                                   \
 -    mv_mp_mode_mx_lt(s, x ## v ## _pu, y ## v ## _pu, pred,     \
 -                     &mx, ref_idx_curr, ref_idx)
 +    mv_mp_mode_mx_lt(s,                                         \
-                      (x ## v) >> s->sps->log2_min_pu_size,      \
-                      (y ## v) >> s->sps->log2_min_pu_size,      \
++                     (x ## v) >> s->ps.sps->log2_min_pu_size,      \
++                     (y ## v) >> s->ps.sps->log2_min_pu_size,      \
 +                     pred, &mx, ref_idx_curr, ref_idx)
  
  void ff_hevc_luma_mv_mvp_mode(HEVCContext *s, int x0, int y0, int nPbW,
                                int nPbH, int log2_cb_size, int part_idx,
                                int merge_idx, MvField *mv,
                                int mvp_lx_flag, int LX)
  {
 -    HEVCLocalContext *lc = &s->HEVClc;
 +    HEVCLocalContext *lc = s->HEVClc;
      MvField *tab_mvf = s->ref->tab_mvf;
      int isScaledFlag_L0 = 0;
 -    int availableFlagLXA0 = 0;
 -    int availableFlagLXB0 = 0;
 +    int availableFlagLXA0 = 1;
 +    int availableFlagLXB0 = 1;
      int numMVPCandLX = 0;
-     int min_pu_width = s->sps->min_pu_width;
+     int min_pu_width = s->ps.sps->min_pu_width;
  
      int xA0, yA0;
 -    int xA0_pu, yA0_pu;
      int is_available_a0;
 -
      int xA1, yA1;
 -    int xA1_pu, yA1_pu;
      int is_available_a1;
 -
      int xB0, yB0;
 -    int xB0_pu, yB0_pu;
      int is_available_b0;
 -
      int xB1, yB1;
 -    int xB1_pu = 0, yB1_pu = 0;
 -    int is_available_b1 = 0;
 -
 +    int is_available_b1;
      int xB2, yB2;
 -    int xB2_pu = 0, yB2_pu = 0;
 -    int is_available_b2 = 0;
 +    int is_available_b2;
 +
      Mv mvpcand_list[2] = { { 0 } };
 -    Mv mxA = { 0 };
 -    Mv mxB = { 0 };
 -    int ref_idx_curr = 0;
 +    Mv mxA;
 +    Mv mxB;
 +    int ref_idx_curr;
      int ref_idx = 0;
      int pred_flag_index_l0;
      int pred_flag_index_l1;
      // left bottom spatial candidate
      xA0 = x0 - 1;
      yA0 = y0 + nPbH;
 -    xA0_pu = xA0 >> s->ps.sps->log2_min_pu_size;
 -    yA0_pu = yA0 >> s->ps.sps->log2_min_pu_size;
  
 -    is_available_a0 = PRED_BLOCK_AVAILABLE(A0) && AVAILABLE(cand_bottom_left, A0);
 +    is_available_a0 = AVAILABLE(cand_bottom_left, A0) &&
-                       yA0 < s->sps->height &&
++                      yA0 < s->ps.sps->height &&
 +                      PRED_BLOCK_AVAILABLE(A0);
  
      //left spatial merge candidate
      xA1    = x0 - 1;
@@@ -678,28 -750,30 +678,28 @@@ b_candidates
      // above right spatial merge candidate
      xB0    = x0 + nPbW;
      yB0    = y0 - 1;
 -    xB0_pu = xB0 >> s->ps.sps->log2_min_pu_size;
 -    yB0_pu = yB0 >> s->ps.sps->log2_min_pu_size;
  
 -    is_available_b0 = PRED_BLOCK_AVAILABLE(B0) && AVAILABLE(cand_up_right, B0);
 +    is_available_b0 =  AVAILABLE(cand_up_right, B0) &&
-                        xB0 < s->sps->width &&
++                       xB0 < s->ps.sps->width &&
 +                       PRED_BLOCK_AVAILABLE(B0);
  
 -    if (is_available_b0) {
 -        availableFlagLXB0 = MP_MX(B0, pred_flag_index_l0, mxB);
 -        if (!availableFlagLXB0)
 -            availableFlagLXB0 = MP_MX(B0, pred_flag_index_l1, mxB);
 -    }
 -
 -    if (!availableFlagLXB0) {
 -        // above spatial merge candidate
 -        xB1    = x0 + nPbW - 1;
 -        yB1    = y0 - 1;
 -        xB1_pu = xB1 >> s->ps.sps->log2_min_pu_size;
 -        yB1_pu = yB1 >> s->ps.sps->log2_min_pu_size;
 +    // above spatial merge candidate
 +    xB1    = x0 + nPbW - 1;
 +    yB1    = y0 - 1;
 +    is_available_b1 = AVAILABLE(cand_up, B1);
  
 -        is_available_b1 = AVAILABLE(cand_up, B1);
 +    // above left spatial merge candidate
 +    xB2 = x0 - 1;
 +    yB2 = y0 - 1;
 +    is_available_b2 = AVAILABLE(cand_up_left, B2);
  
 -        if (is_available_b1) {
 -            availableFlagLXB0 = MP_MX(B1, pred_flag_index_l0, mxB);
 -            if (!availableFlagLXB0)
 -                availableFlagLXB0 = MP_MX(B1, pred_flag_index_l1, mxB);
 +    // above right spatial merge candidate
 +    if (is_available_b0) {
 +        if (MP_MX(B0, pred_flag_index_l0, mxB)) {
 +            goto scalef;
 +        }
 +        if (MP_MX(B0, pred_flag_index_l1, mxB)) {
 +            goto scalef;
          }
      }
  
@@@ -76,189 -71,7 +76,190 @@@ static int hevc_find_frame_end(AVCodecP
      return END_NOT_FOUND;
  }
  
 -static int hevc_parse(AVCodecParserContext *s, AVCodecContext *avctx,
 +/**
 + * Parse NAL units of found picture and decode some basic information.
 + *
 + * @param s parser context.
 + * @param avctx codec context.
 + * @param buf buffer with field/frame data.
 + * @param buf_size size of the buffer.
 + */
 +static inline int parse_nal_units(AVCodecParserContext *s, AVCodecContext *avctx,
 +                      const uint8_t *buf, int buf_size)
 +{
 +    HEVCContext   *h  = &((HEVCParseContext *)s->priv_data)->h;
 +    GetBitContext *gb = &h->HEVClc->gb;
 +    SliceHeader   *sh = &h->sh;
++    HEVCParamSets *ps = &h->ps;
 +    const uint8_t *buf_end = buf + buf_size;
 +    int state = -1, i;
 +    HEVCNAL *nal;
 +
 +    /* set some sane default values */
 +    s->pict_type         = AV_PICTURE_TYPE_I;
 +    s->key_frame         = 0;
 +    s->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN;
 +
 +    h->avctx = avctx;
 +
 +    if (!buf_size)
 +        return 0;
 +
 +    if (h->nals_allocated < 1) {
 +        HEVCNAL *tmp = av_realloc_array(h->nals, 1, sizeof(*tmp));
 +        if (!tmp)
 +            return AVERROR(ENOMEM);
 +        h->nals = tmp;
 +        memset(h->nals, 0, sizeof(*tmp));
 +        h->nals_allocated = 1;
 +    }
 +
 +    nal = &h->nals[0];
 +
 +    for (;;) {
 +        int src_length, consumed;
 +        buf = avpriv_find_start_code(buf, buf_end, &state);
 +        if (--buf + 2 >= buf_end)
 +            break;
 +        src_length = buf_end - buf;
 +
 +        h->nal_unit_type = (*buf >> 1) & 0x3f;
 +        h->temporal_id   = (*(buf + 1) & 0x07) - 1;
 +        if (h->nal_unit_type <= NAL_CRA_NUT) {
 +            // Do not walk the whole buffer just to decode slice segment header
 +            if (src_length > 20)
 +                src_length = 20;
 +        }
 +
 +        consumed = ff_hevc_extract_rbsp(h, buf, src_length, nal);
 +        if (consumed < 0)
 +            return consumed;
 +
 +        init_get_bits8(gb, nal->data + 2, nal->size);
 +        switch (h->nal_unit_type) {
 +        case NAL_VPS:
-             ff_hevc_decode_nal_vps(h);
++            ff_hevc_decode_nal_vps(gb, avctx, ps);
 +            break;
 +        case NAL_SPS:
-             ff_hevc_decode_nal_sps(h);
++            ff_hevc_decode_nal_sps(gb, avctx, ps, h->apply_defdispwin);
 +            break;
 +        case NAL_PPS:
-             ff_hevc_decode_nal_pps(h);
++            ff_hevc_decode_nal_pps(gb, avctx, ps);
 +            break;
 +        case NAL_SEI_PREFIX:
 +        case NAL_SEI_SUFFIX:
 +            ff_hevc_decode_nal_sei(h);
 +            break;
 +        case NAL_TRAIL_N:
 +        case NAL_TRAIL_R:
 +        case NAL_TSA_N:
 +        case NAL_TSA_R:
 +        case NAL_STSA_N:
 +        case NAL_STSA_R:
 +        case NAL_RADL_N:
 +        case NAL_RADL_R:
 +        case NAL_RASL_N:
 +        case NAL_RASL_R:
 +        case NAL_BLA_W_LP:
 +        case NAL_BLA_W_RADL:
 +        case NAL_BLA_N_LP:
 +        case NAL_IDR_W_RADL:
 +        case NAL_IDR_N_LP:
 +        case NAL_CRA_NUT:
 +            sh->first_slice_in_pic_flag = get_bits1(gb);
 +            s->picture_structure = h->picture_struct;
 +            s->field_order = h->picture_struct;
 +
 +            if (IS_IRAP(h)) {
 +                s->key_frame = 1;
 +                sh->no_output_of_prior_pics_flag = get_bits1(gb);
 +            }
 +
 +            sh->pps_id = get_ue_golomb(gb);
-             if (sh->pps_id >= MAX_PPS_COUNT || !h->pps_list[sh->pps_id]) {
++            if (sh->pps_id >= MAX_PPS_COUNT || !ps->pps_list[sh->pps_id]) {
 +                av_log(h->avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", sh->pps_id);
 +                return AVERROR_INVALIDDATA;
 +            }
-             h->pps = (HEVCPPS*)h->pps_list[sh->pps_id]->data;
++            ps->pps = (HEVCPPS*)ps->pps_list[sh->pps_id]->data;
 +
-             if (h->pps->sps_id >= MAX_SPS_COUNT || !h->sps_list[h->pps->sps_id]) {
-                 av_log(h->avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", h->pps->sps_id);
++            if (ps->pps->sps_id >= MAX_SPS_COUNT || !ps->sps_list[ps->pps->sps_id]) {
++                av_log(h->avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", ps->pps->sps_id);
 +                return AVERROR_INVALIDDATA;
 +            }
-             if (h->sps != (HEVCSPS*)h->sps_list[h->pps->sps_id]->data) {
-                 h->sps = (HEVCSPS*)h->sps_list[h->pps->sps_id]->data;
-                 h->vps = (HEVCVPS*)h->vps_list[h->sps->vps_id]->data;
++            if (ps->sps != (HEVCSPS*)ps->sps_list[ps->pps->sps_id]->data) {
++                ps->sps = (HEVCSPS*)ps->sps_list[ps->pps->sps_id]->data;
++                ps->vps = (HEVCVPS*)ps->vps_list[ps->sps->vps_id]->data;
 +            }
 +
 +            if (!sh->first_slice_in_pic_flag) {
 +                int slice_address_length;
 +
-                 if (h->pps->dependent_slice_segments_enabled_flag)
++                if (ps->pps->dependent_slice_segments_enabled_flag)
 +                    sh->dependent_slice_segment_flag = get_bits1(gb);
 +                else
 +                    sh->dependent_slice_segment_flag = 0;
 +
-                 slice_address_length = av_ceil_log2_c(h->sps->ctb_width *
-                                                       h->sps->ctb_height);
++                slice_address_length = av_ceil_log2_c(ps->sps->ctb_width *
++                                                      ps->sps->ctb_height);
 +                sh->slice_segment_addr = slice_address_length ? get_bits(gb, slice_address_length) : 0;
-                 if (sh->slice_segment_addr >= h->sps->ctb_width * h->sps->ctb_height) {
++                if (sh->slice_segment_addr >= ps->sps->ctb_width * ps->sps->ctb_height) {
 +                    av_log(h->avctx, AV_LOG_ERROR, "Invalid slice segment address: %u.\n",
 +                           sh->slice_segment_addr);
 +                    return AVERROR_INVALIDDATA;
 +                }
 +            } else
 +                sh->dependent_slice_segment_flag = 0;
 +
 +            if (sh->dependent_slice_segment_flag)
 +                break;
 +
-             for (i = 0; i < h->pps->num_extra_slice_header_bits; i++)
++            for (i = 0; i < ps->pps->num_extra_slice_header_bits; i++)
 +                skip_bits(gb, 1); // slice_reserved_undetermined_flag[]
 +
 +            sh->slice_type = get_ue_golomb(gb);
 +            if (!(sh->slice_type == I_SLICE || sh->slice_type == P_SLICE ||
 +                  sh->slice_type == B_SLICE)) {
 +                av_log(h->avctx, AV_LOG_ERROR, "Unknown slice type: %d.\n",
 +                       sh->slice_type);
 +                return AVERROR_INVALIDDATA;
 +            }
 +            s->pict_type = sh->slice_type == B_SLICE ? AV_PICTURE_TYPE_B :
 +                           sh->slice_type == P_SLICE ? AV_PICTURE_TYPE_P :
 +                                                       AV_PICTURE_TYPE_I;
 +
-             if (h->pps->output_flag_present_flag)
++            if (ps->pps->output_flag_present_flag)
 +                sh->pic_output_flag = get_bits1(gb);
 +
-             if (h->sps->separate_colour_plane_flag)
++            if (ps->sps->separate_colour_plane_flag)
 +                sh->colour_plane_id = get_bits(gb, 2);
 +
 +            if (!IS_IDR(h)) {
-                 sh->pic_order_cnt_lsb = get_bits(gb, h->sps->log2_max_poc_lsb);
++                sh->pic_order_cnt_lsb = get_bits(gb, ps->sps->log2_max_poc_lsb);
 +                s->output_picture_number = h->poc = ff_hevc_compute_poc(h, sh->pic_order_cnt_lsb);
 +            } else
 +                s->output_picture_number = h->poc = 0;
 +
 +            if (h->temporal_id == 0 &&
 +                h->nal_unit_type != NAL_TRAIL_N &&
 +                h->nal_unit_type != NAL_TSA_N &&
 +                h->nal_unit_type != NAL_STSA_N &&
 +                h->nal_unit_type != NAL_RADL_N &&
 +                h->nal_unit_type != NAL_RASL_N &&
 +                h->nal_unit_type != NAL_RADL_R &&
 +                h->nal_unit_type != NAL_RASL_R)
 +                h->pocTid0 = h->poc;
 +
 +            return 0; /* no need to evaluate the rest */
 +        }
 +        buf += consumed;
 +    }
 +    /* didn't find a picture! */
 +    av_log(h->avctx, AV_LOG_ERROR, "missing picture in access unit\n");
 +    return -1;
 +}
 +
 +static int hevc_parse(AVCodecParserContext *s,
 +                      AVCodecContext *avctx,
                        const uint8_t **poutbuf, int *poutbuf_size,
                        const uint8_t *buf, int buf_size)
  {
@@@ -305,47 -116,10 +306,48 @@@ static int hevc_split(AVCodecContext *a
      return 0;
  }
  
-     for (i = 0; i < FF_ARRAY_ELEMS(h->vps_list); i++)
-         av_buffer_unref(&h->vps_list[i]);
-     for (i = 0; i < FF_ARRAY_ELEMS(h->sps_list); i++)
-         av_buffer_unref(&h->sps_list[i]);
-     for (i = 0; i < FF_ARRAY_ELEMS(h->pps_list); i++)
-         av_buffer_unref(&h->pps_list[i]);
 +static int hevc_init(AVCodecParserContext *s)
 +{
 +    HEVCContext  *h  = &((HEVCParseContext *)s->priv_data)->h;
 +    h->HEVClc = av_mallocz(sizeof(HEVCLocalContext));
 +    if (!h->HEVClc)
 +        return AVERROR(ENOMEM);
 +    h->skipped_bytes_pos_size = INT_MAX;
 +
 +    return 0;
 +}
 +
 +static void hevc_close(AVCodecParserContext *s)
 +{
 +    int i;
 +    HEVCContext  *h  = &((HEVCParseContext *)s->priv_data)->h;
 +    ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc;
++    HEVCParamSets *ps = &h->ps;
 +
 +    av_freep(&h->skipped_bytes_pos);
 +    av_freep(&h->HEVClc);
 +    av_freep(&pc->buffer);
 +
-     h->sps = NULL;
++    for (i = 0; i < FF_ARRAY_ELEMS(ps->vps_list); i++)
++        av_buffer_unref(&ps->vps_list[i]);
++    for (i = 0; i < FF_ARRAY_ELEMS(ps->sps_list); i++)
++        av_buffer_unref(&ps->sps_list[i]);
++    for (i = 0; i < FF_ARRAY_ELEMS(ps->pps_list); i++)
++        av_buffer_unref(&ps->pps_list[i]);
 +
++    ps->sps = NULL;
 +
 +    for (i = 0; i < h->nals_allocated; i++)
 +        av_freep(&h->nals[i].rbsp_buffer);
 +    av_freep(&h->nals);
 +    h->nals_allocated = 0;
 +}
 +
  AVCodecParser ff_hevc_parser = {
      .codec_ids      = { AV_CODEC_ID_HEVC },
 -    .priv_data_size = sizeof(ParseContext),
 +    .priv_data_size = sizeof(HEVCParseContext),
 +    .parser_init    = hevc_init,
      .parser_parse   = hevc_parse,
 -    .parser_close   = ff_parse_close,
 +    .parser_close   = hevc_close,
      .split          = hevc_split,
  };
@@@ -386,13 -348,12 +386,13 @@@ static int decode_hrd(GetBitContext *gb
          if (vcl_params_present)
              decode_sublayer_hrd(gb, nb_cpb, subpic_params_present);
      }
 +    return 0;
  }
  
- int ff_hevc_decode_nal_vps(HEVCContext *s)
+ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx,
+                            HEVCParamSets *ps)
  {
      int i,j;
-     GetBitContext *gb = &s->HEVClc->gb;
      int vps_id = 0;
      HEVCVPS *vps;
      AVBufferRef *vps_buf = av_buffer_allocz(sizeof(*vps));
          goto err;
      }
  
-     if (parse_ptl(gb, s->avctx, &vps->ptl, vps->vps_max_sub_layers) < 0)
 -    parse_ptl(gb, avctx, &vps->ptl, vps->vps_max_sub_layers);
++    if (parse_ptl(gb, avctx, &vps->ptl, vps->vps_max_sub_layers) < 0)
 +        goto err;
  
      vps->vps_sub_layer_ordering_info_present_flag = get_bits1(gb);
  
          vps->vps_num_reorder_pics[i]      = get_ue_golomb_long(gb);
          vps->vps_max_latency_increase[i]  = get_ue_golomb_long(gb) - 1;
  
 -        if (vps->vps_max_dec_pic_buffering[i] > MAX_DPB_SIZE) {
 +        if (vps->vps_max_dec_pic_buffering[i] > MAX_DPB_SIZE || !vps->vps_max_dec_pic_buffering[i]) {
-             av_log(s->avctx, AV_LOG_ERROR, "vps_max_dec_pic_buffering_minus1 out of range: %d\n",
+             av_log(avctx, AV_LOG_ERROR, "vps_max_dec_pic_buffering_minus1 out of range: %d\n",
                     vps->vps_max_dec_pic_buffering[i] - 1);
              goto err;
          }
  
      vps->vps_max_layer_id   = get_bits(gb, 6);
      vps->vps_num_layer_sets = get_ue_golomb_long(gb) + 1;
-         av_log(s->avctx, AV_LOG_ERROR, "too many layer_id_included_flags\n");
 +    if (vps->vps_num_layer_sets < 1 || vps->vps_num_layer_sets > 1024 ||
 +        (vps->vps_num_layer_sets - 1LL) * (vps->vps_max_layer_id + 1LL) > get_bits_left(gb)) {
++        av_log(avctx, AV_LOG_ERROR, "too many layer_id_included_flags\n");
 +        goto err;
 +    }
 +
      for (i = 1; i < vps->vps_num_layer_sets; i++)
          for (j = 0; j <= vps->vps_max_layer_id; j++)
              skip_bits(gb, 1);  // layer_id_included_flag[i][j]
          if (vps->vps_poc_proportional_to_timing_flag)
              vps->vps_num_ticks_poc_diff_one = get_ue_golomb_long(gb) + 1;
          vps->vps_num_hrd_parameters = get_ue_golomb_long(gb);
-             av_log(s->avctx, AV_LOG_ERROR,
 +        if (vps->vps_num_hrd_parameters > (unsigned)vps->vps_num_layer_sets) {
++            av_log(avctx, AV_LOG_ERROR,
 +                   "vps_num_hrd_parameters %d is invalid\n", vps->vps_num_hrd_parameters);
 +            goto err;
 +        }
          for (i = 0; i < vps->vps_num_hrd_parameters; i++) {
              int common_inf_present = 1;
  
      }
      get_bits1(gb); /* vps_extension_flag */
  
-         av_log(s->avctx, AV_LOG_ERROR,
 +    if (get_bits_left(gb) < 0) {
-         if (s->vps_list[vps_id])
++        av_log(avctx, AV_LOG_ERROR,
 +               "Overread VPS by %d bits\n", -get_bits_left(gb));
-     if (s->vps_list[vps_id] &&
-         !memcmp(s->vps_list[vps_id]->data, vps_buf->data, vps_buf->size)) {
++        if (ps->vps_list[vps_id])
 +            goto err;
 +    }
 +
+     if (ps->vps_list[vps_id] &&
+         !memcmp(ps->vps_list[vps_id]->data, vps_buf->data, vps_buf->size)) {
          av_buffer_unref(&vps_buf);
      } else {
-         remove_vps(s, vps_id);
-         s->vps_list[vps_id] = vps_buf;
+         remove_vps(ps, vps_id);
+         ps->vps_list[vps_id] = vps_buf;
      }
  
      return 0;
@@@ -1123,19 -959,17 +1123,20 @@@ int ff_hevc_parse_sps(HEVCSPS *sps, Get
          av_log(avctx, AV_LOG_ERROR,
                 "max transform block size out of range: %d\n",
                 sps->log2_max_trafo_size);
 -        goto err;
 +        return AVERROR_INVALIDDATA;
      }
  
 -    return 0;
 +    if (get_bits_left(gb) < 0) {
 +        av_log(avctx, AV_LOG_ERROR,
 +               "Overread SPS by %d bits\n", -get_bits_left(gb));
 +        return AVERROR_INVALIDDATA;
 +    }
  
 -err:
 -    return ret;
 +    return 0;
  }
  
- int ff_hevc_decode_nal_sps(HEVCContext *s)
+ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx,
+                            HEVCParamSets *ps, int apply_defdispwin)
  {
      HEVCSPS *sps;
      AVBufferRef *sps_buf = av_buffer_allocz(sizeof(*sps));
@@@ -1197,47 -1031,11 +1198,47 @@@ static void hevc_pps_free(void *opaque
      av_freep(&pps);
  }
  
- static int pps_range_extensions(HEVCContext *s, HEVCPPS *pps, HEVCSPS *sps) {
-     GetBitContext *gb = &s->HEVClc->gb;
++static int pps_range_extensions(GetBitContext *gb, AVCodecContext *avctx,
++                                HEVCPPS *pps, HEVCSPS *sps) {
 +    int i;
 +
 +    if (pps->transform_skip_enabled_flag) {
 +        pps->log2_max_transform_skip_block_size = get_ue_golomb_long(gb) + 2;
 +    }
 +    pps->cross_component_prediction_enabled_flag = get_bits1(gb);
 +    pps->chroma_qp_offset_list_enabled_flag = get_bits1(gb);
 +    if (pps->chroma_qp_offset_list_enabled_flag) {
 +        pps->diff_cu_chroma_qp_offset_depth = get_ue_golomb_long(gb);
 +        pps->chroma_qp_offset_list_len_minus1 = get_ue_golomb_long(gb);
 +        if (pps->chroma_qp_offset_list_len_minus1 && pps->chroma_qp_offset_list_len_minus1 >= 5) {
-             av_log(s->avctx, AV_LOG_ERROR,
++            av_log(avctx, AV_LOG_ERROR,
 +                   "chroma_qp_offset_list_len_minus1 shall be in the range [0, 5].\n");
 +            return AVERROR_INVALIDDATA;
 +        }
 +        for (i = 0; i <= pps->chroma_qp_offset_list_len_minus1; i++) {
 +            pps->cb_qp_offset_list[i] = get_se_golomb_long(gb);
 +            if (pps->cb_qp_offset_list[i]) {
-                 av_log(s->avctx, AV_LOG_WARNING,
++                av_log(avctx, AV_LOG_WARNING,
 +                       "cb_qp_offset_list not tested yet.\n");
 +            }
 +            pps->cr_qp_offset_list[i] = get_se_golomb_long(gb);
 +            if (pps->cr_qp_offset_list[i]) {
-                 av_log(s->avctx, AV_LOG_WARNING,
++                av_log(avctx, AV_LOG_WARNING,
 +                       "cb_qp_offset_list not tested yet.\n");
 +            }
 +        }
 +    }
 +    pps->log2_sao_offset_scale_luma = get_ue_golomb_long(gb);
 +    pps->log2_sao_offset_scale_chroma = get_ue_golomb_long(gb);
 +
 +    return(0);
 +}
 +
- int ff_hevc_decode_nal_pps(HEVCContext *s)
+ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx,
+                            HEVCParamSets *ps)
  {
-     GetBitContext *gb = &s->HEVClc->gb;
      HEVCSPS      *sps = NULL;
 -    int pic_area_in_ctbs, pic_area_in_min_tbs;
 +    int pic_area_in_ctbs;
      int log2_diff_ctb_min_tb_size;
      int i, j, x, y, ctb_addr_rs, tile_id;
      int ret = 0;
      if (pps->cu_qp_delta_enabled_flag)
          pps->diff_cu_qp_delta_depth = get_ue_golomb_long(gb);
  
-         av_log(s->avctx, AV_LOG_ERROR, "diff_cu_qp_delta_depth %d is invalid\n",
 +    if (pps->diff_cu_qp_delta_depth < 0 ||
 +        pps->diff_cu_qp_delta_depth > sps->log2_diff_max_min_coding_block_size) {
++        av_log(avctx, AV_LOG_ERROR, "diff_cu_qp_delta_depth %d is invalid\n",
 +               pps->diff_cu_qp_delta_depth);
 +        ret = AVERROR_INVALIDDATA;
 +        goto err;
 +    }
 +
      pps->cb_qp_offset = get_se_golomb(gb);
      if (pps->cb_qp_offset < -12 || pps->cb_qp_offset > 12) {
-         av_log(s->avctx, AV_LOG_ERROR, "pps_cb_qp_offset out of range: %d\n",
+         av_log(avctx, AV_LOG_ERROR, "pps_cb_qp_offset out of range: %d\n",
                 pps->cb_qp_offset);
          ret = AVERROR_INVALIDDATA;
          goto err;
      if (pps->tiles_enabled_flag) {
          pps->num_tile_columns = get_ue_golomb_long(gb) + 1;
          pps->num_tile_rows    = get_ue_golomb_long(gb) + 1;
 -        if (pps->num_tile_columns == 0 ||
 +        if (pps->num_tile_columns <= 0 ||
              pps->num_tile_columns >= sps->width) {
-             av_log(s->avctx, AV_LOG_ERROR, "num_tile_columns_minus1 out of range: %d\n",
+             av_log(avctx, AV_LOG_ERROR, "num_tile_columns_minus1 out of range: %d\n",
                     pps->num_tile_columns - 1);
              ret = AVERROR_INVALIDDATA;
              goto err;
          }
 -        if (pps->num_tile_rows == 0 ||
 +        if (pps->num_tile_rows <= 0 ||
              pps->num_tile_rows >= sps->height) {
-             av_log(s->avctx, AV_LOG_ERROR, "num_tile_rows_minus1 out of range: %d\n",
+             av_log(avctx, AV_LOG_ERROR, "num_tile_rows_minus1 out of range: %d\n",
                     pps->num_tile_rows - 1);
              ret = AVERROR_INVALIDDATA;
              goto err;
      pps->scaling_list_data_present_flag = get_bits1(gb);
      if (pps->scaling_list_data_present_flag) {
          set_default_scaling_list_data(&pps->scaling_list);
-         ret = scaling_list_data(gb, s->avctx, &pps->scaling_list, sps);
 -        ret = scaling_list_data(gb, avctx, &pps->scaling_list);
++        ret = scaling_list_data(gb, avctx, &pps->scaling_list, sps);
          if (ret < 0)
              goto err;
      }
      }
  
      pps->slice_header_extension_present_flag = get_bits1(gb);
 -    skip_bits1(gb);     // pps_extension_flag
 +
 +    if (get_bits1(gb)) { // pps_extension_present_flag
 +        int pps_range_extensions_flag = get_bits1(gb);
 +        /* int pps_extension_7bits = */ get_bits(gb, 7);
 +        if (sps->ptl.general_ptl.profile_idc == FF_PROFILE_HEVC_REXT && pps_range_extensions_flag) {
-             if ((ret = pps_range_extensions(s, pps, sps)) < 0)
++            if ((ret = pps_range_extensions(gb, avctx, pps, sps)) < 0)
 +                goto err;
 +        }
 +    }
  
      // Inferred parameters
      pps->col_bd   = av_malloc_array(pps->num_tile_columns + 1, sizeof(*pps->col_bd));
          }
      }
  
-         av_log(s->avctx, AV_LOG_ERROR,
 +    if (get_bits_left(gb) < 0) {
-     remove_pps(s, pps_id);
-     s->pps_list[pps_id] = pps_buf;
++        av_log(avctx, AV_LOG_ERROR,
 +               "Overread PPS by %d bits\n", -get_bits_left(gb));
 +        goto err;
 +    }
 +
+     remove_pps(ps, pps_id);
+     ps->pps_list[pps_id] = pps_buf;
  
      return 0;
  
@@@ -55,10 -55,11 +55,10 @@@ void ff_hevc_unref_frame(HEVCContext *s
  
  RefPicList *ff_hevc_get_ref_list(HEVCContext *s, HEVCFrame *ref, int x0, int y0)
  {
-     int x_cb         = x0 >> s->sps->log2_ctb_size;
-     int y_cb         = y0 >> s->sps->log2_ctb_size;
-     int pic_width_cb = s->sps->ctb_width;
-     int ctb_addr_ts  = s->pps->ctb_addr_rs_to_ts[y_cb * pic_width_cb + x_cb];
+     int x_cb         = x0 >> s->ps.sps->log2_ctb_size;
+     int y_cb         = y0 >> s->ps.sps->log2_ctb_size;
 -    int pic_width_cb = (s->ps.sps->width + (1 << s->ps.sps->log2_ctb_size) - 1) >>
 -        s->ps.sps->log2_ctb_size;
++    int pic_width_cb = s->ps.sps->ctb_width;
+     int ctb_addr_ts  = s->ps.pps->ctb_addr_rs_to_ts[y_cb * pic_width_cb + x_cb];
      return (RefPicList *)ref->rpl_tab[ctb_addr_ts];
  }
  
@@@ -237,46 -226,6 +237,46 @@@ int ff_hevc_output_frame(HEVCContext *s
      return 0;
  }
  
-     if (s->sps && dpb >= s->sps->temporal_layer[s->sps->max_sub_layers - 1].max_dec_pic_buffering) {
 +void ff_hevc_bump_frame(HEVCContext *s)
 +{
 +    int dpb = 0;
 +    int min_poc = INT_MAX;
 +    int i;
 +
 +    for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
 +        HEVCFrame *frame = &s->DPB[i];
 +        if ((frame->flags) &&
 +            frame->sequence == s->seq_output &&
 +            frame->poc != s->poc) {
 +            dpb++;
 +        }
 +    }
 +
++    if (s->ps.sps && dpb >= s->ps.sps->temporal_layer[s->ps.sps->max_sub_layers - 1].max_dec_pic_buffering) {
 +        for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
 +            HEVCFrame *frame = &s->DPB[i];
 +            if ((frame->flags) &&
 +                frame->sequence == s->seq_output &&
 +                frame->poc != s->poc) {
 +                if (frame->flags == HEVC_FRAME_FLAG_OUTPUT && frame->poc < min_poc) {
 +                    min_poc = frame->poc;
 +                }
 +            }
 +        }
 +
 +        for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
 +            HEVCFrame *frame = &s->DPB[i];
 +            if (frame->flags & HEVC_FRAME_FLAG_OUTPUT &&
 +                frame->sequence == s->seq_output &&
 +                frame->poc <= min_poc) {
 +                frame->flags |= HEVC_FRAME_FLAG_BUMPING;
 +            }
 +        }
 +
 +        dpb--;
 +    }
 +}
 +
  static int init_slice_rpl(HEVCContext *s)
  {
      HEVCFrame *frame = s->ref;
@@@ -89,64 -86,9 +89,64 @@@ static void decode_nal_sei_display_orie
      }
  }
  
-     if (!s->sps_list[s->active_seq_parameter_set_id])
 +static int decode_pic_timing(HEVCContext *s)
 +{
 +    GetBitContext *gb = &s->HEVClc->gb;
 +    HEVCSPS *sps;
 +
-     sps = (HEVCSPS*)s->sps_list[s->active_seq_parameter_set_id]->data;
++    if (!s->ps.sps_list[s->active_seq_parameter_set_id])
 +        return(AVERROR(ENOMEM));
++    sps = (HEVCSPS*)s->ps.sps_list[s->active_seq_parameter_set_id]->data;
 +
 +    if (sps->vui.frame_field_info_present_flag) {
 +        int pic_struct = get_bits(gb, 4);
 +        s->picture_struct = AV_PICTURE_STRUCTURE_UNKNOWN;
 +        if (pic_struct == 2) {
 +            av_log(s->avctx, AV_LOG_DEBUG, "BOTTOM Field\n");
 +            s->picture_struct = AV_PICTURE_STRUCTURE_BOTTOM_FIELD;
 +        } else if (pic_struct == 1) {
 +            av_log(s->avctx, AV_LOG_DEBUG, "TOP Field\n");
 +            s->picture_struct = AV_PICTURE_STRUCTURE_TOP_FIELD;
 +        }
 +        get_bits(gb, 2);                   // source_scan_type
 +        get_bits(gb, 1);                   // duplicate_flag
 +    }
 +    return 1;
 +}
 +
 +static int active_parameter_sets(HEVCContext *s)
 +{
 +    GetBitContext *gb = &s->HEVClc->gb;
 +    int num_sps_ids_minus1;
 +    int i;
 +    unsigned active_seq_parameter_set_id;
 +
 +    get_bits(gb, 4); // active_video_parameter_set_id
 +    get_bits(gb, 1); // self_contained_cvs_flag
 +    get_bits(gb, 1); // num_sps_ids_minus1
 +    num_sps_ids_minus1 = get_ue_golomb_long(gb); // num_sps_ids_minus1
 +
 +    if (num_sps_ids_minus1 < 0 || num_sps_ids_minus1 > 15) {
 +        av_log(s->avctx, AV_LOG_ERROR, "num_sps_ids_minus1 %d invalid\n", num_sps_ids_minus1);
 +        return AVERROR_INVALIDDATA;
 +    }
 +
 +    active_seq_parameter_set_id = get_ue_golomb_long(gb);
 +    if (active_seq_parameter_set_id >= MAX_SPS_COUNT) {
 +        av_log(s->avctx, AV_LOG_ERROR, "active_parameter_set_id %d invalid\n", active_seq_parameter_set_id);
 +        return AVERROR_INVALIDDATA;
 +    }
 +    s->active_seq_parameter_set_id = active_seq_parameter_set_id;
 +
 +    for (i = 1; i <= num_sps_ids_minus1; i++)
 +        get_ue_golomb_long(gb); // active_seq_parameter_set_id[i]
 +
 +    return 0;
 +}
 +
  static int decode_nal_sei_message(HEVCContext *s)
  {
 -    GetBitContext *gb = &s->HEVClc.gb;
 +    GetBitContext *gb = &s->HEVClc->gb;
  
      int payload_type = 0;
      int payload_size = 0;
@@@ -37,9 -38,10 +37,9 @@@ static av_always_inline void FUNC(intra
  #define MVF_PU(x, y) \
      MVF(PU(x0 + ((x) << hshift)), PU(y0 + ((y) << vshift)))
  #define IS_INTRA(x, y) \
 -    MVF_PU(x, y).is_intra
 +    (MVF_PU(x, y).pred_flag == PF_INTRA)
  #define MIN_TB_ADDR_ZS(x, y) \
-     s->pps->min_tb_addr_zs[(y) * (s->sps->tb_mask+2) + (x)]
 -    s->ps.pps->min_tb_addr_zs[(y) * s->ps.sps->min_tb_width + (x)]
 -
++    s->ps.pps->min_tb_addr_zs[(y) * (s->ps.sps->tb_mask+2) + (x)]
  #define EXTEND(ptr, val, len)         \
  do {                                  \
      pixel4 pix = PIXEL_SPLAT_X4(val); \
          AV_WN4P(ptr + i, pix);        \
  } while (0)
  
 +#define EXTEND_RIGHT_CIP(ptr, start, length)                                   \
 +        for (i = start; i < (start) + (length); i += 4)                        \
 +            if (!IS_INTRA(i, -1))                                              \
 +                AV_WN4P(&ptr[i], a);                                           \
 +            else                                                               \
 +                a = PIXEL_SPLAT_X4(ptr[i+3])
  #define EXTEND_LEFT_CIP(ptr, start, length) \
 -        for (i = (start); i > (start) - (length); i--) \
 +        for (i = start; i > (start) - (length); i--) \
              if (!IS_INTRA(i - 1, -1)) \
                  ptr[i - 1] = ptr[i]
 -#define EXTEND_RIGHT_CIP(ptr, start, length) \
 -        for (i = (start); i < (start) + (length); i++) \
 -            if (!IS_INTRA(i, -1)) \
 -                ptr[i] = ptr[i - 1]
 -#define EXTEND_UP_CIP(ptr, start, length) \
 -        for (i = (start); i > (start) - (length); i--) \
 -            if (!IS_INTRA(-1, i - 1)) \
 -                ptr[i - 1] = ptr[i]
 -#define EXTEND_UP_CIP_0(ptr, start, length) \
 -        for (i = (start); i > (start) - (length); i--) \
 -            ptr[i - 1] = ptr[i]
 -#define EXTEND_DOWN_CIP(ptr, start, length) \
 -        for (i = (start); i < (start) + (length); i++) \
 -            if (!IS_INTRA(-1, i)) \
 -                ptr[i] = ptr[i - 1]
 -    HEVCLocalContext *lc = &s->HEVClc;
 +#define EXTEND_UP_CIP(ptr, start, length)                                      \
 +        for (i = (start); i > (start) - (length); i -= 4)                      \
 +            if (!IS_INTRA(-1, i - 3))                                          \
 +                AV_WN4P(&ptr[i - 3], a);                                       \
 +            else                                                               \
 +                a = PIXEL_SPLAT_X4(ptr[i - 3])
 +#define EXTEND_DOWN_CIP(ptr, start, length)                                    \
 +        for (i = start; i < (start) + (length); i += 4)                        \
 +            if (!IS_INTRA(-1, i))                                              \
 +                AV_WN4P(&ptr[i], a);                                           \
 +            else                                                               \
 +                a = PIXEL_SPLAT_X4(ptr[i + 3])
 +
 +    HEVCLocalContext *lc = s->HEVClc;
      int i;
-     int hshift = s->sps->hshift[c_idx];
-     int vshift = s->sps->vshift[c_idx];
+     int hshift = s->ps.sps->hshift[c_idx];
+     int vshift = s->ps.sps->vshift[c_idx];
      int size = (1 << log2_size);
 -    int size_in_luma = size << hshift;
 -    int size_in_tbs = size_in_luma >> s->ps.sps->log2_min_tb_size;
 +    int size_in_luma_h = size << hshift;
-     int size_in_tbs_h  = size_in_luma_h >> s->sps->log2_min_tb_size;
++    int size_in_tbs_h  = size_in_luma_h >> s->ps.sps->log2_min_tb_size;
 +    int size_in_luma_v = size << vshift;
-     int size_in_tbs_v  = size_in_luma_v >> s->sps->log2_min_tb_size;
++    int size_in_tbs_v  = size_in_luma_v >> s->ps.sps->log2_min_tb_size;
      int x = x0 >> hshift;
      int y = y0 >> vshift;
-     int x_tb = (x0 >> s->sps->log2_min_tb_size) & s->sps->tb_mask;
-     int y_tb = (y0 >> s->sps->log2_min_tb_size) & s->sps->tb_mask;
 -    int x_tb = x0 >> s->ps.sps->log2_min_tb_size;
 -    int y_tb = y0 >> s->ps.sps->log2_min_tb_size;
++    int x_tb = (x0 >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask;
++    int y_tb = (y0 >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask;
 +
      int cur_tb_addr = MIN_TB_ADDR_ZS(x_tb, y_tb);
  
      ptrdiff_t stride = s->frame->linesize[c_idx] / sizeof(pixel);
      pixel *src = (pixel*)s->frame->data[c_idx] + x + y * stride;
  
-     int min_pu_width = s->sps->min_pu_width;
+     int min_pu_width = s->ps.sps->min_pu_width;
  
 -    enum IntraPredMode mode = c_idx ? lc->pu.intra_pred_mode_c :
 -                              lc->tu.cur_intra_pred_mode;
 -
 -    pixel left_array[2 * MAX_TB_SIZE + 1];
 -    pixel filtered_left_array[2 * MAX_TB_SIZE + 1];
 -    pixel top_array[2 * MAX_TB_SIZE + 1];
 -    pixel filtered_top_array[2 * MAX_TB_SIZE + 1];
 -
 -    pixel *left          = left_array + 1;
 -    pixel *top           = top_array  + 1;
 -    pixel *filtered_left = filtered_left_array + 1;
 -    pixel *filtered_top  = filtered_top_array  + 1;
 -
 -    int cand_bottom_left = lc->na.cand_bottom_left && cur_tb_addr > MIN_TB_ADDR_ZS(x_tb - 1, y_tb + size_in_tbs);
 +    enum IntraPredMode mode = c_idx ? lc->tu.intra_pred_mode_c :
 +                              lc->tu.intra_pred_mode;
 +    pixel4 a;
 +    pixel  left_array[2 * MAX_TB_SIZE + 1];
 +    pixel  filtered_left_array[2 * MAX_TB_SIZE + 1];
 +    pixel  top_array[2 * MAX_TB_SIZE + 1];
 +    pixel  filtered_top_array[2 * MAX_TB_SIZE + 1];
 +
 +    pixel  *left          = left_array + 1;
 +    pixel  *top           = top_array  + 1;
 +    pixel  *filtered_left = filtered_left_array + 1;
 +    pixel  *filtered_top  = filtered_top_array  + 1;
-     int cand_bottom_left = lc->na.cand_bottom_left && cur_tb_addr > MIN_TB_ADDR_ZS( x_tb - 1, (y_tb + size_in_tbs_v) & s->sps->tb_mask);
++    int cand_bottom_left = lc->na.cand_bottom_left && cur_tb_addr > MIN_TB_ADDR_ZS( x_tb - 1, (y_tb + size_in_tbs_v) & s->ps.sps->tb_mask);
      int cand_left        = lc->na.cand_left;
      int cand_up_left     = lc->na.cand_up_left;
      int cand_up          = lc->na.cand_up;
-     int cand_up_right    = lc->na.cand_up_right    && cur_tb_addr > MIN_TB_ADDR_ZS((x_tb + size_in_tbs_h) & s->sps->tb_mask, y_tb - 1);
 -    int cand_up_right    = lc->na.cand_up_right && cur_tb_addr > MIN_TB_ADDR_ZS(x_tb + size_in_tbs, y_tb - 1);
++    int cand_up_right    = lc->na.cand_up_right    && cur_tb_addr > MIN_TB_ADDR_ZS((x_tb + size_in_tbs_h) & s->ps.sps->tb_mask, y_tb - 1);
  
-     int bottom_left_size = (FFMIN(y0 + 2 * size_in_luma_v, s->sps->height) -
 -    int bottom_left_size = (FFMIN(y0 + 2 * size_in_luma, s->ps.sps->height) -
 -                            (y0 + size_in_luma)) >> vshift;
 -    int top_right_size   = (FFMIN(x0 + 2 * size_in_luma, s->ps.sps->width) -
 -                            (x0 + size_in_luma)) >> hshift;
++    int bottom_left_size = (FFMIN(y0 + 2 * size_in_luma_v, s->ps.sps->height) -
 +                           (y0 + size_in_luma_v)) >> vshift;
-     int top_right_size   = (FFMIN(x0 + 2 * size_in_luma_h, s->sps->width) -
++    int top_right_size   = (FFMIN(x0 + 2 * size_in_luma_h, s->ps.sps->width) -
 +                           (x0 + size_in_luma_h)) >> hshift;
  
-     if (s->pps->constrained_intra_pred_flag == 1) {
+     if (s->ps.pps->constrained_intra_pred_flag == 1) {
 -        int size_in_luma_pu = PU(size_in_luma);
 -        int on_pu_edge_x    = !(x0 & ((1 << s->ps.sps->log2_min_pu_size) - 1));
 -        int on_pu_edge_y    = !(y0 & ((1 << s->ps.sps->log2_min_pu_size) - 1));
 -        if (!size_in_luma_pu)
 -            size_in_luma_pu++;
 +        int size_in_luma_pu_v = PU(size_in_luma_v);
 +        int size_in_luma_pu_h = PU(size_in_luma_h);
-         int on_pu_edge_x    = !av_mod_uintp2(x0, s->sps->log2_min_pu_size);
-         int on_pu_edge_y    = !av_mod_uintp2(y0, s->sps->log2_min_pu_size);
++        int on_pu_edge_x    = !av_mod_uintp2(x0, s->ps.sps->log2_min_pu_size);
++        int on_pu_edge_y    = !av_mod_uintp2(y0, s->ps.sps->log2_min_pu_size);
 +        if (!size_in_luma_pu_h)
 +            size_in_luma_pu_h++;
          if (cand_bottom_left == 1 && on_pu_edge_x) {
              int x_left_pu   = PU(x0 - 1);
 -            int y_bottom_pu = PU(y0 + size_in_luma);
 -            int max = FFMIN(size_in_luma_pu, s->ps.sps->min_pu_height - y_bottom_pu);
 +            int y_bottom_pu = PU(y0 + size_in_luma_v);
-             int max = FFMIN(size_in_luma_pu_v, s->sps->min_pu_height - y_bottom_pu);
++            int max = FFMIN(size_in_luma_pu_v, s->ps.sps->min_pu_height - y_bottom_pu);
              cand_bottom_left = 0;
 -            for (i = 0; i < max; i++)
 -                cand_bottom_left |= MVF(x_left_pu, y_bottom_pu + i).is_intra;
 +            for (i = 0; i < max; i += 2)
 +                cand_bottom_left |= (MVF(x_left_pu, y_bottom_pu + i).pred_flag == PF_INTRA);
          }
          if (cand_left == 1 && on_pu_edge_x) {
              int x_left_pu   = PU(x0 - 1);
              int y_left_pu   = PU(y0);
-             int max = FFMIN(size_in_luma_pu_v, s->sps->min_pu_height - y_left_pu);
 -            int max = FFMIN(size_in_luma_pu, s->ps.sps->min_pu_height - y_left_pu);
++            int max = FFMIN(size_in_luma_pu_v, s->ps.sps->min_pu_height - y_left_pu);
              cand_left = 0;
 -            for (i = 0; i < max; i++)
 -                cand_left |= MVF(x_left_pu, y_left_pu + i).is_intra;
 +            for (i = 0; i < max; i += 2)
 +                cand_left |= (MVF(x_left_pu, y_left_pu + i).pred_flag == PF_INTRA);
          }
          if (cand_up_left == 1) {
              int x_left_pu   = PU(x0 - 1);
          if (cand_up == 1 && on_pu_edge_y) {
              int x_top_pu    = PU(x0);
              int y_top_pu    = PU(y0 - 1);
-             int max = FFMIN(size_in_luma_pu_h, s->sps->min_pu_width - x_top_pu);
 -            int max = FFMIN(size_in_luma_pu, s->ps.sps->min_pu_width - x_top_pu);
++            int max = FFMIN(size_in_luma_pu_h, s->ps.sps->min_pu_width - x_top_pu);
              cand_up = 0;
 -            for (i = 0; i < max; i++)
 -                cand_up |= MVF(x_top_pu + i, y_top_pu).is_intra;
 +            for (i = 0; i < max; i += 2)
 +                cand_up |= (MVF(x_top_pu + i, y_top_pu).pred_flag == PF_INTRA);
          }
          if (cand_up_right == 1 && on_pu_edge_y) {
              int y_top_pu    = PU(y0 - 1);
 -            int x_right_pu  = PU(x0 + size_in_luma);
 -            int max = FFMIN(size_in_luma_pu, s->ps.sps->min_pu_width - x_right_pu);
 +            int x_right_pu  = PU(x0 + size_in_luma_h);
-             int max = FFMIN(size_in_luma_pu_h, s->sps->min_pu_width - x_right_pu);
++            int max = FFMIN(size_in_luma_pu_h, s->ps.sps->min_pu_width - x_right_pu);
              cand_up_right = 0;
 -            for (i = 0; i < max; i++)
 -                cand_up_right |= MVF(x_right_pu + i, y_top_pu).is_intra;
 +            for (i = 0; i < max; i += 2)
 +                cand_up_right |= (MVF(x_right_pu + i, y_top_pu).pred_flag == PF_INTRA);
          }
 -        for (i = 0; i < 2 * MAX_TB_SIZE; i++) {
 -            left[i] = 128;
 -            top[i]  = 128;
 -        }
 -    }
 -    if (cand_bottom_left) {
 -        for (i = size; i < size + bottom_left_size; i++)
 -            left[i] = POS(-1, i);
 -        EXTEND(left + size + bottom_left_size, POS(-1, size + bottom_left_size - 1),
 -               size - bottom_left_size);
 +        memset(left, 128, 2 * MAX_TB_SIZE*sizeof(pixel));
 +        memset(top , 128, 2 * MAX_TB_SIZE*sizeof(pixel));
 +        top[-1] = 128;
      }
 -    if (cand_left)
 -        for (i = size - 1; i >= 0; i--)
 -            left[i] = POS(-1, i);
      if (cand_up_left) {
          left[-1] = POS(-1, -1);
          top[-1]  = left[-1];
          EXTEND(top + size + top_right_size, POS(size + top_right_size - 1, -1),
                 size - top_right_size);
      }
 +    if (cand_left)
 +        for (i = 0; i < size; i++)
 +            left[i] = POS(-1, i);
 +    if (cand_bottom_left) {
 +        for (i = size; i < size + bottom_left_size; i++)
 +            left[i] = POS(-1, i);
 +        EXTEND(left + size + bottom_left_size, POS(-1, size + bottom_left_size - 1),
 +               size - bottom_left_size);
 +    }
  
-     if (s->pps->constrained_intra_pred_flag == 1) {
+     if (s->ps.pps->constrained_intra_pred_flag == 1) {
          if (cand_bottom_left || cand_left || cand_up_left || cand_up || cand_up_right) {
-             int size_max_x = x0 + ((2 * size) << hshift) < s->sps->width ?
-                                     2 * size : (s->sps->width - x0) >> hshift;
-             int size_max_y = y0 + ((2 * size) << vshift) < s->sps->height ?
-                                     2 * size : (s->sps->height - y0) >> vshift;
+             int size_max_x = x0 + ((2 * size) << hshift) < s->ps.sps->width ?
+                                     2 * size : (s->ps.sps->width - x0) >> hshift;
+             int size_max_y = y0 + ((2 * size) << vshift) < s->ps.sps->height ?
+                                     2 * size : (s->ps.sps->height - y0) >> vshift;
              int j = size + (cand_bottom_left? bottom_left_size: 0) -1;
              if (!cand_up_right) {
-                 size_max_x = x0 + ((size) << hshift) < s->sps->width ?
-                                                     size : (s->sps->width - x0) >> hshift;
+                 size_max_x = x0 + ((size) << hshift) < s->ps.sps->width ?
+                                                     size : (s->ps.sps->width - x0) >> hshift;
              }
              if (!cand_bottom_left) {
-                 size_max_y = y0 + (( size) << vshift) < s->sps->height ?
-                                                      size : (s->sps->height - y0) >> vshift;
+                 size_max_y = y0 + (( size) << vshift) < s->ps.sps->height ?
+                                                      size : (s->ps.sps->height - y0) >> vshift;
              }
              if (cand_bottom_left || cand_left || cand_up_left) {
                  while (j > -1 && !IS_INTRA(-1, j))
      top[-1] = left[-1];
  
      // Filtering process
-     if (!s->sps->intra_smoothing_disabled_flag && (c_idx == 0  || s->sps->chroma_format_idc == 3)) {
 -    if (c_idx == 0 && mode != INTRA_DC && size != 4) {
 -        int intra_hor_ver_dist_thresh[] = { 7, 1, 0 };
 -        int min_dist_vert_hor = FFMIN(FFABS((int)mode - 26),
 -                                      FFABS((int)mode - 10));
 -        if (min_dist_vert_hor > intra_hor_ver_dist_thresh[log2_size - 3]) {
 -            int threshold = 1 << (BIT_DEPTH - 5);
 -            if (s->ps.sps->sps_strong_intra_smoothing_enable_flag &&
 -                log2_size == 5 &&
 -                FFABS(top[-1]  + top[63]  - 2 * top[31])  < threshold &&
 -                FFABS(left[-1] + left[63] - 2 * left[31]) < threshold) {
 -                // We can't just overwrite values in top because it could be
 -                // a pointer into src
 -                filtered_top[-1] = top[-1];
 -                filtered_top[63] = top[63];
 -                for (i = 0; i < 63; i++)
 -                    filtered_top[i] = ((64 - (i + 1)) * top[-1] +
 -                                             (i + 1)  * top[63] + 32) >> 6;
 -                for (i = 0; i < 63; i++)
 -                    left[i] = ((64 - (i + 1)) * left[-1] +
 -                                     (i + 1)  * left[63] + 32) >> 6;
 -                top = filtered_top;
 -            } else {
 -                filtered_left[2 * size - 1] = left[2 * size - 1];
 -                filtered_top[2 * size - 1]  = top[2 * size - 1];
 -                for (i = 2 * size - 2; i >= 0; i--)
 -                    filtered_left[i] = (left[i + 1] + 2 * left[i] +
 -                                        left[i - 1] + 2) >> 2;
 -                filtered_top[-1]  =
 -                filtered_left[-1] = (left[0] + 2 * left[-1] + top[0] + 2) >> 2;
 -                for (i = 2 * size - 2; i >= 0; i--)
 -                    filtered_top[i] = (top[i + 1] + 2 * top[i] +
 -                                       top[i - 1] + 2) >> 2;
 -                left = filtered_left;
 -                top  = filtered_top;
++    if (!s->ps.sps->intra_smoothing_disabled_flag && (c_idx == 0  || s->ps.sps->chroma_format_idc == 3)) {
 +        if (mode != INTRA_DC && size != 4){
 +            int intra_hor_ver_dist_thresh[] = { 7, 1, 0 };
 +            int min_dist_vert_hor = FFMIN(FFABS((int)(mode - 26U)),
 +                                          FFABS((int)(mode - 10U)));
 +            if (min_dist_vert_hor > intra_hor_ver_dist_thresh[log2_size - 3]) {
 +                int threshold = 1 << (BIT_DEPTH - 5);
-                 if (s->sps->sps_strong_intra_smoothing_enable_flag && c_idx == 0 &&
++                if (s->ps.sps->sps_strong_intra_smoothing_enable_flag && c_idx == 0 &&
 +                    log2_size == 5 &&
 +                    FFABS(top[-1]  + top[63]  - 2 * top[31])  < threshold &&
 +                    FFABS(left[-1] + left[63] - 2 * left[31]) < threshold) {
 +                    // We can't just overwrite values in top because it could be
 +                    // a pointer into src
 +                    filtered_top[-1] = top[-1];
 +                    filtered_top[63] = top[63];
 +                    for (i = 0; i < 63; i++)
 +                        filtered_top[i] = ((64 - (i + 1)) * top[-1] +
 +                                           (i + 1)  * top[63] + 32) >> 6;
 +                    for (i = 0; i < 63; i++)
 +                        left[i] = ((64 - (i + 1)) * left[-1] +
 +                                   (i + 1)  * left[63] + 32) >> 6;
 +                    top = filtered_top;
 +                } else {
 +                    filtered_left[2 * size - 1] = left[2 * size - 1];
 +                    filtered_top[2 * size - 1]  = top[2 * size - 1];
 +                    for (i = 2 * size - 2; i >= 0; i--)
 +                        filtered_left[i] = (left[i + 1] + 2 * left[i] +
 +                                            left[i - 1] + 2) >> 2;
 +                    filtered_top[-1]  =
 +                    filtered_left[-1] = (left[0] + 2 * left[-1] + top[0] + 2) >> 2;
 +                    for (i = 2 * size - 2; i >= 0; i--)
 +                        filtered_top[i] = (top[i + 1] + 2 * top[i] +
 +                                           top[i - 1] + 2) >> 2;
 +                    left = filtered_left;
 +                    top  = filtered_top;
 +                }
              }
          }
      }