shithub: dav1d

Download patch

ref: e071d257cae01c07d2204478dcc489200df66750
parent: 41e64ac1f8762167b3d3787bc9649ca26ace2386
author: Ronald S. Bultje <[email protected]>
date: Sat Nov 17 13:31:18 EST 2018

Make sequence header a referenced object

--- a/src/decode.c
+++ b/src/decode.c
@@ -702,7 +702,7 @@
     const int cbw4 = (bw4 + ss_hor) >> ss_hor, cbh4 = (bh4 + ss_ver) >> ss_ver;
     const int have_left = t->bx > ts->tiling.col_start;
     const int have_top = t->by > ts->tiling.row_start;
-    const int has_chroma = f->seq_hdr.layout != DAV1D_PIXEL_LAYOUT_I400 &&
+    const int has_chroma = f->seq_hdr->layout != DAV1D_PIXEL_LAYOUT_I400 &&
                            (bw4 > ss_hor || t->bx & 1) &&
                            (bh4 > ss_ver || t->by & 1);
 
@@ -894,7 +894,7 @@
 
     // cdef index
     if (!b->skip) {
-        const int idx = f->seq_hdr.sb128 ? ((t->bx & 16) >> 4) +
+        const int idx = f->seq_hdr->sb128 ? ((t->bx & 16) >> 4) +
                                            ((t->by & 16) >> 3) : 0;
         if (t->cur_sb_cdef_idx_ptr[idx] == -1) {
             const int v = msac_decode_bools(&ts->msac, f->frame_hdr.cdef.n_bits);
@@ -910,12 +910,12 @@
     }
 
     // delta-q/lf
-    if (!(t->bx & (31 >> !f->seq_hdr.sb128)) &&
-        !(t->by & (31 >> !f->seq_hdr.sb128)))
+    if (!(t->bx & (31 >> !f->seq_hdr->sb128)) &&
+        !(t->by & (31 >> !f->seq_hdr->sb128)))
     {
         const int prev_qidx = ts->last_qidx;
         const int have_delta_q = f->frame_hdr.delta.q.present &&
-            (bs != (f->seq_hdr.sb128 ? BS_128x128 : BS_64x64) || !b->skip);
+            (bs != (f->seq_hdr->sb128 ? BS_128x128 : BS_64x64) || !b->skip);
 
         int8_t prev_delta_lf[4];
         memcpy(prev_delta_lf, ts->last_delta_lf, 4);
@@ -937,7 +937,7 @@
 
             if (f->frame_hdr.delta.lf.present) {
                 const int n_lfs = f->frame_hdr.delta.lf.multi ?
-                    f->seq_hdr.layout != DAV1D_PIXEL_LAYOUT_I400 ? 4 : 2 : 1;
+                    f->seq_hdr->layout != DAV1D_PIXEL_LAYOUT_I400 ? 4 : 2 : 1;
 
                 for (int i = 0; i < n_lfs; i++) {
                     int delta_lf =
@@ -966,7 +966,7 @@
             ts->dq = f->dq;
         } else if (ts->last_qidx != prev_qidx) {
             // find sb-specific quant parameters
-            init_quant_tables(&f->seq_hdr, &f->frame_hdr, ts->last_qidx, ts->dqmem);
+            init_quant_tables(f->seq_hdr, &f->frame_hdr, ts->last_qidx, ts->dqmem);
             ts->dq = ts->dqmem;
         }
         if (!memcmp(ts->last_delta_lf, (int8_t[4]) { 0, 0, 0, 0 }, 4)) {
@@ -1094,7 +1094,7 @@
         }
 
         if (b->y_mode == DC_PRED && !b->pal_sz[0] &&
-            imax(b_dim[2], b_dim[3]) <= 3 && f->seq_hdr.filter_intra)
+            imax(b_dim[2], b_dim[3]) <= 3 && f->seq_hdr->filter_intra)
         {
             const int is_filter = msac_decode_bool_adapt(&ts->msac,
                                             ts->cdf.m.use_filter_intra[bs]);
@@ -1241,11 +1241,11 @@
         else if (mvlist[0][1].y | mvlist[0][1].x)
             b->mv[0] = mvlist[0][1];
         else {
-            if (t->by - (16 << f->seq_hdr.sb128) < ts->tiling.row_start) {
+            if (t->by - (16 << f->seq_hdr->sb128) < ts->tiling.row_start) {
                 b->mv[0].y = 0;
-                b->mv[0].x = -(512 << f->seq_hdr.sb128) - 2048;
+                b->mv[0].x = -(512 << f->seq_hdr->sb128) - 2048;
             } else {
-                b->mv[0].y = -(512 << f->seq_hdr.sb128);
+                b->mv[0].y = -(512 << f->seq_hdr->sb128);
                 b->mv[0].x = 0;
             }
         }
@@ -1281,9 +1281,9 @@
             src_top    += border_top - src_top;
         }
 
-        const int sbx = (t->bx >> (4 + f->seq_hdr.sb128)) << (6 + f->seq_hdr.sb128);
-        const int sby = (t->by >> (4 + f->seq_hdr.sb128)) << (6 + f->seq_hdr.sb128);
-        const int sb_size = 1 << (6 + f->seq_hdr.sb128);
+        const int sbx = (t->bx >> (4 + f->seq_hdr->sb128)) << (6 + f->seq_hdr->sb128);
+        const int sby = (t->by >> (4 + f->seq_hdr->sb128)) << (6 + f->seq_hdr->sb128);
+        const int sb_size = 1 << (6 + f->seq_hdr->sb128);
         // check for overlap with current superblock
         if (src_bottom > sby && src_right > sbx) {
             if (src_top - border_top >= src_bottom - sby) {
@@ -1529,7 +1529,7 @@
 
             // jnt_comp vs. seg vs. wedge
             int is_segwedge = 0;
-            if (f->seq_hdr.masked_compound) {
+            if (f->seq_hdr->masked_compound) {
                 const int mask_ctx = get_mask_comp_ctx(t->a, &t->l, by4, bx4);
 
                 is_segwedge = msac_decode_bool_adapt(&ts->msac,
@@ -1540,9 +1540,9 @@
             }
 
             if (!is_segwedge) {
-                if (f->seq_hdr.jnt_comp) {
+                if (f->seq_hdr->jnt_comp) {
                     const int jnt_ctx =
-                        get_jnt_comp_ctx(f->seq_hdr.order_hint_n_bits,
+                        get_jnt_comp_ctx(f->seq_hdr->order_hint_n_bits,
                                          f->cur.poc, f->refp[b->ref[0]].p.poc,
                                          f->refp[b->ref[1]].p.poc, t->a, &t->l,
                                          by4, bx4);
@@ -1707,7 +1707,7 @@
 
             // interintra flags
             const int ii_sz_grp = dav1d_ymode_size_context[bs];
-            if (f->seq_hdr.inter_intra &&
+            if (f->seq_hdr->inter_intra &&
                 interintra_allowed_mask & (1 << bs) &&
                 msac_decode_bool_adapt(&ts->msac, ts->cdf.m.interintra[ii_sz_grp]))
             {
@@ -1724,7 +1724,7 @@
             } else {
                 b->interintra_type = INTER_INTRA_NONE;
             }
-            if (DEBUG_BLOCK_INFO && f->seq_hdr.inter_intra &&
+            if (DEBUG_BLOCK_INFO && f->seq_hdr->inter_intra &&
                 interintra_allowed_mask & (1 << bs))
             {
                 printf("Post-interintra[t=%d,m=%d,w=%d]: r=%d\n",
@@ -1792,7 +1792,7 @@
                                                 by4, bx4);
                 filter[0] = msac_decode_symbol_adapt(&ts->msac,
                     ts->cdf.m.filter[0][ctx1], N_SWITCHABLE_FILTERS);
-                if (f->seq_hdr.dual_filter) {
+                if (f->seq_hdr->dual_filter) {
                     const int ctx2 = get_filter_ctx(t->a, &t->l, comp, 1,
                                                     b->ref[0], by4, bx4);
                     if (DEBUG_BLOCK_INFO)
@@ -2206,7 +2206,7 @@
                        const int tile_start_off)
 {
     const int col_sb_start = f->frame_hdr.tiling.col_start_sb[tile_col];
-    const int col_sb128_start = col_sb_start >> !f->seq_hdr.sb128;
+    const int col_sb128_start = col_sb_start >> !f->seq_hdr->sb128;
     const int col_sb_end = f->frame_hdr.tiling.col_start_sb[tile_col + 1];
     const int row_sb_start = f->frame_hdr.tiling.row_start_sb[tile_row];
     const int row_sb_end = f->frame_hdr.tiling.row_start_sb[tile_row + 1];
@@ -2354,13 +2354,13 @@
 
 int dav1d_decode_tile_sbrow(Dav1dTileContext *const t) {
     const Dav1dFrameContext *const f = t->f;
-    const enum BlockLevel root_bl = f->seq_hdr.sb128 ? BL_128X128 : BL_64X64;
+    const enum BlockLevel root_bl = f->seq_hdr->sb128 ? BL_128X128 : BL_64X64;
     Dav1dTileState *const ts = t->ts;
     const Dav1dContext *const c = f->c;
     const int sb_step = f->sb_step;
     const int tile_row = ts->tiling.row, tile_col = ts->tiling.col;
     const int col_sb_start = f->frame_hdr.tiling.col_start_sb[tile_col];
-    const int col_sb128_start = col_sb_start >> !f->seq_hdr.sb128;
+    const int col_sb128_start = col_sb_start >> !f->seq_hdr->sb128;
 
     reset_context(&t->l, !(f->frame_hdr.frame_type & 1), f->frame_thread.pass);
     if (f->frame_thread.pass == 2) {
@@ -2372,7 +2372,7 @@
                 return 1;
             if (decode_sb(t, root_bl, c->intra_edge.root[root_bl]))
                 return 1;
-            if (t->bx & 16 || f->seq_hdr.sb128)
+            if (t->bx & 16 || f->seq_hdr->sb128)
                 t->a++;
         }
         f->bd_fn.backup_ipred_edge(t);
@@ -2467,7 +2467,7 @@
         }
         if (decode_sb(t, root_bl, c->intra_edge.root[root_bl]))
             return 1;
-        if (t->bx & 16 || f->seq_hdr.sb128) {
+        if (t->bx & 16 || f->seq_hdr->sb128) {
             t->a++;
             t->lf_mask++;
         }
@@ -2680,9 +2680,9 @@
     // init ref mvs
     if ((f->frame_hdr.frame_type & 1) || f->frame_hdr.allow_intrabc) {
         f->mvs = f->mvs_ref->data;
-        const int order_hint_n_bits = f->seq_hdr.order_hint * f->seq_hdr.order_hint_n_bits;
+        const int order_hint_n_bits = f->seq_hdr->order_hint * f->seq_hdr->order_hint_n_bits;
         const int ret = av1_init_ref_mv_common(f->libaom_cm, f->bw >> 1, f->bh >> 1,
-                                               f->b4_stride, f->seq_hdr.sb128,
+                                               f->b4_stride, f->seq_hdr->sb128,
                                                f->mvs, f->ref_mvs, f->cur.poc, f->refpoc,
                                                f->refrefpoc, f->frame_hdr.gmv,
                                                f->frame_hdr.hp, f->frame_hdr.force_integer_mv,
@@ -2694,7 +2694,7 @@
     }
 
     // setup dequant tables
-    init_quant_tables(&f->seq_hdr, &f->frame_hdr, f->frame_hdr.quant.yac, f->dq);
+    init_quant_tables(f->seq_hdr, &f->frame_hdr, f->frame_hdr.quant.yac, f->dq);
     if (f->frame_hdr.quant.qm)
         for (int j = 0; j < N_RECT_TX_SIZES; j++) {
             f->qm[0][j][0] = dav1d_qm_tbl[f->frame_hdr.quant.qm_y][0][j];
@@ -2714,9 +2714,9 @@
             for (int j = i + 1; j < 7; j++) {
                 const unsigned ref1poc = f->refp[j].p.poc;
 
-                const unsigned d1 = imin(abs(get_poc_diff(f->seq_hdr.order_hint_n_bits,
+                const unsigned d1 = imin(abs(get_poc_diff(f->seq_hdr->order_hint_n_bits,
                                                           ref0poc, f->cur.poc)), 31);
-                const unsigned d0 = imin(abs(get_poc_diff(f->seq_hdr.order_hint_n_bits,
+                const unsigned d0 = imin(abs(get_poc_diff(f->seq_hdr->order_hint_n_bits,
                                                           ref1poc, f->cur.poc)), 31);
                 const int order = d0 <= d1;
 
@@ -2822,7 +2822,7 @@
                 for (int sby = f->frame_hdr.tiling.row_start_sb[tile_row];
                      sby < sbh_end; sby++)
                 {
-                    t->by = sby << (4 + f->seq_hdr.sb128);
+                    t->by = sby << (4 + f->seq_hdr->sb128);
                     for (int tile_col = 0; tile_col < f->frame_hdr.tiling.cols; tile_col++) {
                         t->ts = &f->ts[tile_row * f->frame_hdr.tiling.cols + tile_col];
 
@@ -2947,6 +2947,7 @@
     dav1d_ref_dec(&f->cur_segmap_ref);
     dav1d_ref_dec(&f->prev_segmap_ref);
     dav1d_ref_dec(&f->mvs_ref);
+    dav1d_ref_dec(&f->seq_hdr_ref);
 
     for (int i = 0; i < f->n_tile_data; i++)
         dav1d_data_unref(&f->tile[i].data);
@@ -2987,14 +2988,16 @@
     }
 
     f->seq_hdr = c->seq_hdr;
+    f->seq_hdr_ref = c->seq_hdr_ref;
+    dav1d_ref_inc(f->seq_hdr_ref);
     f->frame_hdr = c->frame_hdr;
-    const int bd_idx = (f->seq_hdr.bpc - 8) >> 1;
+    const int bd_idx = (f->seq_hdr->bpc - 8) >> 1;
     f->dsp = &c->dsp[bd_idx];
 
     if (!f->dsp->ipred.intra_pred[DC_PRED]) {
         Dav1dDSPContext *const dsp = &c->dsp[bd_idx];
 
-        switch (f->seq_hdr.bpc) {
+        switch (f->seq_hdr->bpc) {
 #define assign_bitdepth_case(bd) \
         case bd: \
             dav1d_cdef_dsp_init_##bd##bpc(&dsp->cdef); \
@@ -3013,7 +3016,7 @@
 #undef assign_bitdepth_case
         default:
             fprintf(stderr, "Compiled without support for %d-bit decoding\n",
-                    f->seq_hdr.bpc);
+                    f->seq_hdr->bpc);
             res = -ENOPROTOOPT;
             goto error;
         }
@@ -3025,7 +3028,7 @@
         f->bd_fn.filter_sbrow = dav1d_filter_sbrow_##bd##bpc; \
         f->bd_fn.backup_ipred_edge = dav1d_backup_ipred_edge_##bd##bpc; \
         f->bd_fn.read_coef_blocks = dav1d_read_coef_blocks_##bd##bpc
-    if (f->seq_hdr.bpc <= 8) {
+    if (f->seq_hdr->bpc <= 8) {
 #if CONFIG_8BPC
         assign_bitdepth_case(8);
 #endif
@@ -3051,8 +3054,8 @@
                 f->frame_hdr.height * 2 < c->refs[refidx].p.p.p.h ||
                 f->frame_hdr.width[0] > c->refs[refidx].p.p.p.w * 16 ||
                 f->frame_hdr.height > c->refs[refidx].p.p.p.h * 16 ||
-                f->seq_hdr.layout != c->refs[refidx].p.p.p.layout ||
-                f->seq_hdr.bpc != c->refs[refidx].p.p.p.bpc)
+                f->seq_hdr->layout != c->refs[refidx].p.p.p.layout ||
+                f->seq_hdr->bpc != c->refs[refidx].p.p.p.bpc)
             {
                 for (int j = 0; j < i; j++)
                     dav1d_thread_picture_unref(&f->refp[j]);
@@ -3101,7 +3104,7 @@
     // allocate frame
     res = dav1d_thread_picture_alloc(&f->sr_cur, f->frame_hdr.width[1],
                                      f->frame_hdr.height,
-                                     f->seq_hdr.layout, f->seq_hdr.bpc,
+                                     f->seq_hdr->layout, f->seq_hdr->bpc,
                                      c->n_fc > 1 ? &f->frame_thread.td : NULL,
                                      f->frame_hdr.show_frame, &c->allocator);
     if (res < 0) goto error;
@@ -3109,11 +3112,11 @@
     f->sr_cur.p.poc = f->frame_hdr.frame_offset;
     f->sr_cur.p.p.type = f->frame_hdr.frame_type;
     f->sr_cur.p.p.film_grain = f->frame_hdr.film_grain.data;
-    f->sr_cur.p.p.pri = f->seq_hdr.pri;
-    f->sr_cur.p.p.trc = f->seq_hdr.trc;
-    f->sr_cur.p.p.mtrx = f->seq_hdr.mtrx;
-    f->sr_cur.p.p.chr = f->seq_hdr.chr;
-    f->sr_cur.p.p.fullrange = f->seq_hdr.color_range;
+    f->sr_cur.p.p.pri = f->seq_hdr->pri;
+    f->sr_cur.p.p.trc = f->seq_hdr->trc;
+    f->sr_cur.p.p.mtrx = f->seq_hdr->mtrx;
+    f->sr_cur.p.p.chr = f->seq_hdr->chr;
+    f->sr_cur.p.p.fullrange = f->seq_hdr->color_range;
     f->sr_cur.p.m = f->tile[0].data.m;
     f->sr_cur.p.p.spatial_id = f->frame_hdr.spatial_id;
 
@@ -3149,8 +3152,8 @@
     f->bh = ((f->frame_hdr.height + 7) >> 3) << 1;
     f->sb128w = (f->bw + 31) >> 5;
     f->sb128h = (f->bh + 31) >> 5;
-    f->sb_shift = 4 + f->seq_hdr.sb128;
-    f->sb_step = 16 << f->seq_hdr.sb128;
+    f->sb_shift = 4 + f->seq_hdr->sb128;
+    f->sb_step = 16 << f->seq_hdr->sb128;
     f->sbh = (f->bh + f->sb_step - 1) >> f->sb_shift;
     f->b4_stride = (f->bw + 31) & ~31;
 
@@ -3305,6 +3308,7 @@
     dav1d_picture_unref(&f->cur);
     dav1d_thread_picture_unref(&f->sr_cur);
     dav1d_ref_dec(&f->mvs_ref);
+    dav1d_ref_dec(&f->seq_hdr_ref);
 
     for (int i = 0; i < f->n_tile_data; i++)
         dav1d_data_unref(&f->tile[i].data);
--- a/src/internal.h
+++ b/src/internal.h
@@ -75,9 +75,10 @@
         Dav1dData data;
         int start, end;
     } tile[256];
-    int n_tile_data, have_seq_hdr, have_frame_hdr;
+    int n_tile_data, have_frame_hdr;
     int n_tiles;
-    Av1SequenceHeader seq_hdr; // FIXME make ref?
+    Dav1dRef *seq_hdr_ref;
+    Av1SequenceHeader *seq_hdr;
     Av1FrameHeader frame_hdr; // FIXME make ref?
 
     // decoded output picture queue
@@ -122,7 +123,8 @@
 };
 
 struct Dav1dFrameContext {
-    Av1SequenceHeader seq_hdr;
+    Dav1dRef *seq_hdr_ref;
+    Av1SequenceHeader *seq_hdr;
     Av1FrameHeader frame_hdr;
     Dav1dThreadPicture refp[7];
     Dav1dPicture cur; // during block coding / reconstruction
--- a/src/lf_apply_tmpl.c
+++ b/src/lf_apply_tmpl.c
@@ -178,7 +178,7 @@
     int x, have_left;
     // Don't filter outside the frame
     const int have_top = sby > 0;
-    const int is_sb64 = !f->seq_hdr.sb128;
+    const int is_sb64 = !f->seq_hdr->sb128;
     const int starty4 = (sby & is_sb64) << 4;
     const int sbsz = 32 >> is_sb64;
     const int sbl2 = 5 - is_sb64;
--- a/src/lr_apply_tmpl.c
+++ b/src/lr_apply_tmpl.c
@@ -110,11 +110,11 @@
     if (restore_planes & LR_RESTORE_Y) {
         const int h = f->bh << 2;
         const int w = f->bw << 2;
-        const int row_h = imin((sby + 1) << (6 + f->seq_hdr.sb128), h - 4);
-        const int y_stripe = (sby << (6 + f->seq_hdr.sb128)) - offset;
+        const int row_h = imin((sby + 1) << (6 + f->seq_hdr->sb128), h - 4);
+        const int y_stripe = (sby << (6 + f->seq_hdr->sb128)) - offset;
         backup_lpf(f, f->lf.lr_lpf_line_ptr[0], lr_stride,
                    src[0] - offset * PXSTRIDE(src_stride[0]), src_stride[0],
-                   0, f->seq_hdr.sb128, y_stripe, row_h, w, 0);
+                   0, f->seq_hdr->sb128, y_stripe, row_h, w, 0);
     }
     if (restore_planes & (LR_RESTORE_U | LR_RESTORE_V)) {
         const int ss_ver = f->sr_cur.p.p.layout == DAV1D_PIXEL_LAYOUT_I420;
@@ -121,20 +121,20 @@
         const int ss_hor = f->sr_cur.p.p.layout != DAV1D_PIXEL_LAYOUT_I444;
         const int h = f->bh << (2 - ss_ver);
         const int w = f->bw << (2 - ss_hor);
-        const int row_h = imin((sby + 1) << ((6 - ss_ver) + f->seq_hdr.sb128), h - 4);
+        const int row_h = imin((sby + 1) << ((6 - ss_ver) + f->seq_hdr->sb128), h - 4);
         const ptrdiff_t offset_uv = offset >> ss_ver;
         const int y_stripe =
-            (sby << ((6 - ss_ver) + f->seq_hdr.sb128)) - offset_uv;
+            (sby << ((6 - ss_ver) + f->seq_hdr->sb128)) - offset_uv;
 
         if (restore_planes & LR_RESTORE_U) {
             backup_lpf(f, f->lf.lr_lpf_line_ptr[1], lr_stride,
                        src[1] - offset_uv * PXSTRIDE(src_stride[1]), src_stride[1],
-                       ss_ver, f->seq_hdr.sb128, y_stripe, row_h, w, ss_hor);
+                       ss_ver, f->seq_hdr->sb128, y_stripe, row_h, w, ss_hor);
         }
         if (restore_planes & LR_RESTORE_V) {
             backup_lpf(f, f->lf.lr_lpf_line_ptr[2], lr_stride,
                        src[2] - offset_uv * PXSTRIDE(src_stride[1]), src_stride[1],
-                       ss_ver, f->seq_hdr.sb128, y_stripe, row_h, w, ss_hor);
+                       ss_ver, f->seq_hdr->sb128, y_stripe, row_h, w, ss_hor);
         }
     }
 }
@@ -278,8 +278,8 @@
     if (restore_planes & LR_RESTORE_Y) {
         const int h = f->sr_cur.p.p.h;
         const int w = f->sr_cur.p.p.w;
-        const int row_h = imin((sby + 1) << (6 + f->seq_hdr.sb128), h);
-        const int y_stripe = (sby << (6 + f->seq_hdr.sb128)) - offset_y;
+        const int row_h = imin((sby + 1) << (6 + f->seq_hdr->sb128), h);
+        const int y_stripe = (sby << (6 + f->seq_hdr->sb128)) - offset_y;
         lr_sbrow(f, dst[0] - offset_y * PXSTRIDE(dst_stride[0]), y_stripe, w,
                  h, row_h, 0);
     }
@@ -288,10 +288,10 @@
         const int ss_hor = f->sr_cur.p.p.layout != DAV1D_PIXEL_LAYOUT_I444;
         const int h = (f->sr_cur.p.p.h + ss_ver) >> ss_ver;
         const int w = (f->sr_cur.p.p.w + ss_hor) >> ss_hor;
-        const int row_h = imin((sby + 1) << ((6 - ss_ver) + f->seq_hdr.sb128), h);
+        const int row_h = imin((sby + 1) << ((6 - ss_ver) + f->seq_hdr->sb128), h);
         const ptrdiff_t offset_uv = offset_y >> ss_ver;
         const int y_stripe =
-            (sby << ((6 - ss_ver) + f->seq_hdr.sb128)) - offset_uv;
+            (sby << ((6 - ss_ver) + f->seq_hdr->sb128)) - offset_uv;
         if (restore_planes & LR_RESTORE_U)
             lr_sbrow(f, dst[1] - offset_uv * PXSTRIDE(dst_stride[1]), y_stripe,
                      w, h, row_h, 1);
--- a/src/obu.c
+++ b/src/obu.c
@@ -274,7 +274,7 @@
 static int read_frame_size(Dav1dContext *const c, GetBits *const gb,
                            const int use_ref)
 {
-    const Av1SequenceHeader *const seqhdr = &c->seq_hdr;
+    const Av1SequenceHeader *const seqhdr = c->seq_hdr;
     Av1FrameHeader *const hdr = &c->frame_hdr;
 
     if (use_ref) {
@@ -344,7 +344,7 @@
 #if DEBUG_FRAME_HDR
     const uint8_t *const init_ptr = gb->ptr;
 #endif
-    const Av1SequenceHeader *const seqhdr = &c->seq_hdr;
+    const Av1SequenceHeader *const seqhdr = c->seq_hdr;
     Av1FrameHeader *const hdr = &c->frame_hdr;
     int res;
 
@@ -407,7 +407,7 @@
     if (seqhdr->decoder_model_info_present) {
         hdr->buffer_removal_time_present = dav1d_get_bits(gb, 1);
         if (hdr->buffer_removal_time_present) {
-            for (int i = 0; i < c->seq_hdr.num_operating_points; i++) {
+            for (int i = 0; i < c->seq_hdr->num_operating_points; i++) {
                 const struct Av1SequenceHeaderOperatingPoint *const seqop = &seqhdr->operating_points[i];
                 struct Av1FrameHeaderOperatingPoint *const op = &hdr->operating_points[i];
                 if (seqop->decoder_model_param_present) {
@@ -1203,17 +1203,23 @@
 
     switch (type) {
     case OBU_SEQ_HDR: {
-        Av1SequenceHeader hdr, *const hdr_ptr = c->have_seq_hdr ? &hdr : &c->seq_hdr;
-        memset(hdr_ptr, 0, sizeof(*hdr_ptr));
+        Dav1dRef *ref = dav1d_ref_create(sizeof(Av1SequenceHeader));
+        if (!ref) return -ENOMEM;
+        Av1SequenceHeader *seq_hdr = ref->data;
+        memset(seq_hdr, 0, sizeof(*seq_hdr));
         c->have_frame_hdr = 0;
-        if ((res = parse_seq_hdr(c, &gb, hdr_ptr)) < 0)
+        if ((res = parse_seq_hdr(c, &gb, seq_hdr)) < 0) {
+            dav1d_ref_dec(&ref);
             return res;
-        if (check_for_overrun(&gb, init_bit_pos, len))
+        }
+        if (check_for_overrun(&gb, init_bit_pos, len)) {
+            dav1d_ref_dec(&ref);
             return -EINVAL;
+        }
         // If we have read a sequence header which is different from
         // the old one, this is a new video sequence and can't use any
         // previous state. Free that state.
-        if (c->have_seq_hdr && memcmp(&hdr, &c->seq_hdr, sizeof(hdr))) {
+        if (c->seq_hdr && memcmp(seq_hdr, c->seq_hdr, sizeof(*seq_hdr))) {
             for (int i = 0; i < 8; i++) {
                 if (c->refs[i].p.p.data[0])
                     dav1d_thread_picture_unref(&c->refs[i].p);
@@ -1222,9 +1228,10 @@
                 if (c->cdf[i].cdf)
                     dav1d_cdf_thread_unref(&c->cdf[i]);
             }
-            c->seq_hdr = hdr;
+            dav1d_ref_dec(&c->seq_hdr_ref);
         }
-        c->have_seq_hdr = 1;
+        c->seq_hdr_ref = ref;
+        c->seq_hdr = seq_hdr;
         break;
     }
     case OBU_REDUNDANT_FRAME_HDR:
@@ -1233,7 +1240,7 @@
     case OBU_FRAME:
     case OBU_FRAME_HDR:
         c->have_frame_hdr = 0;
-        if (!c->have_seq_hdr) goto error;
+        if (!c->seq_hdr) goto error;
         c->frame_hdr.temporal_id = temporal_id;
         c->frame_hdr.spatial_id = spatial_id;
         if ((res = parse_frame_hdr(c, &gb)) < 0)
@@ -1306,7 +1313,7 @@
         return -EINVAL;
     }
 
-    if (c->have_seq_hdr && c->have_frame_hdr &&
+    if (c->seq_hdr && c->have_frame_hdr &&
         c->n_tiles == c->frame_hdr.tiling.cols * c->frame_hdr.tiling.rows)
     {
         if (!c->n_tile_data)
@@ -1316,7 +1323,7 @@
         assert(!c->n_tile_data);
         c->have_frame_hdr = 0;
         c->n_tiles = 0;
-    } else if (c->have_seq_hdr && c->have_frame_hdr &&
+    } else if (c->seq_hdr && c->have_frame_hdr &&
                c->frame_hdr.show_existing_frame)
     {
         if (c->n_fc == 1) {
--- a/src/recon_tmpl.c
+++ b/src/recon_tmpl.c
@@ -368,7 +368,7 @@
     const uint8_t *const b_dim = dav1d_block_dimensions[bs];
     const int bw4 = b_dim[0], bh4 = b_dim[1];
     const int cbw4 = (bw4 + ss_hor) >> ss_hor, cbh4 = (bh4 + ss_ver) >> ss_ver;
-    const int has_chroma = f->seq_hdr.layout != DAV1D_PIXEL_LAYOUT_I400 &&
+    const int has_chroma = f->seq_hdr->layout != DAV1D_PIXEL_LAYOUT_I400 &&
                            (bw4 > ss_hor || t->bx & 1) &&
                            (bh4 > ss_ver || t->by & 1);
 
@@ -748,7 +748,7 @@
     const int bw4 = b_dim[0], bh4 = b_dim[1];
     const int w4 = imin(bw4, f->bw - t->bx), h4 = imin(bh4, f->bh - t->by);
     const int cw4 = (w4 + ss_hor) >> ss_hor, ch4 = (h4 + ss_ver) >> ss_ver;
-    const int has_chroma = f->seq_hdr.layout != DAV1D_PIXEL_LAYOUT_I400 &&
+    const int has_chroma = f->seq_hdr->layout != DAV1D_PIXEL_LAYOUT_I400 &&
                            (bw4 > ss_hor || t->bx & 1) &&
                            (bh4 > ss_ver || t->by & 1);
     const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[b->tx];
@@ -759,7 +759,7 @@
     pixel *const edge = edge_buf + 128;
     const int cbw4 = (bw4 + ss_hor) >> ss_hor, cbh4 = (bh4 + ss_ver) >> ss_ver;
 
-    const int intra_edge_filter_flag = f->seq_hdr.intra_edge_filter << 10;
+    const int intra_edge_filter_flag = f->seq_hdr->intra_edge_filter << 10;
 
     for (int init_y = 0; init_y < h4; init_y += 16) {
         for (int init_x = 0; init_x < w4; init_x += 16) {
@@ -1139,7 +1139,7 @@
     const uint8_t *const b_dim = dav1d_block_dimensions[bs];
     const int bw4 = b_dim[0], bh4 = b_dim[1];
     const int w4 = imin(bw4, f->bw - t->bx), h4 = imin(bh4, f->bh - t->by);
-    const int has_chroma = f->seq_hdr.layout != DAV1D_PIXEL_LAYOUT_I400 &&
+    const int has_chroma = f->seq_hdr->layout != DAV1D_PIXEL_LAYOUT_I400 &&
                            (bw4 > ss_hor || t->bx & 1) &&
                            (bh4 > ss_ver || t->by & 1);
     const int chr_layout_idx = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I400 ? 0 :
@@ -1579,11 +1579,11 @@
                                        start_of_tile_row);
     }
 
-    if (f->seq_hdr.restoration) {
+    if (f->seq_hdr->restoration) {
         // Store loop filtered pixels required by loop restoration
         bytefn(dav1d_lr_copy_lpf)(f, f->lf.p, sby);
     }
-    if (f->seq_hdr.cdef) {
+    if (f->seq_hdr->cdef) {
         if (sby) {
             const int ss_ver = f->cur.p.layout == DAV1D_PIXEL_LAYOUT_I420;
             pixel *p_up[3] = {
@@ -1618,7 +1618,7 @@
                               f->resize_start[!!pl]);
         }
     }
-    if (f->seq_hdr.restoration) {
+    if (f->seq_hdr->restoration) {
         bytefn(dav1d_lr_sbrow)(f, f->lf.sr_p, sby);
     }
 
@@ -1630,7 +1630,7 @@
     f->lf.sr_p[1] += sbsz * 4 * PXSTRIDE(f->sr_cur.p.stride[1]) >> ss_ver;
     f->lf.sr_p[2] += sbsz * 4 * PXSTRIDE(f->sr_cur.p.stride[1]) >> ss_ver;
     f->lf.prev_mask_ptr = f->lf.mask_ptr;
-    if ((sby & 1) || f->seq_hdr.sb128) {
+    if ((sby & 1) || f->seq_hdr->sb128) {
         f->lf.mask_ptr += f->sb128w;
     }
 }