Skip to content

Commit b78dc3e

Browse files
alfredoyangkinetiknz
alfredoyang
authored andcommitted
support matrix rotation
1 parent c27a2ea commit b78dc3e

File tree

5 files changed

+86
-1
lines changed

5 files changed

+86
-1
lines changed

mp4parse/src/lib.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,19 @@ struct MovieHeaderBox {
120120
duration: u64,
121121
}
122122

123+
#[derive(Debug, Clone, Copy)]
124+
pub struct Matrix {
125+
pub a: i32, // 16.16 fix point
126+
pub b: i32, // 16.16 fix point
127+
pub u: i32, // 2.30 fix point
128+
pub c: i32, // 16.16 fix point
129+
pub d: i32, // 16.16 fix point
130+
pub v: i32, // 2.30 fix point
131+
pub x: i32, // 16.16 fix point
132+
pub y: i32, // 16.16 fix point
133+
pub w: i32, // 2.30 fix point
134+
}
135+
123136
/// Track header box 'tkhd'
124137
#[derive(Debug, Clone)]
125138
pub struct TrackHeaderBox {
@@ -128,6 +141,7 @@ pub struct TrackHeaderBox {
128141
pub duration: u64,
129142
pub width: u32,
130143
pub height: u32,
144+
pub matrix: Matrix,
131145
}
132146

133147
/// Edit list box 'elst'
@@ -999,7 +1013,14 @@ fn read_tkhd<T: Read>(src: &mut BMFFBox<T>) -> Result<TrackHeaderBox> {
9991013
_ => return Err(Error::InvalidData("unhandled tkhd version")),
10001014
};
10011015
// Skip uninteresting fields.
1002-
skip(src, 52)?;
1016+
skip(src, 16)?;
1017+
1018+
let matrix = Matrix{
1019+
a: be_i32(src)?, b: be_i32(src)?, u: be_i32(src)?,
1020+
c: be_i32(src)?, d: be_i32(src)?, v: be_i32(src)?,
1021+
x: be_i32(src)?, y: be_i32(src)?, w: be_i32(src)?,
1022+
};
1023+
10031024
let width = be_u32(src)?;
10041025
let height = be_u32(src)?;
10051026
Ok(TrackHeaderBox {
@@ -1008,6 +1029,7 @@ fn read_tkhd<T: Read>(src: &mut BMFFBox<T>) -> Result<TrackHeaderBox> {
10081029
duration: duration,
10091030
width: width,
10101031
height: height,
1032+
matrix: matrix,
10111033
})
10121034
}
10131035

mp4parse_capi/examples/afl-capi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ fn doit() {
5252
display_height: 0,
5353
image_width: 0,
5454
image_height: 0,
55+
rotation: 0,
5556
extra_data: mp4parse_byte_data::default(),
5657
protected_data: Default::default(),
5758
};

mp4parse_capi/src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ pub struct mp4parse_track_video_info {
196196
pub display_height: u32,
197197
pub image_width: u16,
198198
pub image_height: u16,
199+
pub rotation: u16,
199200
pub extra_data: mp4parse_byte_data,
200201
pub protected_data: mp4parse_sinf_info,
201202
}
@@ -633,6 +634,14 @@ pub unsafe extern fn mp4parse_get_track_video_info(parser: *mut mp4parse_parser,
633634
if let Some(ref tkhd) = track.tkhd {
634635
(*info).display_width = tkhd.width >> 16; // 16.16 fixed point
635636
(*info).display_height = tkhd.height >> 16; // 16.16 fixed point
637+
let matrix = (tkhd.matrix.a >> 16, tkhd.matrix.b >> 16,
638+
tkhd.matrix.c >> 16, tkhd.matrix.d >> 16);
639+
(*info).rotation = match matrix {
640+
( 0, 1, -1, 0) => 90, // rotate 90 degrees
641+
(-1, 0, 0, -1) => 180, // rotate 180 degrees
642+
( 0, -1, 1, 0) => 270, // rotate 270 degrees
643+
_ => 0,
644+
};
636645
} else {
637646
return MP4PARSE_ERROR_INVALID;
638647
}
@@ -1221,6 +1230,7 @@ fn arg_validation() {
12211230
display_height: 0,
12221231
image_width: 0,
12231232
image_height: 0,
1233+
rotation: 0,
12241234
extra_data: mp4parse_byte_data::default(),
12251235
protected_data: Default::default(),
12261236
};
@@ -1267,6 +1277,7 @@ fn arg_validation_with_parser() {
12671277
display_height: 0,
12681278
image_width: 0,
12691279
image_height: 0,
1280+
rotation: 0,
12701281
extra_data: mp4parse_byte_data::default(),
12711282
protected_data: Default::default(),
12721283
};
@@ -1340,6 +1351,7 @@ fn arg_validation_with_data() {
13401351
display_height: 0,
13411352
image_width: 0,
13421353
image_height: 0,
1354+
rotation: 0,
13431355
extra_data: mp4parse_byte_data::default(),
13441356
protected_data: Default::default(),
13451357
};
@@ -1374,6 +1386,7 @@ fn arg_validation_with_data() {
13741386
display_height: 0,
13751387
image_width: 0,
13761388
image_height: 0,
1389+
rotation: 0,
13771390
extra_data: mp4parse_byte_data::default(),
13781391
protected_data: Default::default(),
13791392
};

mp4parse_capi/tests/test_rotation.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
extern crate mp4parse_capi;
2+
use std::io::Read;
3+
use mp4parse_capi::*;
4+
5+
extern fn buf_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize {
6+
let mut input: &mut std::fs::File = unsafe { &mut *(userdata as *mut _) };
7+
let mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
8+
match input.read(&mut buf) {
9+
Ok(n) => n as isize,
10+
Err(_) => -1,
11+
}
12+
}
13+
14+
#[test]
15+
fn parse_rotation() {
16+
let mut file = std::fs::File::open("tests/video_rotation_90.mp4").expect("Unknown file");
17+
let io = mp4parse_io {
18+
read: buf_read,
19+
userdata: &mut file as *mut _ as *mut std::os::raw::c_void
20+
};
21+
22+
unsafe {
23+
let parser = mp4parse_new(&io);
24+
25+
let mut rv = mp4parse_read(parser);
26+
assert_eq!(rv, mp4parse_error::MP4PARSE_OK);
27+
28+
let mut counts: u32 = 0;
29+
rv = mp4parse_get_track_count(parser, &mut counts);
30+
assert_eq!(rv, mp4parse_error::MP4PARSE_OK);
31+
assert_eq!(counts, 1);
32+
33+
let mut video = mp4parse_track_video_info {
34+
display_width: 0,
35+
display_height: 0,
36+
image_width: 0,
37+
image_height: 0,
38+
rotation: 0,
39+
extra_data: mp4parse_byte_data::default(),
40+
protected_data: Default::default(),
41+
};
42+
43+
let rv = mp4parse_get_track_video_info(parser, 0, &mut video);
44+
assert_eq!(rv, mp4parse_error::MP4PARSE_OK);
45+
assert_eq!(video.rotation, 90);
46+
47+
mp4parse_free(parser);
48+
}
49+
}
1.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)