1use super::{
4 component_sampling_for_jpeg, dct_blocks_to_8x8_f64, decompose_97_from_first_level,
5 decomposition_levels_for_components,
6 encode_precomputed_htj2k_53_with_accelerator_and_max_host_bytes,
7 encode_precomputed_htj2k_97_batch_owned_with_accelerator_and_max_host_bytes,
8 encode_precomputed_htj2k_97_with_accelerator_and_max_host_bytes,
9 encode_preencoded_htj2k_97_compact_owned_with_accelerator_and_max_host_bytes,
10 encode_preencoded_htj2k_97_compact_owned_with_accelerator_and_max_host_bytes_and_required_magnitude_bound,
11 encode_preencoded_htj2k_97_owned_with_accelerator_and_max_host_bytes,
12 encode_preencoded_htj2k_97_owned_with_accelerator_and_max_host_bytes_and_required_magnitude_bound,
13 encode_prequantized_htj2k_97_with_accelerator_and_max_host_bytes,
14 encoded_transcode_retained_bytes, error_metrics_i32_with_live_budget, extract_dct_blocks,
15 flatten_integer_wavelet, float97_reference_coefficients,
16 float_direct_97_wavelet_from_component, float_reference_coefficients,
17 integer_dct_job_for_component, integer_direct_wavelet_from_component,
18 integer_reference_coefficients, integer_wavelet_from_first_level, j2k_dwt97_from_wavelet,
19 j2k_dwt_from_integer_wavelet, jpeg_to_htj2k_with_scratch, map_encode_error,
20 rounded_wavelet97_i32, transcode_path_name, validate_component_block_grid,
21 validate_jpeg_transcode_workspace, validate_transcode_options, BatchTranscodeReport,
22 ComponentWavelet97, CpuOnlyJ2kEncodeStageAccelerator, DctExtractOptions,
23 DctGridI16ToHtj2k97CodeBlockBatch, DctGridI16ToHtj2k97CodeBlockJob, DctGridToDwt97Job,
24 DctGridToHtj2k97CodeBlockJob, DctToWaveletStageAccelerator, Dwt97BatchStageTimings,
25 EncodedTranscode, EncodedTranscodeBatch, HostLiveBudget, Htj2k97CodeBlockOptions,
26 IndexedParallelIterator, Instant, IntegerWavelet, IntoParallelIterator,
27 IntoParallelRefIterator, J2kEncodeDispatchReport, J2kEncodeStageAccelerator, JpegDctImage,
28 JpegTileBatchInput, JpegToHtj2kCoefficientPath, JpegToHtj2kEncodeOptions, JpegToHtj2kError,
29 JpegToHtj2kOptions, JpegToHtj2kScratch, JpegToHtj2kTranscoder, ParallelIterator,
30 PrecomputedHtj2k53Component, PrecomputedHtj2k53Image, PrecomputedHtj2k97Component,
31 PrecomputedHtj2k97Image, PreencodedHtj2k97CompactComponent, PreencodedHtj2k97CompactImage,
32 PreencodedHtj2k97Component, PreencodedHtj2k97Image, PrequantizedHtj2k97Component,
33 PrequantizedHtj2k97Image, TranscodeComponentReport, TranscodeReport, TranscodeTimingReport,
34 TranscodeValidationClassification,
35};
36use crate::allocation::try_vec_with_capacity;
37mod group_budget;
38mod workspace;
39use self::workspace::{validate_batch_workspace, BatchWorkspaceKind};
40mod result_slots;
41use self::result_slots::BatchResultSlots;
42mod prepare;
43pub(super) use self::prepare::{
44 batch_component_groups, float97_batch_component_groups, prepare_float97_batch_tile,
45 prepare_integer_batch_tile, BatchComponentRef, Float97BatchTile, Float97PrecomputedBatchRecord,
46 IntegerBatchTile,
47};
48mod transform;
49pub(super) use self::transform::{
50 add_dwt97_batch_stage_timings, htj2k97_codeblock_options, i16_htj2k97_jobs_for_batch_group,
51 record_accelerator_attempt, record_accelerator_dispatch, record_batch_attempt,
52 record_batch_dispatch, record_cpu_fallback, transform_float97_batch_tiles,
53 transform_integer_batch_tiles,
54};
55mod accelerated_storage;
56#[cfg(test)]
57pub(super) use self::accelerated_storage::store_compact_preencoded_component;
58pub(super) use self::accelerated_storage::{
59 try_store_grouped_i16_preencoded_float97_batches, try_store_prequantized_float97_batch_group,
60};
61mod storage;
62pub(super) use self::storage::{store_float97_batch_wavelet, store_integer_batch_wavelet};
63mod encode;
64pub(super) use self::encode::{
65 add_encode_timing_counters_from_result, encode_float97_prepared_tiles,
66 encode_integer_prepared_tiles, record_encode_dispatch_delta,
67};
68mod actual_live;
69use self::actual_live::{
70 validate_float97_prepared_collection, validate_integer_prepared_collection,
71};
72mod individual;
73use self::individual::transcode_tile_batch_individually;
74
75pub fn jpeg_to_htj2k_batch(
77 tiles: &[JpegTileBatchInput<'_>],
78 options: &JpegToHtj2kOptions,
79) -> Result<EncodedTranscodeBatch, JpegToHtj2kError> {
80 JpegToHtj2kTranscoder::default().transcode_batch(tiles, options)
81}
82
83enum BatchExecutionRoute {
84 Integer53,
85 AcceleratedFloat97,
86 Individual,
87}
88
89fn validate_batch_route(
90 tiles: &[JpegTileBatchInput<'_>],
91 options: &JpegToHtj2kOptions,
92 accelerator: &impl DctToWaveletStageAccelerator,
93) -> Result<BatchExecutionRoute, JpegToHtj2kError> {
94 validate_transcode_options(options)?;
95 let (route, workspace_kind) = match options.coefficient_path {
96 JpegToHtj2kCoefficientPath::IntegerDirect53 => {
97 (BatchExecutionRoute::Integer53, BatchWorkspaceKind::Integer)
98 }
99 JpegToHtj2kCoefficientPath::FloatDirectLinear97
100 if accelerator.supports_dwt97_batch()
101 || accelerator.supports_htj2k97_codeblock_batch() =>
102 {
103 (
104 BatchExecutionRoute::AcceleratedFloat97,
105 BatchWorkspaceKind::AcceleratedFloat97,
106 )
107 }
108 JpegToHtj2kCoefficientPath::FloatDirectLinear53
109 | JpegToHtj2kCoefficientPath::FloatDirectLinear97 => (
110 BatchExecutionRoute::Individual,
111 BatchWorkspaceKind::Individual,
112 ),
113 };
114 validate_batch_workspace(tiles, options, workspace_kind)?;
115 Ok(route)
116}
117
118pub(super) fn jpeg_tile_batch_to_htj2k_with_scratch<
119 A: DctToWaveletStageAccelerator,
120 E: J2kEncodeStageAccelerator,
121>(
122 tiles: &[JpegTileBatchInput<'_>],
123 options: &JpegToHtj2kOptions,
124 scratch: &mut JpegToHtj2kScratch,
125 accelerator: &mut A,
126 encode_accelerator: &mut E,
127) -> Result<EncodedTranscodeBatch, JpegToHtj2kError> {
128 match validate_batch_route(tiles, options, accelerator)? {
129 BatchExecutionRoute::Integer53 => {}
130 BatchExecutionRoute::AcceleratedFloat97 => {
131 return jpeg_float97_tile_batch_to_htj2k_with_scratch(
132 tiles,
133 options,
134 scratch,
135 accelerator,
136 encode_accelerator,
137 );
138 }
139 BatchExecutionRoute::Individual => {
140 return transcode_tile_batch_individually(
141 tiles,
142 options,
143 scratch,
144 accelerator,
145 encode_accelerator,
146 );
147 }
148 }
149
150 let extract_start = Instant::now();
151 let mut prepared_results = try_vec_with_capacity(tiles.len())?;
152 tiles
153 .par_iter()
154 .enumerate()
155 .map(|(tile_index, tile)| {
156 (
157 tile_index,
158 prepare_integer_batch_tile(tile_index, tile.bytes, options),
159 )
160 })
161 .collect_into_vec(&mut prepared_results);
162 validate_integer_prepared_collection(&prepared_results, prepared_results.capacity(), scratch)?;
163 let extract_us = extract_start.elapsed().as_micros();
164 let mut tile_results = BatchResultSlots::try_new(tiles.len())?;
165 let mut prepared_tiles = try_vec_with_capacity(tiles.len())?;
166 for (tile_index, result) in prepared_results {
167 match result {
168 Ok(prepared) => prepared_tiles.push(prepared),
169 Err(error) => tile_results.insert(tile_index, Err(error))?,
170 }
171 }
172
173 let transform_start = Instant::now();
174 let mut timings = TranscodeTimingReport::default();
175 let (reversible_dwt53_batches, reversible_dwt53_batch_jobs) = transform_integer_batch_tiles(
176 &mut prepared_tiles,
177 options,
178 scratch,
179 accelerator,
180 &mut timings,
181 )?;
182 let transform_us = transform_start.elapsed().as_micros();
183 timings.jpeg_dct_extract_us = extract_us;
184 timings.dct_to_wavelet_total_us = transform_us;
185 timings.tile_count = prepared_tiles.len();
186
187 let encode_start = Instant::now();
188 let mut encode_external = HostLiveBudget::process_cap();
189 encode_external.add_bytes(scratch.retained_bytes()?)?;
190 encode_external.add_bytes(tile_results.retained_slot_bytes()?)?;
191 let encoded_tiles = encode_integer_prepared_tiles(
192 prepared_tiles,
193 options,
194 encode_accelerator,
195 encode_external.live_bytes(),
196 )?;
197 for (tile_index, encoded) in encoded_tiles {
198 add_encode_timing_counters_from_result(&mut timings, &encoded);
199 tile_results.insert(tile_index, encoded)?;
200 }
201 let encode_us = encode_start.elapsed().as_micros();
202 timings.htj2k_encode_us = encode_us;
203
204 let output_tiles =
205 tile_results.into_results_with_live_budget(scratch.retained_bytes()?, |result| {
206 result
207 .as_ref()
208 .map_or(Ok(0), encoded_transcode_retained_bytes)
209 })?;
210 Ok(batch_output(
211 output_tiles,
212 BatchTranscodeReport {
213 tile_count: tiles.len(),
214 successful_tiles: 0,
215 failed_tiles: 0,
216 transformed_components: reversible_dwt53_batch_jobs,
217 reversible_dwt53_batches,
218 reversible_dwt53_batch_jobs,
219 extract_us,
220 transform_us,
221 encode_us,
222 timings,
223 coefficient_path: options.coefficient_path,
224 },
225 ))
226}
227
228pub(super) fn jpeg_float97_tile_batch_to_htj2k_with_scratch<
229 A: DctToWaveletStageAccelerator,
230 E: J2kEncodeStageAccelerator,
231>(
232 tiles: &[JpegTileBatchInput<'_>],
233 options: &JpegToHtj2kOptions,
234 scratch: &mut JpegToHtj2kScratch,
235 accelerator: &mut A,
236 encode_accelerator: &mut E,
237) -> Result<EncodedTranscodeBatch, JpegToHtj2kError> {
238 let extract_start = Instant::now();
239 let mut prepared_results = try_vec_with_capacity(tiles.len())?;
240 tiles
241 .par_iter()
242 .enumerate()
243 .map(|(tile_index, tile)| {
244 (
245 tile_index,
246 prepare_float97_batch_tile(tile_index, tile.bytes, options),
247 )
248 })
249 .collect_into_vec(&mut prepared_results);
250 validate_float97_prepared_collection(&prepared_results, prepared_results.capacity(), scratch)?;
251 let extract_us = extract_start.elapsed().as_micros();
252 let mut tile_results = BatchResultSlots::try_new(tiles.len())?;
253 let mut prepared_tiles = try_vec_with_capacity(tiles.len())?;
254 for (tile_index, result) in prepared_results {
255 match result {
256 Ok(prepared) => prepared_tiles.push(prepared),
257 Err(error) => tile_results.insert(tile_index, Err(error))?,
258 }
259 }
260
261 let transform_start = Instant::now();
262 let mut timings = TranscodeTimingReport::default();
263 let (_dwt97_batches, dwt97_batch_jobs) = transform_float97_batch_tiles(
264 &mut prepared_tiles,
265 options,
266 scratch,
267 accelerator,
268 &mut timings,
269 )?;
270 let transform_us = transform_start.elapsed().as_micros();
271 timings.jpeg_dct_extract_us = extract_us;
272 timings.dct_to_wavelet_total_us = transform_us;
273 timings.tile_count = prepared_tiles.len();
274
275 let encode_start = Instant::now();
276 let mut encode_external = HostLiveBudget::process_cap();
277 encode_external.add_bytes(scratch.retained_bytes()?)?;
278 encode_external.add_bytes(tile_results.retained_slot_bytes()?)?;
279 let encoded_tiles = encode_float97_prepared_tiles(
280 prepared_tiles,
281 options,
282 encode_accelerator,
283 encode_external.live_bytes(),
284 )?;
285 for (tile_index, encoded) in encoded_tiles {
286 add_encode_timing_counters_from_result(&mut timings, &encoded);
287 tile_results.insert(tile_index, encoded)?;
288 }
289 let encode_us = encode_start.elapsed().as_micros();
290 timings.htj2k_encode_us = encode_us;
291
292 let output_tiles =
293 tile_results.into_results_with_live_budget(scratch.retained_bytes()?, |result| {
294 result
295 .as_ref()
296 .map_or(Ok(0), encoded_transcode_retained_bytes)
297 })?;
298 Ok(batch_output(
299 output_tiles,
300 BatchTranscodeReport {
301 tile_count: tiles.len(),
302 successful_tiles: 0,
303 failed_tiles: 0,
304 transformed_components: dwt97_batch_jobs,
305 reversible_dwt53_batches: 0,
306 reversible_dwt53_batch_jobs: 0,
307 extract_us,
308 transform_us,
309 encode_us,
310 timings,
311 coefficient_path: options.coefficient_path,
312 },
313 ))
314}
315
316pub(super) fn batch_output(
317 tiles: Vec<Result<EncodedTranscode, JpegToHtj2kError>>,
318 mut report: BatchTranscodeReport,
319) -> EncodedTranscodeBatch {
320 report.successful_tiles = tiles.iter().filter(|tile| tile.is_ok()).count();
321 report.failed_tiles = tiles.len().saturating_sub(report.successful_tiles);
322 EncodedTranscodeBatch { tiles, report }
323}