Compare commits
	
		
			4 Commits
		
	
	
		
			37ce43cbde
			...
			e9238660d8
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e9238660d8 | |||
| bd7cc019cf | |||
| 0f3c3453ac | |||
| 7d905adf10 | 
							
								
								
									
										12
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -1,4 +1,6 @@
 | 
				
			|||||||
#![feature(iter_array_chunks)]
 | 
					#![feature(iter_array_chunks)]
 | 
				
			||||||
 | 
					#![feature(error_generic_member_access)]
 | 
				
			||||||
 | 
					#![feature(provide_any)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern crate ffmpeg_next as ffmpeg;
 | 
					extern crate ffmpeg_next as ffmpeg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -8,7 +10,6 @@ use ffmpeg::media::Type;
 | 
				
			|||||||
use ffmpeg::software::scaling::{context::Context, flag::Flags};
 | 
					use ffmpeg::software::scaling::{context::Context, flag::Flags};
 | 
				
			||||||
use ffmpeg::util::frame::video::Video;
 | 
					use ffmpeg::util::frame::video::Video;
 | 
				
			||||||
use std::path::Path;
 | 
					use std::path::Path;
 | 
				
			||||||
use std::time::Instant;
 | 
					 | 
				
			||||||
mod out;
 | 
					mod out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() -> Result<(), Error> {
 | 
					fn main() -> Result<(), Error> {
 | 
				
			||||||
@@ -17,14 +18,13 @@ fn main() -> Result<(), Error> {
 | 
				
			|||||||
    ffmpeg::init()?;
 | 
					    ffmpeg::init()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // read the input file
 | 
					    // read the input file
 | 
				
			||||||
    if let Ok(mut ictx) = input(&Path::new("output.mkv")) {
 | 
					    if let Ok(mut ictx) = input(&Path::new("rgb.png")) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let input = ictx
 | 
					        let input = ictx
 | 
				
			||||||
            .streams()
 | 
					            .streams()
 | 
				
			||||||
            .best(Type::Video)
 | 
					            .best(Type::Video)
 | 
				
			||||||
            .ok_or(ffmpeg::Error::StreamNotFound)?;
 | 
					            .ok_or(ffmpeg::Error::StreamNotFound)?;
 | 
				
			||||||
        let video_stream_index = input.index();
 | 
					        let video_stream_index = input.index();
 | 
				
			||||||
        let fps = input.avg_frame_rate();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let context_decoder = ffmpeg::codec::context::Context::from_parameters(input.parameters())?;
 | 
					        let context_decoder = ffmpeg::codec::context::Context::from_parameters(input.parameters())?;
 | 
				
			||||||
        // Ctx's video decoder
 | 
					        // Ctx's video decoder
 | 
				
			||||||
@@ -52,7 +52,7 @@ fn main() -> Result<(), Error> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    // test::print_raw(&rgb_frame.data(0));
 | 
					                    // test::print_raw(&rgb_frame.data(0));
 | 
				
			||||||
                    // test::print_square(&rgb_frame.data(0), rgb_frame.width() as usize);
 | 
					                    // test::print_square(&rgb_frame.data(0), rgb_frame.width() as usize);
 | 
				
			||||||
                    out::print_square(&rgb_frame, out::LinesFormat::RightLeft, video_stream_index);
 | 
					                    out::print_square(&rgb_frame, out::LinesFormat::RightLeft, video_stream_index).unwrap();
 | 
				
			||||||
                    // test::small_matrix();
 | 
					                    // test::small_matrix();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                Ok(())
 | 
					                Ok(())
 | 
				
			||||||
@@ -63,12 +63,10 @@ fn main() -> Result<(), Error> {
 | 
				
			|||||||
            // Is this for multiple video streams?
 | 
					            // Is this for multiple video streams?
 | 
				
			||||||
            if stream.index() == video_stream_index {
 | 
					            if stream.index() == video_stream_index {
 | 
				
			||||||
                decoder.send_packet(&packet)?;
 | 
					                decoder.send_packet(&packet)?;
 | 
				
			||||||
 | 
					 | 
				
			||||||
                let now = Instant::now();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                receive_and_process_decoded_frames(&mut decoder)?;
 | 
					                receive_and_process_decoded_frames(&mut decoder)?;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        decoder.send_eof()?;
 | 
					        decoder.send_eof()?;
 | 
				
			||||||
        receive_and_process_decoded_frames(&mut decoder)?;
 | 
					        receive_and_process_decoded_frames(&mut decoder)?;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										107
									
								
								src/out.rs
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								src/out.rs
									
									
									
									
									
								
							@@ -13,62 +13,93 @@ pub enum LinesFormat {
 | 
				
			|||||||
    Left,
 | 
					    Left,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub enum ParseError {
 | 
				
			||||||
 | 
					    NotRGB24,
 | 
				
			||||||
 | 
					    NotSquareAspectRatio,
 | 
				
			||||||
 | 
					    VideoIndexOutOfBounds,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl std::fmt::Display for ParseError {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        let s = match self {
 | 
				
			||||||
 | 
					            ParseError::NotRGB24 => "Not in RGB24 format!",
 | 
				
			||||||
 | 
					            ParseError::NotSquareAspectRatio => "Not in a square (1:1) aspect ratio!",
 | 
				
			||||||
 | 
					            ParseError::VideoIndexOutOfBounds => "Selected video index is not valid (Out of Bounds)!",
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        write!(f, "{s}")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl std::error::Error for ParseError {} 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Must use square images
 | 
					/// Must use square images
 | 
				
			||||||
pub fn print_square(frame: &ffmpeg::frame::Video, lines_format: LinesFormat, video_index: usize) {
 | 
					/// Images must be in RGB24
 | 
				
			||||||
    if frame.format() != Pixel::RGB24 { panic!("Must use Pixel::RGB24"); }
 | 
					pub fn print_square(frame: &ffmpeg::frame::Video, lines_format: LinesFormat, video_index: usize) -> Result<(), ParseError> {
 | 
				
			||||||
    if frame.width() != frame.height() { panic!("Must be 1:1 aspect ratio"); } 
 | 
					    if frame.format() != Pixel::RGB24   { return Err(ParseError::NotRGB24); }
 | 
				
			||||||
 | 
					    if frame.width() != frame.height()  { return Err(ParseError::NotSquareAspectRatio); } 
 | 
				
			||||||
 | 
					    // 8 is the value hard-coded in AVFrame
 | 
				
			||||||
 | 
					    if !(0..=8).contains(&video_index)  { return Err(ParseError::VideoIndexOutOfBounds); } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // This will panic if it's out of bounds.
 | 
					    let pixels_wide = frame.width() as usize;
 | 
				
			||||||
    let z = video_index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let size = frame.width() as usize;
 | 
					 | 
				
			||||||
    // How many bytes per pixel RGBA
 | 
					 | 
				
			||||||
    let linesize = unsafe { std::ptr::addr_of!((*frame.as_ptr()).linesize) };
 | 
					 | 
				
			||||||
    let step = (unsafe { *linesize })[z] as usize;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut stdout = stdout();
 | 
					    let mut stdout = stdout();
 | 
				
			||||||
    let mut lock = stdout.lock();
 | 
					    let mut lock = stdout.lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let buf = frame.data(z); 
 | 
					    // EXPLANATION: (12x12 image)
 | 
				
			||||||
 | 
					    // The full buffer will be 1152 bytes.
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // 1152/12=96   Buffer length   / Pixels high       = 96 Bytes per line.
 | 
				
			||||||
 | 
					    // 96/12=8      Bytes per line  / Pixels per line   = 8 Bytes per pixel.
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // But RGB24 should only use 3 bytes per pixel. The other 5 we just discard.
 | 
				
			||||||
 | 
					    // They might be alpha, or grayscale overlay, I'm not really sure.
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // 8-5=3        Bytes per pixel - Discarded bytes = Used bytes
 | 
				
			||||||
 | 
					    // 3*12=36      Used bytes      * Pixels per line = Slice length
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // This is because all the extra data (the 5 extra bytes) are at the end
 | 
				
			||||||
 | 
					    // of each line. So we just take the first (Pixel width)*3 bytes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let buf = frame.data(video_index); 
 | 
				
			||||||
 | 
					    let step = buf.len() / frame.height() as usize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // (Assuming square) Step thru buffer.
 | 
					    // (Assuming square) Step thru buffer.
 | 
				
			||||||
    for i in 0..size {
 | 
					    for i in 0..pixels_wide {
 | 
				
			||||||
        let j = i*step;
 | 
					        let j = i*step;
 | 
				
			||||||
        // Slices non-inclusively, ie: Even though j(n)+step = j(n+1) the ranges don't overlap. It take from..until
 | 
					        // Have to take ownership, by implicilty Cloning the data. (Copying?)
 | 
				
			||||||
        let pre_slice = &buf[j..j+step];
 | 
					        let mut slice = Vec::from(&buf[j..j+pixels_wide*3]);
 | 
				
			||||||
        // Only take the size*3 of bytes, ignoring alpha values which are stored after.
 | 
					 | 
				
			||||||
        // let slice = &pre_slice[0..size*3];
 | 
					 | 
				
			||||||
        let mut slice = Vec::from(&pre_slice[0..size*3]);
 | 
					 | 
				
			||||||
        // let lol = &buf[j..j+step][0..size*3];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        match lines_format {
 | 
					        match lines_format {
 | 
				
			||||||
            LinesFormat::Right => {/* Do nothing */},
 | 
					            LinesFormat::RightLeft =>  if i & 1 == 1 { rev_in_place_with_groupings(&mut slice) },
 | 
				
			||||||
            LinesFormat::RightLeft => if i & 1 == 1 { reverse(&mut slice) },
 | 
					            LinesFormat::LeftRight  => if i & 1 != 1 { rev_in_place_with_groupings(&mut slice) },
 | 
				
			||||||
            LinesFormat::LeftRight => if i & 1 != 1 { reverse(&mut slice) },
 | 
					            LinesFormat::Left       => rev_in_place_with_groupings(&mut slice),
 | 
				
			||||||
            LinesFormat::Left => slice.reverse(),
 | 
					            LinesFormat::Right      => {},
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // DEBUG
 | 
					        // DEBUG
 | 
				
			||||||
        // println!("{:?} || {}-{}", slice, j, j+step);
 | 
					        // println!("{:?} || {}-{}", slice, j, j+step);
 | 
				
			||||||
        // NORMAL
 | 
					        // NORMAL
 | 
				
			||||||
        lock.write(&slice).unwrap();
 | 
					        lock.write(&slice).unwrap();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    stdout.flush().unwrap();
 | 
					    stdout.flush().unwrap();
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn rev_in_place_with_groupings(raw: &mut Vec<u8>) {
 | 
				
			||||||
/// Reverses the order of every grouping of 3 bytes.
 | 
					    for i in 0..raw.len() {
 | 
				
			||||||
fn reverse(raw: & mut [u8]) {
 | 
					        match i % 3 {
 | 
				
			||||||
    // I would prefer this only went over the elements once,
 | 
					            // Think of these as the indexes of each
 | 
				
			||||||
    // not twice.
 | 
					            // RGB tuple. [0, 1, 2] [R, G, B].
 | 
				
			||||||
 | 
					            // 0 and 2 have to be switched, while 1 can stay.
 | 
				
			||||||
    let x = raw
 | 
					            2 => {
 | 
				
			||||||
        .iter()
 | 
					                let zero = raw[i-2];
 | 
				
			||||||
        .array_chunks::<3>()
 | 
					                let two  = raw[i];
 | 
				
			||||||
        .rev()
 | 
					                raw[i-2] = two;
 | 
				
			||||||
        .flatten()
 | 
					                raw[i] = zero;
 | 
				
			||||||
        .map(|f| *f)
 | 
					            },
 | 
				
			||||||
        .collect::<Vec<u8>>();
 | 
					            _ => { /* 0 and 1*/ },
 | 
				
			||||||
    
 | 
					        } 
 | 
				
			||||||
    x.iter().enumerate().for_each(|f| raw[f.0] = *f.1);
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user