1use alloc::vec::Vec;
6use std::sync::Arc;
7
8pub use j2k_core::TileBatchOptions;
9use j2k_core::{
10 BatchResultSlot, DecodeOutcome, DecoderContext, PixelFormat, Rect, TileBatchDecode,
11};
12
13use crate::{J2kCodec, J2kContext, J2kDecodeWarning, J2kError, J2kScratchPool};
14
15mod admission;
16mod allocation;
17mod direct;
18mod planning;
19mod scheduler;
20mod worker;
21
22use admission::BatchAllocationBudget;
23use direct::build_repeated_direct_color_region_plan;
24
25pub type TileDecodeJob<'i, 'o> = j2k_core::TileDecodeJob<'i, 'o>;
27
28pub type TileRegionDecodeJob<'i, 'o> = j2k_core::TileRegionDecodeJob<'i, 'o>;
30
31pub type TileScaledDecodeJob<'i, 'o> = j2k_core::TileScaledDecodeJob<'i, 'o>;
33
34pub type TileRegionScaledDecodeJob<'i, 'o> = j2k_core::TileRegionScaledDecodeJob<'i, 'o>;
36
37pub struct TileDecodeOutput<'o> {
39 pub out: &'o mut [u8],
41 pub stride: usize,
43 pub fmt: PixelFormat,
45}
46
47pub type TileBatchError = j2k_core::BatchDecodeError<J2kError>;
53
54type BatchOutcome = DecodeOutcome<J2kDecodeWarning>;
55type J2kBatchResultSlot = BatchResultSlot<BatchOutcome, J2kError>;
56
57#[doc(hidden)]
61pub fn decode_tile_into_in_context(
62 bytes: &[u8],
63 ctx: &mut DecoderContext<J2kContext>,
64 pool: &mut J2kScratchPool,
65 output: TileDecodeOutput<'_>,
66) -> Result<BatchOutcome, J2kError> {
67 let TileDecodeOutput { out, stride, fmt } = output;
68 <J2kCodec as TileBatchDecode>::decode_tile(ctx, pool, bytes, out, stride, fmt)
69}
70
71#[doc(hidden)]
75pub fn decode_tile_region_into_in_context(
76 bytes: &[u8],
77 ctx: &mut DecoderContext<J2kContext>,
78 pool: &mut J2kScratchPool,
79 output: TileDecodeOutput<'_>,
80 roi: Rect,
81) -> Result<BatchOutcome, J2kError> {
82 let TileDecodeOutput { out, stride, fmt } = output;
83 <J2kCodec as TileBatchDecode>::decode_tile_region(ctx, pool, bytes, out, stride, fmt, roi)
84}
85
86#[doc(hidden)]
90pub fn decode_tile_scaled_into_in_context(
91 bytes: &[u8],
92 ctx: &mut DecoderContext<J2kContext>,
93 pool: &mut J2kScratchPool,
94 output: TileDecodeOutput<'_>,
95 scale: j2k_core::Downscale,
96) -> Result<BatchOutcome, J2kError> {
97 let TileDecodeOutput { out, stride, fmt } = output;
98 <J2kCodec as TileBatchDecode>::decode_tile_scaled(ctx, pool, bytes, out, stride, fmt, scale)
99}
100
101#[doc(hidden)]
105pub fn decode_tile_region_scaled_into_in_context(
106 bytes: &[u8],
107 ctx: &mut DecoderContext<J2kContext>,
108 pool: &mut J2kScratchPool,
109 output: TileDecodeOutput<'_>,
110 roi: Rect,
111 scale: j2k_core::Downscale,
112) -> Result<BatchOutcome, J2kError> {
113 let TileDecodeOutput { out, stride, fmt } = output;
114 <J2kCodec as TileBatchDecode>::decode_tile_region_scaled(
115 ctx,
116 pool,
117 fmt,
118 TileRegionScaledDecodeJob {
119 input: bytes,
120 out,
121 stride,
122 roi,
123 scale,
124 },
125 )
126}
127
128pub fn decode_tiles_into(
135 jobs: &mut [TileDecodeJob<'_, '_>],
136 fmt: PixelFormat,
137 options: TileBatchOptions,
138) -> Result<Vec<BatchOutcome>, TileBatchError> {
139 scheduler::decode_batch(jobs, options, |worker, chunk, results| {
140 worker.decode_tile_jobs(chunk, results, fmt)
141 })
142}
143
144pub fn decode_tiles_region_into(
146 jobs: &mut [TileRegionDecodeJob<'_, '_>],
147 fmt: PixelFormat,
148 options: TileBatchOptions,
149) -> Result<Vec<BatchOutcome>, TileBatchError> {
150 scheduler::decode_batch(jobs, options, |worker, chunk, results| {
151 worker.decode_tile_region_jobs(chunk, results, fmt)
152 })
153}
154
155pub fn decode_tiles_scaled_into(
158 jobs: &mut [TileScaledDecodeJob<'_, '_>],
159 fmt: PixelFormat,
160 options: TileBatchOptions,
161) -> Result<Vec<BatchOutcome>, TileBatchError> {
162 scheduler::decode_batch(jobs, options, |worker, chunk, results| {
163 worker.decode_tile_scaled_jobs(chunk, results, fmt)
164 })
165}
166
167pub fn decode_tiles_region_scaled_into(
170 jobs: &mut [TileRegionScaledDecodeJob<'_, '_>],
171 fmt: PixelFormat,
172 options: TileBatchOptions,
173) -> Result<Vec<BatchOutcome>, TileBatchError> {
174 if jobs.is_empty() {
175 return Ok(Vec::new());
176 }
177
178 let shared_direct_plan = build_repeated_direct_color_region_plan(jobs, fmt)
179 .map_err(|source| TileBatchError::Tile(j2k_core::TileBatchError { index: 0, source }))?;
180 let plan = scheduler::plan_direct_batch(jobs.len(), options)?;
181 let shared_plan_bytes = shared_direct_plan
182 .as_ref()
183 .map_or(
184 Ok(0),
185 direct::DirectColorRegionCache::retained_allocation_bytes,
186 )
187 .map_err(|source| TileBatchError::Tile(j2k_core::TileBatchError { index: 0, source }))?;
188 let allocation_budget = BatchAllocationBudget::with_baseline(shared_plan_bytes)?;
189 let results = scheduler::run_chunks_scoped(
190 jobs,
191 plan,
192 Some(Arc::clone(&allocation_budget)),
193 |worker, chunk, results| {
194 worker.decode_tile_region_scaled_jobs(chunk, results, fmt, shared_direct_plan.as_ref())
195 },
196 )?;
197
198 drop(shared_direct_plan);
201 drop(allocation_budget);
202 scheduler::collect_results(results)
203}