/rust/registry/src/index.crates.io-1949cf8c6b5b557f/av-scenechange-0.14.1/src/y4m.rs
Line | Count | Source |
1 | | use std::io::Read; |
2 | | |
3 | | use num_rational::Rational32; |
4 | | use v_frame::{ |
5 | | frame::Frame, |
6 | | pixel::{ChromaSampling, Pixel}, |
7 | | }; |
8 | | |
9 | | use crate::decoder::VideoDetails; |
10 | | |
11 | 0 | pub fn get_video_details<R: Read>(dec: &y4m::Decoder<R>) -> VideoDetails { |
12 | 0 | let width = dec.get_width(); |
13 | 0 | let height = dec.get_height(); |
14 | 0 | let color_space = dec.get_colorspace(); |
15 | 0 | let bit_depth = color_space.get_bit_depth(); |
16 | 0 | let chroma_sampling = map_y4m_color_space(color_space); |
17 | 0 | let framerate = dec.get_framerate(); |
18 | 0 | let time_base = Rational32::new(framerate.den as i32, framerate.num as i32); |
19 | | |
20 | 0 | VideoDetails { |
21 | 0 | width, |
22 | 0 | height, |
23 | 0 | bit_depth, |
24 | 0 | chroma_sampling, |
25 | 0 | time_base, |
26 | 0 | } |
27 | 0 | } |
28 | | |
29 | 0 | const fn map_y4m_color_space(color_space: y4m::Colorspace) -> ChromaSampling { |
30 | | use y4m::Colorspace::{ |
31 | | C420jpeg, |
32 | | C420mpeg2, |
33 | | C420p10, |
34 | | C420p12, |
35 | | C420paldv, |
36 | | C422p10, |
37 | | C422p12, |
38 | | C444p10, |
39 | | C444p12, |
40 | | Cmono, |
41 | | Cmono12, |
42 | | C420, |
43 | | C422, |
44 | | C444, |
45 | | }; |
46 | | use ChromaSampling::{Cs400, Cs420, Cs422, Cs444}; |
47 | 0 | match color_space { |
48 | 0 | Cmono | Cmono12 => Cs400, |
49 | 0 | C420jpeg | C420paldv => Cs420, |
50 | 0 | C420mpeg2 => Cs420, |
51 | 0 | C420 | C420p10 | C420p12 => Cs420, |
52 | 0 | C422 | C422p10 | C422p12 => Cs422, |
53 | 0 | C444 | C444p10 | C444p12 => Cs444, |
54 | 0 | _ => unimplemented!(), |
55 | | } |
56 | 0 | } |
57 | | |
58 | 0 | pub fn read_video_frame<R: Read, T: Pixel>( |
59 | 0 | dec: &mut y4m::Decoder<R>, |
60 | 0 | cfg: &VideoDetails, |
61 | 0 | ) -> anyhow::Result<Frame<T>> { |
62 | | const SB_SIZE_LOG2: usize = 6; |
63 | | const SB_SIZE: usize = 1 << SB_SIZE_LOG2; |
64 | | const SUBPEL_FILTER_SIZE: usize = 8; |
65 | | const FRAME_MARGIN: usize = 16 + SUBPEL_FILTER_SIZE; |
66 | | const LUMA_PADDING: usize = SB_SIZE + FRAME_MARGIN; |
67 | | |
68 | 0 | let bytes = dec.get_bytes_per_sample(); |
69 | 0 | dec.read_frame() |
70 | 0 | .map(|frame| { |
71 | 0 | let mut f: Frame<T> = |
72 | 0 | Frame::new_with_padding(cfg.width, cfg.height, cfg.chroma_sampling, LUMA_PADDING); |
73 | | |
74 | 0 | let (chroma_width, _) = cfg |
75 | 0 | .chroma_sampling |
76 | 0 | .get_chroma_dimensions(cfg.width, cfg.height); |
77 | | |
78 | 0 | f.planes[0].copy_from_raw_u8(frame.get_y_plane(), cfg.width * bytes, bytes); |
79 | 0 | f.planes[1].copy_from_raw_u8(frame.get_u_plane(), chroma_width * bytes, bytes); |
80 | 0 | f.planes[2].copy_from_raw_u8(frame.get_v_plane(), chroma_width * bytes, bytes); |
81 | 0 | f |
82 | 0 | }) |
83 | 0 | .map_err(|e| e.into()) |
84 | 0 | } |