@@ -6,6 +6,9 @@ use tokio_util::sync::CancellationToken;
66
77use crate :: frame_ws:: { WSFrame , create_frame_ws} ;
88
9+ const WS_PREVIEW_MAX_WIDTH : u32 = 640 ;
10+ const WS_PREVIEW_MAX_HEIGHT : u32 = 360 ;
11+
912pub async fn create_camera_preview_ws ( ) -> ( Sender < FFmpegVideoFrame > , u16 , CancellationToken ) {
1013 let ( camera_tx, camera_rx) = flume:: bounded :: < FFmpegVideoFrame > ( 4 ) ;
1114 let ( frame_tx, _) = tokio:: sync:: broadcast:: channel :: < WSFrame > ( 4 ) ;
@@ -14,64 +17,90 @@ pub async fn create_camera_preview_ws() -> (Sender<FFmpegVideoFrame>, u16, Cance
1417 use ffmpeg:: format:: Pixel ;
1518
1619 let mut converter: Option < ( Pixel , ffmpeg:: software:: scaling:: Context ) > = None ;
20+ let mut reusable_frame: Option < ffmpeg:: util:: frame:: Video > = None ;
1721
1822 while let Ok ( raw_frame) = camera_rx. recv ( ) {
1923 let mut frame = raw_frame. inner ;
2024
21- if frame. format ( ) != Pixel :: RGBA || frame. width ( ) > 1280 || frame. height ( ) > 720 {
22- let converter = match & mut converter {
23- Some ( ( format, converter) )
25+ while let Ok ( newer) = camera_rx. try_recv ( ) {
26+ frame = newer. inner ;
27+ }
28+
29+ let needs_convert = frame. format ( ) != Pixel :: RGBA
30+ || frame. width ( ) > WS_PREVIEW_MAX_WIDTH
31+ || frame. height ( ) > WS_PREVIEW_MAX_HEIGHT ;
32+
33+ if needs_convert {
34+ let target_width = WS_PREVIEW_MAX_WIDTH . min ( frame. width ( ) ) ;
35+ let target_height =
36+ ( target_width as f64 / ( frame. width ( ) as f64 / frame. height ( ) as f64 ) ) as u32 ;
37+
38+ let ctx = match & mut converter {
39+ Some ( ( format, ctx) )
2440 if * format == frame. format ( )
25- && converter . input ( ) . width == frame. width ( )
26- && converter . input ( ) . height == frame. height ( ) =>
41+ && ctx . input ( ) . width == frame. width ( )
42+ && ctx . input ( ) . height == frame. height ( ) =>
2743 {
28- converter
44+ ctx
2945 }
3046 _ => {
3147 let Ok ( new_converter) = ffmpeg:: software:: scaling:: Context :: get (
3248 frame. format ( ) ,
3349 frame. width ( ) ,
3450 frame. height ( ) ,
3551 Pixel :: RGBA ,
36- 1280 ,
37- ( 1280.0 / ( frame . width ( ) as f64 / frame . height ( ) as f64 ) ) as u32 ,
52+ target_width ,
53+ target_height ,
3854 ffmpeg:: software:: scaling:: flag:: Flags :: FAST_BILINEAR ,
3955 ) else {
4056 continue ;
4157 } ;
4258
59+ reusable_frame = None ;
4360 & mut converter. insert ( ( frame. format ( ) , new_converter) ) . 1
4461 }
4562 } ;
4663
47- let mut new_frame = ffmpeg:: util:: frame:: Video :: new (
48- Pixel :: RGBA ,
49- converter. output ( ) . width ,
50- converter. output ( ) . height ,
51- ) ;
64+ let out_frame = reusable_frame. get_or_insert_with ( || {
65+ ffmpeg:: util:: frame:: Video :: new (
66+ Pixel :: RGBA ,
67+ ctx. output ( ) . width ,
68+ ctx. output ( ) . height ,
69+ )
70+ } ) ;
5271
53- if converter . run ( & frame, & mut new_frame ) . is_err ( ) {
72+ if ctx . run ( & frame, out_frame ) . is_err ( ) {
5473 continue ;
5574 }
5675
57- frame = new_frame;
76+ frame_tx_clone
77+ . send ( WSFrame {
78+ data : std:: sync:: Arc :: new ( out_frame. data ( 0 ) . to_vec ( ) ) ,
79+ width : out_frame. width ( ) ,
80+ height : out_frame. height ( ) ,
81+ stride : out_frame. stride ( 0 ) as u32 ,
82+ frame_number : 0 ,
83+ target_time_ns : 0 ,
84+ format : crate :: frame_ws:: WSFrameFormat :: Rgba ,
85+ created_at : Instant :: now ( ) ,
86+ } )
87+ . ok ( ) ;
88+ } else {
89+ frame_tx_clone
90+ . send ( WSFrame {
91+ data : std:: sync:: Arc :: new ( frame. data ( 0 ) . to_vec ( ) ) ,
92+ width : frame. width ( ) ,
93+ height : frame. height ( ) ,
94+ stride : frame. stride ( 0 ) as u32 ,
95+ frame_number : 0 ,
96+ target_time_ns : 0 ,
97+ format : crate :: frame_ws:: WSFrameFormat :: Rgba ,
98+ created_at : Instant :: now ( ) ,
99+ } )
100+ . ok ( ) ;
58101 }
59-
60- frame_tx_clone
61- . send ( WSFrame {
62- data : std:: sync:: Arc :: new ( frame. data ( 0 ) . to_vec ( ) ) ,
63- width : frame. width ( ) ,
64- height : frame. height ( ) ,
65- stride : frame. stride ( 0 ) as u32 ,
66- frame_number : 0 ,
67- target_time_ns : 0 ,
68- format : crate :: frame_ws:: WSFrameFormat :: Rgba ,
69- created_at : Instant :: now ( ) ,
70- } )
71- . ok ( ) ;
72102 }
73103 } ) ;
74- // _shutdown needs to be kept alive to keep the camera ws running
75104 let ( camera_ws_port, _shutdown) = create_frame_ws ( frame_tx) . await ;
76105
77106 ( camera_tx, camera_ws_port, _shutdown)
0 commit comments