iso_bmff/isobmff/
cenc_box.rs1#![forbid(unsafe_code)]
4
5use iso_cenc::Subsample;
6use smallvec::SmallVec;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct TrackEncryption {
11 pub is_protected: bool,
13 pub per_sample_iv_size: u8,
15 pub kid: [u8; 16],
17 pub constant_iv: SmallVec<[u8; 16]>,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct SencSample {
24 pub iv: SmallVec<[u8; 16]>,
26 pub subsamples: SmallVec<[Subsample; 4]>,
28}
29
30#[must_use]
32pub fn parse_tenc(body: &[u8]) -> Option<TrackEncryption> {
33 if body.len() < 20 {
34 return None;
35 }
36 let mut pos = 4;
37 pos += 1;
39 if pos + 18 > body.len() {
40 return None;
41 }
42 let is_protected = body[pos] != 0;
43 let per_sample_iv_size = body[pos + 1];
44 let mut kid = [0u8; 16];
45 kid.copy_from_slice(&body[pos + 2..pos + 18]);
46 pos += 18;
47 let mut constant_iv = SmallVec::new();
48 if is_protected && per_sample_iv_size == 0 {
49 if pos >= body.len() {
50 return None;
51 }
52 let iv_size = body[pos] as usize;
53 pos += 1;
54 if pos + iv_size > body.len() || (iv_size != 8 && iv_size != 16) {
55 return None;
56 }
57 constant_iv.extend_from_slice(&body[pos..pos + iv_size]);
58 }
59 Some(TrackEncryption {
60 is_protected,
61 per_sample_iv_size,
62 kid,
63 constant_iv,
64 })
65}
66
67#[must_use]
69pub fn parse_senc(body: &[u8], per_sample_iv_size: u8) -> Vec<SencSample> {
70 if body.len() < 8 {
71 return Vec::new();
72 }
73 let flags = u32::from_be_bytes([body[0], body[1], body[2], body[3]]);
74 let use_subsamples = flags & 0x0000_0002 != 0;
75 let count = u32::from_be_bytes([body[4], body[5], body[6], body[7]]) as usize;
76 let iv_size = usize::from(per_sample_iv_size);
77 let mut out = Vec::with_capacity(count);
78 let mut pos = 8;
79 for _ in 0..count {
80 let mut iv = SmallVec::new();
81 if iv_size > 0 {
82 if pos + iv_size > body.len() {
83 break;
84 }
85 iv.extend_from_slice(&body[pos..pos + iv_size]);
86 pos += iv_size;
87 }
88 let mut subsamples = SmallVec::new();
89 if use_subsamples {
90 if pos + 2 > body.len() {
91 break;
92 }
93 let n = u16::from_be_bytes([body[pos], body[pos + 1]]) as usize;
94 pos += 2;
95 for _ in 0..n {
96 if pos + 6 > body.len() {
97 return out;
98 }
99 let clear = u16::from_be_bytes([body[pos], body[pos + 1]]);
100 let protected = u32::from_be_bytes([
101 body[pos + 2],
102 body[pos + 3],
103 body[pos + 4],
104 body[pos + 5],
105 ]);
106 subsamples.push(Subsample {
107 clear_bytes: clear,
108 protected_bytes: protected,
109 });
110 pos += 6;
111 }
112 }
113 out.push(SencSample { iv, subsamples });
114 }
115 out
116}