@@ -44,13 +44,15 @@ pub use minipool::new as private_minipool;
44
44
45
45
use crossbeam_channel:: { Receiver , Sender } ;
46
46
use std:: io:: prelude:: * ;
47
+ use std:: num:: NonZeroU8 ;
47
48
use std:: thread;
48
49
49
50
struct InputFrameUnresized {
50
51
/// The pixels to resize and encode
51
52
frame : ImgVec < RGBA8 > ,
52
53
/// Time in seconds when to display the frame. First frame should start at 0.
53
54
presentation_timestamp : f64 ,
55
+ frame_index : usize ,
54
56
}
55
57
56
58
struct InputFrame {
@@ -84,6 +86,7 @@ pub struct Settings {
84
86
#[ non_exhaustive]
85
87
struct SettingsExt {
86
88
pub s : Settings ,
89
+ pub max_threads : NonZeroU8 ,
87
90
pub extra_effort : bool ,
88
91
pub motion_quality : u8 ,
89
92
pub giflossy_quality : u8 ,
@@ -124,13 +127,13 @@ impl Default for Settings {
124
127
/// Note that writing will finish only when the collector is dropped.
125
128
/// Collect frames on another thread, or call `drop(collector)` before calling `writer.write()`!
126
129
pub struct Collector {
127
- queue : OrdQueue < CatResult < InputFrameUnresized > > ,
130
+ queue : Sender < CatResult < InputFrameUnresized > > ,
128
131
}
129
132
130
133
/// Perform GIF writing
131
134
pub struct Writer {
132
135
/// Input frame decoder results
133
- queue_iter : Option < OrdQueueIter < CatResult < InputFrameUnresized > > > ,
136
+ queue_iter : Option < Receiver < CatResult < InputFrameUnresized > > > ,
134
137
settings : SettingsExt ,
135
138
}
136
139
@@ -195,7 +198,7 @@ pub fn new(settings: Settings) -> CatResult<(Collector, Writer)> {
195
198
if settings. width . unwrap_or ( 0 ) > 1 <<16 || settings. height . unwrap_or ( 0 ) > 1 <<16 {
196
199
return Err ( Error :: WrongSize ( "image size too large" . into ( ) ) ) ;
197
200
}
198
- let ( queue, queue_iter) = ordqueue :: new ( 6 ) ; // should be sufficient for denoiser lookahead
201
+ let ( queue, queue_iter) = crossbeam_channel :: bounded ( 6 ) ; // should be sufficient for denoiser lookahead
199
202
200
203
Ok ( (
201
204
Collector {
@@ -204,6 +207,7 @@ pub fn new(settings: Settings) -> CatResult<(Collector, Writer)> {
204
207
Writer {
205
208
queue_iter : Some ( queue_iter) ,
206
209
settings : SettingsExt {
210
+ max_threads : thread:: available_parallelism ( ) . map ( |t| t. get ( ) . min ( 255 ) as u8 ) . unwrap_or ( 8 ) . try_into ( ) . unwrap ( ) ,
207
211
motion_quality : settings. quality ,
208
212
giflossy_quality : settings. quality ,
209
213
extra_effort : false ,
@@ -223,10 +227,12 @@ impl Collector {
223
227
/// If the first frame doesn't start at pts=0, the delay will be used for the last frame.
224
228
pub fn add_frame_rgba ( & self , frame_index : usize , frame : ImgVec < RGBA8 > , presentation_timestamp : f64 ) -> CatResult < ( ) > {
225
229
debug_assert ! ( frame_index == 0 || presentation_timestamp > 0. ) ;
226
- self . queue . push ( frame_index, Ok ( InputFrameUnresized {
230
+ self . queue . send ( Ok ( InputFrameUnresized {
231
+ frame_index,
227
232
frame,
228
233
presentation_timestamp,
229
- } ) )
234
+ } ) ) ?;
235
+ Ok ( ( ) )
230
236
}
231
237
232
238
/// Read and decode a PNG file from disk.
@@ -242,10 +248,12 @@ impl Collector {
242
248
. map_err ( |err| Error :: PNG ( format ! ( "Can't load {}: {err}" , path. display( ) ) ) ) ?;
243
249
244
250
let frame = Img :: new ( image. buffer , image. width , image. height ) ;
245
- self . queue . push ( frame_index , Ok ( InputFrameUnresized {
251
+ self . queue . send ( Ok ( InputFrameUnresized {
246
252
frame,
247
- presentation_timestamp}
248
- ) )
253
+ presentation_timestamp,
254
+ frame_index,
255
+ } ) ) ?;
256
+ Ok ( ( ) )
249
257
}
250
258
}
251
259
@@ -383,7 +391,7 @@ impl Writer {
383
391
///
384
392
/// `background` is the previous frame.
385
393
fn quantize ( image : ImgVec < RGBA8 > , importance_map : & [ u8 ] , first_frame : bool , needs_transparency : bool , prev_frame_keeps : bool , settings : & SettingsExt ) -> CatResult < ( Attributes , QuantizationResult , Image < ' static > ) > {
386
- let SettingsExt { s : settings, extra_effort, motion_quality : _, giflossy_quality : _} = settings;
394
+ let SettingsExt { s : settings, extra_effort, motion_quality : _, giflossy_quality : _, max_threads : _ } = settings;
387
395
let mut liq = Attributes :: new ( ) ;
388
396
if settings. fast {
389
397
liq. set_speed ( 10 ) ?;
@@ -481,13 +489,13 @@ impl Writer {
481
489
482
490
let settings_ext = self . settings ;
483
491
let settings = self . settings . s ;
484
- let ( resize_queue , resize_queue_recv ) = crossbeam_channel :: bounded ( 2 ) ;
492
+ let ( diff_queue , diff_queue_recv ) = ordqueue :: new ( 2 ) ;
485
493
let resize_thread = thread:: Builder :: new ( ) . name ( "resize" . into ( ) ) . spawn ( move || {
486
- Self :: make_resize ( decode_queue_recv, resize_queue , & settings_ext. s )
494
+ Self :: make_resize ( decode_queue_recv, diff_queue , & settings_ext)
487
495
} ) ?;
488
496
let ( quant_queue, quant_queue_recv) = crossbeam_channel:: bounded ( 2 ) ;
489
497
let diff_thread = thread:: Builder :: new ( ) . name ( "diff" . into ( ) ) . spawn ( move || {
490
- Self :: make_diffs ( resize_queue_recv , quant_queue, & settings_ext)
498
+ Self :: make_diffs ( diff_queue_recv , quant_queue, & settings_ext)
491
499
} ) ?;
492
500
let ( remap_queue, remap_queue_recv) = ordqueue:: new ( 2 ) ;
493
501
let quant_thread = thread:: Builder :: new ( ) . name ( "quant" . into ( ) ) . spawn ( move || {
@@ -505,21 +513,25 @@ impl Writer {
505
513
combine_res ( combine_res ( combine_res ( res0, res1) , combine_res ( res2, res3) ) , res4)
506
514
}
507
515
508
- fn make_resize ( inputs : OrdQueueIter < CatResult < InputFrameUnresized > > , diff_queue : Sender < InputFrame > , settings : & Settings ) -> CatResult < ( ) > {
509
- for frame in inputs {
510
- let frame = frame?;
511
- let resized = resized_binary_alpha ( frame. frame , settings. width , settings. height ) ?;
512
- diff_queue. send ( InputFrame {
513
- frame_blurred : smart_blur ( resized. as_ref ( ) ) ,
516
+ fn make_resize ( inputs : Receiver < CatResult < InputFrameUnresized > > , diff_queue : OrdQueue < InputFrame > , settings : & SettingsExt ) -> CatResult < ( ) > {
517
+ minipool:: new ( settings. max_threads . min ( if settings. s . fast { 6 } else { 4 } . try_into ( ) . unwrap ( ) ) , "resize" , move |to_remap| {
518
+ for frame in inputs {
519
+ to_remap. send ( frame?) ?;
520
+ }
521
+ Ok ( ( ) )
522
+ } , move |frame| {
523
+ let resized = resized_binary_alpha ( frame. frame , settings. s . width , settings. s . height ) ?;
524
+ let frame_blurred = smart_blur ( resized. as_ref ( ) ) ;
525
+ diff_queue. push ( frame. frame_index , InputFrame {
514
526
frame : resized,
527
+ frame_blurred,
515
528
presentation_timestamp : frame. presentation_timestamp ,
516
529
} ) ?;
517
- }
518
- Ok ( ( ) )
519
-
530
+ Ok ( ( ) )
531
+ } )
520
532
}
521
533
522
- fn make_diffs ( inputs : Receiver < InputFrame > , quant_queue : Sender < DiffMessage > , settings : & SettingsExt ) -> CatResult < ( ) > {
534
+ fn make_diffs ( inputs : OrdQueueIter < InputFrame > , quant_queue : Sender < DiffMessage > , settings : & SettingsExt ) -> CatResult < ( ) > {
523
535
let mut inputs = inputs. into_iter ( ) ;
524
536
let first_frame = inputs. next ( ) . ok_or ( Error :: NoFrames ) ?;
525
537
@@ -591,7 +603,7 @@ impl Writer {
591
603
}
592
604
593
605
fn quantize_frames ( inputs : Receiver < DiffMessage > , remap_queue : OrdQueue < RemapMessage > , settings : & SettingsExt ) -> CatResult < ( ) > {
594
- minipool:: new ( 3 , "quant" , move |to_remap| {
606
+ minipool:: new ( settings . max_threads . min ( 3 . try_into ( ) . unwrap ( ) ) , "quant" , move |to_remap| {
595
607
let mut inputs = inputs. into_iter ( ) . peekable ( ) ;
596
608
597
609
let DiffMessage { image : first_frame, ..} = inputs. peek ( ) . ok_or ( Error :: NoFrames ) ?;
0 commit comments