mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 10:37:03 -06:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63a2e099a6 | ||
|
|
c955407373 | ||
|
|
54962c6389 | ||
|
|
6189fa8bf6 | ||
|
|
713f605566 | ||
|
|
9641817a15 | ||
|
|
1e097e3edd | ||
|
|
d94790d97a |
@@ -407,7 +407,7 @@ fn frame_paths(out: &str, ts: &[f64]) -> Result<Vec<String>, String> {
|
||||
return Ok(vec![out.to_string()]);
|
||||
}
|
||||
let p = std::path::Path::new(out);
|
||||
let stem = p.file_stem().and_then(|x| x.to_str()).unwrap_or("frame");
|
||||
let stem = p.file_stem().and_then(std::ffi::OsStr::to_str).unwrap_or("frame");
|
||||
let mut paths: Vec<String> = Vec::with_capacity(ts.len());
|
||||
for t in ts {
|
||||
let path = p.with_file_name(format!("{stem}-t{t:.3}.png")).to_string_lossy().into_owned();
|
||||
|
||||
@@ -41,8 +41,9 @@ pub fn poll(inbox: &Inbox, app: &mut SlideApp, ctx: &egui::Context) {
|
||||
Event::Open(paths) => {
|
||||
for p in paths.iter().filter_map(|p| p.to_str()) {
|
||||
if let Err(e) = app.open_path(p) {
|
||||
log::error!("{p}: {e}");
|
||||
app.set_status(format!("Couldn't open {p}: {e}"));
|
||||
let safe_p = p.replace(['\r', '\n'], " ");
|
||||
log::error!("{safe_p}: {e}");
|
||||
app.set_status(format!("Couldn't open {safe_p}: {e}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@ use std::f64::consts::PI;
|
||||
|
||||
use crate::easing::ease;
|
||||
use crate::transition::{FULL, Layer, R, Source};
|
||||
use crate::transition_geom::*;
|
||||
use crate::transition_geom::{
|
||||
Cam, V3, boundary, card, center, clip, dir, edge, ein, eout, facing_shade, fan, field, hash64, moved, offset, poly_layers, pow_inout, q2,
|
||||
rect_poly, rnd, rot, rot_quad, scale_rect, scaled, soft_rect, ss, v3, win,
|
||||
};
|
||||
|
||||
use Source::{Black, New, NewBack, NewContent, Old, OldBack, OldContent, White};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! CDEF (7.15).
|
||||
|
||||
use crate::frame::{FrameBuf, Plane};
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{CDEF_DIRECTIONS, CDEF_PRI_TAPS, CDEF_SEC_TAPS, CDEF_UV_DIR, DIV_TABLE};
|
||||
use crate::state::FrameState;
|
||||
|
||||
/// Run CDEF on `fs.cur`; returns the CdefFrame, or None when no block is filtered (CdefFrame
|
||||
@@ -242,14 +242,14 @@ fn filter_rows<const W: usize>(
|
||||
}
|
||||
for i in 0..h {
|
||||
let ci = ((i + 2) * PAD_STRIDE + 2) as isize;
|
||||
let Some(&x) = b16.get(ci as usize..).and_then(|r| r.first_chunk::<W>()) else {
|
||||
let Some(&x) = b16.get(ci as usize..).and_then(<[_]>::first_chunk::<W>) else {
|
||||
return;
|
||||
};
|
||||
let (mut sum, mut max, mut min) = ([0i16; W], x, x);
|
||||
for &(off, weight, thr, adj) in taps {
|
||||
let (weight, thr) = (weight as i16, thr as i16);
|
||||
let start = (ci + off) as usize;
|
||||
let Some(p) = b16.get(start..).and_then(|r| r.first_chunk::<W>()) else {
|
||||
let Some(p) = b16.get(start..).and_then(<[_]>::first_chunk::<W>) else {
|
||||
return;
|
||||
};
|
||||
for j in 0..W {
|
||||
|
||||
+21
-1
@@ -1,6 +1,26 @@
|
||||
//! The adaptive CDF arrays (spec 6.8.2 init_non_coeff_cdfs / init_coeff_cdfs, load_cdfs).
|
||||
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
DEFAULT_ANGLE_DELTA_CDF, DEFAULT_CFL_ALPHA_CDF, DEFAULT_CFL_SIGN_CDF, DEFAULT_COEFF_BASE_CDF, DEFAULT_COEFF_BASE_EOB_CDF, DEFAULT_COEFF_BR_CDF,
|
||||
DEFAULT_COMP_BWD_REF_CDF, DEFAULT_COMP_GROUP_IDX_CDF, DEFAULT_COMP_MODE_CDF, DEFAULT_COMP_REF_CDF, DEFAULT_COMP_REF_TYPE_CDF,
|
||||
DEFAULT_COMPOUND_IDX_CDF, DEFAULT_COMPOUND_MODE_CDF, DEFAULT_COMPOUND_TYPE_CDF, DEFAULT_DC_SIGN_CDF, DEFAULT_DELTA_LF_CDF, DEFAULT_DELTA_Q_CDF,
|
||||
DEFAULT_DRL_MODE_CDF, DEFAULT_EOB_EXTRA_CDF, DEFAULT_EOB_PT_16_CDF, DEFAULT_EOB_PT_32_CDF, DEFAULT_EOB_PT_64_CDF, DEFAULT_EOB_PT_128_CDF,
|
||||
DEFAULT_EOB_PT_256_CDF, DEFAULT_EOB_PT_512_CDF, DEFAULT_EOB_PT_1024_CDF, DEFAULT_FILTER_INTRA_CDF, DEFAULT_FILTER_INTRA_MODE_CDF,
|
||||
DEFAULT_INTER_INTRA_CDF, DEFAULT_INTER_INTRA_MODE_CDF, DEFAULT_INTER_TX_TYPE_SET1_CDF, DEFAULT_INTER_TX_TYPE_SET2_CDF,
|
||||
DEFAULT_INTER_TX_TYPE_SET3_CDF, DEFAULT_INTERP_FILTER_CDF, DEFAULT_INTRA_TX_TYPE_SET1_CDF, DEFAULT_INTRA_TX_TYPE_SET2_CDF, DEFAULT_INTRABC_CDF,
|
||||
DEFAULT_IS_INTER_CDF, DEFAULT_MOTION_MODE_CDF, DEFAULT_MV_BIT_CDF, DEFAULT_MV_CLASS_CDF, DEFAULT_MV_CLASS0_BIT_CDF, DEFAULT_MV_CLASS0_FR_CDF,
|
||||
DEFAULT_MV_CLASS0_HP_CDF, DEFAULT_MV_FR_CDF, DEFAULT_MV_HP_CDF, DEFAULT_MV_JOINT_CDF, DEFAULT_MV_SIGN_CDF, DEFAULT_NEW_MV_CDF,
|
||||
DEFAULT_PALETTE_SIZE_2_UV_COLOR_CDF, DEFAULT_PALETTE_SIZE_2_Y_COLOR_CDF, DEFAULT_PALETTE_SIZE_3_UV_COLOR_CDF, DEFAULT_PALETTE_SIZE_3_Y_COLOR_CDF,
|
||||
DEFAULT_PALETTE_SIZE_4_UV_COLOR_CDF, DEFAULT_PALETTE_SIZE_4_Y_COLOR_CDF, DEFAULT_PALETTE_SIZE_5_UV_COLOR_CDF, DEFAULT_PALETTE_SIZE_5_Y_COLOR_CDF,
|
||||
DEFAULT_PALETTE_SIZE_6_UV_COLOR_CDF, DEFAULT_PALETTE_SIZE_6_Y_COLOR_CDF, DEFAULT_PALETTE_SIZE_7_UV_COLOR_CDF, DEFAULT_PALETTE_SIZE_7_Y_COLOR_CDF,
|
||||
DEFAULT_PALETTE_SIZE_8_UV_COLOR_CDF, DEFAULT_PALETTE_SIZE_8_Y_COLOR_CDF, DEFAULT_PALETTE_UV_MODE_CDF, DEFAULT_PALETTE_UV_SIZE_CDF,
|
||||
DEFAULT_PALETTE_Y_MODE_CDF, DEFAULT_PALETTE_Y_SIZE_CDF, DEFAULT_PARTITION_W8_CDF, DEFAULT_PARTITION_W16_CDF, DEFAULT_PARTITION_W32_CDF,
|
||||
DEFAULT_PARTITION_W64_CDF, DEFAULT_PARTITION_W128_CDF, DEFAULT_REF_MV_CDF, DEFAULT_RESTORATION_TYPE_CDF, DEFAULT_SEGMENT_ID_CDF,
|
||||
DEFAULT_SEGMENT_ID_PREDICTED_CDF, DEFAULT_SINGLE_REF_CDF, DEFAULT_SKIP_CDF, DEFAULT_SKIP_MODE_CDF, DEFAULT_TX_8X8_CDF, DEFAULT_TX_16X16_CDF,
|
||||
DEFAULT_TX_32X32_CDF, DEFAULT_TX_64X64_CDF, DEFAULT_TXB_SKIP_CDF, DEFAULT_TXFM_SPLIT_CDF, DEFAULT_UNI_COMP_REF_CDF, DEFAULT_USE_OBMC_CDF,
|
||||
DEFAULT_USE_SGRPROJ_CDF, DEFAULT_USE_WIENER_CDF, DEFAULT_UV_MODE_CFL_ALLOWED_CDF, DEFAULT_UV_MODE_CFL_NOT_ALLOWED_CDF, DEFAULT_WEDGE_INDEX_CDF,
|
||||
DEFAULT_WEDGE_INTER_INTRA_CDF, DEFAULT_Y_MODE_CDF, DEFAULT_ZERO_MV_CDF, FRAME_LF_COUNT, MV_CONTEXTS,
|
||||
};
|
||||
|
||||
/// Every CDF array listed by init_non_coeff_cdfs and init_coeff_cdfs. Each innermost array holds
|
||||
/// N cumulative values (the last is 32768) plus the adaptation counter.
|
||||
|
||||
@@ -17,7 +17,11 @@ use crate::cdf::Cdfs;
|
||||
use crate::frame::FrameBuf;
|
||||
use crate::header::{FilmGrainParams, FrameHeader, HeaderState, LoopFilterDeltas, RefInfo, SegmentationFeatures, SequenceHeader, default_gm_params};
|
||||
use crate::par::Pool;
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
ALTREF_FRAME, ALTREF2_FRAME, BWDREF_FRAME, DEFAULT_INTRA_FRAME_Y_MODE_CDF, DIV_MULT, GOLDEN_FRAME, INTRA_FRAME, INTRA_ONLY_FRAME, KEY_FRAME,
|
||||
LAST_FRAME, LAST2_FRAME, MAX_FRAME_DISTANCE, MAX_OFFSET_HEIGHT, MAX_OFFSET_WIDTH, MFMV_STACK_SIZE, NUM_REF_FRAMES, PRIMARY_REF_NONE,
|
||||
REFMVS_LIMIT, REFS_PER_FRAME,
|
||||
};
|
||||
use crate::state::{FrameShared, FrameState, TileState};
|
||||
use crate::stats::{DecodeStats, Stage, Timer};
|
||||
use crate::tile::TileDecoder;
|
||||
@@ -61,7 +65,7 @@ impl<T: Clone> Slot<T> {
|
||||
}
|
||||
|
||||
fn set(&self, v: Result<T>) {
|
||||
let mut g = self.value.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut g = self.value.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
*g = Some(v);
|
||||
self.cv.notify_all();
|
||||
}
|
||||
@@ -71,12 +75,12 @@ impl<T: Clone> Slot<T> {
|
||||
}
|
||||
|
||||
fn wait(&self) -> Result<T> {
|
||||
let mut g = self.value.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut g = self.value.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
loop {
|
||||
if let Some(v) = g.as_ref() {
|
||||
return v.clone();
|
||||
}
|
||||
g = self.cv.wait(g).unwrap_or_else(|e| e.into_inner());
|
||||
g = self.cv.wait(g).unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ const POOL_MAX_SAMPLES: usize = 96 << 20;
|
||||
fn zeroed(len: usize) -> Vec<u16> {
|
||||
if len >= POOL_MIN_LEN {
|
||||
let found = {
|
||||
let mut pool = PLANE_POOL.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut pool = PLANE_POOL.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
pool.iter().position(|v| v.capacity() >= len && v.capacity() <= 2 * len).map(|i| pool.swap_remove(i))
|
||||
};
|
||||
if let Some(mut v) = found {
|
||||
@@ -52,8 +52,8 @@ impl Drop for Plane {
|
||||
fn drop(&mut self) {
|
||||
if self.data.capacity() >= POOL_MIN_LEN {
|
||||
let v = std::mem::take(&mut self.data);
|
||||
let mut pool = PLANE_POOL.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let kept: usize = pool.iter().map(|b| b.capacity()).sum();
|
||||
let mut pool = PLANE_POOL.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
let kept: usize = pool.iter().map(Vec::capacity).sum();
|
||||
if kept + v.capacity() <= POOL_MAX_SAMPLES {
|
||||
pool.push(v);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
//! Sequence header (5.5) and uncompressed frame header (5.9) parsing.
|
||||
|
||||
use crate::bits::BitReader;
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
AFFINE, ALTREF_FRAME, ALTREF2_FRAME, BWDREF_FRAME, GM_ABS_ALPHA_BITS, GM_ABS_TRANS_BITS, GM_ABS_TRANS_ONLY_BITS, GM_ALPHA_PREC_BITS,
|
||||
GM_TRANS_ONLY_PREC_BITS, GM_TRANS_PREC_BITS, GOLDEN_FRAME, IDENTITY, INTER_FRAME, INTRA_ONLY_FRAME, KEY_FRAME, LAST_FRAME, MAX_SEGMENTS,
|
||||
MAX_TILE_AREA, MAX_TILE_COLS, MAX_TILE_ROWS, MAX_TILE_WIDTH, NUM_REF_FRAMES, ONLY_4X4, PRIMARY_REF_NONE, REF_FRAME_LIST, REFS_PER_FRAME,
|
||||
RESTORATION_TILESIZE_MAX, RESTORE_NONE, RESTORE_SGRPROJ, RESTORE_SWITCHABLE, RESTORE_WIENER, ROTZOOM, SEG_LVL_ALT_Q, SEG_LVL_MAX,
|
||||
SEG_LVL_REF_FRAME, SELECT_INTEGER_MV, SELECT_SCREEN_CONTENT_TOOLS, SUPERRES_DENOM_BITS, SUPERRES_DENOM_MIN, SUPERRES_NUM, SWITCH_FRAME,
|
||||
TOTAL_REFS_PER_FRAME, TRANSLATION, TX_MODE_LARGEST, TX_MODE_SELECT, WARPEDMODEL_PREC_BITS,
|
||||
};
|
||||
use crate::{Error, Result};
|
||||
|
||||
pub const EIGHTTAP: u8 = 0;
|
||||
|
||||
+12
-3
@@ -5,7 +5,16 @@ use std::sync::OnceLock;
|
||||
|
||||
use crate::frame::Plane;
|
||||
use crate::mvpred::round2_signed64;
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
BLOCK_8X8, BLOCK_SIZES, COMPOUND_AVERAGE, COMPOUND_DIFFWTD, COMPOUND_DISTANCE, COMPOUND_INTRA, COMPOUND_WEDGE, DIV_LUT, DIV_LUT_BITS,
|
||||
DIV_LUT_PREC_BITS, EIGHTTAP, EIGHTTAP_SHARP, EIGHTTAP_SMOOTH, FILTER_BITS, GLOBAL_GLOBALMV, GLOBALMV, II_H_PRED, II_SMOOTH_PRED, II_V_PRED,
|
||||
II_WEIGHTS_1D, INTRA_FRAME, LAST_FRAME, LOCALWARP, LS_MV_MAX, MASK_MASTER_SIZE, MAX_FRAME_DISTANCE, MAX_SB_SIZE, MI_HEIGHT_LOG2, MI_WIDTH_LOG2,
|
||||
NUM_4X4_BLOCKS_HIGH, NUM_4X4_BLOCKS_WIDE, OBMC, OBMC_MASK_2, OBMC_MASK_4, OBMC_MASK_8, OBMC_MASK_16, OBMC_MASK_32, QUANT_DIST_LOOKUP,
|
||||
QUANT_DIST_WEIGHT, REF_SCALE_SHIFT, SCALE_SUBPEL_BITS, SUBPEL_BITS, SUBPEL_FILTERS, SUBPEL_MASK, TRANSLATION, WARP_PARAM_REDUCE_BITS,
|
||||
WARPED_FILTERS, WARPEDDIFF_PREC_BITS, WARPEDMODEL_NONDIAGAFFINE_CLAMP, WARPEDMODEL_PREC_BITS, WARPEDMODEL_TRANS_CLAMP, WARPEDPIXEL_PREC_SHIFTS,
|
||||
WEDGE_BITS, WEDGE_CODEBOOK, WEDGE_HORIZONTAL, WEDGE_MASTER_OBLIQUE_EVEN, WEDGE_MASTER_OBLIQUE_ODD, WEDGE_MASTER_VERTICAL, WEDGE_OBLIQUE27,
|
||||
WEDGE_OBLIQUE63, WEDGE_OBLIQUE117, WEDGE_OBLIQUE153, WEDGE_TYPES, WEDGE_VERTICAL,
|
||||
};
|
||||
use crate::tile::TileDecoder;
|
||||
|
||||
const PRED_STRIDE: usize = 128;
|
||||
@@ -678,7 +687,7 @@ fn hpass<const W: usize>(src: &[u16], hf: &[i16; 8], out: &mut [i32], half: i32,
|
||||
let mut acc = [half; W];
|
||||
for t in 0..8 {
|
||||
let f = hf[t] as i32;
|
||||
let Some(p) = src.get(t..).and_then(|s| s.first_chunk::<W>()) else {
|
||||
let Some(p) = src.get(t..).and_then(<[_]>::first_chunk::<W>) else {
|
||||
return;
|
||||
};
|
||||
for j in 0..W {
|
||||
@@ -699,7 +708,7 @@ fn vpass<const W: usize>(rows: &[i32], vf: &[i16; 8], out: &mut [i32], half: i32
|
||||
let mut acc = [half; W];
|
||||
for t in 0..8 {
|
||||
let f = vf[t] as i32;
|
||||
let Some(p) = rows.get(t * W..).and_then(|s| s.first_chunk::<W>()) else {
|
||||
let Some(p) = rows.get(t * W..).and_then(<[_]>::first_chunk::<W>) else {
|
||||
return;
|
||||
};
|
||||
for j in 0..W {
|
||||
|
||||
@@ -3,7 +3,14 @@
|
||||
use crate::Result;
|
||||
use crate::header::{EIGHTTAP, SWITCHABLE};
|
||||
use crate::mvpred::MvP;
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
ALTREF_FRAME, ALTREF2_FRAME, BLOCK_8X8, BLOCK_32X32, BLOCK_64X64, BLOCK_128X128, BWDREF_FRAME, CLASS0_SIZE, COMP_NEWMV_CTXS, COMPOUND_AVERAGE,
|
||||
COMPOUND_DIFFWTD, COMPOUND_DISTANCE, COMPOUND_INTRA, COMPOUND_MODE_CTX_MAP, COMPOUND_REFERENCE, COMPOUND_WEDGE, GLOBAL_GLOBALMV, GLOBALMV,
|
||||
GOLDEN_FRAME, INTRA_FRAME, INTRABC_DELAY_PIXELS, LAST_FRAME, LAST2_FRAME, LAST3_FRAME, LOCALWARP, MV_CLASS_0, MV_INTRABC_CONTEXT,
|
||||
MV_JOINT_HNZVNZ, MV_JOINT_HNZVZ, MV_JOINT_HZVNZ, NEAR_NEARMV, NEAR_NEWMV, NEAREST_NEARESTMV, NEAREST_NEWMV, NEARESTMV, NEARMV, NEW_NEARESTMV,
|
||||
NEW_NEARMV, NEW_NEWMV, NEWMV, NUM_4X4_BLOCKS_HIGH, NUM_4X4_BLOCKS_WIDE, OBMC, REF_SCALE_SHIFT, SEG_LVL_GLOBALMV, SEG_LVL_REF_FRAME, SEG_LVL_SKIP,
|
||||
SIMPLE, SINGLE_REFERENCE, SIZE_GROUP, TRANSLATION, UNIDIR_COMP_REFERENCE, UV_CFL_PRED, WEDGE_BITS,
|
||||
};
|
||||
use crate::tile::TileDecoder;
|
||||
|
||||
fn block_width(bs: usize) -> usize {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
//! Intra prediction (spec 7.11.2), palette prediction (7.11.4) and chroma from luma (7.11.5).
|
||||
|
||||
use crate::frame::Plane;
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
ANGLE_STEP, D67_PRED, DC_PRED, DR_INTRA_DERIVATIVE, INTRA_EDGE_KERNEL, INTRA_EDGE_TAPS, INTRA_FILTER_SCALE_BITS, INTRA_FILTER_TAPS,
|
||||
MODE_TO_ANGLE, SM_WEIGHTS_TX_4X4, SM_WEIGHTS_TX_8X8, SM_WEIGHTS_TX_16X16, SM_WEIGHTS_TX_32X32, SM_WEIGHTS_TX_64X64, SMOOTH_H_PRED, SMOOTH_PRED,
|
||||
SMOOTH_V_PRED, V_PRED,
|
||||
};
|
||||
use crate::transform::round2;
|
||||
|
||||
/// Inputs of the intra prediction process that come from the block.
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
//! Motion vector prediction processes (spec 7.10): find_mv_stack, has_overlappable_candidates
|
||||
//! and find_warp_samples.
|
||||
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
GLOBAL_GLOBALMV, GLOBALMV, IDENTITY, INTRA_FRAME, LEAST_SQUARES_SAMPLES_MAX, MAX_REF_MV_STACK_SIZE, MV_BORDER, NEAR_NEWMV, NEAREST_NEWMV,
|
||||
NEW_NEARESTMV, NEW_NEARMV, NEW_NEWMV, NEWMV, NUM_4X4_BLOCKS_HIGH, NUM_4X4_BLOCKS_WIDE, REF_CAT_LEVEL, TRANSLATION, WARPEDMODEL_PREC_BITS,
|
||||
};
|
||||
use crate::tile::TileDecoder;
|
||||
|
||||
pub(crate) type MvP = [i32; 2];
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
//! In-loop post filters run by decode_frame_wrapup: loop filter (7.14), CDEF (7.15),
|
||||
//! super-resolution upscaling (7.16) and loop restoration (7.17).
|
||||
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
GLOBAL_GLOBALMV, GLOBALMV, INTRA_FRAME, MAX_LOOP_FILTER, NEARESTMV, NUM_4X4_BLOCKS_HIGH, NUM_4X4_BLOCKS_WIDE, SEG_LVL_ALT_LF_Y_V, TX_HEIGHT,
|
||||
TX_WIDTH,
|
||||
};
|
||||
use crate::state::FrameState;
|
||||
use crate::stats::{DecodeStats, Stage, Timer};
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
//! Super-resolution upscaling (7.16) and loop restoration (7.17).
|
||||
|
||||
use crate::frame::{FrameBuf, Plane};
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
FILTER_BITS, RESTORE_NONE, RESTORE_SGRPROJ, RESTORE_WIENER, SGR_PARAMS, SGRPROJ_MTABLE_BITS, SGRPROJ_PRJ_BITS, SGRPROJ_RECIP_BITS,
|
||||
SGRPROJ_RST_BITS, SGRPROJ_SGR_BITS, SUPERRES_EXTRA_BITS, SUPERRES_FILTER_OFFSET, SUPERRES_FILTER_TAPS, SUPERRES_SCALE_BITS, SUPERRES_SCALE_MASK,
|
||||
UPSCALE_FILTER,
|
||||
};
|
||||
use crate::state::FrameState;
|
||||
|
||||
/// Upscale a frame horizontally from FrameWidth to UpscaledWidth (7.16).
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
use crate::decoder::RefFrame;
|
||||
use crate::frame::{FrameBuf, MiInfo};
|
||||
use crate::header::{FrameHeader, RefInfo, SequenceHeader};
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{DEFAULT_INTRA_FRAME_Y_MODE_CDF, NUM_REF_FRAMES, RESTORE_NONE, SUBSAMPLED_SIZE};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
+21
-1
@@ -6,7 +6,27 @@ use crate::cdf::Cdfs;
|
||||
use crate::frame::{MiInfo, Mv};
|
||||
use crate::header::{FrameHeader, NONE, SequenceHeader};
|
||||
use crate::intra::{IntraParams, is_directional_mode, predict_intra, round2_signed};
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
AC_QLOOKUP, ADJUSTED_TX_SIZE, ADST_FLIPADST, BLOCK_4X4, BLOCK_8X8, BLOCK_64X64, BLOCK_128X128, BR_CDF_SIZE, CFL_SIGN_NEG, CFL_SIGN_ZERO,
|
||||
COEFF_BASE_CTX_OFFSET, COEFF_BASE_POS_CTX_OFFSET, COEFF_BASE_RANGE, COMPOUND_AVERAGE, DC_PRED, DC_QLOOKUP, DCT_DCT, DCT_FLIPADST,
|
||||
DEFAULT_SCAN_4X4, DEFAULT_SCAN_4X8, DEFAULT_SCAN_4X16, DEFAULT_SCAN_8X4, DEFAULT_SCAN_8X8, DEFAULT_SCAN_8X16, DEFAULT_SCAN_8X32,
|
||||
DEFAULT_SCAN_16X4, DEFAULT_SCAN_16X8, DEFAULT_SCAN_16X16, DEFAULT_SCAN_16X32, DEFAULT_SCAN_32X8, DEFAULT_SCAN_32X16, DEFAULT_SCAN_32X32,
|
||||
DELTA_LF_SMALL, DELTA_Q_SMALL, FILTER_INTRA_MODE_TO_INTRA_DIR, FLIPADST_ADST, FLIPADST_DCT, FLIPADST_FLIPADST, FRAME_LF_COUNT, H_ADST, H_DCT,
|
||||
H_FLIPADST, H_PRED, IDTX, II_DC_PRED, II_H_PRED, II_V_PRED, INTRA_FRAME, INTRA_MODE_CONTEXT, MAG_REF_OFFSET_WITH_TX_CLASS, MAX_ANGLE_DELTA,
|
||||
MAX_LOOP_FILTER, MAX_TX_DEPTH_TABLE, MAX_TX_SIZE_RECT, MAX_VARTX_DEPTH, MCOL_SCAN_4X4, MCOL_SCAN_4X8, MCOL_SCAN_4X16, MCOL_SCAN_8X4,
|
||||
MCOL_SCAN_8X8, MCOL_SCAN_8X16, MCOL_SCAN_16X4, MCOL_SCAN_16X8, MCOL_SCAN_16X16, MI_HEIGHT_LOG2, MI_WIDTH_LOG2, MODE_TO_TXFM, MROW_SCAN_4X4,
|
||||
MROW_SCAN_4X8, MROW_SCAN_4X16, MROW_SCAN_8X4, MROW_SCAN_8X8, MROW_SCAN_8X16, MROW_SCAN_16X4, MROW_SCAN_16X8, MROW_SCAN_16X16,
|
||||
NUM_4X4_BLOCKS_HIGH, NUM_4X4_BLOCKS_WIDE, NUM_BASE_LEVELS, PALETTE_COLOR_CONTEXT, PALETTE_COLOR_HASH_MULTIPLIERS, PALETTE_COLORS,
|
||||
PALETTE_NUM_NEIGHBORS, PARTITION_HORZ, PARTITION_HORZ_4, PARTITION_HORZ_A, PARTITION_HORZ_B, PARTITION_NONE, PARTITION_SPLIT, PARTITION_SUBSIZE,
|
||||
PARTITION_VERT, PARTITION_VERT_4, PARTITION_VERT_A, PARTITION_VERT_B, QM_OFFSET, QUANTIZER_MATRIX, RESTORE_NONE, RESTORE_SGRPROJ, RESTORE_WIENER,
|
||||
SEG_LVL_SKIP, SGR_PARAMS, SGRPROJ_PARAMS_BITS, SGRPROJ_PRJ_BITS, SGRPROJ_PRJ_SUBEXP_K, SIG_REF_DIFF_OFFSET, SIG_REF_DIFF_OFFSET_NUM, SIMPLE,
|
||||
SMOOTH_H_PRED, SMOOTH_PRED, SMOOTH_V_PRED, SPLIT_TX_SIZE, SUPERRES_NUM, TX_4X4, TX_4X8, TX_4X16, TX_8X4, TX_8X8, TX_8X16, TX_8X32, TX_16X4,
|
||||
TX_16X8, TX_16X16, TX_16X32, TX_16X64, TX_32X8, TX_32X16, TX_32X32, TX_32X64, TX_64X16, TX_64X32, TX_64X64, TX_CLASS_2D, TX_CLASS_HORIZ,
|
||||
TX_CLASS_VERT, TX_HEIGHT, TX_HEIGHT_LOG2, TX_MODE_SELECT, TX_SET_DCTONLY, TX_SET_INTER_1, TX_SET_INTER_2, TX_SET_INTER_3, TX_SET_INTRA_1,
|
||||
TX_SET_INTRA_2, TX_SIZE_SQR, TX_SIZE_SQR_UP, TX_SIZES, TX_SIZES_ALL, TX_TYPE_IN_SET_INTER, TX_TYPE_IN_SET_INTRA, TX_TYPE_INTER_INV_SET1,
|
||||
TX_TYPE_INTER_INV_SET2, TX_TYPE_INTER_INV_SET3, TX_TYPE_INTRA_INV_SET1, TX_TYPE_INTRA_INV_SET2, TX_WIDTH, TX_WIDTH_LOG2, UV_CFL_PRED, V_ADST,
|
||||
V_DCT, V_FLIPADST, V_PRED,
|
||||
};
|
||||
use crate::state::{FrameShared, TileState};
|
||||
use crate::symbol::SymbolDecoder;
|
||||
use crate::transform::inverse_transform_2d;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
//! Inverse transforms (spec 7.13), implemented step by step as specified.
|
||||
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
ADST_ADST, ADST_DCT, ADST_FLIPADST, COS128_LOOKUP, DCT_ADST, DCT_DCT, DCT_FLIPADST, FLIPADST_ADST, FLIPADST_DCT, FLIPADST_FLIPADST, H_ADST,
|
||||
H_DCT, H_FLIPADST, TRANSFORM_ROW_SHIFT, TX_HEIGHT_LOG2, TX_WIDTH_LOG2, V_ADST, V_DCT, V_FLIPADST,
|
||||
};
|
||||
|
||||
#[inline(always)]
|
||||
fn round2_64(x: i64, n: u32) -> i32 {
|
||||
|
||||
@@ -577,7 +577,7 @@ fn commit_album(s: &mut Session, items: Vec<AlbumItem>, opts: AlbumOpts, replace
|
||||
}
|
||||
|
||||
fn album_norm(s: &str) -> String {
|
||||
s.chars().filter(|c| c.is_ascii_alphanumeric()).collect::<String>().to_ascii_lowercase()
|
||||
s.chars().filter(char::is_ascii_alphanumeric).collect::<String>().to_ascii_lowercase()
|
||||
}
|
||||
|
||||
fn album_layout(p: &Value) -> Result<AlbumLayout> {
|
||||
@@ -770,7 +770,7 @@ fn image_px(bytes: &[u8]) -> (f64, f64) {
|
||||
}
|
||||
|
||||
fn file_stem(name: &str) -> String {
|
||||
let base = std::path::Path::new(name).file_name().and_then(|n| n.to_str()).unwrap_or(name);
|
||||
let base = std::path::Path::new(name).file_name().and_then(std::ffi::OsStr::to_str).unwrap_or(name);
|
||||
let stem = match base.rsplit_once('.') {
|
||||
Some((s, ext)) if !s.is_empty() && !ext.is_empty() => s,
|
||||
_ => base,
|
||||
|
||||
@@ -107,14 +107,16 @@ pub fn html_to_body(html: &str) -> Option<TextBody> {
|
||||
}
|
||||
if closing {
|
||||
let kind = tag_kind(&name);
|
||||
if !kind.is_empty()
|
||||
&& let Some(pos) = stack.iter().rposition(|e| e.0 == kind)
|
||||
{
|
||||
let (_, db, di, du) = stack[pos];
|
||||
bold -= db;
|
||||
italic -= di;
|
||||
underline -= du;
|
||||
stack.truncate(pos);
|
||||
if !kind.is_empty() {
|
||||
let search_start = stack.len().saturating_sub(64);
|
||||
if let Some(offset) = stack[search_start..].iter().rposition(|e| e.0 == kind) {
|
||||
let pos = search_start + offset;
|
||||
let (_, db, di, du) = stack[pos];
|
||||
bold -= db;
|
||||
italic -= di;
|
||||
underline -= du;
|
||||
stack.truncate(pos);
|
||||
}
|
||||
}
|
||||
if is_block(&name) {
|
||||
new_para(&mut paragraphs);
|
||||
@@ -130,7 +132,7 @@ pub fn html_to_body(html: &str) -> Option<TextBody> {
|
||||
bold += db;
|
||||
italic += di;
|
||||
underline += du;
|
||||
if !token.ends_with('/') {
|
||||
if !token.ends_with('/') && stack.len() < 128 {
|
||||
stack.push((tag_kind(&name), db, di, du));
|
||||
} else {
|
||||
bold -= db;
|
||||
@@ -302,9 +304,11 @@ fn decode_text(raw: &str) -> String {
|
||||
while let Some(at) = rest.find('&') {
|
||||
out.push_str(&collapse_space(&rest[..at]));
|
||||
rest = &rest[at..];
|
||||
let Some(end) = rest.find(';') else {
|
||||
out.push_str(&collapse_space(rest));
|
||||
break;
|
||||
let search_window = rest.len().min(32);
|
||||
let Some(end) = rest[..search_window].find(';') else {
|
||||
out.push('&');
|
||||
rest = &rest[1..];
|
||||
continue;
|
||||
};
|
||||
let entity = &rest[1..end];
|
||||
let decoded = match entity {
|
||||
@@ -391,6 +395,10 @@ mod tests {
|
||||
assert_eq!(text("<p>R&D costs; up</p>"), "R&D costs; up");
|
||||
assert_eq!(text("<p>AT&T; Q&A</p>"), "AT&T; Q&A");
|
||||
assert_eq!(text("<p>A & B & C & D</p>"), "A & B & C & D");
|
||||
|
||||
// Verify many bare ampersands do not cause quadratic scan freeze
|
||||
let hostile = format!("<p>{}</p>", "&".repeat(2000));
|
||||
assert_eq!(text(&hostile), "&".repeat(2000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+59
-5
@@ -8,6 +8,14 @@
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn read_file(path: &str) -> Result<Vec<u8>, String> {
|
||||
crate::file_access::check_read(path)?;
|
||||
let meta = std::fs::metadata(path).map_err(|e| format!("{path}: {e}"))?;
|
||||
if !meta.is_file() {
|
||||
return Err(format!("{path}: not a regular file"));
|
||||
}
|
||||
const MAX_FILE_SIZE: u64 = 2 << 30; // 2 GiB
|
||||
if meta.len() > MAX_FILE_SIZE {
|
||||
return Err(format!("{path}: file size {} exceeds 2 GiB limit", meta.len()));
|
||||
}
|
||||
std::fs::read(path).map_err(|e| format!("{path}: {e}"))
|
||||
}
|
||||
|
||||
@@ -28,21 +36,29 @@ pub fn write_file(path: &str, bytes: &[u8]) -> Result<(), String> {
|
||||
static COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||
crate::file_access::check_write(path)?;
|
||||
let err = |e: std::io::Error| format!("{path}: {e}");
|
||||
// A uniquely named temporary sibling, created exclusively (never following or reusing an
|
||||
// existing file or symlink), is renamed over the destination: concurrent saves never share
|
||||
// temporary bytes.
|
||||
|
||||
let target_path = match std::fs::canonicalize(path) {
|
||||
Ok(canonical) => canonical,
|
||||
Err(_) => std::path::PathBuf::from(path),
|
||||
};
|
||||
let target_str = target_path.to_str().unwrap_or(path);
|
||||
let existing_perms = std::fs::metadata(&target_path).ok().map(|m| m.permissions());
|
||||
|
||||
let mut attempts = 0;
|
||||
let (tmp, mut file) = loop {
|
||||
let tmp = format!("{path}.{}.{}.saving", std::process::id(), COUNTER.fetch_add(1, Ordering::Relaxed));
|
||||
let tmp = format!("{target_str}.{}.{}.saving", std::process::id(), COUNTER.fetch_add(1, Ordering::Relaxed));
|
||||
match std::fs::OpenOptions::new().write(true).create_new(true).open(&tmp) {
|
||||
Ok(f) => break (tmp, f),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists && attempts < 16 => attempts += 1,
|
||||
Err(e) => return Err(err(e)),
|
||||
}
|
||||
};
|
||||
if let Some(perms) = existing_perms {
|
||||
let _ = file.set_permissions(perms);
|
||||
}
|
||||
let written = file.write_all(bytes).and_then(|()| file.sync_all());
|
||||
drop(file);
|
||||
let result = written.and_then(|()| std::fs::rename(&tmp, path));
|
||||
let result = written.and_then(|()| std::fs::rename(&tmp, &target_path));
|
||||
if let Err(e) = result {
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
return Err(err(e));
|
||||
@@ -67,3 +83,41 @@ pub fn file_len(path: &str) -> Option<u64> {
|
||||
pub fn file_len(_path: &str) -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn read_file_rejects_directory() {
|
||||
let dir = std::env::temp_dir();
|
||||
let res = read_file(dir.to_str().unwrap());
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_file_preserves_permissions_and_writes_content() {
|
||||
let tmp_dir = std::env::temp_dir().join("deckcraft_io_test");
|
||||
let _ = std::fs::create_dir_all(&tmp_dir);
|
||||
let test_file = tmp_dir.join("test_write.txt");
|
||||
let path_str = test_file.to_str().unwrap();
|
||||
|
||||
assert!(write_file(path_str, b"hello world").is_ok());
|
||||
let read = read_file(path_str).unwrap();
|
||||
assert_eq!(read, b"hello world");
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let perms = std::fs::Permissions::from_mode(0o640);
|
||||
std::fs::set_permissions(&test_file, perms).unwrap();
|
||||
|
||||
assert!(write_file(path_str, b"updated world").is_ok());
|
||||
let new_meta = std::fs::metadata(&test_file).unwrap();
|
||||
assert_eq!(new_meta.permissions().mode() & 0o777, 0o640);
|
||||
}
|
||||
|
||||
let _ = std::fs::remove_file(&test_file);
|
||||
let _ = std::fs::remove_dir(&tmp_dir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,8 +85,20 @@ fn owner_alive(dir: &Path, owner: u64) -> bool {
|
||||
|
||||
/// Write `bytes` to `path` through a temporary file and a rename, so a crash never leaves it torn.
|
||||
fn write_atomic(path: &Path, bytes: &[u8]) -> Result<()> {
|
||||
use std::io::Write;
|
||||
let tmp = path.with_extension(format!("{}.tmp", path.extension().and_then(|e| e.to_str()).unwrap_or("")));
|
||||
std::fs::write(&tmp, bytes).and_then(|_| std::fs::rename(&tmp, path)).map_err(|e| EngineError::Other(format!("{}: {e}", path.display())))
|
||||
let mut opts = std::fs::OpenOptions::new();
|
||||
opts.write(true).create(true).truncate(true);
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
opts.mode(0o600);
|
||||
}
|
||||
let mut file = opts.open(&tmp).map_err(|e| EngineError::Other(format!("{}: {e}", tmp.display())))?;
|
||||
file.write_all(bytes).and_then(|()| file.sync_all()).and_then(|()| std::fs::rename(&tmp, path)).map_err(|e| {
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
EngineError::Other(format!("{}: {e}", path.display()))
|
||||
})
|
||||
}
|
||||
|
||||
/// Presentations reopened per start; the rest stay on disk for the next one, so a folder
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::cabac::Cabac;
|
||||
use crate::error::{Result, ensure, invalid};
|
||||
use crate::mbtypes::*;
|
||||
use crate::mbtypes::{MbTypeInfo, Part, SubMbInfo, b_mb_type, b_sub_mb_type, intra_mb_type, p_mb_type, p_sub_mb_type};
|
||||
use crate::picture::MbKind;
|
||||
use crate::slice::SliceType;
|
||||
use crate::slicedec::{MbCur, SliceDecoder};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! CAVLC residual block parsing (9.2).
|
||||
|
||||
use crate::cavlc_tables::*;
|
||||
use crate::cavlc_tables::{COEFF_TOKEN, RUN_BEFORE, TOTAL_ZEROS_2X2, TOTAL_ZEROS_2X4, TOTAL_ZEROS_4X4};
|
||||
use crate::error::{Result, ensure};
|
||||
use deckcraft_bitstream::BitReader;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
@@ -232,7 +232,7 @@ fn filter_vertical<const N: usize>(pix: &mut [u8], stride: usize, x: usize, y: u
|
||||
let mut w = [0u64; N];
|
||||
for (i, w) in w.iter_mut().enumerate() {
|
||||
let o = (y + i) * stride + x - 4;
|
||||
let Some(&b) = pix.get(o..).and_then(|p| p.first_chunk::<8>()) else {
|
||||
let Some(&b) = pix.get(o..).and_then(<[_]>::first_chunk::<8>) else {
|
||||
return;
|
||||
};
|
||||
*w = u64::from_le_bytes(b);
|
||||
@@ -259,7 +259,7 @@ fn filter_horizontal<const N: usize>(pix: &mut [u8], stride: usize, x: usize, y:
|
||||
let base = (y - 4) * stride + x;
|
||||
let mut s = [[0i16; N]; 8];
|
||||
for (k, row) in s.iter_mut().enumerate() {
|
||||
let Some(src) = pix.get(base + k * stride..).and_then(|p| p.first_chunk::<N>()) else {
|
||||
let Some(src) = pix.get(base + k * stride..).and_then(<[_]>::first_chunk::<N>) else {
|
||||
return;
|
||||
};
|
||||
for i in 0..N {
|
||||
@@ -269,7 +269,7 @@ fn filter_horizontal<const N: usize>(pix: &mut [u8], stride: usize, x: usize, y:
|
||||
filter_lanes(&mut s, ep, chroma);
|
||||
let (k0, k1) = if chroma { (3, 5) } else { (1, 7) };
|
||||
for (k, row) in s.iter().enumerate().take(k1).skip(k0) {
|
||||
let Some(dst) = pix.get_mut(base + k * stride..).and_then(|p| p.first_chunk_mut::<N>()) else {
|
||||
let Some(dst) = pix.get_mut(base + k * stride..).and_then(<[_]>::first_chunk_mut::<N>) else {
|
||||
return;
|
||||
};
|
||||
for i in 0..N {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Sequence and picture parameter sets (7.3.2.1, 7.3.2.2) including VUI and scaling lists.
|
||||
|
||||
use crate::error::{Result, ensure, unsupported};
|
||||
use crate::tables::*;
|
||||
use crate::tables::{DEFAULT_4X4_INTER, DEFAULT_4X4_INTRA, DEFAULT_8X8_INTER, DEFAULT_8X8_INTRA, ZIGZAG4, ZIGZAG8};
|
||||
use deckcraft_bitstream::BitReader;
|
||||
|
||||
/// Scaling matrices after applying fall-back rules, stored in raster order (weightScale).
|
||||
|
||||
@@ -301,7 +301,7 @@ fn plane_allocator() -> fn(usize) -> Vec<u8> {
|
||||
fn copy_line<const N: usize>(line: &[u8], x0: i32, out: &mut [u8], w: usize) {
|
||||
if w <= N
|
||||
&& x0 >= 0
|
||||
&& let Some(src) = line.get(x0 as usize..).and_then(|l| l.first_chunk::<N>())
|
||||
&& let Some(src) = line.get(x0 as usize..).and_then(<[_]>::first_chunk::<N>)
|
||||
&& let Some(dst) = out.first_chunk_mut::<N>()
|
||||
{
|
||||
*dst = *src;
|
||||
|
||||
@@ -5,11 +5,11 @@ use crate::deblock;
|
||||
use crate::error::{Result, ensure, invalid};
|
||||
use crate::inter::{self, Weight};
|
||||
use crate::intra::{self, Avail};
|
||||
use crate::mbtypes::*;
|
||||
use crate::mbtypes::{CBP_ME, MbTypeInfo, Part, SubMbInfo, SubPart, b_mb_type, b_sub_mb_type, intra_mb_type, p_mb_type, p_sub_mb_type};
|
||||
use crate::params::{Pps, Sps};
|
||||
use crate::picture::*;
|
||||
use crate::picture::{Frame, FrameRef, MbKind, MbState, Planes, RefPic};
|
||||
use crate::slice::{SliceHeader, SliceType};
|
||||
use crate::tables::*;
|
||||
use crate::tables::{BLK4_XY, QPC_TABLE, RASTER_TO_BLK4, ZIGZAG4, ZIGZAG8};
|
||||
use crate::transform::{self, LevelScale};
|
||||
use deckcraft_bitstream::BitReader;
|
||||
|
||||
@@ -907,7 +907,7 @@ impl<'a> SliceDecoder<'a> {
|
||||
let stride = self.pic.planes.width;
|
||||
let px = self.mb_x * 16 + (raster & 3) * 4;
|
||||
let py = self.mb_y * 16 + (raster >> 2) * 4;
|
||||
let Some(blk) = self.s.coef.get_mut(raster * 16..).and_then(|c| c.first_chunk_mut::<16>()) else {
|
||||
let Some(blk) = self.s.coef.get_mut(raster * 16..).and_then(<[_]>::first_chunk_mut::<16>) else {
|
||||
return;
|
||||
};
|
||||
transform::idct4_add(blk, &mut self.pic.planes.y[py * stride + px..], stride);
|
||||
@@ -921,7 +921,7 @@ impl<'a> SliceDecoder<'a> {
|
||||
let stride = self.pic.planes.width;
|
||||
let px = self.mb_x * 16 + (b8 & 1) * 8;
|
||||
let py = self.mb_y * 16 + (b8 >> 1) * 8;
|
||||
let Some(blk) = self.s.coef.get_mut(b8 * 64..).and_then(|c| c.first_chunk_mut::<64>()) else {
|
||||
let Some(blk) = self.s.coef.get_mut(b8 * 64..).and_then(<[_]>::first_chunk_mut::<64>) else {
|
||||
return;
|
||||
};
|
||||
transform::idct8_add(blk, &mut self.pic.planes.y[py * stride + px..], stride);
|
||||
@@ -940,7 +940,7 @@ impl<'a> SliceDecoder<'a> {
|
||||
}
|
||||
let px = self.mb_x * 8 + (b & 1) * 4;
|
||||
let py = self.mb_y * 8 + (b >> 1) * 4;
|
||||
let Some(blk) = self.s.coef_c[c].get_mut(b * 16..).and_then(|c| c.first_chunk_mut::<16>()) else {
|
||||
let Some(blk) = self.s.coef_c[c].get_mut(b * 16..).and_then(<[_]>::first_chunk_mut::<16>) else {
|
||||
continue;
|
||||
};
|
||||
let plane = if c == 0 { &mut self.pic.planes.cb } else { &mut self.pic.planes.cr };
|
||||
|
||||
@@ -107,7 +107,7 @@ struct Pic {
|
||||
|
||||
impl Pic {
|
||||
fn is_p(&self) -> bool {
|
||||
!self.idr && !self.b && self.mbs.iter().any(|m| m.is_none())
|
||||
!self.idr && !self.b && self.mbs.iter().any(Option::is_none)
|
||||
}
|
||||
fn inter(&self) -> bool {
|
||||
self.b || self.is_p()
|
||||
|
||||
@@ -117,7 +117,7 @@ pub fn idct4_add(d: &[i32; 16], dst: &mut [u8], stride: usize) {
|
||||
o[3][j] = e - h;
|
||||
}
|
||||
for (i, row) in o.iter().enumerate() {
|
||||
let Some(line) = dst.get_mut(i * stride..).and_then(|d| d.first_chunk_mut::<4>()) else {
|
||||
let Some(line) = dst.get_mut(i * stride..).and_then(<[_]>::first_chunk_mut::<4>) else {
|
||||
return;
|
||||
};
|
||||
for (p, &v) in line.iter_mut().zip(row) {
|
||||
@@ -173,7 +173,7 @@ pub fn idct8_add(d: &[i32; 64], dst: &mut [u8], stride: usize) {
|
||||
}
|
||||
}
|
||||
for (i, row) in o.iter().enumerate() {
|
||||
let Some(line) = dst.get_mut(i * stride..).and_then(|d| d.first_chunk_mut::<8>()) else {
|
||||
let Some(line) = dst.get_mut(i * stride..).and_then(<[_]>::first_chunk_mut::<8>) else {
|
||||
return;
|
||||
};
|
||||
for (p, &v) in line.iter_mut().zip(row) {
|
||||
|
||||
@@ -25,7 +25,7 @@ fn filt_w<const T: usize, const W: usize>(src: &[i16], step: usize, f: &[i8; T],
|
||||
let mut acc = [0i32; W];
|
||||
for k in 0..T {
|
||||
let c = f[k] as i32;
|
||||
let Some(p) = src.get(k * step..).and_then(|s| s.first_chunk::<W>()) else {
|
||||
let Some(p) = src.get(k * step..).and_then(<[_]>::first_chunk::<W>) else {
|
||||
return;
|
||||
};
|
||||
for j in 0..W {
|
||||
|
||||
+142
-118
@@ -10,7 +10,11 @@ use crate::intra::{self, Refs};
|
||||
use crate::params::{Layout, Pps, Sps};
|
||||
use crate::picture::{FrameRef, RefPic};
|
||||
use crate::slice::{SliceHeader, SliceType};
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{
|
||||
ABS_MVD_GT0, ABS_MVD_GT1, CBF_CHROMA, CBF_LUMA, CODED_SUB_BLOCK, CU_QP_DELTA_ABS, CU_SKIP, CU_TRANSQUANT_BYPASS, GT1, GT2, INTER_PRED_IDC,
|
||||
INTRA_CHROMA, LAST_X_PREFIX, LAST_Y_PREFIX, MERGE_FLAG, MERGE_IDX, MVP_FLAG, PART_MODE, PRED_MODE, PREV_INTRA_LUMA, REF_IDX, RQT_ROOT_CBF,
|
||||
SAO_MERGE, SAO_TYPE, SIG_COEFF, SPLIT_CU, SPLIT_TRANSFORM, TRANSFORM_SKIP,
|
||||
};
|
||||
use crate::tables::{CTX_IDX_MAP, LEVEL_SCALE, SCAN_4, qpc_420, scan_order};
|
||||
use crate::transform;
|
||||
use std::sync::Arc;
|
||||
@@ -393,6 +397,37 @@ impl<'a> SliceDecoder<'a> {
|
||||
d.decode_data()
|
||||
}
|
||||
|
||||
/// Context initialisation / synchronisation at the start of a CTB (9.3.1, 9.3.2.1).
|
||||
fn init_ctb_contexts(&mut self, layout: &Layout, ts: u32, rs: u32, wctb: u32, first: bool) -> Result<()> {
|
||||
let ctb = 1i32 << self.sps.log2_ctb;
|
||||
let first_in_tile = ts == 0 || layout.tile_id[ts as usize] != layout.tile_id[ts as usize - 1];
|
||||
let wpp_row_start = self.pps.entropy_coding_sync
|
||||
&& (rs.is_multiple_of(wctb) || layout.tile_id[ts as usize] != layout.tile_id[layout.rs_to_ts[rs as usize - 1] as usize]);
|
||||
if first_in_tile {
|
||||
if !first {
|
||||
init_contexts(&mut self.c.ctx, self.slice_qp, self.init_type);
|
||||
}
|
||||
self.last_qp = self.slice_qp;
|
||||
} else if wpp_row_start {
|
||||
let (x0, y0) = (self.ctb_x, self.ctb_y);
|
||||
let avail = self.pic.zavail(x0, y0, x0 + ctb, y0 - ctb, self.slice_addr);
|
||||
match (&self.pic.wpp_ctx, avail) {
|
||||
(Some(saved), true) => self.c.ctx = **saved,
|
||||
_ => init_contexts(&mut self.c.ctx, self.slice_qp, self.init_type),
|
||||
}
|
||||
self.last_qp = self.slice_qp;
|
||||
} else if first && self.sh.dependent {
|
||||
match &self.pic.ds_ctx {
|
||||
Some((saved, qp)) => {
|
||||
self.c.ctx = **saved;
|
||||
self.last_qp = *qp;
|
||||
}
|
||||
None => return invalid("dependent slice segment without stored contexts"),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decode_data(&mut self) -> Result<()> {
|
||||
let layout = self.pic.layout.clone();
|
||||
let wctb = self.pic.wctb as u32;
|
||||
@@ -408,32 +443,7 @@ impl<'a> SliceDecoder<'a> {
|
||||
self.ctb_y = ry * ctb;
|
||||
self.pic.ctb_slice[rs as usize] = self.slice_idx;
|
||||
self.pic.ctb_addr[rs as usize] = self.slice_addr;
|
||||
// context initialisation / synchronisation (9.3.1, 9.3.2.1)
|
||||
let first_in_tile = ts == 0 || layout.tile_id[ts as usize] != layout.tile_id[ts as usize - 1];
|
||||
let wpp_row_start = self.pps.entropy_coding_sync
|
||||
&& (rs.is_multiple_of(wctb) || layout.tile_id[ts as usize] != layout.tile_id[layout.rs_to_ts[rs as usize - 1] as usize]);
|
||||
if first_in_tile {
|
||||
if !first {
|
||||
init_contexts(&mut self.c.ctx, self.slice_qp, self.init_type);
|
||||
}
|
||||
self.last_qp = self.slice_qp;
|
||||
} else if wpp_row_start {
|
||||
let (x0, y0) = (self.ctb_x, self.ctb_y);
|
||||
let avail = self.pic.zavail(x0, y0, x0 + ctb, y0 - ctb, self.slice_addr);
|
||||
match (&self.pic.wpp_ctx, avail) {
|
||||
(Some(saved), true) => self.c.ctx = **saved,
|
||||
_ => init_contexts(&mut self.c.ctx, self.slice_qp, self.init_type),
|
||||
}
|
||||
self.last_qp = self.slice_qp;
|
||||
} else if first && self.sh.dependent {
|
||||
match &self.pic.ds_ctx {
|
||||
Some((saved, qp)) => {
|
||||
self.c.ctx = **saved;
|
||||
self.last_qp = *qp;
|
||||
}
|
||||
None => return invalid("dependent slice segment without stored contexts"),
|
||||
}
|
||||
}
|
||||
self.init_ctb_contexts(&layout, ts, rs, wctb, first)?;
|
||||
first = false;
|
||||
if self.sh.sao_luma || self.sh.sao_chroma {
|
||||
self.parse_sao(rx, ry, rs)?;
|
||||
@@ -502,56 +512,60 @@ impl<'a> SliceDecoder<'a> {
|
||||
let mut p = SaoParams::default();
|
||||
for c in 0..3 {
|
||||
let enabled = if c == 0 { self.sh.sao_luma } else { self.sh.sao_chroma };
|
||||
if !enabled {
|
||||
continue;
|
||||
}
|
||||
if c == 2 {
|
||||
p.type_idx[2] = p.type_idx[1];
|
||||
p.eo_class[2] = p.eo_class[1];
|
||||
} else {
|
||||
p.type_idx[c] = if self.dd(SAO_TYPE) == 0 {
|
||||
0
|
||||
} else if self.bypass() == 0 {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
};
|
||||
}
|
||||
if p.type_idx[c] == 0 {
|
||||
continue;
|
||||
}
|
||||
let bd = if c == 0 { self.pic.bd_y } else { self.pic.bd_c };
|
||||
let cmax = (1u32 << (bd.min(10) - 5)) - 1;
|
||||
let mut abs = [0i16; 4];
|
||||
for a in abs.iter_mut() {
|
||||
let mut v = 0;
|
||||
while v < cmax && self.bypass() == 1 {
|
||||
v += 1;
|
||||
}
|
||||
*a = v as i16;
|
||||
}
|
||||
if p.type_idx[c] == 1 {
|
||||
for a in abs.iter_mut() {
|
||||
if *a != 0 && self.bypass() == 1 {
|
||||
*a = -*a;
|
||||
}
|
||||
}
|
||||
p.band_pos[c] = self.bypass_bits(5) as u8;
|
||||
p.offsets[c] = abs;
|
||||
} else {
|
||||
p.offsets[c] = [abs[0], abs[1], -abs[2], -abs[3]];
|
||||
if c == 0 {
|
||||
p.eo_class[0] = self.bypass_bits(2) as u8;
|
||||
}
|
||||
if c == 1 {
|
||||
p.eo_class[1] = self.bypass_bits(2) as u8;
|
||||
}
|
||||
if enabled {
|
||||
self.parse_sao_component(&mut p, c);
|
||||
}
|
||||
}
|
||||
self.pic.sao[rs as usize] = p;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// SAO syntax of one enabled colour component `c` (7.3.8.3).
|
||||
fn parse_sao_component(&mut self, p: &mut SaoParams, c: usize) {
|
||||
if c == 2 {
|
||||
p.type_idx[2] = p.type_idx[1];
|
||||
p.eo_class[2] = p.eo_class[1];
|
||||
} else {
|
||||
p.type_idx[c] = if self.dd(SAO_TYPE) == 0 {
|
||||
0
|
||||
} else if self.bypass() == 0 {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
};
|
||||
}
|
||||
if p.type_idx[c] == 0 {
|
||||
return;
|
||||
}
|
||||
let bd = if c == 0 { self.pic.bd_y } else { self.pic.bd_c };
|
||||
let cmax = (1u32 << (bd.min(10) - 5)) - 1;
|
||||
let mut abs = [0i16; 4];
|
||||
for a in abs.iter_mut() {
|
||||
let mut v = 0;
|
||||
while v < cmax && self.bypass() == 1 {
|
||||
v += 1;
|
||||
}
|
||||
*a = v as i16;
|
||||
}
|
||||
if p.type_idx[c] == 1 {
|
||||
for a in abs.iter_mut() {
|
||||
if *a != 0 && self.bypass() == 1 {
|
||||
*a = -*a;
|
||||
}
|
||||
}
|
||||
p.band_pos[c] = self.bypass_bits(5) as u8;
|
||||
p.offsets[c] = abs;
|
||||
} else {
|
||||
p.offsets[c] = [abs[0], abs[1], -abs[2], -abs[3]];
|
||||
if c == 0 {
|
||||
p.eo_class[0] = self.bypass_bits(2) as u8;
|
||||
}
|
||||
if c == 1 {
|
||||
p.eo_class[1] = self.bypass_bits(2) as u8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn coding_quadtree(&mut self, x0: i32, y0: i32, log2: u32, depth: u32) -> Result<()> {
|
||||
let size = 1i32 << log2;
|
||||
let (w, h) = (self.pic.width as i32, self.pic.height as i32);
|
||||
@@ -822,6 +836,34 @@ impl<'a> SliceDecoder<'a> {
|
||||
self.c.init_engine()
|
||||
}
|
||||
|
||||
/// Most probable luma intra modes of the block at (xp, yp) (8.4.2).
|
||||
fn mpm_list(&self, xp: i32, yp: i32) -> [u32; 3] {
|
||||
let cand_a = if self.pic.zavail(xp, yp, xp - 1, yp, self.slice_addr) {
|
||||
let b = self.pic.blk_at(xp - 1, yp);
|
||||
if b.flags & F_INTRA != 0 { b.ipm as u32 } else { 1 }
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let cand_b = if self.pic.zavail(xp, yp, xp, yp - 1, self.slice_addr) && yp > ((yp >> self.sps.log2_ctb) << self.sps.log2_ctb) {
|
||||
let b = self.pic.blk_at(xp, yp - 1);
|
||||
if b.flags & F_INTRA != 0 { b.ipm as u32 } else { 1 }
|
||||
} else {
|
||||
1
|
||||
};
|
||||
if cand_a == cand_b {
|
||||
if cand_a < 2 { [0, 1, 26] } else { [cand_a, 2 + ((cand_a + 29) % 32), 2 + ((cand_a - 2 + 1) % 32)] }
|
||||
} else {
|
||||
let c = if cand_a != 0 && cand_b != 0 {
|
||||
0
|
||||
} else if cand_a != 1 && cand_b != 1 {
|
||||
1
|
||||
} else {
|
||||
26
|
||||
};
|
||||
[cand_a, cand_b, c]
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_intra_modes(&mut self, x0: i32, y0: i32, n: i32, part: PartMode) -> Result<()> {
|
||||
let nb = if part == PartMode::PNxN { 2 } else { 1 };
|
||||
let pb = n / nb;
|
||||
@@ -834,31 +876,7 @@ impl<'a> SliceDecoder<'a> {
|
||||
for i in 0..nb {
|
||||
let k = (j * nb + i) as usize;
|
||||
let (xp, yp) = (x0 + i * pb, y0 + j * pb);
|
||||
// candidate modes (8.4.2)
|
||||
let cand_a = if self.pic.zavail(xp, yp, xp - 1, yp, self.slice_addr) {
|
||||
let b = self.pic.blk_at(xp - 1, yp);
|
||||
if b.flags & F_INTRA != 0 { b.ipm as u32 } else { 1 }
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let cand_b = if self.pic.zavail(xp, yp, xp, yp - 1, self.slice_addr) && yp > ((yp >> self.sps.log2_ctb) << self.sps.log2_ctb) {
|
||||
let b = self.pic.blk_at(xp, yp - 1);
|
||||
if b.flags & F_INTRA != 0 { b.ipm as u32 } else { 1 }
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let mut list = if cand_a == cand_b {
|
||||
if cand_a < 2 { [0, 1, 26] } else { [cand_a, 2 + ((cand_a + 29) % 32), 2 + ((cand_a - 2 + 1) % 32)] }
|
||||
} else {
|
||||
let c = if cand_a != 0 && cand_b != 0 {
|
||||
0
|
||||
} else if cand_a != 1 && cand_b != 1 {
|
||||
1
|
||||
} else {
|
||||
26
|
||||
};
|
||||
[cand_a, cand_b, c]
|
||||
};
|
||||
let mut list = self.mpm_list(xp, yp);
|
||||
let mode = if prev[k] {
|
||||
let idx = if self.bypass() == 0 {
|
||||
0
|
||||
@@ -934,33 +952,39 @@ impl<'a> SliceDecoder<'a> {
|
||||
self.transform_unit(x0, y0, xb, yb, log2, blk_idx, cbf_luma, cbf_c)
|
||||
}
|
||||
|
||||
/// cu_qp_delta_abs / sign and QP update (7.3.8.14).
|
||||
fn parse_cu_qp_delta(&mut self) -> Result<()> {
|
||||
// cu_qp_delta_abs: prefix TU(5) with ctx 0,1,1,1,1, suffix EG0
|
||||
let mut v = 0;
|
||||
while v < 5 && self.dd(CU_QP_DELTA_ABS + if v == 0 { 0 } else { 1 }) == 1 {
|
||||
v += 1;
|
||||
}
|
||||
if v == 5 {
|
||||
let mut k = 0;
|
||||
while self.bypass() == 1 {
|
||||
v += 1 << k;
|
||||
k += 1;
|
||||
ensure!(k < 32, "invalid cu_qp_delta_abs");
|
||||
}
|
||||
v += self.bypass_bits(k) as i32;
|
||||
}
|
||||
if v != 0 && self.bypass() == 1 {
|
||||
v = -v;
|
||||
}
|
||||
let off = 6 * (self.pic.bd_y as i32 - 8);
|
||||
ensure!(v >= -(26 + off / 2) && v <= 25 + off / 2, "CuQpDeltaVal out of range");
|
||||
self.is_cu_qp_delta_coded = true;
|
||||
self.cu_qp_delta = v;
|
||||
self.update_qp();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transform_unit(&mut self, x0: i32, y0: i32, xb: i32, yb: i32, log2: u32, blk_idx: u32, cbf_luma: bool, cbf_c: [bool; 2]) -> Result<()> {
|
||||
let n = 1i32 << log2;
|
||||
let chroma_here = log2 > 2 || blk_idx == 3;
|
||||
let cbf_chroma = cbf_c[0] || cbf_c[1];
|
||||
if (cbf_luma || cbf_chroma) && self.pps.cu_qp_delta_enabled && !self.is_cu_qp_delta_coded {
|
||||
// cu_qp_delta_abs: prefix TU(5) with ctx 0,1,1,1,1, suffix EG0
|
||||
let mut v = 0;
|
||||
while v < 5 && self.dd(CU_QP_DELTA_ABS + if v == 0 { 0 } else { 1 }) == 1 {
|
||||
v += 1;
|
||||
}
|
||||
if v == 5 {
|
||||
let mut k = 0;
|
||||
while self.bypass() == 1 {
|
||||
v += 1 << k;
|
||||
k += 1;
|
||||
ensure!(k < 32, "invalid cu_qp_delta_abs");
|
||||
}
|
||||
v += self.bypass_bits(k) as i32;
|
||||
}
|
||||
if v != 0 && self.bypass() == 1 {
|
||||
v = -v;
|
||||
}
|
||||
let off = 6 * (self.pic.bd_y as i32 - 8);
|
||||
ensure!(v >= -(26 + off / 2) && v <= 25 + off / 2, "CuQpDeltaVal out of range");
|
||||
self.is_cu_qp_delta_coded = true;
|
||||
self.cu_qp_delta = v;
|
||||
self.update_qp();
|
||||
self.parse_cu_qp_delta()?;
|
||||
}
|
||||
// luma
|
||||
if self.cu_intra {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
use crate::Decoder;
|
||||
use crate::cabac::{Contexts, NEXT_STATE, RANGE_TAB_LPS, init_contexts};
|
||||
use crate::spec_tables::*;
|
||||
use crate::spec_tables::{CU_SKIP, NUM_CTX, PRED_MODE, SPLIT_CU};
|
||||
use deckcraft_bitstream::{BitWriter, escape_rbsp};
|
||||
|
||||
const W: usize = 96;
|
||||
|
||||
Vendored
+6
-4
@@ -28,11 +28,13 @@ for f in range(6):
|
||||
sys.stdout.buffer.write(bytes(v for y in range(h) for x in range(w) for v in ((x * 4 + f * 20) % 256, (y * 5) % 256, (f * 40) % 256)))
|
||||
" > "$out"
|
||||
}
|
||||
frames 64 48 /tmp/deckcraft-fixture-64x48.rgb
|
||||
frames 64 64 /tmp/deckcraft-fixture-64x64.rgb
|
||||
VID="-f rawvideo -pix_fmt rgb24 -s 64x48 -r 10 -i /tmp/deckcraft-fixture-64x48.rgb"
|
||||
TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/deckcraft-fixture.XXXXXX")"
|
||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||
frames 64 48 "$TMP_DIR/deckcraft-fixture-64x48.rgb"
|
||||
frames 64 64 "$TMP_DIR/deckcraft-fixture-64x64.rgb"
|
||||
VID="-f rawvideo -pix_fmt rgb24 -s 64x48 -r 10 -i $TMP_DIR/deckcraft-fixture-64x48.rgb"
|
||||
$FF $VID $TONE44 -c:v libx264 -pix_fmt yuv420p -g 5 -bf 2 -c:a aac -b:a 48k -shortest $META clip-h264.mp4
|
||||
$FF $VID -c:v libx264 -pix_fmt yuv420p -g 5 -bf 0 $META clip-h264.mov
|
||||
$FF $VID -c:v libx265 -pix_fmt yuv420p -x265-params log-level=error:keyint=5 -tag:v hvc1 $META clip-hevc.mp4
|
||||
$FF $VID $TONE -c:v libvpx-vp9 -pix_fmt yuv420p -g 5 -b:v 100k -c:a libopus -b:a 32k -shortest $META clip-vp9.webm
|
||||
$FF -f rawvideo -pix_fmt rgb24 -s 64x64 -r 10 -i /tmp/deckcraft-fixture-64x64.rgb -c:v libsvtav1 -pix_fmt yuv420p -g 5 -svtav1-params loglevel=0 $META clip-av1.mkv
|
||||
$FF -f rawvideo -pix_fmt rgb24 -s 64x64 -r 10 -i "$TMP_DIR/deckcraft-fixture-64x64.rgb" -c:v libsvtav1 -pix_fmt yuv420p -g 5 -svtav1-params loglevel=0 $META clip-av1.mkv
|
||||
|
||||
@@ -1217,7 +1217,7 @@ fn savedc_restores_text_colour_and_font() {
|
||||
fn efont(height: i32, esc: i32, weight: i32, italic: u8, charset: u8, face: &str) -> Vec<u8> {
|
||||
let mut v = cat(vec![h32(1), e32(height), e32(0), e32(esc), e32(esc), e32(weight)]);
|
||||
v.extend([italic, 0, 0, charset, 0, 0, 0, 0]);
|
||||
let mut name: Vec<u8> = face.encode_utf16().flat_map(|u| u.to_le_bytes()).collect();
|
||||
let mut name: Vec<u8> = face.encode_utf16().flat_map(u16::to_le_bytes).collect();
|
||||
name.resize(64, 0);
|
||||
v.extend(name);
|
||||
erec(82, &v)
|
||||
|
||||
+32
-15
@@ -609,27 +609,44 @@ impl Chart {
|
||||
return (!secondary && self.kind != ChartType::Combo).then_some((0.0, 0.0));
|
||||
}
|
||||
let (mut lo, mut hi) = (f64::INFINITY, f64::NEG_INFINITY);
|
||||
let n = ser.iter().map(|s| s.values.len()).max().unwrap_or(0);
|
||||
let has_stacked_or_percent = ser.iter().any(|s| {
|
||||
let k = self.series_kind(s);
|
||||
k.stacked() || k.percent()
|
||||
});
|
||||
|
||||
let mut percent = false;
|
||||
for i in 0..n {
|
||||
let (mut p, mut m, mut stacked) = (0.0, 0.0, false);
|
||||
if has_stacked_or_percent {
|
||||
let n = ser.iter().map(|s| s.values.len()).max().unwrap_or(0);
|
||||
let budget = (ser.len() * n).min(10_000_000);
|
||||
let n_clamped = if ser.is_empty() { 0 } else { n.min(budget / ser.len()) };
|
||||
|
||||
for i in 0..n_clamped {
|
||||
let (mut p, mut m, mut stacked) = (0.0, 0.0, false);
|
||||
for s in &ser {
|
||||
let k = self.series_kind(s);
|
||||
let Some(v) = s.values.get(i).copied().flatten().filter(|v| v.is_finite()) else { continue };
|
||||
if k.percent() {
|
||||
percent = true;
|
||||
} else if k.stacked() {
|
||||
stacked = true;
|
||||
if v >= 0.0 { p += v } else { m += v }
|
||||
} else {
|
||||
hi = hi.max(v);
|
||||
lo = lo.min(v);
|
||||
}
|
||||
}
|
||||
if stacked {
|
||||
hi = hi.max(p);
|
||||
lo = lo.min(m);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for s in &ser {
|
||||
let k = self.series_kind(s);
|
||||
let Some(v) = s.values.get(i).copied().flatten().filter(|v| v.is_finite()) else { continue };
|
||||
if k.percent() {
|
||||
percent = true;
|
||||
} else if k.stacked() {
|
||||
stacked = true;
|
||||
if v >= 0.0 { p += v } else { m += v }
|
||||
} else {
|
||||
for v in s.values.iter().flatten().copied().filter(|v| v.is_finite()) {
|
||||
hi = hi.max(v);
|
||||
lo = lo.min(v);
|
||||
}
|
||||
}
|
||||
if stacked {
|
||||
hi = hi.max(p);
|
||||
lo = lo.min(m);
|
||||
}
|
||||
}
|
||||
if !percent {
|
||||
for s in &ser {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//! (RFC 6716 §4.3.4 – §4.3.6).
|
||||
|
||||
use super::rate::{Mode, QTHETA_OFFSET, QTHETA_OFFSET_TWOPHASE, get_pulses};
|
||||
use super::tables::*;
|
||||
use super::tables::{E_MEANS, EBANDS, NB_EBANDS, ORDERY, SHORT_MDCT};
|
||||
use crate::range::{BITRES, RangeDecoder, ilog};
|
||||
|
||||
pub const SPREAD_NONE: usize = 0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//! (RFC 6716 §4.3.2).
|
||||
|
||||
use super::rate::MAX_FINE_BITS;
|
||||
use super::tables::*;
|
||||
use super::tables::{BETA_COEF, BETA_INTRA, E_PROB_MODEL, NB_EBANDS, PRED_COEF, SMALL_ENERGY_ICDF};
|
||||
use crate::range::RangeDecoder;
|
||||
|
||||
const LAPLACE_MINP: u32 = 1;
|
||||
|
||||
@@ -12,7 +12,7 @@ use bands::{anti_collapse, denormalise_bands, quant_all_bands, renormalise_vecto
|
||||
use energy::{unquant_coarse_energy, unquant_energy_finalise, unquant_fine_energy};
|
||||
use mdct::ImdctScratch;
|
||||
use rate::{Mode, compute_allocation};
|
||||
use tables::*;
|
||||
use tables::{COMB_GAINS, EBANDS, MAX_LM, NB_EBANDS, OVERLAP, PREEMPH, SHORT_MDCT, SPREAD_ICDF, TAPSET_ICDF, TF_SELECT_TABLE, TRIM_ICDF};
|
||||
|
||||
use crate::range::{BITRES, RangeDecoder};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Pulse cache and bit allocation (RFC 6716 §4.3.3, §4.3.4.1).
|
||||
|
||||
use super::tables::*;
|
||||
use super::tables::{ALLOC, EBANDS, LOG2_FRAC_TABLE, MAX_LM, NB_EBANDS, OVERLAP};
|
||||
use crate::range::{BITRES, RangeDecoder};
|
||||
|
||||
const MAX_PSEUDO: i32 = 40;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
//! Fixed-point NLSF decoding, NLSF→LPC conversion and filter stabilisation
|
||||
//! (RFC 6716 §4.2.7.5, with the RFC 8251 §6/§7 overflow fixes).
|
||||
|
||||
use super::tables::*;
|
||||
use super::tables::{
|
||||
COS_Q12, LSF_ORDER_NBMB, LSF_ORDER_WB, NLSF_CB_NBMB, NLSF_CB_WB, NLSF_MIN_SPACING_NBMB, NLSF_MIN_SPACING_WB, NLSF_PRED_NBMB, NLSF_PRED_WB,
|
||||
NLSF_PSEL_NBMB, NLSF_PSEL_WB,
|
||||
};
|
||||
|
||||
pub const MAX_LPC_ORDER: usize = 16;
|
||||
|
||||
|
||||
@@ -9,9 +9,14 @@ mod resampler;
|
||||
#[allow(dead_code)]
|
||||
pub(crate) mod tables;
|
||||
|
||||
use lpc::*;
|
||||
use lpc::{MAX_LPC_ORDER, bwexpander, div32_varq, inverse32_varq, nlsf_decode, nlsf2a, rshift_round, sat16, smlawb, smulwb, smulww};
|
||||
use resampler::Resampler;
|
||||
use tables::*;
|
||||
use tables::{
|
||||
CB_NB_10, CB_NB_20, CB_WB_10, CB_WB_20, DELTA_GAIN, EXC_LSB, EXC_SIGN, GAIN_MSB, LBRR_FLAGS, LTP_FILTER, LTP_PERIODICITY, LTP_SCALE, LTP_TAPS_0,
|
||||
LTP_TAPS_1, LTP_TAPS_2, MID_ONLY, NLSF_EXT, NLSF_INTERP, NLSF_SEL_NBMB, NLSF_SEL_WB, NLSF_STAGE1, NLSF_STAGE2, PITCH_CONTOUR, PITCH_DELTA,
|
||||
PITCH_HIGH, PITCH_LOW, PULSE_COUNT, RATE_LEVEL, SHELL_2, SHELL_4, SHELL_8, SHELL_16, STEREO_PRED_JOINT, STEREO_WEIGHTS_Q13, TYPE_ACTIVE,
|
||||
TYPE_INACTIVE, UNIFORM3, UNIFORM4, UNIFORM5, UNIFORM8,
|
||||
};
|
||||
|
||||
use crate::range::RangeDecoder;
|
||||
use crate::{Error, Result};
|
||||
|
||||
@@ -437,7 +437,7 @@ fn next_rid(rels: &str) -> String {
|
||||
let mut max = 0u32;
|
||||
let mut rest = rels;
|
||||
while let Some(i) = rest.find("rId") {
|
||||
let digits: String = rest[i + 3..].chars().take_while(|c| c.is_ascii_digit()).collect();
|
||||
let digits: String = rest[i + 3..].chars().take_while(char::is_ascii_digit).collect();
|
||||
if let Ok(n) = digits.parse::<u32>() {
|
||||
max = max.max(n);
|
||||
}
|
||||
|
||||
@@ -696,6 +696,7 @@ fn draw_inner(ctx: &mut RenderContext, rctx: &Ctx, c: &Chart, m: Affine, w: f64,
|
||||
let stacked = kind.stacked();
|
||||
let area_kind = matches!(kind, ChartType::Area | ChartType::StackedArea | ChartType::FilledRadar);
|
||||
let col = if area_kind { series_fill(rctx, c, si, Some(s)) } else { series_line(rctx, c, si, s) };
|
||||
let series_stats = s.error_bars.as_ref().map(|_| deckcraft_model::chart::SeriesStats::of(&s.values));
|
||||
let mut pts = vec![];
|
||||
for i in 0..ncat {
|
||||
let Some(v) = s.values.get(i).copied().flatten() else { continue };
|
||||
@@ -719,7 +720,7 @@ fn draw_inner(ctx: &mut RenderContext, rctx: &Ctx, c: &Chart, m: Affine, w: f64,
|
||||
}
|
||||
_ => plot.x0 + band * (slot(i) + 0.5),
|
||||
};
|
||||
if let Some((lo, hi)) = s.error_bars.as_ref().and_then(|e| e.range(&s.values, i, v)) {
|
||||
if let Some((lo, hi)) = s.error_bars.as_ref().and_then(|e| series_stats.as_ref().and_then(|st| e.range_in(st, i, v))) {
|
||||
err_marks.push((x, to_axis(sec, lo), to_axis(sec, hi), base * 0.4, s.error_bars.as_ref().is_some_and(|e| e.end_cap)));
|
||||
}
|
||||
pts.push(Point::new(x, to_axis(sec, v)));
|
||||
|
||||
@@ -208,7 +208,7 @@ pub(crate) fn draw(
|
||||
}
|
||||
}
|
||||
let unmatched_b =
|
||||
tb.iter().enumerate().filter(|(j, _)| pairs.get(*j).is_none_or(|p| p.is_none())).flat_map(|(_, tok)| tok.glyphs.iter().copied());
|
||||
tb.iter().enumerate().filter(|(j, _)| pairs.get(*j).is_none_or(Option::is_none)).flat_map(|(_, tok)| tok.glyphs.iter().copied());
|
||||
for g in unmatched_b.chain(loose_b) {
|
||||
if let Some((run, gid, pos)) = glyph_at(&lb, g) {
|
||||
draw_glyph(ctx, run, gid, place_b * Affine::translate(pos.to_vec2()), t);
|
||||
|
||||
@@ -572,11 +572,10 @@ fn alpha_num(n: u32, upper: bool) -> String {
|
||||
if n == 0 {
|
||||
return String::new();
|
||||
}
|
||||
let mut n = n - 1;
|
||||
let n = n - 1;
|
||||
let c = (b'a' + (n % 26) as u8) as char;
|
||||
let reps = n / 26 + 1;
|
||||
n = reps;
|
||||
let s: String = std::iter::repeat_n(c, n as usize).collect();
|
||||
let reps = (n / 26 + 1).min(50);
|
||||
let s: String = std::iter::repeat_n(c, reps as usize).collect();
|
||||
if upper { s.to_uppercase() } else { s }
|
||||
}
|
||||
|
||||
|
||||
@@ -394,6 +394,7 @@ fn autonum_formats() {
|
||||
assert_eq!(autonum("alphaLcParenR", 2), "b)");
|
||||
assert_eq!(autonum("arabicParenBoth", 1), "(1)");
|
||||
assert_eq!(autonum("alphaUcPeriod", 27), "AA.");
|
||||
assert_eq!(autonum("alphaUcPeriod", u32::MAX).len(), 51); // 50 letters + '.'
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -572,8 +572,8 @@ fn template_tiles(app: &mut SlideApp, ui: &mut Ui, query: &str, limit: usize) ->
|
||||
/// File name and folder of a recent path, split as text (nothing on disk is read).
|
||||
pub fn split_path(path: &str) -> (String, String) {
|
||||
let p = std::path::Path::new(path);
|
||||
let name = p.file_name().and_then(|n| n.to_str()).unwrap_or(path).to_string();
|
||||
let folder = p.parent().and_then(|f| f.to_str()).unwrap_or("").to_string();
|
||||
let name = p.file_name().and_then(std::ffi::OsStr::to_str).unwrap_or(path).to_string();
|
||||
let folder = p.parent().and_then(std::path::Path::to_str).unwrap_or("").to_string();
|
||||
(name, folder)
|
||||
}
|
||||
|
||||
@@ -827,7 +827,7 @@ fn info(app: &mut SlideApp, ui: &mut Ui, bs: &mut Backstage) {
|
||||
app.set_status("Copied the path");
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if let Some(dir) = std::path::Path::new(p).parent().and_then(|d| d.to_str())
|
||||
if let Some(dir) = std::path::Path::new(p).parent().and_then(std::path::Path::to_str)
|
||||
&& ui.button("Open file location").clicked()
|
||||
{
|
||||
app.open_url(&format!("file:///{}", dir.replace('\\', "/").trim_start_matches('/')));
|
||||
|
||||
@@ -272,7 +272,7 @@ fn pick_album_picture(app: &mut SlideApp) -> Option<Value> {
|
||||
app.set_status("That picture is larger than 32 MB");
|
||||
return None;
|
||||
}
|
||||
let name = std::path::Path::new(&path).file_name().and_then(|n| n.to_str()).filter(|s| !s.is_empty()).unwrap_or("picture").to_string();
|
||||
let name = std::path::Path::new(&path).file_name().and_then(std::ffi::OsStr::to_str).filter(|s| !s.is_empty()).unwrap_or("picture").to_string();
|
||||
Some(json!({"name": name, "data": deckcraft_engine::cmd::base64_encode(&loaded)}))
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ impl<'a> BoolDecoder<'a> {
|
||||
fn fill(&mut self) {
|
||||
// Room for whole bytes below the top 8 bits and the `count` valid bits.
|
||||
let mut shift = 48 - self.count;
|
||||
if let Some(&bytes) = self.data.get(self.pos..).and_then(|d| d.first_chunk::<8>()) {
|
||||
if let Some(&bytes) = self.data.get(self.pos..).and_then(<[_]>::first_chunk::<8>) {
|
||||
let v = u64::from_be_bytes(bytes);
|
||||
let n = ((shift + 8) / 8) as usize; // bytes that fit
|
||||
let n = n.min(7);
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::frame::{BAND_PAD, Band, Frame, FrameInfo, MiGrid, MiInfo, Pools};
|
||||
use crate::header::{FrameHeader, HeaderState, KEY_FRAME, RefInfo, parse_compressed, parse_uncompressed, split_superframe};
|
||||
use crate::loopfilter::{LfFrame, PlaneView, filter_superblock};
|
||||
use crate::probs::{Counts, adapt_coef_probs, adapt_noncoef_probs};
|
||||
use crate::tables::*;
|
||||
use crate::tables::{AC_QLOOKUP, DC_QLOOKUP, SEG_LVL_ALT_Q, SWITCHABLE, TX_MODE_SELECT};
|
||||
use crate::tile::{FrameShared, RefUse, Strip, TileDecoder};
|
||||
use crate::{ColorInfo, Picture, Plane};
|
||||
use std::collections::VecDeque;
|
||||
@@ -347,7 +347,7 @@ impl Decoder {
|
||||
let sz = if last {
|
||||
data.len() - pos
|
||||
} else {
|
||||
let Some(&b) = data.get(pos..).and_then(|d| d.first_chunk::<4>()) else {
|
||||
let Some(&b) = data.get(pos..).and_then(<[_]>::first_chunk::<4>) else {
|
||||
return Err(Error::Invalid("tile size beyond frame data".into()));
|
||||
};
|
||||
let s = u32::from_be_bytes(b) as usize;
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
use crate::boolcoder::BoolDecoder;
|
||||
use crate::error::{Error, Result, ensure};
|
||||
use crate::probs::FrameContext;
|
||||
use crate::tables::*;
|
||||
use crate::tables::{
|
||||
ALTREF_FRAME, GOLDEN_FRAME, INV_MAP_TABLE, LAST_FRAME, LITERAL_TO_TYPE, MAX_SEGMENTS, MAX_TILE_WIDTH_B64, MIN_TILE_WIDTH_B64,
|
||||
SEGMENTATION_FEATURE_BITS, SEGMENTATION_FEATURE_SIGNED, SWITCHABLE, TX_MODE_SELECT, TX_MODE_TO_BIGGEST_TX_SIZE,
|
||||
};
|
||||
use deckcraft_bitstream::BitReader;
|
||||
|
||||
pub const KEY_FRAME: u8 = 0;
|
||||
|
||||
@@ -148,7 +148,7 @@ fn filter_h_n<const W: usize>(s: &[u16], f: &[i16], max: i32, o: &mut [u16]) {
|
||||
let mut acc = [64u16; W];
|
||||
for t in 0..8 {
|
||||
let c = f[t] as u16;
|
||||
let Some(p) = s.get(t..).and_then(|s| s.first_chunk::<W>()) else {
|
||||
let Some(p) = s.get(t..).and_then(<[_]>::first_chunk::<W>) else {
|
||||
return;
|
||||
};
|
||||
for j in 0..W {
|
||||
@@ -161,7 +161,7 @@ fn filter_h_n<const W: usize>(s: &[u16], f: &[i16], max: i32, o: &mut [u16]) {
|
||||
let mut acc = [64i32; W];
|
||||
for t in 0..8 {
|
||||
let c = f[t] as i32;
|
||||
let Some(p) = s.get(t..).and_then(|s| s.first_chunk::<W>()) else {
|
||||
let Some(p) = s.get(t..).and_then(<[_]>::first_chunk::<W>) else {
|
||||
return;
|
||||
};
|
||||
for j in 0..W {
|
||||
@@ -212,7 +212,7 @@ fn filter_v_n<const W: usize>(s: &[u16], ss: usize, f: &[i16], max: i32, o: &mut
|
||||
let mut acc = [64u16; W];
|
||||
for t in 0..8 {
|
||||
let c = f[t] as u16;
|
||||
let Some(p) = s.get(t * ss..).and_then(|s| s.first_chunk::<W>()) else {
|
||||
let Some(p) = s.get(t * ss..).and_then(<[_]>::first_chunk::<W>) else {
|
||||
return;
|
||||
};
|
||||
for j in 0..W {
|
||||
@@ -225,7 +225,7 @@ fn filter_v_n<const W: usize>(s: &[u16], ss: usize, f: &[i16], max: i32, o: &mut
|
||||
let mut acc = [64i32; W];
|
||||
for t in 0..8 {
|
||||
let c = f[t] as i32;
|
||||
let Some(p) = s.get(t * ss..).and_then(|s| s.first_chunk::<W>()) else {
|
||||
let Some(p) = s.get(t * ss..).and_then(<[_]>::first_chunk::<W>) else {
|
||||
return;
|
||||
};
|
||||
for j in 0..W {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Intra prediction process (8.5.1).
|
||||
|
||||
use crate::tables::*;
|
||||
use crate::tables::{D45_PRED, D63_PRED, D117_PRED, D135_PRED, D153_PRED, D207_PRED, H_PRED, TM_PRED, V_PRED};
|
||||
|
||||
/// Edge availability and geometry of one intra-predicted transform block.
|
||||
pub struct IntraEdge {
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
use crate::frame::{MiGrid, MiInfo};
|
||||
use crate::header::{LoopFilterParams, Segmentation};
|
||||
use crate::tables::*;
|
||||
use crate::tables::{
|
||||
BLOCK_8X8, BLOCK_16X16, INTRA_FRAME, MAX_LOOP_FILTER, MAX_TXSIZE, NEARESTMV, NEARMV, NEWMV, NUM_8X8_HIGH, NUM_8X8_WIDE, SEG_LVL_ALT_L,
|
||||
SS_SIZE_LOOKUP, TX_4X4, TX_8X8, TX_16X16,
|
||||
};
|
||||
|
||||
/// Frame-level loop filter setup (8.8.1) plus the per-level limits of 8.8.4.
|
||||
pub struct LfFrame {
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
//! Probability tables (a "frame context"), syntax element counters and the backward adaptation
|
||||
//! processes of section 8.4.
|
||||
|
||||
use crate::tables::*;
|
||||
use crate::tables::{
|
||||
BINARY_TREE, COUNT_SAT, DEFAULT_COEF_PROBS, DEFAULT_COMP_MODE_PROB, DEFAULT_COMP_REF_PROB, DEFAULT_INTER_MODE_PROBS, DEFAULT_INTERP_FILTER_PROBS,
|
||||
DEFAULT_IS_INTER_PROB, DEFAULT_MV_BITS_PROB, DEFAULT_MV_CLASS_PROBS, DEFAULT_MV_CLASS0_BIT_PROB, DEFAULT_MV_CLASS0_FR_PROBS,
|
||||
DEFAULT_MV_CLASS0_HP_PROB, DEFAULT_MV_FR_PROBS, DEFAULT_MV_HP_PROB, DEFAULT_MV_JOINT_PROBS, DEFAULT_MV_SIGN_PROB, DEFAULT_PARTITION_PROBS,
|
||||
DEFAULT_SINGLE_REF_PROB, DEFAULT_SKIP_PROB, DEFAULT_TX_PROBS, DEFAULT_UV_MODE_PROBS, DEFAULT_Y_MODE_PROBS, INTER_MODE_TREE, INTERP_FILTER_TREE,
|
||||
INTRA_MODE_TREE, MAX_UPDATE_FACTOR, MV_CLASS_TREE, MV_FR_TREE, MV_JOINT_TREE, PARTITION_TREE, SMALL_TOKEN_TREE, TX_SIZE_8_TREE, TX_SIZE_16_TREE,
|
||||
TX_SIZE_32_TREE,
|
||||
};
|
||||
|
||||
/// coef_probs[txSz][plane > 0][is_inter][band][ctx][node].
|
||||
pub type CoefProbs = [[[[[[u8; 3]; 6]; 6]; 2]; 2]; 4];
|
||||
|
||||
@@ -6,7 +6,14 @@ use crate::boolcoder::BoolDecoder;
|
||||
use crate::frame::{Frame, MiGrid, MiInfo, Mv};
|
||||
use crate::header::{FrameHeader, Segmentation};
|
||||
use crate::probs::{Counts, FrameContext};
|
||||
use crate::tables::*;
|
||||
use crate::tables::{
|
||||
ALTREF_FRAME, B_HEIGHT_LOG2, B_WIDTH_LOG2, BLOCK_8X8, BLOCK_64X64, BLOCK_INVALID, BORDERINPIXELS, COMPANDED_MVREF_THRESH, COUNTER_TO_CONTEXT,
|
||||
DC_PRED, GOLDEN_FRAME, IDX_N_COLUMN_TO_SUBBLOCK, INTER_MODE_TREE, INTERP_EXTEND, INTERP_FILTER_TREE, INTRA_FRAME, INTRA_MODE_TREE,
|
||||
KF_PARTITION_PROBS, KF_UV_MODE_PROBS, KF_Y_MODE_PROBS, LAST_FRAME, MAX_TXSIZE, MI_WIDTH_LOG2, MODE_2_COUNTER, MV_BORDER, MV_CLASS_TREE,
|
||||
MV_FR_TREE, MV_JOINT_TREE, MV_REF_BLOCKS, NEARESTMV, NEARMV, NEWMV, NONE, NUM_4X4_HIGH, NUM_4X4_WIDE, NUM_8X8_HIGH, NUM_8X8_WIDE, PARTITION_TREE,
|
||||
SEG_LVL_REF_FRAME, SEG_LVL_SKIP, SEGMENT_TREE, SIZE_GROUP, SS_SIZE_LOOKUP, SUBSIZE_LOOKUP, SWITCHABLE, TX_MODE_SELECT,
|
||||
TX_MODE_TO_BIGGEST_TX_SIZE, TX_SIZE_8_TREE, TX_SIZE_16_TREE, TX_SIZE_32_TREE, ZEROMV,
|
||||
};
|
||||
|
||||
mod recon;
|
||||
|
||||
|
||||
@@ -7,7 +7,10 @@ use crate::error::Error;
|
||||
use crate::frame::Mv;
|
||||
use crate::inter::{self, RefPlane};
|
||||
use crate::intra::{self, IntraEdge};
|
||||
use crate::tables::*;
|
||||
use crate::tables::{
|
||||
BLOCK_8X8, CAT_PROBS, COEFBAND_4X4, COEFBAND_8X8PLUS, DCT_DCT, ENERGY_CLASS, EXTRA_BITS, INTERP_EXTEND, INTRA_FRAME, MAX_TXSIZE, MODE2TXFM,
|
||||
NUM_4X4_HIGH, NUM_4X4_WIDE, NUM_8X8_HIGH, NUM_8X8_WIDE, SS_SIZE_LOOKUP, TX_4X4, TX_32X32, neighbors, pareto_full, scan,
|
||||
};
|
||||
use crate::transform;
|
||||
|
||||
/// round_mv_comp_q2 / q4 (8.5.2.1).
|
||||
|
||||
@@ -161,7 +161,7 @@ pub fn inverse_transform_add(
|
||||
if lossless {
|
||||
let mut t = [0i32; 16];
|
||||
for i in 0..4 {
|
||||
let c = coefs.get(i * 4..).and_then(|c| c.first_chunk::<4>()).copied().unwrap_or_default();
|
||||
let c = coefs.get(i * 4..).and_then(<[_]>::first_chunk::<4>).copied().unwrap_or_default();
|
||||
let r = iwht4(c, 2);
|
||||
t[i * 4..i * 4 + 4].copy_from_slice(&r);
|
||||
}
|
||||
@@ -235,7 +235,7 @@ fn itx_narrow<const N: usize>(coefs: &[i32], p: &TxParams, dst: &mut [u16], stri
|
||||
add_cols(&y, 0, p, dst, stride);
|
||||
} else {
|
||||
for c0 in (0..N).step_by(8) {
|
||||
let x: [Cols<8>; N] = std::array::from_fn(|i| Cols(t[i].get(c0..).and_then(|r| r.first_chunk::<8>()).copied().unwrap_or_default()));
|
||||
let x: [Cols<8>; N] = std::array::from_fn(|i| Cols(t[i].get(c0..).and_then(<[_]>::first_chunk::<8>).copied().unwrap_or_default()));
|
||||
let y = col_tx8(x, p.col_adst);
|
||||
add_cols(&y, c0, p, dst, stride);
|
||||
}
|
||||
@@ -246,7 +246,7 @@ fn itx_narrow<const N: usize>(coefs: &[i32], p: &TxParams, dst: &mut [u16], stri
|
||||
#[inline(always)]
|
||||
fn add_cols<const N: usize, const W: usize>(y: &[Cols<W>; N], c0: usize, p: &TxParams, dst: &mut [u16], stride: usize) {
|
||||
for (i, v) in y.iter().enumerate() {
|
||||
let Some(d) = dst.get_mut(i * stride + c0..).and_then(|d| d.first_chunk_mut::<W>()) else {
|
||||
let Some(d) = dst.get_mut(i * stride + c0..).and_then(<[_]>::first_chunk_mut::<W>) else {
|
||||
return;
|
||||
};
|
||||
for j in 0..W {
|
||||
|
||||
@@ -17,12 +17,14 @@ if [[ -z "${APPLE_CERTIFICATE:-}" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TMP="${RUNNER_TEMP:-${TMPDIR:-/tmp}}"
|
||||
KEYCHAIN="$TMP/deckcraft-signing.keychain-db"
|
||||
CERT="$TMP/deckcraft-signing.p12"
|
||||
TMP_BASE="${RUNNER_TEMP:-${TMPDIR:-/tmp}}"
|
||||
TMP_DIR="$(mktemp -d "$TMP_BASE/deckcraft-cert.XXXXXX")"
|
||||
chmod 0700 "$TMP_DIR"
|
||||
KEYCHAIN="$TMP_DIR/deckcraft-signing.keychain-db"
|
||||
CERT="$TMP_DIR/deckcraft-signing.p12"
|
||||
KC_PASS="${KEYCHAIN_PASSWORD:-$(openssl rand -hex 24)}"
|
||||
|
||||
trap 'rm -f "$CERT"' EXIT
|
||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||
printf '%s' "$APPLE_CERTIFICATE" | base64 --decode >"$CERT"
|
||||
security create-keychain -p "$KC_PASS" "$KEYCHAIN"
|
||||
security set-keychain-settings -lut 21600 "$KEYCHAIN"
|
||||
|
||||
Reference in New Issue
Block a user