Skip to content

Commit bc73a94

Browse files
committed
decode and compare all frames in the video, not just the first one
1 parent af0eaaf commit bc73a94

File tree

3 files changed

+97
-38
lines changed

3 files changed

+97
-38
lines changed

src/h264/decoder.rs

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl DecoderContext {
5959
#[derive(Debug, Default)]
6060
pub struct Decoder {
6161
context: DecoderContext,
62-
frame_buffer: Option<VideoFrame>,
62+
frame_buffer: Vec<VideoFrame>,
6363
}
6464

6565
impl Decoder {
@@ -108,8 +108,17 @@ impl Decoder {
108108

109109
info!("non-IDR Slice: {:#?}", slice);
110110
if slice.header.slice_type != SliceType::I {
111-
break;
111+
todo!("implement P-slices")
112112
}
113+
114+
let frame = VideoFrame::new_with_padding(
115+
slice.sps.pic_width(),
116+
slice.sps.pic_hight(),
117+
v_frame::pixel::ChromaSampling::Cs420,
118+
16,
119+
);
120+
self.frame_buffer.push(frame);
121+
113122
parser::parse_slice_data(&mut unit_input, &mut slice)
114123
.map_err(parse_error_handler)?;
115124
info!("Blocks: {:#?}", slice.get_macroblock_count());
@@ -121,23 +130,24 @@ impl Decoder {
121130
.map_err(parse_error_handler)?;
122131

123132
info!("IDR Slice: {:#?}", slice);
133+
let frame = VideoFrame::new_with_padding(
134+
slice.sps.pic_width(),
135+
slice.sps.pic_hight(),
136+
v_frame::pixel::ChromaSampling::Cs420,
137+
16,
138+
);
139+
self.frame_buffer.push(frame);
140+
124141
parser::parse_slice_data(&mut unit_input, &mut slice)
125142
.map_err(parse_error_handler)?;
126143
info!("Blocks: {:#?}", slice.get_macroblock_count());
127-
return self.process_slice(&mut slice); // Temporarily stop after first slice
144+
self.process_slice(&mut slice)?; // Temporarily stop after first slice
128145
}
129146
NalUnitType::SupplementalEnhancementInfo => {}
130147
NalUnitType::SeqParameterSet => {
131148
let sps = parser::parse_sps(&mut unit_input).map_err(parse_error_handler)?;
132149
info!("SPS: {:#?}", sps);
133150
assert_eq!(sps.ChromaArrayType(), ChromaFormat::YUV420);
134-
let frame = VideoFrame::new_with_padding(
135-
sps.pic_width(),
136-
sps.pic_hight(),
137-
v_frame::pixel::ChromaSampling::Cs420,
138-
16,
139-
);
140-
self.frame_buffer = Some(frame);
141151
self.context.put_sps(sps);
142152
}
143153
NalUnitType::PicParameterSet => {
@@ -162,16 +172,16 @@ impl Decoder {
162172
Ok(())
163173
}
164174

165-
pub fn get_frame_buffer(&self) -> Option<&VideoFrame> {
166-
self.frame_buffer.as_ref()
175+
pub fn get_frame_buffer(&self) -> &[VideoFrame] {
176+
self.frame_buffer.as_slice()
167177
}
168178

169179
fn process_slice(&mut self, slice: &mut Slice) -> Result<(), DecodingError> {
170-
if self.frame_buffer.is_none() {
180+
if self.frame_buffer.is_empty() {
171181
return Err(DecodingError::Wtf);
172182
}
173183
let mut qp = slice.pps.pic_init_qp_minus26 + 26 + slice.header.slice_qp_delta;
174-
let frame = self.frame_buffer.as_mut().unwrap();
184+
let frame = self.frame_buffer.last_mut().unwrap();
175185
for mb_addr in 0..(slice.sps.pic_size_in_mbs() as u32) {
176186
let mb_loc = slice.get_mb_location(mb_addr);
177187
if let Some(mb) = slice.get_mb(mb_addr) {

src/main.rs

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::io;
1717

1818
use log::info;
1919
use v_frame::plane::PlaneOffset;
20-
use y4m_cmp::compare_frames;
20+
use y4m_cmp::{compare_files, compare_frames};
2121

2222
fn main() {
2323
diag::init(false);
@@ -30,39 +30,38 @@ fn main() {
3030
let buf = fs::read(input_filename).unwrap();
3131
let mut decoder = h264::decoder::Decoder::new();
3232
decoder.decode(&buf).expect("parsing error");
33-
let frame = decoder.get_frame_buffer().unwrap();
34-
let y_plane = &frame.planes[0];
3533

34+
let first_frame = decoder.get_frame_buffer().first().unwrap();
35+
let y_plane = &first_frame.planes[0];
3636
let w = y_plane.cfg.width as u32;
3737
let h = y_plane.cfg.height as u32;
3838

39-
info!("Writing frame {w} x {h} to y4m");
4039
let mut writer = io::BufWriter::new(fs::File::create("output.y4m").unwrap());
4140
let mut encoder = y4m::encode(w as usize, h as usize, y4m::Ratio { num: 15, den: 1 })
4241
.with_colorspace(y4m::Colorspace::C420)
4342
.write_header(&mut writer)
4443
.unwrap();
45-
let mut planes = Vec::<Vec<u8>>::new();
46-
for plane in &frame.planes {
47-
let data_size = plane.cfg.width * plane.cfg.height;
48-
let mut data = vec![0; data_size];
49-
plane.copy_to_raw_u8(&mut data, plane.cfg.width, 1);
50-
planes.push(data)
51-
}
5244

53-
let yuv_frame =
54-
y4m::Frame::new([planes[0].as_slice(), planes[1].as_slice(), planes[2].as_slice()], None);
45+
for (num, frame) in decoder.get_frame_buffer().iter().enumerate() {
46+
info!("Writing frame #{num} {w} x {h} to y4m");
47+
48+
let mut planes = Vec::<Vec<u8>>::new();
49+
for plane in &frame.planes {
50+
let data_size = plane.cfg.width * plane.cfg.height;
51+
let mut data = vec![0; data_size];
52+
plane.copy_to_raw_u8(&mut data, plane.cfg.width, 1);
53+
planes.push(data)
54+
}
55+
56+
let yuv_frame = y4m::Frame::new(
57+
[planes[0].as_slice(), planes[1].as_slice(), planes[2].as_slice()],
58+
None,
59+
);
60+
encoder.write_frame(&yuv_frame).unwrap();
61+
}
62+
drop(encoder);
5563

56-
if let Ok(expected_file) = fs::File::open("data/NL1_Sony_D.y4m") {
57-
let reader = io::BufReader::new(expected_file);
58-
let mut decoder = y4m::Decoder::new(reader).unwrap();
59-
let expected_h = decoder.get_height();
60-
let expected_w = decoder.get_width();
61-
let expected_frame = decoder.read_frame().unwrap();
62-
assert!(w == expected_w as u32);
63-
assert!(h == expected_h as u32);
64-
let compare_result = compare_frames(expected_w, expected_h, &yuv_frame, &expected_frame);
65-
print!("Frame comparison result: {compare_result}");
64+
if let Err(message) = compare_files("output.y4m", "data/NL1_Sony_D.y4m") {
65+
print!("File comparison result: {message}");
6666
}
67-
encoder.write_frame(&yuv_frame).unwrap();
6867
}

src/y4m_cmp.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1+
use v_frame::frame;
2+
13
use crate::h264::tables::MB_WIDTH;
24

5+
use std::fmt::format;
6+
use std::fs;
7+
use std::io;
8+
use std::io::Error;
9+
310
fn compare_plane(
411
width: usize,
512
height: usize,
@@ -54,3 +61,46 @@ pub fn compare_frames(
5461

5562
result
5663
}
64+
65+
pub fn compare_files(actual_filename: &str, expected_filename: &str) -> Result<(), String> {
66+
fn stringify(x: Error) -> String {
67+
format!("error code: {x}")
68+
}
69+
fn y4m_stringify(x: y4m::Error) -> String {
70+
format!("error code: {x}")
71+
}
72+
73+
let expected_file = fs::File::open(expected_filename).map_err(stringify)?;
74+
let expected_reader = io::BufReader::new(expected_file);
75+
let mut expected_decoder = y4m::Decoder::new(expected_reader).map_err(y4m_stringify)?;
76+
77+
let actual_file = fs::File::open(actual_filename).map_err(stringify)?;
78+
let actual_reader = io::BufReader::new(actual_file);
79+
let mut actual_decoder = y4m::Decoder::new(actual_reader).map_err(y4m_stringify)?;
80+
81+
let expected_h = expected_decoder.get_height();
82+
let expected_w = expected_decoder.get_width();
83+
let actual_h = actual_decoder.get_height();
84+
let actual_w = actual_decoder.get_width();
85+
if (expected_w, expected_h) != (actual_w, actual_h) {
86+
return Err(format!("Unexpected size of frames. {actual_w}x{actual_h} vs expected {expected_w}x{expected_h}"));
87+
}
88+
89+
let mut frame_idx = 0;
90+
while let (Ok(actual_frame), Ok(expected_frame)) =
91+
(actual_decoder.read_frame(), expected_decoder.read_frame())
92+
{
93+
let compare_result = compare_frames(expected_w, expected_h, &actual_frame, &expected_frame);
94+
if !compare_result.is_empty() {
95+
return Err(format!("Frame #{frame_idx} mismatch: {compare_result}"));
96+
}
97+
frame_idx += 1;
98+
}
99+
100+
if let Err(y4m::Error::EOF) = actual_decoder.read_frame() {
101+
} else {
102+
return Err(format!("Unexpected number of frames. {frame_idx}"));
103+
}
104+
105+
Ok(())
106+
}

0 commit comments

Comments
 (0)