/* * Copyright © 2018-2021, VideoLAN and dav1d authors * Copyright © 2018, Two Orioles, LLC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef DAV1D_SRC_INTERNAL_H #define DAV1D_SRC_INTERNAL_H #include #include "dav1d/data.h" typedef struct Dav1dFrameContext Dav1dFrameContext; typedef struct Dav1dTileState Dav1dTileState; typedef struct Dav1dTaskContext Dav1dTaskContext; typedef struct Dav1dTask Dav1dTask; #include "common/attributes.h" #include "src/cdef.h" #include "src/cdf.h" #include "src/data.h" #include "src/env.h" #include "src/filmgrain.h" #include "src/intra_edge.h" #include "src/ipred.h" #include "src/itx.h" #include "src/levels.h" #include "src/lf_mask.h" #include "src/loopfilter.h" #include "src/looprestoration.h" #include "src/mc.h" #include "src/msac.h" #include "src/picture.h" #include "src/recon.h" #include "src/refmvs.h" #include "src/thread.h" typedef struct Dav1dDSPContext { Dav1dFilmGrainDSPContext fg; Dav1dIntraPredDSPContext ipred; Dav1dMCDSPContext mc; Dav1dInvTxfmDSPContext itx; Dav1dLoopFilterDSPContext lf; Dav1dCdefDSPContext cdef; Dav1dLoopRestorationDSPContext lr; } Dav1dDSPContext; struct Dav1dTileGroup { Dav1dData data; int start, end; }; enum TaskType { DAV1D_TASK_TYPE_INIT, DAV1D_TASK_TYPE_INIT_CDF, DAV1D_TASK_TYPE_TILE_ENTROPY, DAV1D_TASK_TYPE_ENTROPY_PROGRESS, DAV1D_TASK_TYPE_TILE_RECONSTRUCTION, DAV1D_TASK_TYPE_DEBLOCK_COLS, DAV1D_TASK_TYPE_DEBLOCK_ROWS, DAV1D_TASK_TYPE_CDEF, DAV1D_TASK_TYPE_SUPER_RESOLUTION, DAV1D_TASK_TYPE_LOOP_RESTORATION, DAV1D_TASK_TYPE_RECONSTRUCTION_PROGRESS, DAV1D_TASK_TYPE_FG_PREP, DAV1D_TASK_TYPE_FG_APPLY, }; struct Dav1dContext { Dav1dFrameContext *fc; unsigned n_fc; Dav1dTaskContext *tc; unsigned n_tc; // cache of OBUs that make up a single frame before we submit them // to a frame worker to be decoded struct Dav1dTileGroup *tile; int n_tile_data_alloc; int n_tile_data; int n_tiles; Dav1dMemPool *seq_hdr_pool; Dav1dRef *seq_hdr_ref; Dav1dSequenceHeader *seq_hdr; Dav1dMemPool *frame_hdr_pool; Dav1dRef *frame_hdr_ref; Dav1dFrameHeader *frame_hdr; Dav1dRef *content_light_ref; Dav1dContentLightLevel *content_light; Dav1dRef *mastering_display_ref; Dav1dMasteringDisplay *mastering_display; Dav1dRef *itut_t35_ref; Dav1dITUTT35 *itut_t35; // decoded output picture queue Dav1dData in; Dav1dThreadPicture out, cache; // dummy is a pointer to prevent compiler errors about atomic_load() // not taking const arguments atomic_int flush_mem, *flush; struct { Dav1dThreadPicture *out_delayed; unsigned next; } frame_thread; // task threading (refer to tc[] for per_thread thingies) struct TaskThreadData { pthread_mutex_t lock; pthread_cond_t cond; atomic_uint first; unsigned cur; // This is used for delayed reset of the task cur pointer when // such operation is needed but the thread doesn't enter a critical // section (typically when executing the next sbrow task locklessly). // See src/thread_task.c:reset_task_cur(). atomic_uint reset_task_cur; atomic_int cond_signaled; struct { int exec; pthread_cond_t cond; const Dav1dPicture *in; Dav1dPicture *out; enum TaskType type; atomic_int progress[2]; /* [0]=started, [1]=completed */ union { struct { ALIGN(int8_t grain_lut_8bpc[3][GRAIN_HEIGHT + 1][GRAIN_WIDTH], 16); ALIGN(uint8_t scaling_8bpc[3][256], 64); }; struct { ALIGN(int16_t grain_lut_16bpc[3][GRAIN_HEIGHT + 1][GRAIN_WIDTH], 16); ALIGN(uint8_t scaling_16bpc[3][4096], 64); }; }; } delayed_fg; int inited; } task_thread; // reference/entropy state Dav1dMemPool *segmap_pool; Dav1dMemPool *refmvs_pool; struct { Dav1dThreadPicture p; Dav1dRef *segmap; Dav1dRef *refmvs; unsigned refpoc[7]; } refs[8]; Dav1dMemPool *cdf_pool; CdfThreadContext cdf[8]; Dav1dDSPContext dsp[3 /* 8, 10, 12 bits/component */]; Dav1dRefmvsDSPContext refmvs_dsp; // tree to keep track of which edges are available struct { EdgeNode *root[2 /* BL_128X128 vs. BL_64X64 */]; EdgeBranch branch_sb128[1 + 4 + 16 + 64]; EdgeBranch branch_sb64[1 + 4 + 16]; EdgeTip tip_sb128[256]; EdgeTip tip_sb64[64]; } intra_edge; Dav1dPicAllocator allocator; int apply_grain; int operating_point; unsigned operating_point_idc; int all_layers; int max_spatial_id; unsigned frame_size_limit; int strict_std_compliance; int output_invisible_frames; enum Dav1dInloopFilterType inloop_filters; int drain; enum PictureFlags frame_flags; enum Dav1dEventFlags event_flags; Dav1dDataProps cached_error_props; int cached_error; Dav1dLogger logger; Dav1dMemPool *picture_pool; }; struct Dav1dTask { unsigned frame_idx; // frame thread id enum TaskType type; // task work int sby; // sbrow // task dependencies int recon_progress, deblock_progress; int deps_skip; struct Dav1dTask *next; // only used in task queue }; struct Dav1dFrameContext { Dav1dRef *seq_hdr_ref; Dav1dSequenceHeader *seq_hdr; Dav1dRef *frame_hdr_ref; Dav1dFrameHeader *frame_hdr; Dav1dThreadPicture refp[7]; Dav1dPicture cur; // during block coding / reconstruction Dav1dThreadPicture sr_cur; // after super-resolution upscaling Dav1dRef *mvs_ref; refmvs_temporal_block *mvs, *ref_mvs[7]; Dav1dRef *ref_mvs_ref[7]; Dav1dRef *cur_segmap_ref, *prev_segmap_ref; uint8_t *cur_segmap; const uint8_t *prev_segmap; unsigned refpoc[7], refrefpoc[7][7]; uint8_t gmv_warp_allowed[7]; CdfThreadContext in_cdf, out_cdf; struct Dav1dTileGroup *tile; int n_tile_data_alloc; int n_tile_data; // for scalable references struct ScalableMotionParams { int scale; // if no scaling, this is 0 int step; } svc[7][2 /* x, y */]; int resize_step[2 /* y, uv */], resize_start[2 /* y, uv */]; const Dav1dContext *c; Dav1dTileState *ts; int n_ts; const Dav1dDSPContext *dsp; struct { recon_b_intra_fn recon_b_intra; recon_b_inter_fn recon_b_inter; filter_sbrow_fn filter_sbrow; filter_sbrow_fn filter_sbrow_deblock_cols; filter_sbrow_fn filter_sbrow_deblock_rows; void (*filter_sbrow_cdef)(Dav1dTaskContext *tc, int sby); filter_sbrow_fn filter_sbrow_resize; filter_sbrow_fn filter_sbrow_lr; backup_ipred_edge_fn backup_ipred_edge; read_coef_blocks_fn read_coef_blocks; } bd_fn; int ipred_edge_sz; pixel *ipred_edge[3]; ptrdiff_t b4_stride; int w4, h4, bw, bh, sb128w, sb128h, sbh, sb_shift, sb_step, sr_sb128w; uint16_t dq[DAV1D_MAX_SEGMENTS][3 /* plane */][2 /* dc/ac */]; const uint8_t *qm[N_RECT_TX_SIZES][3 /* plane */]; BlockContext *a; int a_sz /* w*tile_rows */; refmvs_frame rf; uint8_t jnt_weights[7][7]; int bitdepth_max; struct { int next_tile_row[2 /* 0: reconstruction, 1: entropy */]; atomic_int entropy_progress; atomic_int deblock_progress; // in sby units atomic_uint *frame_progress, *copy_lpf_progress; // indexed using t->by * f->b4_stride + t->bx Av1Block *b; struct CodedBlockInfo { int16_t eob[3 /* plane */]; uint8_t txtp[3 /* plane */]; } *cbi; // indexed using (t->by >> 1) * (f->b4_stride >> 1) + (t->bx >> 1) uint16_t (*pal)[3 /* plane */][8 /* idx */]; // iterated over inside tile state uint8_t *pal_idx; coef *cf; int prog_sz; int pal_sz, pal_idx_sz, cf_sz; // start offsets per tile int *tile_start_off; } frame_thread; // loopfilter struct { uint8_t (*level)[4]; Av1Filter *mask; Av1Restoration *lr_mask; int mask_sz /* w*h */, lr_mask_sz; int cdef_buf_plane_sz[2]; /* stride*sbh*4 */ int cdef_buf_sbh; int lr_buf_plane_sz[2]; /* (stride*sbh*4) << sb128 if n_tc > 1, else stride*4 */ int re_sz /* h */; ALIGN(Av1FilterLUT lim_lut, 16); int last_sharpness; uint8_t lvl[8 /* seg_id */][4 /* dir */][8 /* ref */][2 /* is_gmv */]; uint8_t *tx_lpf_right_edge[2]; uint8_t *cdef_line_buf, *lr_line_buf; pixel *cdef_line[2 /* pre, post */][3 /* plane */]; pixel *cdef_lpf_line[3 /* plane */]; pixel *lr_lpf_line[3 /* plane */]; // in-loop filter per-frame state keeping uint8_t *start_of_tile_row; int start_of_tile_row_sz; int need_cdef_lpf_copy; pixel *p[3], *sr_p[3]; Av1Filter *mask_ptr, *prev_mask_ptr; int restore_planes; // enum LrRestorePlanes } lf; struct { pthread_mutex_t lock; pthread_cond_t cond; struct TaskThreadData *ttd; struct Dav1dTask *tasks, *tile_tasks[2], init_task; int num_tasks, num_tile_tasks; atomic_int init_done; atomic_int done[2]; int retval; int update_set; // whether we need to update CDF reference atomic_int error; atomic_int task_counter; struct Dav1dTask *task_head, *task_tail; // Points to the task directly before the cur pointer in the queue. // This cur pointer is theoretical here, we actually keep track of the // "prev_t" variable. This is needed to not loose the tasks in // [head;cur-1] when picking one for execution. struct Dav1dTask *task_cur_prev; struct { // async task insertion atomic_int merge; pthread_mutex_t lock; Dav1dTask *head, *tail; } pending_tasks; } task_thread; // threading (refer to tc[] for per-thread things) struct FrameTileThreadData { int (*lowest_pixel_mem)[7][2]; int lowest_pixel_mem_sz; } tile_thread; }; struct Dav1dTileState { CdfContext cdf; MsacContext msac; struct { int col_start, col_end, row_start, row_end; // in 4px units int col, row; // in tile units } tiling; // in sby units, TILE_ERROR after a decoding error atomic_int progress[2 /* 0: reconstruction, 1: entropy */]; struct { uint8_t *pal_idx; coef *cf; } frame_thread[2 /* 0: reconstruction, 1: entropy */]; // in fullpel units, [0] = Y, [1] = UV, used for progress requirements // each entry is one tile-sbrow; middle index is refidx int (*lowest_pixel)[7][2]; uint16_t dqmem[DAV1D_MAX_SEGMENTS][3 /* plane */][2 /* dc/ac */]; const uint16_t (*dq)[3][2]; int last_qidx; int8_t last_delta_lf[4]; uint8_t lflvlmem[8 /* seg_id */][4 /* dir */][8 /* ref */][2 /* is_gmv */]; const uint8_t (*lflvl)[4][8][2]; Av1RestorationUnit *lr_ref[3]; }; struct Dav1dTaskContext { const Dav1dContext *c; const Dav1dFrameContext *f; Dav1dTileState *ts; int bx, by; BlockContext l, *a; refmvs_tile rt; ALIGN(union, 64) { int16_t cf_8bpc [32 * 32]; int32_t cf_16bpc[32 * 32]; }; // FIXME types can be changed to pixel (and dynamically allocated) // which would make copy/assign operations slightly faster? uint16_t al_pal[2 /* a/l */][32 /* bx/y4 */][3 /* plane */][8 /* palette_idx */]; uint8_t pal_sz_uv[2 /* a/l */][32 /* bx4/by4 */]; uint8_t txtp_map[32 * 32]; // inter-only ALIGN(union, 64) { struct { union { uint8_t lap_8bpc [128 * 32]; uint16_t lap_16bpc[128 * 32]; struct { int16_t compinter[2][128 * 128]; uint8_t seg_mask[128 * 128]; }; }; union { // stride=192 for non-SVC, or 320 for SVC uint8_t emu_edge_8bpc [320 * (256 + 7)]; uint16_t emu_edge_16bpc[320 * (256 + 7)]; }; }; struct { union { uint8_t levels[32 * 34]; struct { uint8_t pal_order[64][8]; uint8_t pal_ctx[64]; }; }; int16_t ac[32 * 32]; uint8_t pal_idx[2 * 64 * 64]; uint16_t pal[3 /* plane */][8 /* palette_idx */]; ALIGN(union, 64) { struct { uint8_t interintra_8bpc[64 * 64]; uint8_t edge_8bpc[257]; }; struct { uint16_t interintra_16bpc[64 * 64]; uint16_t edge_16bpc[257]; }; }; }; } scratch; Dav1dWarpedMotionParams warpmv; Av1Filter *lf_mask; int top_pre_cdef_toggle; int8_t *cur_sb_cdef_idx_ptr; // for chroma sub8x8, we need to know the filter for all 4 subblocks in // a 4x4 area, but the top/left one can go out of cache already, so this // keeps it accessible enum Filter2d tl_4x4_filter; struct { int pass; } frame_thread; struct { struct thread_data td; struct TaskThreadData *ttd; struct FrameTileThreadData *fttd; int flushed; int die; } task_thread; }; #endif /* DAV1D_SRC_INTERNAL_H */