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