@@ -3,6 +3,7 @@ use std::process::{Command, Stdio};
33
44use anyhow:: { Context , Result } ;
55use log:: info;
6+ use rayon:: prelude:: * ;
67
78use crate :: config:: { self , Yts3Config } ;
89use crate :: video:: dct:: DctTables ;
@@ -57,6 +58,10 @@ impl VideoEncoder {
5758 self . fps
5859 ) ;
5960
61+ // Scale FFV1 slice count to available threads for better intra-frame parallelism
62+ // inside ffmpeg. Clamped to 16 (a reasonable FFV1 upper bound).
63+ let ffv1_slices = rayon:: current_num_threads ( ) . min ( 16 ) . to_string ( ) ;
64+
6065 let mut child = Command :: new ( "ffmpeg" )
6166 . args ( [
6267 "-y" ,
@@ -75,7 +80,7 @@ impl VideoEncoder {
7580 "-level" ,
7681 "3" ,
7782 "-slices" ,
78- "4" ,
83+ & ffv1_slices ,
7984 "-slicecrc" ,
8085 "1" ,
8186 output_path,
@@ -88,19 +93,33 @@ impl VideoEncoder {
8893
8994 let stdin = child. stdin . as_mut ( ) . unwrap ( ) ;
9095
91- for frame_idx in 0 ..num_frames {
92- let data_offset = frame_idx * self . bytes_per_frame ;
93- let data_end = ( data_offset + self . bytes_per_frame ) . min ( packet_data. len ( ) ) ;
94- let frame_data = if data_offset < packet_data. len ( ) {
95- & packet_data[ data_offset..data_end]
96- } else {
97- & [ ]
98- } ;
99-
100- let frame_pixels = self . render_frame ( frame_data) ;
101- stdin
102- . write_all ( & frame_pixels)
103- . context ( "failed to write frame data to ffmpeg" ) ?;
96+ // Render frames in parallel batches, then write each batch to ffmpeg in order.
97+ // Batch size matches the rayon thread pool so we keep all cores busy without
98+ // holding more than `threads * frame_size` bytes of rendered pixel data at once.
99+ let batch_size = rayon:: current_num_threads ( ) ;
100+ let mut frame_idx = 0 ;
101+ while frame_idx < num_frames {
102+ let batch_end = ( frame_idx + batch_size) . min ( num_frames) ;
103+ let frames: Vec < Vec < u8 > > = ( frame_idx..batch_end)
104+ . into_par_iter ( )
105+ . map ( |idx| {
106+ let data_offset = idx * self . bytes_per_frame ;
107+ let data_end = ( data_offset + self . bytes_per_frame ) . min ( packet_data. len ( ) ) ;
108+ let frame_data = if data_offset < packet_data. len ( ) {
109+ & packet_data[ data_offset..data_end]
110+ } else {
111+ & [ ]
112+ } ;
113+ self . render_frame ( frame_data)
114+ } )
115+ . collect ( ) ;
116+
117+ for frame_pixels in & frames {
118+ stdin
119+ . write_all ( frame_pixels)
120+ . context ( "failed to write frame data to ffmpeg" ) ?;
121+ }
122+ frame_idx = batch_end;
104123 }
105124
106125 drop ( child. stdin . take ( ) ) ;
0 commit comments