use crate::{ cli::{ImageProcessingOptions, PixelCommand, SendImageOptions}, image_processing::ImageProcessingPipeline, stream_window::stream_window, transport::Transport, }; use ffmpeg_next as ffmpeg; use image::{DynamicImage, RgbImage}; use log::info; use servicepoint::{ BinaryOperation, BitVecCommand, BitmapCommand, ClearCommand, CompressionCode, DisplayBitVec, Origin, PIXEL_COUNT, }; pub(crate) fn pixels(connection: &Transport, pixel_command: PixelCommand) { match pixel_command { PixelCommand::Off => pixels_off(connection), PixelCommand::Flip => pixels_invert(connection), PixelCommand::On => pixels_on(connection), PixelCommand::Image { image_processing_options: processing_options, send_image_options: image_options, } => pixels_image(connection, image_options, processing_options), PixelCommand::Screen { stream_options, image_processing, } => stream_window(connection, stream_options, image_processing), PixelCommand::Video { image_processing_options: processing_options, send_image_options: image_options, } => pixels_video(connection, image_options, processing_options), } } fn pixels_on(connection: &Transport) { let mask = DisplayBitVec::repeat(true, PIXEL_COUNT); let command = BitVecCommand { offset: 0, bitvec: mask, compression: CompressionCode::Lzma, operation: BinaryOperation::Overwrite, }; connection .send_command(command) .expect("could not send command"); info!("turned on all pixels") } fn pixels_invert(connection: &Transport) { let mask = DisplayBitVec::repeat(true, PIXEL_COUNT); let command = BitVecCommand { offset: 0, bitvec: mask, compression: CompressionCode::Lzma, operation: BinaryOperation::Xor, }; connection .send_command(command) .expect("could not send command"); info!("inverted all pixels"); } pub(crate) fn pixels_off(connection: &Transport) { connection .send_command(ClearCommand) .expect("failed to clear pixels"); info!("reset pixels"); } fn pixels_image( connection: &Transport, options: SendImageOptions, processing_options: ImageProcessingOptions, ) { let image = image::open(&options.file_name).expect("failed to open image file"); let mut pipeline = ImageProcessingPipeline::new(processing_options); let bitmap = pipeline.process(image); connection .send_command(BitmapCommand { origin: Origin::ZERO, bitmap, compression: CompressionCode::default(), }) .expect("failed to send image command"); info!("sent image to display"); } fn pixels_video( connection: &Transport, options: SendImageOptions, processing_options: ImageProcessingOptions, ) { ffmpeg::init().unwrap(); let mut ictx = ffmpeg::format::input(&options.file_name).expect("failed to open video input file"); let input = ictx .streams() .best(ffmpeg::media::Type::Video) .ok_or(ffmpeg::Error::StreamNotFound) .expect("could not get video stream from input file"); let video_stream_index = input.index(); let context_decoder = ffmpeg::codec::context::Context::from_parameters(input.parameters()) .expect("could not extract video context from parameters"); let mut decoder = context_decoder.decoder().video() .expect("failed to create decoder for video stream"); let src_width = decoder.width(); let src_height = decoder.height(); let mut scaler = ffmpeg::software::scaling::Context::get( decoder.format(), src_width, src_height, ffmpeg::format::Pixel::RGB24, src_width, src_height, ffmpeg::software::scaling::Flags::BILINEAR, ).expect("failed to create scaling context"); let mut frame_index = 0; let mut processing_pipeline = ImageProcessingPipeline::new(processing_options); let mut receive_and_process_decoded_frames = |decoder: &mut ffmpeg::decoder::Video| -> Result<(), ffmpeg::Error> { let mut decoded = ffmpeg::util::frame::video::Video::empty(); let mut rgb_frame = ffmpeg::util::frame::video::Video::empty(); while decoder.receive_frame(&mut decoded).is_ok() { scaler.run(&decoded, &mut rgb_frame) .expect("failed to scale frame"); let image = RgbImage::from_raw(src_width, src_height, rgb_frame.data(0).to_owned()) .expect("could not read rgb data to image"); let image = DynamicImage::from(image); let bitmap= processing_pipeline.process(image); connection.send_command(BitmapCommand::from(bitmap)) .expect("failed to send image command"); frame_index += 1; } Ok(()) }; for (stream, packet) in ictx.packets() { if stream.index() == video_stream_index { decoder.send_packet(&packet) .expect("failed to send video packet"); receive_and_process_decoded_frames(&mut decoder) .expect("failed to process video packet"); } } decoder.send_eof().expect("failed to send eof"); receive_and_process_decoded_frames(&mut decoder) .expect("failed to eof packet"); }