1use std::io::Read;
2
3use num_rational::Rational32;
4use v_frame::{
5 frame::Frame,
6 pixel::{ChromaSampling, Pixel},
7};
8
9use crate::decoder::VideoDetails;
10
11pub fn get_video_details<R: Read>(dec: &y4m::Decoder<R>) -> VideoDetails {
12 let width = dec.get_width();
13 let height = dec.get_height();
14 let color_space = dec.get_colorspace();
15 let bit_depth = color_space.get_bit_depth();
16 let chroma_sampling = map_y4m_color_space(color_space);
17 let framerate = dec.get_framerate();
18 let time_base = Rational32::new(framerate.den as i32, framerate.num as i32);
19
20 VideoDetails {
21 width,
22 height,
23 bit_depth,
24 chroma_sampling,
25 time_base,
26 }
27}
28
29const 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 match color_space {
48 Cmono | Cmono12 => Cs400,
49 C420jpeg | C420paldv => Cs420,
50 C420mpeg2 => Cs420,
51 C420 | C420p10 | C420p12 => Cs420,
52 C422 | C422p10 | C422p12 => Cs422,
53 C444 | C444p10 | C444p12 => Cs444,
54 _ => unimplemented!(),
55 }
56}
57
58pub fn read_video_frame<R: Read, T: Pixel>(
59 dec: &mut y4m::Decoder<R>,
60 cfg: &VideoDetails,
61) -> 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 let bytes = dec.get_bytes_per_sample();
69 dec.read_frame()
70 .map(|frame| {
71 let mut f: Frame<T> =
72 Frame::new_with_padding(cfg.width, cfg.height, cfg.chroma_sampling, LUMA_PADDING);
73
74 let (chroma_width, _) = cfg
75 .chroma_sampling
76 .get_chroma_dimensions(cfg.width, cfg.height);
77
78 f.planes[0].copy_from_raw_u8(frame.get_y_plane(), cfg.width * bytes, bytes);
79 f.planes[1].copy_from_raw_u8(frame.get_u_plane(), chroma_width * bytes, bytes);
80 f.planes[2].copy_from_raw_u8(frame.get_v_plane(), chroma_width * bytes, bytes);
81 f
82 })
83 .map_err(|e| e.into())
84}