Skip to main content

j2k/owned_batch/
prepared.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use alloc::{sync::Arc, vec::Vec};
4
5use j2k_core::{BatchInfrastructureError, Downscale, TileLayout};
6
7use super::{
8    prepare_batch, prepare_batch_from_images, BatchDecodeOptions, BatchGroupInfo, DecodeRequest,
9    EncodedImage, IndexedBatchError, J2kCodestreamRange, PreparationDepth, PreparedClassicPlan,
10    PreparedHtj2kPlan,
11};
12use crate::{DecodeSettings, DeviceDecodePlan, J2kSupportInfo};
13
14/// Cheaply cloneable preparation result for one image.
15#[derive(Debug, Clone)]
16pub struct PreparedImage {
17    pub(super) inner: Arc<PreparedImageInner>,
18}
19
20#[derive(Debug)]
21pub(super) enum PreparedCodecPlan {
22    MetadataOnly,
23    Htj2k(PreparedHtj2kPlan),
24    Classic(PreparedClassicPlan),
25}
26
27impl PreparedCodecPlan {
28    pub(super) const fn preparation_depth(&self) -> PreparationDepth {
29        match self {
30            Self::MetadataOnly => PreparationDepth::MetadataOnly,
31            Self::Htj2k(_) => PreparationDepth::Htj2kOffsetPlan,
32            Self::Classic(_) => PreparationDepth::ClassicOffsetPlan,
33        }
34    }
35}
36
37#[derive(Debug)]
38pub(super) struct PreparedImageInner {
39    pub(super) bytes: Arc<[u8]>,
40    pub(super) request: DecodeRequest,
41    pub(super) source_index: usize,
42    pub(super) decode_settings: DecodeSettings,
43    pub(super) used_lenient_metadata_recovery: bool,
44    pub(super) support: Arc<J2kSupportInfo>,
45    pub(super) plan: DeviceDecodePlan,
46    pub(super) codestream_range: J2kCodestreamRange,
47    pub(super) codec_plan: PreparedCodecPlan,
48}
49
50impl PreparedImage {
51    /// Original encoded bytes.
52    #[must_use]
53    pub fn bytes(&self) -> &Arc<[u8]> {
54        &self.inner.bytes
55    }
56
57    /// Caller decode request.
58    #[must_use]
59    pub fn request(&self) -> DecodeRequest {
60        self.inner.request
61    }
62
63    /// Original caller input index.
64    #[must_use]
65    pub fn source_index(&self) -> usize {
66        self.inner.source_index
67    }
68
69    /// Validation policy used to parse and build this retained execution plan.
70    #[must_use]
71    pub fn decode_settings(&self) -> DecodeSettings {
72        self.inner.decode_settings
73    }
74
75    /// Whether preparation used an explicitly documented lenient metadata recovery.
76    #[doc(hidden)]
77    #[must_use]
78    pub fn used_lenient_metadata_recovery(&self) -> bool {
79        self.inner.used_lenient_metadata_recovery
80    }
81
82    /// Parsed codestream and wrapper metadata.
83    #[must_use]
84    pub fn support(&self) -> &J2kSupportInfo {
85        &self.inner.support
86    }
87
88    /// Normalized source and output geometry.
89    #[must_use]
90    pub fn plan(&self) -> DeviceDecodePlan {
91        self.inner.plan
92    }
93
94    /// Raw codestream range inside [`Self::bytes`].
95    #[must_use]
96    pub fn codestream_range(&self) -> J2kCodestreamRange {
97        self.inner.codestream_range
98    }
99
100    /// Whether this image retains metadata only or a parse-free codec offset plan.
101    #[must_use]
102    pub fn preparation_depth(&self) -> PreparationDepth {
103        self.inner.codec_plan.preparation_depth()
104    }
105
106    /// Reusable HTJ2K geometry and payload references, when supported.
107    /// Payload offsets are absolute byte ranges inside [`Self::bytes`],
108    /// including any JP2/JPH container prefix.
109    #[must_use]
110    pub fn htj2k_plan(&self) -> Option<&PreparedHtj2kPlan> {
111        match &self.inner.codec_plan {
112            PreparedCodecPlan::Htj2k(plan) => Some(plan),
113            PreparedCodecPlan::MetadataOnly | PreparedCodecPlan::Classic(_) => None,
114        }
115    }
116
117    /// Reusable classic JPEG 2000 geometry and payload-fragment references,
118    /// when supported. Fragment offsets are absolute ranges inside
119    /// [`Self::bytes`], including any JP2 container prefix.
120    #[must_use]
121    pub fn classic_plan(&self) -> Option<&PreparedClassicPlan> {
122        match &self.inner.codec_plan {
123            PreparedCodecPlan::Classic(plan) => Some(plan),
124            PreparedCodecPlan::MetadataOnly | PreparedCodecPlan::Htj2k(_) => None,
125        }
126    }
127
128    pub(super) fn codec_plan(&self) -> &PreparedCodecPlan {
129        &self.inner.codec_plan
130    }
131}
132
133/// One homogeneous set of prepared images.
134#[derive(Debug)]
135pub struct PreparedBatchGroup {
136    pub(super) info: BatchGroupInfo,
137    pub(super) options: BatchDecodeOptions,
138    pub(super) execution_shape: BatchExecutionShape,
139    pub(super) images: Vec<PreparedImage>,
140    pub(super) source_indices: Vec<usize>,
141}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144pub(super) struct BatchExecutionShape {
145    pub(super) source_dimensions: (u32, u32),
146    pub(super) source_rect_dimensions: (u32, u32),
147    pub(super) scale: Downscale,
148    pub(super) tile_layout: Option<TileLayout>,
149    pub(super) resolution_levels: u8,
150    pub(super) preparation_depth: PreparationDepth,
151}
152
153impl PreparedBatchGroup {
154    /// Shared output metadata and grouping key.
155    #[must_use]
156    pub fn info(&self) -> &BatchGroupInfo {
157        &self.info
158    }
159
160    /// Decode policy captured when every image in this group was prepared.
161    ///
162    /// Backend sessions use this value instead of their current defaults so a
163    /// reusable group cannot silently drift between strict and lenient decode.
164    #[must_use]
165    pub const fn options(&self) -> BatchDecodeOptions {
166        self.options
167    }
168
169    /// Prepared images in caller order.
170    #[must_use]
171    pub fn images(&self) -> &[PreparedImage] {
172        &self.images
173    }
174
175    /// Original caller indices in group order.
176    #[must_use]
177    pub fn source_indices(&self) -> &[usize] {
178        &self.source_indices
179    }
180}
181
182/// Cheaply cloneable parsed and grouped batch reusable across decode calls.
183#[derive(Debug, Clone)]
184pub struct PreparedBatch {
185    pub(super) groups: Arc<[PreparedBatchGroup]>,
186    pub(super) errors: Arc<[IndexedBatchError]>,
187    pub(super) options: BatchDecodeOptions,
188}
189
190/// Common synchronous boundary implemented by persistent codec batch sessions.
191///
192/// GPU implementations may choose a resident or pending associated output;
193/// synchronization and submission details remain backend-specific.
194pub trait BatchDecoder {
195    /// Backend-specific successful output.
196    type Output;
197    /// Backend-specific infrastructure or execution error.
198    type Error: From<BatchInfrastructureError>;
199
200    /// Preparation and output policy retained by this persistent session.
201    fn options(&self) -> BatchDecodeOptions;
202
203    /// Inspect and group owned inputs without consuming their encoded byte owners.
204    fn prepare_batch(&self, inputs: Vec<EncodedImage>) -> Result<PreparedBatch, Self::Error> {
205        prepare_batch(inputs, self.options()).map_err(Self::Error::from)
206    }
207
208    /// Regroup caller-supplied prepared images without reparsing their encoded bytes.
209    fn prepare_prepared_images(
210        &self,
211        images: Vec<PreparedImage>,
212    ) -> Result<PreparedBatch, Self::Error> {
213        prepare_batch_from_images(images, self.options()).map_err(Self::Error::from)
214    }
215
216    /// Prepare and decode one owned batch through the common session boundary.
217    fn decode_batch(&mut self, inputs: Vec<EncodedImage>) -> Result<Self::Output, Self::Error> {
218        let prepared = self.prepare_batch(inputs)?;
219        self.decode_prepared(&prepared)
220    }
221
222    /// Regroup and decode caller-supplied prepared images without reparsing them.
223    fn decode_prepared_images(
224        &mut self,
225        images: Vec<PreparedImage>,
226    ) -> Result<Self::Output, Self::Error> {
227        let prepared = self.prepare_prepared_images(images)?;
228        self.decode_prepared(&prepared)
229    }
230
231    /// Decode a reusable prepared batch without consuming its encoded inputs or plans.
232    fn decode_prepared(&mut self, prepared: &PreparedBatch) -> Result<Self::Output, Self::Error>;
233}
234
235impl PreparedBatch {
236    /// Homogeneous prepared groups in first-occurrence order.
237    #[must_use]
238    pub fn groups(&self) -> &[PreparedBatchGroup] {
239        &self.groups
240    }
241
242    /// Indexed preflight failures.
243    #[must_use]
244    pub fn errors(&self) -> &[IndexedBatchError] {
245        &self.errors
246    }
247
248    /// Options captured when this batch was prepared.
249    #[must_use]
250    pub const fn options(&self) -> BatchDecodeOptions {
251        self.options
252    }
253
254    /// Consume this handle into its shared group and error owners.
255    #[must_use]
256    pub fn into_parts(
257        self,
258    ) -> (
259        Arc<[PreparedBatchGroup]>,
260        Arc<[IndexedBatchError]>,
261        BatchDecodeOptions,
262    ) {
263        (self.groups, self.errors, self.options)
264    }
265}