@@ -2243,6 +2243,94 @@ async fn seek_to(editor_instance: WindowEditorInstance, frame_number: u32) -> Re
22432243 Ok ( ( ) )
22442244}
22452245
2246+ #[ tauri:: command]
2247+ #[ specta:: specta]
2248+ #[ instrument( skip( editor_instance) ) ]
2249+ async fn get_display_frame_for_cropping (
2250+ editor_instance : WindowEditorInstance ,
2251+ fps : u32 ,
2252+ ) -> Result < Vec < u8 > , String > {
2253+ use cap_project:: ClipOffsets ;
2254+ use cap_rendering:: { PixelFormat , cpu_yuv} ;
2255+ use image:: { ImageEncoder , codecs:: png:: PngEncoder } ;
2256+ use std:: io:: Cursor ;
2257+
2258+ let frame_number = editor_instance. state . lock ( ) . await . playhead_position ;
2259+ let time_secs = frame_number as f64 / fps as f64 ;
2260+
2261+ let project = editor_instance. project_config . 1 . borrow ( ) . clone ( ) ;
2262+
2263+ let ( segment_time, segment) = project
2264+ . get_segment_time ( time_secs)
2265+ . ok_or_else ( || "No segment found for current time" . to_string ( ) ) ?;
2266+
2267+ let segment_medias = editor_instance
2268+ . segment_medias
2269+ . get ( segment. recording_clip as usize )
2270+ . ok_or_else ( || "Segment media not found" . to_string ( ) ) ?;
2271+
2272+ let clip_offsets = project
2273+ . clips
2274+ . iter ( )
2275+ . find ( |v| v. index == segment. recording_clip )
2276+ . map ( |v| v. offsets )
2277+ . unwrap_or ( ClipOffsets :: default ( ) ) ;
2278+
2279+ let segment_frames = segment_medias
2280+ . decoders
2281+ . get_frames ( segment_time as f32 , false , clip_offsets)
2282+ . await
2283+ . ok_or_else ( || "Failed to get frame" . to_string ( ) ) ?;
2284+
2285+ let screen_frame = segment_frames. screen_frame ;
2286+ let width = screen_frame. width ( ) ;
2287+ let height = screen_frame. height ( ) ;
2288+
2289+ let rgba_data = match screen_frame. format ( ) {
2290+ PixelFormat :: Rgba => screen_frame. data ( ) . to_vec ( ) ,
2291+ PixelFormat :: Nv12 => {
2292+ let y_plane = screen_frame. y_plane ( ) . ok_or ( "Missing Y plane" ) ?;
2293+ let uv_plane = screen_frame. uv_plane ( ) . ok_or ( "Missing UV plane" ) ?;
2294+ let mut rgba = vec ! [ 0u8 ; ( width * height * 4 ) as usize ] ;
2295+ cpu_yuv:: nv12_to_rgba (
2296+ y_plane,
2297+ uv_plane,
2298+ width,
2299+ height,
2300+ screen_frame. y_stride ( ) ,
2301+ screen_frame. uv_stride ( ) ,
2302+ & mut rgba,
2303+ ) ;
2304+ rgba
2305+ }
2306+ PixelFormat :: Yuv420p => {
2307+ let y_plane = screen_frame. y_plane ( ) . ok_or ( "Missing Y plane" ) ?;
2308+ let u_plane = screen_frame. u_plane ( ) . ok_or ( "Missing U plane" ) ?;
2309+ let v_plane = screen_frame. v_plane ( ) . ok_or ( "Missing V plane" ) ?;
2310+ let mut rgba = vec ! [ 0u8 ; ( width * height * 4 ) as usize ] ;
2311+ cpu_yuv:: yuv420p_to_rgba (
2312+ y_plane,
2313+ u_plane,
2314+ v_plane,
2315+ width,
2316+ height,
2317+ screen_frame. y_stride ( ) ,
2318+ screen_frame. uv_stride ( ) ,
2319+ & mut rgba,
2320+ ) ;
2321+ rgba
2322+ }
2323+ } ;
2324+
2325+ let mut png_data = Cursor :: new ( Vec :: new ( ) ) ;
2326+ let encoder = PngEncoder :: new ( & mut png_data) ;
2327+ encoder
2328+ . write_image ( & rgba_data, width, height, image:: ExtendedColorType :: Rgba8 )
2329+ . map_err ( |e| format ! ( "Failed to encode PNG: {e}" ) ) ?;
2330+
2331+ Ok ( png_data. into_inner ( ) )
2332+ }
2333+
22462334#[ tauri:: command]
22472335#[ specta:: specta]
22482336#[ instrument( skip( editor_instance) ) ]
@@ -2518,6 +2606,7 @@ pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: PathBuf) {
25182606 reset_microphone_permissions,
25192607 is_camera_window_open,
25202608 seek_to,
2609+ get_display_frame_for_cropping,
25212610 windows:: position_traffic_lights,
25222611 windows:: set_theme,
25232612 global_message_dialog,
0 commit comments