Commit 8b1298f9a6 for ffmpeg

commit 8b1298f9a6dc173344a5157003fae8f8dc7737e5
Author: YoungSoo Lee <youngsoo.lee@navercorp.com>
Date:   Fri Aug 21 10:46:48 2026 +0900

    lavc/hevc: read slice-scoped state through the local context

    The decoding path reads the slice header, the reference lists and the
    collocated reference straight from HEVCContext, which holds one of each per
    frame. Decoding tiles in an order other than the parse order would make them
    observe values belonging to another slice.

    Point the local context at the slice it decodes and read those three through
    it, so that a picture whose tiles carry separate slices can be decoded
    interleaved. The values are bound where a slice starts, which for now is
    always the slice that was just parsed, so there is no functional change.

    Signed-off-by: YoungSoo Lee <youngsoo.lee@navercorp.com>

diff --git a/libavcodec/hevc/cabac.c b/libavcodec/hevc/cabac.c
index 5b53815630..fa4c7ebf86 100644
--- a/libavcodec/hevc/cabac.c
+++ b/libavcodec/hevc/cabac.c
@@ -429,17 +429,17 @@ static int cabac_reinit(HEVCLocalContext *lc)

 static void cabac_init_state(HEVCLocalContext *lc, const HEVCContext *s)
 {
-    int init_type = 2 - s->sh.slice_type;
+    int init_type = 2 - lc->sh->slice_type;
     int i;

-    if (s->sh.cabac_init_flag && s->sh.slice_type != HEVC_SLICE_I)
+    if (lc->sh->cabac_init_flag && lc->sh->slice_type != HEVC_SLICE_I)
         init_type ^= 3;

     for (i = 0; i < HEVC_CONTEXTS; i++) {
         int init_value = init_values[init_type][i];
         int m = (init_value >> 4) * 5 - 45;
         int n = ((init_value & 15) << 3) - 16;
-        int pre = 2 * (((m * av_clip(s->sh.slice_qp, 0, 51)) >> 4) + n) - 127;
+        int pre = 2 * (((m * av_clip(lc->sh->slice_qp, 0, 51)) >> 4) + n) - 127;

         pre ^= pre >> 31;
         if (pre > 124)
@@ -476,24 +476,24 @@ int ff_hevc_cabac_init(HEVCLocalContext *lc, const HEVCPPS *pps,
     const HEVCSPS   *const sps = pps->sps;
     HEVCSubstream *const sub = &lc->sub;

-    if (ctb_addr_ts == pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs]) {
+    if (ctb_addr_ts == pps->ctb_addr_rs_to_ts[lc->sh->slice_ctb_addr_rs]) {
         /* First CTB of a slice segment. For a dependent slice segment the
          * data still belongs to the new segment. */
         int ret = ff_init_cabac_decoder(&sub->cc, sub->data, sub->size);
         if (ret < 0)
             return ret;
         sub->opened = 1;
-        if (s->sh.dependent_slice_segment_flag == 0 ||
+        if (lc->sh->dependent_slice_segment_flag == 0 ||
             (pps->tiles_enabled_flag &&
              pps->tile_id[ctb_addr_ts] != pps->tile_id[ctb_addr_ts - 1]))
             cabac_init_state(lc, s);

-        if (!s->sh.first_slice_in_pic_flag &&
+        if (!lc->sh->first_slice_in_pic_flag &&
             pps->entropy_coding_sync_enabled_flag) {
             if (ctb_addr_ts % sps->ctb_width == 0) {
                 if (sps->ctb_width == 1)
                     cabac_init_state(lc, s);
-                else if (s->sh.dependent_slice_segment_flag == 1)
+                else if (lc->sh->dependent_slice_segment_flag == 1)
                     load_states(lc, sps);
             }
         }
@@ -752,7 +752,7 @@ int ff_hevc_merge_idx_decode(HEVCLocalContext *lc)
     int i = GET_CABAC(MERGE_IDX_OFFSET);

     if (i != 0) {
-        while (i < lc->parent->sh.max_num_merge_cand-1 && get_cabac_bypass(&lc->sub.cc))
+        while (i < lc->sh->max_num_merge_cand-1 && get_cabac_bypass(&lc->sub.cc))
             i++;
     }
     return i;
@@ -1146,10 +1146,10 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps,
             int qp_i, offset;

             if (c_idx == 1)
-                offset = pps->cb_qp_offset + s->sh.slice_cb_qp_offset +
+                offset = pps->cb_qp_offset + lc->sh->slice_cb_qp_offset +
                          lc->sub.cu_qp_offset_cb;
             else
-                offset = pps->cr_qp_offset + s->sh.slice_cr_qp_offset +
+                offset = pps->cr_qp_offset + lc->sh->slice_cr_qp_offset +
                          lc->sub.cu_qp_offset_cr;

             qp_i = av_clip(qp_y + offset, - sps->qp_bd_offset, 57);
diff --git a/libavcodec/hevc/filter.c b/libavcodec/hevc/filter.c
index 1769014602..2042a583b1 100644
--- a/libavcodec/hevc/filter.c
+++ b/libavcodec/hevc/filter.c
@@ -96,7 +96,7 @@ static int get_qPy_pred(HEVCLocalContext *lc, const HEVCContext *s,
     // qPy_pred
     if (lc->sub.first_qp_group || (!xQgBase && !yQgBase)) {
         lc->sub.first_qp_group = !lc->tu.is_cu_qp_delta_coded;
-        qPy_pred = s->sh.slice_qp;
+        qPy_pred = lc->sh->slice_qp;
     } else {
         qPy_pred = lc->sub.qPy_pred;
     }
@@ -693,13 +693,16 @@ static av_always_inline int mvf_run_equal(const MvField *a, const MvField *b, in
     }
 }

-static int boundary_strength(const HEVCContext *s, const MvField *curr, const MvField *neigh,
+/* rpl is the reference list of the slice curr belongs to, neigh_refPicList
+ * the one of the neighbour. */
+static int boundary_strength(const RefPicList *rpl,
+                             const MvField *curr, const MvField *neigh,
                              const RefPicList *neigh_refPicList)
 {
     if (curr->pred_flag == PF_BI &&  neigh->pred_flag == PF_BI) {
         // same L0 and L1
-        if (s->cur_frame->refPicList[0].list[curr->ref_idx[0]] == neigh_refPicList[0].list[neigh->ref_idx[0]]  &&
-            s->cur_frame->refPicList[0].list[curr->ref_idx[0]] == s->cur_frame->refPicList[1].list[curr->ref_idx[1]] &&
+        if (rpl[0].list[curr->ref_idx[0]] == neigh_refPicList[0].list[neigh->ref_idx[0]]  &&
+            rpl[0].list[curr->ref_idx[0]] == rpl[1].list[curr->ref_idx[1]] &&
             neigh_refPicList[0].list[neigh->ref_idx[0]] == neigh_refPicList[1].list[neigh->ref_idx[1]]) {
             if ((FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
                  FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 4) &&
@@ -708,15 +711,15 @@ static int boundary_strength(const HEVCContext *s, const MvField *curr, const Mv
                 return 1;
             else
                 return 0;
-        } else if (neigh_refPicList[0].list[neigh->ref_idx[0]] == s->cur_frame->refPicList[0].list[curr->ref_idx[0]] &&
-                   neigh_refPicList[1].list[neigh->ref_idx[1]] == s->cur_frame->refPicList[1].list[curr->ref_idx[1]]) {
+        } else if (neigh_refPicList[0].list[neigh->ref_idx[0]] == rpl[0].list[curr->ref_idx[0]] &&
+                   neigh_refPicList[1].list[neigh->ref_idx[1]] == rpl[1].list[curr->ref_idx[1]]) {
             if (FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
                 FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 4)
                 return 1;
             else
                 return 0;
-        } else if (neigh_refPicList[1].list[neigh->ref_idx[1]] == s->cur_frame->refPicList[0].list[curr->ref_idx[0]] &&
-                   neigh_refPicList[0].list[neigh->ref_idx[0]] == s->cur_frame->refPicList[1].list[curr->ref_idx[1]]) {
+        } else if (neigh_refPicList[1].list[neigh->ref_idx[1]] == rpl[0].list[curr->ref_idx[0]] &&
+                   neigh_refPicList[0].list[neigh->ref_idx[0]] == rpl[1].list[curr->ref_idx[1]]) {
             if (FFABS(neigh->mv[1].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 4 ||
                 FFABS(neigh->mv[0].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[1].y) >= 4)
                 return 1;
@@ -731,10 +734,10 @@ static int boundary_strength(const HEVCContext *s, const MvField *curr, const Mv

         if (curr->pred_flag & 1) {
             A     = curr->mv[0];
-            ref_A = s->cur_frame->refPicList[0].list[curr->ref_idx[0]];
+            ref_A = rpl[0].list[curr->ref_idx[0]];
         } else {
             A     = curr->mv[1];
-            ref_A = s->cur_frame->refPicList[1].list[curr->ref_idx[1]];
+            ref_A = rpl[1].list[curr->ref_idx[1]];
         }

         if (neigh->pred_flag & 1) {
@@ -775,7 +778,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayer

     boundary_upper = y0 > 0 && !(y0 & 7);
     if (boundary_upper &&
-        ((!s->sh.slice_loop_filter_across_slices_enabled_flag &&
+        ((!lc->sh->slice_loop_filter_across_slices_enabled_flag &&
           lc->boundary_flags & BOUNDARY_UPPER_SLICE &&
           (y0 % (1 << sps->log2_ctb_size)) == 0) ||
          ((!pps->loop_filter_across_tiles_enabled_flag || lc->tile_bs_defer) &&
@@ -786,8 +789,8 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayer
     if (boundary_upper) {
         const RefPicList *rpl_top = (lc->boundary_flags & BOUNDARY_UPPER_SLICE) ?
                                     ff_hevc_get_ref_list(s->cur_frame, x0, y0 - 1) :
-                                    s->cur_frame->refPicList;
-        int same_rpl = rpl_top == s->cur_frame->refPicList;
+                                    lc->rpl;
+        int same_rpl = rpl_top == lc->rpl;
         int yp_pu = (y0 - 1) >> log2_min_pu_size;
         int yq_pu =  y0      >> log2_min_pu_size;
         int yp_tu = (y0 - 1) >> log2_min_tu_size;
@@ -808,7 +811,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayer
                 else if (same_rpl && mvf_equal(curr, top))
                     bs = 0;
                 else
-                    bs = boundary_strength(s, curr, top, rpl_top);
+                    bs = boundary_strength(lc->rpl, curr, top, rpl_top);
                 l->horizontal_bs[((x0 + i) + y0 * l->bs_width) >> 2] = bs;
             }
     }
@@ -816,7 +819,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayer
     // bs for vertical TU boundaries
     boundary_left = x0 > 0 && !(x0 & 7);
     if (boundary_left &&
-        ((!s->sh.slice_loop_filter_across_slices_enabled_flag &&
+        ((!lc->sh->slice_loop_filter_across_slices_enabled_flag &&
           lc->boundary_flags & BOUNDARY_LEFT_SLICE &&
           (x0 % (1 << sps->log2_ctb_size)) == 0) ||
          ((!pps->loop_filter_across_tiles_enabled_flag || lc->tile_bs_defer) &&
@@ -827,8 +830,8 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayer
     if (boundary_left) {
         const RefPicList *rpl_left = (lc->boundary_flags & BOUNDARY_LEFT_SLICE) ?
                                      ff_hevc_get_ref_list(s->cur_frame, x0 - 1, y0) :
-                                     s->cur_frame->refPicList;
-        int same_rpl = rpl_left == s->cur_frame->refPicList;
+                                     lc->rpl;
+        int same_rpl = rpl_left == lc->rpl;
         int xp_pu = (x0 - 1) >> log2_min_pu_size;
         int xq_pu =  x0      >> log2_min_pu_size;
         int xp_tu = (x0 - 1) >> log2_min_tu_size;
@@ -849,13 +852,13 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayer
                 else if (same_rpl && mvf_equal(curr, left))
                     bs = 0;
                 else
-                    bs = boundary_strength(s, curr, left, rpl_left);
+                    bs = boundary_strength(lc->rpl, curr, left, rpl_left);
                 l->vertical_bs[(x0 + (y0 + i) * l->bs_width) >> 2] = bs;
             }
     }

     if (log2_trafo_size > log2_min_pu_size && !is_intra) {
-        const RefPicList *rpl = s->cur_frame->refPicList;
+        const RefPicList *rpl = lc->rpl;

         // whole edge lines can be tested at once when there is one MvField entry per 4px segment
         if (log2_min_pu_size == 2 && log2_trafo_size >= 4 && log2_trafo_size <= 6) {
@@ -873,7 +876,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayer
                     memset(bs_h, 0, n);
                 } else {
                     for (i = 0; i < n; i++)
-                        bs_h[i] = mvf_equal(&curr[i], &top[i]) ? 0 : boundary_strength(s, &curr[i], &top[i], rpl);
+                        bs_h[i] = mvf_equal(&curr[i], &top[i]) ? 0 : boundary_strength(rpl, &curr[i], &top[i], rpl);
                 }
             }

@@ -889,7 +892,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayer
                         bs_v[i] = 0;
                 } else {
                     for (i = 2; i < n; i += 2)
-                        bs_v[i] = mvf_equal(&row[i], &row[i - 1]) ? 0 : boundary_strength(s, &row[i], &row[i - 1], rpl);
+                        bs_v[i] = mvf_equal(&row[i], &row[i - 1]) ? 0 : boundary_strength(rpl, &row[i], &row[i - 1], rpl);
                 }
             }
             return;
@@ -905,7 +908,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayer
                 const MvField *top  = &tab_mvf[yp_pu * min_pu_width + x_pu];
                 const MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu];

-                bs = mvf_equal(curr, top) ? 0 : boundary_strength(s, curr, top, rpl);
+                bs = mvf_equal(curr, top) ? 0 : boundary_strength(rpl, curr, top, rpl);
                 l->horizontal_bs[((x0 + i) + (y0 + j) * l->bs_width) >> 2] = bs;
             }
         }
@@ -920,7 +923,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayer
                 const MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu];
                 const MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu];

-                bs = mvf_equal(curr, left) ? 0 : boundary_strength(s, curr, left, rpl);
+                bs = mvf_equal(curr, left) ? 0 : boundary_strength(rpl, curr, left, rpl);
                 l->vertical_bs[((x0 + i) + (y0 + j) * l->bs_width) >> 2] = bs;
             }
         }
@@ -943,7 +946,7 @@ void ff_hevc_tile_boundary_bs(HEVCLocalContext *lc, const HEVCLayerContext *l,
     if ((lc->boundary_flags & BOUNDARY_UPPER_TILE) && y0 > 0) {
         const RefPicList *rpl_top = (lc->boundary_flags & BOUNDARY_UPPER_SLICE) ?
                                     ff_hevc_get_ref_list(s->cur_frame, x0, y0 - 1) :
-                                    s->cur_frame->refPicList;
+                                    lc->rpl;
         int yp_pu = (y0 - 1) >> log2_min_pu_size, yq_pu = y0 >> log2_min_pu_size;
         int yp_tu = (y0 - 1) >> log2_min_tu_size, yq_tu = y0 >> log2_min_tu_size;
         int len = FFMIN(ctb_size, sps->width - x0);
@@ -959,7 +962,7 @@ void ff_hevc_tile_boundary_bs(HEVCLocalContext *lc, const HEVCLayerContext *l,
             else if (curr_cbf || top_cbf)
                 bs = 1;
             else
-                bs = boundary_strength(s, curr, top, rpl_top);
+                bs = boundary_strength(lc->rpl, curr, top, rpl_top);
             l->horizontal_bs[((x0 + i) + y0 * l->bs_width) >> 2] = bs;
         }
     }
@@ -967,7 +970,7 @@ void ff_hevc_tile_boundary_bs(HEVCLocalContext *lc, const HEVCLayerContext *l,
     if ((lc->boundary_flags & BOUNDARY_LEFT_TILE) && x0 > 0) {
         const RefPicList *rpl_left = (lc->boundary_flags & BOUNDARY_LEFT_SLICE) ?
                                      ff_hevc_get_ref_list(s->cur_frame, x0 - 1, y0) :
-                                     s->cur_frame->refPicList;
+                                     lc->rpl;
         int xp_pu = (x0 - 1) >> log2_min_pu_size, xq_pu = x0 >> log2_min_pu_size;
         int xp_tu = (x0 - 1) >> log2_min_tu_size, xq_tu = x0 >> log2_min_tu_size;
         int len = FFMIN(ctb_size, sps->height - y0);
@@ -983,7 +986,7 @@ void ff_hevc_tile_boundary_bs(HEVCLocalContext *lc, const HEVCLayerContext *l,
             else if (curr_cbf || left_cbf)
                 bs = 1;
             else
-                bs = boundary_strength(s, curr, left, rpl_left);
+                bs = boundary_strength(lc->rpl, curr, left, rpl_left);
             l->vertical_bs[(x0 + (y0 + i) * l->bs_width) >> 2] = bs;
         }
     }
@@ -1004,9 +1007,9 @@ void ff_hevc_hls_filter(HEVCLocalContext *lc, const HEVCLayerContext *l,
     if (s->avctx->skip_loop_filter >= AVDISCARD_ALL ||
         (s->avctx->skip_loop_filter >= AVDISCARD_NONKEY && !IS_IDR(s)) ||
         (s->avctx->skip_loop_filter >= AVDISCARD_NONINTRA &&
-         s->sh.slice_type != HEVC_SLICE_I) ||
+         lc->sh->slice_type != HEVC_SLICE_I) ||
         (s->avctx->skip_loop_filter >= AVDISCARD_BIDIR &&
-         s->sh.slice_type == HEVC_SLICE_B) ||
+         lc->sh->slice_type == HEVC_SLICE_B) ||
         (s->avctx->skip_loop_filter >= AVDISCARD_NONREF &&
         ff_hevc_nal_is_nonref(s->nal_unit_type)))
         skip = 1;
diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
index 7680cd4154..90c903d0c6 100644
--- a/libavcodec/hevc/hevcdec.c
+++ b/libavcodec/hevc/hevcdec.c
@@ -1239,14 +1239,13 @@ static void hls_sao_param(HEVCLocalContext *lc, const HEVCLayerContext *l,
                           const HEVCPPS *pps, const HEVCSPS *sps,
                           int rx, int ry)
 {
-    const HEVCContext *const s = lc->parent;
     int sao_merge_left_flag = 0;
     int sao_merge_up_flag   = 0;
     SAOParams *sao          = &CTB(l->sao, rx, ry);
     int c_idx, i;

-    if (s->sh.slice_sample_adaptive_offset_flag[0] ||
-        s->sh.slice_sample_adaptive_offset_flag[1]) {
+    if (lc->sh->slice_sample_adaptive_offset_flag[0] ||
+        lc->sh->slice_sample_adaptive_offset_flag[1]) {
         if (rx > 0) {
             if (lc->ctb_left_flag)
                 sao_merge_left_flag = ff_hevc_sao_merge_flag_decode(lc);
@@ -1261,7 +1260,7 @@ static void hls_sao_param(HEVCLocalContext *lc, const HEVCLayerContext *l,
         int log2_sao_offset_scale = c_idx == 0 ? pps->log2_sao_offset_scale_luma :
                                                  pps->log2_sao_offset_scale_chroma;

-        if (!s->sh.slice_sample_adaptive_offset_flag[c_idx]) {
+        if (!lc->sh->slice_sample_adaptive_offset_flag[c_idx]) {
             sao->type_idx[c_idx] = SAO_NOT_APPLIED;
             continue;
         }
@@ -1375,7 +1374,7 @@ static int hls_transform_unit(HEVCLocalContext *lc,
             ff_hevc_set_qPy(lc, l, pps, cb_xBase, cb_yBase, log2_cb_size);
         }

-        if (s->sh.cu_chroma_qp_offset_enabled_flag && cbf_chroma &&
+        if (lc->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(lc);
             if (cu_chroma_qp_offset_flag) {
@@ -1564,7 +1563,6 @@ static int hls_transform_tree(HEVCLocalContext *lc,
                               int trafo_depth, int blk_idx,
                               const int *base_cbf_cb, const int *base_cbf_cr)
 {
-    const HEVCContext *const s = lc->parent;
     uint8_t split_transform_flag;
     int cbf_cb[2];
     int cbf_cr[2];
@@ -1673,7 +1671,7 @@ do {
                     l->cbf_luma[y_tu * min_tu_width + x_tu] = 1;
                 }
         }
-        if (!s->sh.disable_deblocking_filter_flag) {
+        if (!lc->sh->disable_deblocking_filter_flag) {
             ff_hevc_deblocking_boundary_strengths(lc, l, pps, x0, y0, log2_trafo_size);
             if (pps->transquant_bypass_enable_flag &&
                 lc->cu.cu_transquant_bypass_flag)
@@ -1700,7 +1698,7 @@ static int hls_pcm_sample(HEVCLocalContext *lc, const HEVCLayerContext *l,
     const uint8_t *pcm = skip_bytes(&lc->sub.cc, (length + 7) >> 3);
     int ret;

-    if (!s->sh.disable_deblocking_filter_flag)
+    if (!lc->sh->disable_deblocking_filter_flag)
         ff_hevc_deblocking_boundary_strengths(lc, l, pps, x0, y0, log2_cb_size);

     ret = init_get_bits(&gb, pcm, length);
@@ -1756,8 +1754,8 @@ static void luma_mc_uni(HEVCLocalContext *lc,
     int pic_height       = sps->height;
     int mx               = mv->x & 3;
     int my               = mv->y & 3;
-    int weight_flag      = (s->sh.slice_type == HEVC_SLICE_P && pps->weighted_pred_flag) ||
-                           (s->sh.slice_type == HEVC_SLICE_B && pps->weighted_bipred_flag);
+    int weight_flag      = (lc->sh->slice_type == HEVC_SLICE_P && pps->weighted_pred_flag) ||
+                           (lc->sh->slice_type == HEVC_SLICE_B && pps->weighted_bipred_flag);
     int idx              = hevc_pel_weight[block_w];

     x_off += mv->x >> 2;
@@ -1787,7 +1785,7 @@ static void luma_mc_uni(HEVCLocalContext *lc,
                                                       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,
+                                                        block_h, lc->sh->luma_log2_weight_denom,
                                                         luma_weight, luma_offset, mx, my, block_w);
 }

@@ -1823,8 +1821,8 @@ static void luma_mc_bi(HEVCLocalContext *lc,
     int my0              = mv0->y & 3;
     int mx1              = mv1->x & 3;
     int my1              = mv1->y & 3;
-    int weight_flag      = (s->sh.slice_type == HEVC_SLICE_P && pps->weighted_pred_flag) ||
-                           (s->sh.slice_type == HEVC_SLICE_B && pps->weighted_bipred_flag);
+    int weight_flag      = (lc->sh->slice_type == HEVC_SLICE_P && pps->weighted_pred_flag) ||
+                           (lc->sh->slice_type == HEVC_SLICE_B && 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);
@@ -1875,11 +1873,11 @@ static void luma_mc_bi(HEVCLocalContext *lc,
                                                        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]],
+                                                         block_h, lc->sh->luma_log2_weight_denom,
+                                                         lc->sh->luma_weight_l0[current_mv->ref_idx[0]],
+                                                         lc->sh->luma_weight_l1[current_mv->ref_idx[1]],
+                                                         lc->sh->luma_offset_l0[current_mv->ref_idx[0]] +
+                                                         lc->sh->luma_offset_l1[current_mv->ref_idx[1]],
                                                          mx1, my1, block_w);

 }
@@ -1912,8 +1910,8 @@ static void chroma_mc_uni(HEVCLocalContext *lc,
     int pic_width        = sps->width >> sps->hshift[1];
     int pic_height       = sps->height >> sps->vshift[1];
     const Mv *mv         = &current_mv->mv[reflist];
-    int weight_flag      = (s->sh.slice_type == HEVC_SLICE_P && pps->weighted_pred_flag) ||
-                           (s->sh.slice_type == HEVC_SLICE_B && pps->weighted_bipred_flag);
+    int weight_flag      = (lc->sh->slice_type == HEVC_SLICE_P && pps->weighted_pred_flag) ||
+                           (lc->sh->slice_type == HEVC_SLICE_B && pps->weighted_bipred_flag);
     int idx              = hevc_pel_weight[block_w];
     int hshift           = sps->hshift[1];
     int vshift           = sps->vshift[1];
@@ -1950,7 +1948,7 @@ static void chroma_mc_uni(HEVCLocalContext *lc,
                                                   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,
+                                                        block_h, lc->sh->chroma_log2_weight_denom,
                                                         chroma_weight, chroma_offset, _mx, _my, block_w);
 }

@@ -1982,8 +1980,8 @@ static void chroma_mc_bi(HEVCLocalContext *lc,
     const 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 == HEVC_SLICE_P && pps->weighted_pred_flag) ||
-                           (s->sh.slice_type == HEVC_SLICE_B && pps->weighted_bipred_flag);
+    int weight_flag      = (lc->sh->slice_type == HEVC_SLICE_P && pps->weighted_pred_flag) ||
+                           (lc->sh->slice_type == HEVC_SLICE_B && pps->weighted_bipred_flag);
     int pic_width        = sps->width >> sps->hshift[1];
     int pic_height       = sps->height >> sps->vshift[1];
     const Mv *const mv0  = &current_mv->mv[0];
@@ -2056,11 +2054,11 @@ static void chroma_mc_bi(HEVCLocalContext *lc,
         s->hevcdsp.put_hevc_epel_bi_w[idx][!!my1][!!mx1](dst0, s->cur_frame->f->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],
+                                                         lc->sh->chroma_log2_weight_denom,
+                                                         lc->sh->chroma_weight_l0[current_mv->ref_idx[0]][cidx],
+                                                         lc->sh->chroma_weight_l1[current_mv->ref_idx[1]][cidx],
+                                                         lc->sh->chroma_offset_l0[current_mv->ref_idx[0]][cidx] +
+                                                         lc->sh->chroma_offset_l1[current_mv->ref_idx[1]][cidx],
                                                          _mx1, _my1, block_w);
 }

@@ -2080,18 +2078,17 @@ static void hevc_luma_mv_mvp_mode(HEVCLocalContext *lc,
                                   int nPbH, int log2_cb_size, int part_idx,
                                   int merge_idx, MvField *mv)
 {
-    const HEVCContext *const s = lc->parent;
     enum InterPredIdc inter_pred_idc = PRED_L0;
     int mvp_flag;

     ff_hevc_set_neighbour_available(lc, x0, y0, nPbW, nPbH, sps->log2_ctb_size);
     mv->pred_flag = 0;
-    if (s->sh.slice_type == HEVC_SLICE_B)
+    if (lc->sh->slice_type == HEVC_SLICE_B)
         inter_pred_idc = ff_hevc_inter_pred_idc_decode(lc, nPbW, nPbH);

     if (inter_pred_idc != PRED_L1) {
-        if (s->sh.nb_refs[L0])
-            mv->ref_idx[0]= ff_hevc_ref_idx_lx_decode(lc, s->sh.nb_refs[L0]);
+        if (lc->sh->nb_refs[L0])
+            mv->ref_idx[0]= ff_hevc_ref_idx_lx_decode(lc, lc->sh->nb_refs[L0]);

         mv->pred_flag = PF_L0;
         ff_hevc_hls_mvd_coding(lc, x0, y0, 0);
@@ -2103,10 +2100,10 @@ static void hevc_luma_mv_mvp_mode(HEVCLocalContext *lc,
     }

     if (inter_pred_idc != PRED_L0) {
-        if (s->sh.nb_refs[L1])
-            mv->ref_idx[1]= ff_hevc_ref_idx_lx_decode(lc, s->sh.nb_refs[L1]);
+        if (lc->sh->nb_refs[L1])
+            mv->ref_idx[1]= ff_hevc_ref_idx_lx_decode(lc, lc->sh->nb_refs[L1]);

-        if (s->sh.mvd_l1_zero_flag == 1 && inter_pred_idc == PRED_BI) {
+        if (lc->sh->mvd_l1_zero_flag == 1 && inter_pred_idc == PRED_BI) {
             AV_ZERO32(&lc->pu.mvd);
         } else {
             ff_hevc_hls_mvd_coding(lc, x0, y0, 1);
@@ -2138,7 +2135,7 @@ static void hls_prediction_unit(HEVCLocalContext *lc,
     int min_pu_width = sps->min_pu_width;

     MvField *tab_mvf = s->cur_frame->tab_mvf;
-    const RefPicList *refPicList = s->cur_frame->refPicList;
+    const RefPicList *refPicList = lc->rpl;
     const HEVCFrame *ref0 = NULL, *ref1 = NULL;
     const int *linesize = s->cur_frame->f->linesize;
     uint8_t *dst0 = s->cur_frame->f->data[0] + y0 * linesize[0] + (x0 << sps->pixel_shift);
@@ -2157,7 +2154,7 @@ static void hls_prediction_unit(HEVCLocalContext *lc,
         lc->pu.merge_flag = ff_hevc_merge_flag_decode(lc);

     if (skip_flag || lc->pu.merge_flag) {
-        if (s->sh.max_num_merge_cand > 1)
+        if (lc->sh->max_num_merge_cand > 1)
             merge_idx = ff_hevc_merge_idx_decode(lc);
         else
             merge_idx = 0;
@@ -2197,16 +2194,16 @@ static void hls_prediction_unit(HEVCLocalContext *lc,

         luma_mc_uni(lc, pps, sps, dst0, linesize[0], ref0->f,
                     &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]]);
+                    lc->sh->luma_weight_l0[current_mv.ref_idx[0]],
+                    lc->sh->luma_offset_l0[current_mv.ref_idx[0]]);

         if (sps->chroma_format_idc) {
             chroma_mc_uni(lc, pps, sps, dst1, linesize[1], ref0->f->data[1], ref0->f->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]);
+                          lc->sh->chroma_weight_l0[current_mv.ref_idx[0]][0], lc->sh->chroma_offset_l0[current_mv.ref_idx[0]][0]);
             chroma_mc_uni(lc, pps, sps, dst2, linesize[2], ref0->f->data[2], ref0->f->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]);
+                          lc->sh->chroma_weight_l0[current_mv.ref_idx[0]][1], lc->sh->chroma_offset_l0[current_mv.ref_idx[0]][1]);
         }
     } else if (current_mv.pred_flag == PF_L1) {
         int x0_c = x0 >> sps->hshift[1];
@@ -2216,17 +2213,17 @@ static void hls_prediction_unit(HEVCLocalContext *lc,

         luma_mc_uni(lc, pps, sps, dst0, linesize[0], ref1->f,
                     &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]]);
+                    lc->sh->luma_weight_l1[current_mv.ref_idx[1]],
+                    lc->sh->luma_offset_l1[current_mv.ref_idx[1]]);

         if (sps->chroma_format_idc) {
             chroma_mc_uni(lc, pps, sps, dst1, linesize[1], ref1->f->data[1], ref1->f->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]);
+                          lc->sh->chroma_weight_l1[current_mv.ref_idx[1]][0], lc->sh->chroma_offset_l1[current_mv.ref_idx[1]][0]);

             chroma_mc_uni(lc, pps, sps, dst2, linesize[2], ref1->f->data[2], ref1->f->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]);
+                          lc->sh->chroma_weight_l1[current_mv.ref_idx[1]][1], lc->sh->chroma_offset_l1[current_mv.ref_idx[1]][1]);
         }
     } else if (current_mv.pred_flag == PF_BI) {
         int x0_c = x0 >> sps->hshift[1];
@@ -2477,7 +2474,7 @@ static int hls_coding_unit(HEVCLocalContext *lc, const HEVCContext *s,
     } else
         lc->cu.cu_transquant_bypass_flag = 0;

-    if (s->sh.slice_type != HEVC_SLICE_I) {
+    if (lc->sh->slice_type != HEVC_SLICE_I) {
         const int x0b = av_zero_extend(x0, sps->log2_ctb_size);
         const int y0b = av_zero_extend(y0, sps->log2_ctb_size);
         uint8_t skip_flag = ff_hevc_skip_flag_decode(lc, l->skip_flag,
@@ -2503,12 +2500,12 @@ static int hls_coding_unit(HEVCLocalContext *lc, const HEVCContext *s,
                             x0, y0, cb_size, cb_size, log2_cb_size, 0, idx);
         intra_prediction_unit_default_value(lc, l, sps, x0, y0, log2_cb_size);

-        if (!s->sh.disable_deblocking_filter_flag)
+        if (!lc->sh->disable_deblocking_filter_flag)
             ff_hevc_deblocking_boundary_strengths(lc, l, pps, x0, y0, log2_cb_size);
     } else {
         int pcm_flag = 0;

-        if (s->sh.slice_type != HEVC_SLICE_I)
+        if (lc->sh->slice_type != HEVC_SLICE_I)
             lc->cu.pred_mode = ff_hevc_pred_mode_decode(lc);
         if (lc->cu.pred_mode != MODE_INTRA ||
             log2_cb_size == sps->log2_min_cb_size) {
@@ -2608,7 +2605,7 @@ static int hls_coding_unit(HEVCLocalContext *lc, const HEVCContext *s,
                 if (ret < 0)
                     return ret;
             } else {
-                if (!s->sh.disable_deblocking_filter_flag)
+                if (!lc->sh->disable_deblocking_filter_flag)
                     ff_hevc_deblocking_boundary_strengths(lc, l, pps, x0, y0, log2_cb_size);
             }
         }
@@ -2659,7 +2656,7 @@ static int hls_coding_quadtree(HEVCLocalContext *lc,
         lc->tu.cu_qp_delta          = 0;
     }

-    if (s->sh.cu_chroma_qp_offset_enabled_flag &&
+    if (lc->sh->cu_chroma_qp_offset_enabled_flag &&
         log2_cb_size >= sps->log2_ctb_size - pps->diff_cu_chroma_qp_offset_depth) {
         lc->tu.is_cu_chroma_qp_offset_coded = 0;
     }
@@ -2731,14 +2728,13 @@ static void hls_decode_neighbour(HEVCLocalContext *lc,
                                  const HEVCPPS *pps, const HEVCSPS *sps,
                                  int x_ctb, int y_ctb, int ctb_addr_ts)
 {
-    const HEVCContext *const s = lc->parent;
     int ctb_size          = 1 << sps->log2_ctb_size;
     int ctb_addr_rs       = pps->ctb_addr_ts_to_rs[ctb_addr_ts];
-    int ctb_addr_in_slice = ctb_addr_rs - s->sh.slice_addr;
+    int ctb_addr_in_slice = ctb_addr_rs - lc->sh->slice_addr;

     /* the tile-parallel path pre-fills this serially, workers only read it */
     if (!lc->tile_bs_defer)
-        l->tab_slice_address[ctb_addr_rs] = s->sh.slice_addr;
+        l->tab_slice_address[ctb_addr_rs] = lc->sh->slice_addr;

     if (pps->entropy_coding_sync_enabled_flag) {
         if (x_ctb == 0 && (y_ctb & (ctb_size - 1)) == 0)
@@ -2789,13 +2785,13 @@ static int hls_decode_entry(HEVCContext *s, GetBitContext *gb)
     int more_data   = 1;
     int x_ctb       = 0;
     int y_ctb       = 0;
-    int ctb_addr_ts = pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs];
+    int ctb_addr_ts = pps->ctb_addr_rs_to_ts[lc->sh->slice_ctb_addr_rs];
     int ret;

     /* The slice segment is one buffer, so CABAC stays open across tile and
      * WPP row boundaries. */
-    lc->sub.data   = gb->buffer + s->sh.data_offset;
-    lc->sub.size   = get_bits_bytesize(gb, 1) - s->sh.data_offset;
+    lc->sub.data   = gb->buffer + lc->sh->data_offset;
+    lc->sub.size   = get_bits_bytesize(gb, 1) - lc->sh->data_offset;
     lc->sub.opened = 0;

     while (more_data && ctb_addr_ts < sps->ctb_size) {
@@ -2814,9 +2810,9 @@ static int hls_decode_entry(HEVCContext *s, GetBitContext *gb)
         hls_sao_param(lc, l, pps, sps,
                       x_ctb >> sps->log2_ctb_size, y_ctb >> sps->log2_ctb_size);

-        l->deblock[ctb_addr_rs].beta_offset = s->sh.beta_offset;
-        l->deblock[ctb_addr_rs].tc_offset   = s->sh.tc_offset;
-        l->filter_slice_edges[ctb_addr_rs]  = s->sh.slice_loop_filter_across_slices_enabled_flag;
+        l->deblock[ctb_addr_rs].beta_offset = lc->sh->beta_offset;
+        l->deblock[ctb_addr_rs].tc_offset   = lc->sh->tc_offset;
+        l->filter_slice_edges[ctb_addr_rs]  = lc->sh->slice_loop_filter_across_slices_enabled_flag;

         more_data = hls_coding_quadtree(lc, l, pps, sps, x_ctb, y_ctb, sps->log2_ctb_size, 0);
         if (more_data < 0) {
@@ -2837,6 +2833,22 @@ static int hls_decode_entry(HEVCContext *s, GetBitContext *gb)
     return ctb_addr_ts;
 }

+/* Bind lc to a slice without touching HEVCContext, so that tiles of
+ * different slices can be decoded interleaved. */
+static void bind_slice_ctx(HEVCLocalContext *lc, const SliceHeader *sh,
+                           const RefPicList *rpl, const HEVCFrame *collocated_ref)
+{
+    lc->sh             = sh;
+    lc->rpl            = rpl;
+    lc->collocated_ref = collocated_ref;
+}
+
+static void bind_current_slice(HEVCContext *s, HEVCLocalContext *lc)
+{
+    bind_slice_ctx(lc, &s->sh, s->cur_frame ? s->cur_frame->refPicList : NULL,
+                   s->collocated_ref);
+}
+
 static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist,
                                 int job, int thread)
 {
@@ -2848,7 +2860,7 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist,
     int ctb_size    = 1 << sps->log2_ctb_size;
     int more_data   = 1;
     int ctb_row = job;
-    int ctb_addr_rs = s->sh.slice_ctb_addr_rs + ctb_row * ((sps->width + ctb_size - 1) >> sps->log2_ctb_size);
+    int ctb_addr_rs = lc->sh->slice_ctb_addr_rs + ctb_row * ((sps->width + ctb_size - 1) >> sps->log2_ctb_size);
     int ctb_addr_ts = pps->ctb_addr_rs_to_ts[ctb_addr_rs];

     int progress = 0;
@@ -2856,8 +2868,8 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist,
     int ret;

     /* Substream of this row, opened at its first CTB */
-    lc->sub.data   = s->data + s->sh.offset[ctb_row];
-    lc->sub.size   = s->sh.size[ctb_row];
+    lc->sub.data   = s->data + lc->sh->offset[ctb_row];
+    lc->sub.size   = lc->sh->size[ctb_row];
     lc->sub.opened = 0;

     /* Slices starting mid-row skip the initialization below */
@@ -2888,9 +2900,9 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist,
         hls_sao_param(lc, l, pps, sps,
                       x_ctb >> sps->log2_ctb_size, y_ctb >> sps->log2_ctb_size);

-        l->deblock[ctb_addr_rs].beta_offset = s->sh.beta_offset;
-        l->deblock[ctb_addr_rs].tc_offset   = s->sh.tc_offset;
-        l->filter_slice_edges[ctb_addr_rs]  = s->sh.slice_loop_filter_across_slices_enabled_flag;
+        l->deblock[ctb_addr_rs].beta_offset = lc->sh->beta_offset;
+        l->deblock[ctb_addr_rs].tc_offset   = lc->sh->tc_offset;
+        l->filter_slice_edges[ctb_addr_rs]  = lc->sh->slice_loop_filter_across_slices_enabled_flag;

         more_data = hls_coding_quadtree(lc, l, pps, sps, x_ctb, y_ctb, sps->log2_ctb_size, 0);

@@ -2905,7 +2917,7 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist,
         ff_thread_progress_report(&s->wpp_progress[ctb_row], ++progress);
         ff_hevc_hls_filters(lc, l, pps, x_ctb, y_ctb, ctb_size);

-        if (!more_data && (x_ctb+ctb_size) < sps->width && ctb_row != s->sh.num_entry_point_offsets) {
+        if (!more_data && (x_ctb+ctb_size) < sps->width && ctb_row != lc->sh->num_entry_point_offsets) {
             /* Casting const away here is safe, because it is an atomic operation. */
             atomic_store((atomic_int*)&s->wpp_err, 1);
             ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX);
@@ -3061,6 +3073,7 @@ static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal)
     for (unsigned i = 1; i < s->nb_local_ctx; i++) {
         s->local_ctx[i].sub.first_qp_group = 1;
         s->local_ctx[i].sub.qp_y = s->local_ctx[0].sub.qp_y;
+        bind_current_slice(s, &s->local_ctx[i]);
     }

     atomic_store(&s->wpp_err, 0);
@@ -3096,8 +3109,8 @@ static int hls_decode_entry_tile(AVCodecContext *avctx, void *hevc_lclist,
     int more_data = 1, ret;

     /* Substream of this tile, opened at its first CTB */
-    lc->sub.data   = s->data + s->sh.offset[job];
-    lc->sub.size   = s->sh.size[job];
+    lc->sub.data   = s->data + lc->sh->offset[job];
+    lc->sub.size   = lc->sh->size[job];
     lc->sub.opened = 0;

     lc->tile_bs_defer       = 1;
@@ -3121,9 +3134,9 @@ static int hls_decode_entry_tile(AVCodecContext *avctx, void *hevc_lclist,
         hls_sao_param(lc, l, pps, sps,
                       x_ctb >> sps->log2_ctb_size, y_ctb >> sps->log2_ctb_size);

-        l->deblock[ctb_addr_rs].beta_offset = s->sh.beta_offset;
-        l->deblock[ctb_addr_rs].tc_offset   = s->sh.tc_offset;
-        l->filter_slice_edges[ctb_addr_rs]  = s->sh.slice_loop_filter_across_slices_enabled_flag;
+        l->deblock[ctb_addr_rs].beta_offset = lc->sh->beta_offset;
+        l->deblock[ctb_addr_rs].tc_offset   = lc->sh->tc_offset;
+        l->filter_slice_edges[ctb_addr_rs]  = lc->sh->slice_loop_filter_across_slices_enabled_flag;

         more_data = hls_coding_quadtree(lc, l, pps, sps, x_ctb, y_ctb, sps->log2_ctb_size, 0);
         if (more_data < 0)
@@ -3155,6 +3168,7 @@ static int hls_slice_data_tiles(HEVCContext *s, const H2645NAL *nal)
     for (unsigned i = 1; i < s->nb_local_ctx; i++) {
         s->local_ctx[i].sub.first_qp_group = 1;
         s->local_ctx[i].sub.qp_y           = s->local_ctx[0].sub.qp_y;
+        bind_current_slice(s, &s->local_ctx[i]);
     }

     for (ctb_addr_ts = start_ts; ctb_addr_ts < sps->ctb_size; ctb_addr_ts++)
@@ -3241,6 +3255,9 @@ static int decode_slice_data(HEVCContext *s, const HEVCLayerContext *l,
         }
     }

+    /* All decoding paths below read the slice state from lc */
+    bind_current_slice(s, &s->local_ctx[0]);
+
     s->local_ctx[0].sub.first_qp_group = !s->sh.dependent_slice_segment_flag;

     if (!pps->cu_qp_delta_enabled_flag)
diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
index b6116e74a3..27efa4d012 100644
--- a/libavcodec/hevc/hevcdec.h
+++ b/libavcodec/hevc/hevcdec.h
@@ -411,6 +411,12 @@ typedef struct HEVCLocalContext {
     void *logctx;
     const struct HEVCContext *parent;

+    /* Slice being decoded, read instead of HEVCContext so that tiles of
+     * different slices can be decoded interleaved. */
+    const SliceHeader *sh;
+    const RefPicList  *rpl;             ///< reference lists of that slice, NULL for I slices
+    const HEVCFrame   *collocated_ref;  ///< picture read by the temporal MVP, NULL if none
+
     /**
      * This is a pointer to the common CABAC state.
      * In case entropy_coding_sync_enabled_flag is set,
diff --git a/libavcodec/hevc/mvs.c b/libavcodec/hevc/mvs.c
index 937c7cf753..b22b3e7ac6 100644
--- a/libavcodec/hevc/mvs.c
+++ b/libavcodec/hevc/mvs.c
@@ -161,11 +161,12 @@ static int check_mvset(Mv *mvLXCol, const Mv *mvCol,
                 refPicList_col, L ## l, temp_col.ref_idx[l])

 // derive the motion vectors section 8.5.3.1.8
-static int derive_temporal_colocated_mvs(const HEVCContext *s, MvField temp_col,
+static int derive_temporal_colocated_mvs(const HEVCContext *s,
+                                         const HEVCLocalContext *lc, MvField temp_col,
                                          int refIdxLx, Mv *mvLXCol, int X,
                                          int colPic, const RefPicList *refPicList_col)
 {
-    const RefPicList *refPicList = s->cur_frame->refPicList;
+    const RefPicList *refPicList = lc->rpl;

     if (temp_col.pred_flag == PF_INTRA)
         return 0;
@@ -191,7 +192,7 @@ static int derive_temporal_colocated_mvs(const HEVCContext *s, MvField temp_col,
             else
                 return CHECK_MVSET(1);
         } else {
-            if (s->sh.collocated_list == L1)
+            if (lc->sh->collocated_list == L1)
                 return CHECK_MVSET(0);
             else
                 return CHECK_MVSET(1);
@@ -209,14 +210,16 @@ static int derive_temporal_colocated_mvs(const HEVCContext *s, MvField temp_col,
             ((y ## v) >> sps->log2_min_pu_size))

 #define DERIVE_TEMPORAL_COLOCATED_MVS                                   \
-    derive_temporal_colocated_mvs(s, temp_col,                          \
+    derive_temporal_colocated_mvs(s, lc, temp_col,                      \
                                   refIdxLx, mvLXCol, X, colPic,         \
                                   ff_hevc_get_ref_list(ref, x, y))

 /*
  * 8.5.3.1.7  temporal luma motion vector prediction
  */
-static int temporal_luma_motion_vector(const HEVCContext *s, const HEVCSPS *sps,
+static int temporal_luma_motion_vector(const HEVCContext *s,
+                                       const HEVCLocalContext *lc,
+                                       const HEVCSPS *sps,
                                        int x0, int y0,
                                        int nPbW, int nPbH, int refIdxLx,
                                        Mv *mvLXCol, int X)
@@ -228,7 +231,7 @@ static int temporal_luma_motion_vector(const HEVCContext *s, const HEVCSPS *sps,
     int availableFlagLXCol = 0;
     int colPic;

-    const HEVCFrame *ref = s->collocated_ref;
+    const HEVCFrame *ref = lc->collocated_ref;

     if (!ref) {
         memset(mvLXCol, 0, sizeof(*mvLXCol));
@@ -293,7 +296,7 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont
                                             int merge_idx,
                                             struct MvField mergecandlist[])
 {
-    const RefPicList *refPicList = s->cur_frame->refPicList;
+    const RefPicList *refPicList = lc->rpl;
     const MvField *tab_mvf       = s->cur_frame->tab_mvf;

     const int min_pu_width = sps->min_pu_width;
@@ -319,8 +322,8 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont
     const int xB2    = x0 - 1;
     const int yB2    = y0 - 1;

-    const int nb_refs = (s->sh.slice_type == HEVC_SLICE_P) ?
-                        s->sh.nb_refs[0] : FFMIN(s->sh.nb_refs[0], s->sh.nb_refs[1]);
+    const int nb_refs = (lc->sh->slice_type == HEVC_SLICE_P) ?
+                        lc->sh->nb_refs[0] : FFMIN(lc->sh->nb_refs[0], lc->sh->nb_refs[1]);

     int zero_idx = 0;

@@ -410,13 +413,13 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont
     }

     // temporal motion vector candidate
-    if (s->sh.slice_temporal_mvp_enabled_flag &&
-        nb_merge_cand < s->sh.max_num_merge_cand) {
+    if (lc->sh->slice_temporal_mvp_enabled_flag &&
+        nb_merge_cand < lc->sh->max_num_merge_cand) {
         Mv mv_l0_col = { 0 }, mv_l1_col = { 0 };
-        int available_l0 = temporal_luma_motion_vector(s, sps, x0, y0, nPbW, nPbH,
+        int available_l0 = temporal_luma_motion_vector(s, lc, sps, x0, y0, nPbW, nPbH,
                                                        0, &mv_l0_col, 0);
-        int available_l1 = (s->sh.slice_type == HEVC_SLICE_B) ?
-                           temporal_luma_motion_vector(s, sps, x0, y0, nPbW, nPbH,
+        int available_l1 = (lc->sh->slice_type == HEVC_SLICE_B) ?
+                           temporal_luma_motion_vector(s, lc, sps, x0, y0, nPbW, nPbH,
                                                        0, &mv_l1_col, 1) : 0;

         if (available_l0 || available_l1) {
@@ -434,11 +437,11 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont
     nb_orig_merge_cand = nb_merge_cand;

     // combined bi-predictive merge candidates  (applies for B slices)
-    if (s->sh.slice_type == HEVC_SLICE_B && nb_orig_merge_cand > 1 &&
-        nb_orig_merge_cand < s->sh.max_num_merge_cand) {
+    if (lc->sh->slice_type == HEVC_SLICE_B && nb_orig_merge_cand > 1 &&
+        nb_orig_merge_cand < lc->sh->max_num_merge_cand) {
         int comb_idx = 0;

-        for (comb_idx = 0; nb_merge_cand < s->sh.max_num_merge_cand &&
+        for (comb_idx = 0; nb_merge_cand < lc->sh->max_num_merge_cand &&
                            comb_idx < nb_orig_merge_cand * (nb_orig_merge_cand - 1); comb_idx++) {
             int l0_cand_idx = l0_l1_cand_idx[comb_idx][0];
             int l1_cand_idx = l0_l1_cand_idx[comb_idx][1];
@@ -462,8 +465,8 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont
     }

     // append Zero motion vector candidates
-    while (nb_merge_cand < s->sh.max_num_merge_cand) {
-        mergecandlist[nb_merge_cand].pred_flag    = PF_L0 + ((s->sh.slice_type == HEVC_SLICE_B) << 1);
+    while (nb_merge_cand < lc->sh->max_num_merge_cand) {
+        mergecandlist[nb_merge_cand].pred_flag    = PF_L0 + ((lc->sh->slice_type == HEVC_SLICE_B) << 1);
         AV_ZERO32(mergecandlist[nb_merge_cand].mv + 0);
         AV_ZERO32(mergecandlist[nb_merge_cand].mv + 1);
         mergecandlist[nb_merge_cand].ref_idx[0]   = zero_idx < nb_refs ? zero_idx : 0;
@@ -514,11 +517,11 @@ void ff_hevc_luma_mv_merge_mode(HEVCLocalContext *lc, const HEVCPPS *pps,
     *mv = mergecand_list[merge_idx];
 }

-static av_always_inline void dist_scale(const HEVCContext *s, Mv *mv,
+static av_always_inline void dist_scale(const HEVCContext *s,
+                                        const RefPicList *refPicList, Mv *mv,
                                         int min_pu_width, int x, int y,
                                         int elist, int ref_idx_curr, int ref_idx)
 {
-    const RefPicList *refPicList = s->cur_frame->refPicList;
     const MvField *tab_mvf       = s->cur_frame->tab_mvf;
     int ref_pic_elist      = refPicList[elist].list[TAB_MVF(x, y).ref_idx[elist]];
     int ref_pic_curr       = refPicList[ref_idx_curr].list[ref_idx];
@@ -531,15 +534,14 @@ static av_always_inline void dist_scale(const HEVCContext *s, Mv *mv,
     }
 }

-static int mv_mp_mode_mx(const HEVCContext *s, const HEVCSPS *sps,
+static int mv_mp_mode_mx(const HEVCContext *s, const RefPicList *refPicList,
+                         const HEVCSPS *sps,
                          int x, int y, int pred_flag_index,
                          Mv *mv, int ref_idx_curr, int ref_idx)
 {
     const MvField *tab_mvf = s->cur_frame->tab_mvf;
     int min_pu_width = sps->min_pu_width;

-    const RefPicList *refPicList = s->cur_frame->refPicList;
-
     if (((TAB_MVF(x, y).pred_flag) & (1 << pred_flag_index)) &&
         refPicList[pred_flag_index].list[TAB_MVF(x, y).ref_idx[pred_flag_index]] == refPicList[ref_idx_curr].list[ref_idx]) {
         *mv = TAB_MVF(x, y).mv[pred_flag_index];
@@ -548,15 +550,14 @@ static int mv_mp_mode_mx(const HEVCContext *s, const HEVCSPS *sps,
     return 0;
 }

-static int mv_mp_mode_mx_lt(const HEVCContext *s, const HEVCSPS *sps,
+static int mv_mp_mode_mx_lt(const HEVCContext *s, const RefPicList *refPicList,
+                            const HEVCSPS *sps,
                             int x, int y, int pred_flag_index,
                             Mv *mv, int ref_idx_curr, int ref_idx)
 {
     const MvField *tab_mvf = s->cur_frame->tab_mvf;
     int min_pu_width = sps->min_pu_width;

-    const RefPicList *refPicList = s->cur_frame->refPicList;
-
     if ((TAB_MVF(x, y).pred_flag) & (1 << pred_flag_index)) {
         int currIsLongTerm     = refPicList[ref_idx_curr].isLongTerm[ref_idx];

@@ -566,7 +567,7 @@ static int mv_mp_mode_mx_lt(const HEVCContext *s, const HEVCSPS *sps,
         if (colIsLongTerm == currIsLongTerm) {
             *mv = TAB_MVF(x, y).mv[pred_flag_index];
             if (!currIsLongTerm)
-                dist_scale(s, mv, min_pu_width, x, y,
+                dist_scale(s, refPicList, mv, min_pu_width, x, y,
                            pred_flag_index, ref_idx_curr, ref_idx);
             return 1;
         }
@@ -575,13 +576,13 @@ static int mv_mp_mode_mx_lt(const HEVCContext *s, const HEVCSPS *sps,
 }

 #define MP_MX(v, pred, mx)                                      \
-    mv_mp_mode_mx(s, sps,                                       \
+    mv_mp_mode_mx(s, lc->rpl, sps,                              \
                   (x ## v) >> sps->log2_min_pu_size,            \
                   (y ## v) >> 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, sps,                                    \
+    mv_mp_mode_mx_lt(s, lc->rpl, sps,                           \
                      (x ## v) >> sps->log2_min_pu_size,         \
                      (y ## v) >> sps->log2_min_pu_size,         \
                      pred, &mx, ref_idx_curr, ref_idx)
@@ -769,10 +770,10 @@ scalef:
         mvpcand_list[numMVPCandLX++] = mxB;

     //temporal motion vector prediction candidate
-    if (numMVPCandLX < 2 && s->sh.slice_temporal_mvp_enabled_flag &&
+    if (numMVPCandLX < 2 && lc->sh->slice_temporal_mvp_enabled_flag &&
         mvp_lx_flag == numMVPCandLX) {
         Mv mv_col;
-        int available_col = temporal_luma_motion_vector(s, sps, x0, y0, nPbW,
+        int available_col = temporal_luma_motion_vector(s, lc, sps, x0, y0, nPbW,
                                                         nPbH, ref_idx,
                                                         &mv_col, LX);
         if (available_col)