Skip to content

Add boxes needed for common encryption #120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions examples/mp4dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,27 @@ fn get_boxes(file: File) -> Result<Vec<Box>> {
if let Some(ref mp4a) = &stbl.stsd.mp4a {
boxes.push(build_box(mp4a));
}
let mut sinf = None;
if let Some(ref encv) = &stbl.stsd.encv {
boxes.push(build_box(encv));
sinf = Some(&encv.sinf)
}
if let Some(ref enca) = &stbl.stsd.enca {
boxes.push(build_box(enca));
sinf = Some(&enca.sinf)
}
if let Some(sinf) = sinf {
boxes.push(build_box(sinf));
if let Some(ref schm) = sinf.schm {
boxes.push(build_box(schm));
}
if let Some(ref schi) = sinf.schi {
boxes.push(build_box(schi));
if let Some(ref tenc) = schi.tenc {
boxes.push(build_box(tenc));
}
}
}
boxes.push(build_box(&stbl.stts));
if let Some(ref ctts) = &stbl.ctts {
boxes.push(build_box(ctts));
Expand Down
131 changes: 131 additions & 0 deletions src/mp4box/enca.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use serde::Serialize;
use std::io::{Read, Seek, Write};

use crate::mp4box::*;

const RESERVED_DATA_SIZE: u64 = 28;

#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
pub struct EncaBox {
#[serde(skip_serializing_if = "Option::is_none")]
pub mp4a: Option<Mp4aBox>,

pub sinf: SinfBox,
}

impl EncaBox {
pub fn get_type(&self) -> BoxType {
BoxType::EncaBox
}

pub fn get_size(&self) -> u64 {
let mut size = 0;
if let Some(ref mp4a) = self.mp4a {
// HEADER_SIZE intentionally omitted
size += mp4a.box_size();
} else {
size += HEADER_SIZE + RESERVED_DATA_SIZE;
}
size += self.sinf.box_size();
size
}
}

impl Mp4Box for EncaBox {
fn box_type(&self) -> BoxType {
self.get_type()
}

fn box_size(&self) -> u64 {
self.get_size()
}

fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}

fn summary(&self) -> Result<String> {
let child_summary = if let Some(ref mp4a) = self.mp4a {
mp4a.summary()
} else {
Err(Error::InvalidData(""))
};
let mut s = format!("original_format={}", &self.sinf.frma.original_format);
if let Ok(summary) = child_summary {
s.push(' ');
s.push_str(&summary);
}
Ok(s)
}
}

impl<R: Read + Seek> ReadBox<&mut R> for EncaBox {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;

let mut mp4a = None;
let mut sinf = None;

// skip current container items
skip_bytes(reader, RESERVED_DATA_SIZE)?;

let mut current = reader.stream_position()?;
let end = start + size;
while current < end {
// Get box header.
let header = BoxHeader::read(reader)?;
let BoxHeader { name, size: s } = header;
if s > size {
return Err(Error::InvalidData(
"enca box contains a box with a larger size than it",
));
}

match name {
BoxType::SinfBox => {
sinf = Some(SinfBox::read_box(reader, s)?);
break;
}
_ => {
skip_box(reader, s)?;
}
}

current = reader.stream_position()?;
}

let sinf = sinf.ok_or(Error::BoxNotFound(BoxType::SinfBox))?;

reader.seek(SeekFrom::Start(start + HEADER_SIZE))?;

let original_format: BoxType = sinf.frma.original_format.into();
if original_format == BoxType::Mp4aBox {
mp4a = Some(Mp4aBox::read_box(reader, size)?);
}

skip_bytes_to(reader, start + size)?;

Ok(EncaBox { mp4a, sinf })
}
}

impl<W: Write> WriteBox<&mut W> for EncaBox {
fn write_box(&self, writer: &mut W) -> Result<u64> {
let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?;

if let Some(ref mp4a) = self.mp4a {
// the enca box header is used, so the header from this box
// must be removed
let mut buf = Vec::with_capacity(mp4a.box_size() as usize);
mp4a.write_box(&mut buf)?;
writer.write_all(&buf[HEADER_SIZE as usize..])?;
} else {
writer.write_all(&[0; RESERVED_DATA_SIZE as usize])?;
}

self.sinf.write_box(writer)?;

Ok(size)
}
}
175 changes: 175 additions & 0 deletions src/mp4box/encv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use serde::Serialize;
use std::io::{Read, Seek, Write};

use crate::mp4box::*;

const RESERVED_DATA_SIZE: u64 = 78;

#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
pub struct EncvBox {
#[serde(skip_serializing_if = "Option::is_none")]
pub avc1: Option<Avc1Box>,

#[serde(skip_serializing_if = "Option::is_none")]
pub hev1: Option<Hev1Box>,

#[serde(skip_serializing_if = "Option::is_none")]
pub vp09: Option<Vp09Box>,

pub sinf: SinfBox,
}

impl EncvBox {
pub fn get_type(&self) -> BoxType {
BoxType::EncvBox
}

pub fn get_size(&self) -> u64 {
let mut size = 0;
if let Some(ref avc1) = self.avc1 {
// HEADER_SIZE intentionally omitted
size += avc1.box_size();
} else if let Some(ref hev1) = self.hev1 {
// HEADER_SIZE intentionally omitted
size += hev1.box_size();
} else if let Some(ref vp09) = self.vp09 {
// HEADER_SIZE intentionally omitted
size += vp09.box_size();
} else {
size += HEADER_SIZE + RESERVED_DATA_SIZE;
}
size += self.sinf.box_size();
size
}
}

impl Mp4Box for EncvBox {
fn box_type(&self) -> BoxType {
self.get_type()
}

fn box_size(&self) -> u64 {
self.get_size()
}

fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}

fn summary(&self) -> Result<String> {
let child_summary = if let Some(ref avc1) = self.avc1 {
avc1.summary()
} else if let Some(ref hev1) = self.hev1 {
hev1.summary()
} else if let Some(ref vp09) = self.vp09 {
vp09.summary()
} else {
Err(Error::InvalidData(""))
};
let mut s = format!("original_format={}", &self.sinf.frma.original_format);
if let Ok(summary) = child_summary {
s.push(' ');
s.push_str(&summary);
}
Ok(s)
}
}

impl<R: Read + Seek> ReadBox<&mut R> for EncvBox {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;

let mut avc1 = None;
let mut hev1 = None;
let mut vp09 = None;
let mut sinf = None;

// skip current container items
skip_bytes(reader, RESERVED_DATA_SIZE)?;

let mut current = reader.stream_position()?;
let end = start + size;
while current < end {
// Get box header.
let header = BoxHeader::read(reader)?;
let BoxHeader { name, size: s } = header;
if s > size {
return Err(Error::InvalidData(
"encv box contains a box with a larger size than it",
));
}

match name {
BoxType::SinfBox => {
sinf = Some(SinfBox::read_box(reader, s)?);
break;
}
_ => {
skip_box(reader, s)?;
}
}

current = reader.stream_position()?;
}

let sinf = sinf.ok_or(Error::BoxNotFound(BoxType::SinfBox))?;

reader.seek(SeekFrom::Start(start + HEADER_SIZE))?;

let original_format: BoxType = sinf.frma.original_format.into();
match original_format {
BoxType::Avc1Box => {
avc1 = Some(Avc1Box::read_box(reader, size)?);
}
BoxType::Hev1Box => {
hev1 = Some(Hev1Box::read_box(reader, size)?);
}
BoxType::Vp09Box => {
vp09 = Some(Vp09Box::read_box(reader, size)?);
}
_ => (),
}

skip_bytes_to(reader, start + size)?;

Ok(EncvBox {
avc1,
hev1,
vp09,
sinf,
})
}
}

impl<W: Write> WriteBox<&mut W> for EncvBox {
fn write_box(&self, writer: &mut W) -> Result<u64> {
let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?;

if let Some(ref avc1) = self.avc1 {
// the encv box header is used, so the header from this box
// must be removed
let mut buf = Vec::with_capacity(avc1.box_size() as usize);
avc1.write_box(&mut buf)?;
writer.write_all(&buf[HEADER_SIZE as usize..])?;
} else if let Some(ref hev1) = self.hev1 {
// the encv box header is used, so the header from this box
// must be removed
let mut buf = Vec::with_capacity(hev1.box_size() as usize);
hev1.write_box(&mut buf)?;
writer.write_all(&buf[HEADER_SIZE as usize..])?;
} else if let Some(ref vp09) = self.vp09 {
// the encv box header is used, so the header from this box
// must be removed
let mut buf = Vec::with_capacity(vp09.box_size() as usize);
vp09.write_box(&mut buf)?;
writer.write_all(&buf[HEADER_SIZE as usize..])?;
} else {
writer.write_all(&[0; RESERVED_DATA_SIZE as usize])?;
}

self.sinf.write_box(writer)?;

Ok(size)
}
}
63 changes: 63 additions & 0 deletions src/mp4box/frma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use serde::Serialize;
use std::io::{Read, Seek, Write};

use crate::mp4box::*;

#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
pub struct FrmaBox {
pub original_format: FourCC,
}

impl FrmaBox {
pub fn get_type(&self) -> BoxType {
BoxType::FrmaBox
}

pub fn get_size(&self) -> u64 {
HEADER_SIZE + 4
}
}

impl Mp4Box for FrmaBox {
fn box_type(&self) -> BoxType {
self.get_type()
}

fn box_size(&self) -> u64 {
self.get_size()
}

fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}

fn summary(&self) -> Result<String> {
let s = format!("original_format={}", self.original_format,);
Ok(s)
}
}

impl<R: Read + Seek> ReadBox<&mut R> for FrmaBox {
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
let start = box_start(reader)?;

let original_format = reader.read_u32::<BigEndian>()?;

skip_bytes_to(reader, start + size)?;

Ok(FrmaBox {
original_format: original_format.into(),
})
}
}

impl<W: Write> WriteBox<&mut W> for FrmaBox {
fn write_box(&self, writer: &mut W) -> Result<u64> {
let size = self.box_size();
BoxHeader::new(self.box_type(), size).write(writer)?;

writer.write_u32::<BigEndian>(self.original_format.into())?;

Ok(size)
}
}
Loading