MP4: Support reading any size flag atom

This commit is contained in:
Serial 2024-09-14 11:29:31 -04:00 committed by Alex
parent 06618cf1a7
commit b565b3e288
2 changed files with 25 additions and 14 deletions

View file

@ -120,10 +120,9 @@ where
parse_data_inner(&mut ilst_reader, parsing_mode, &atom)? parse_data_inner(&mut ilst_reader, parsing_mode, &atom)?
{ {
if let Some((_, content)) = atom_data.first() { if let Some((_, content)) = atom_data.first() {
let data = match content[..] { // Any size integer is technically valid, we'll correct it on write.
[0, ..] => AtomData::Bool(false), let is_true = content.iter().any(|&b| b != 0);
_ => AtomData::Bool(true), let data = AtomData::Bool(is_true);
};
tag.atoms.push(Atom { tag.atoms.push(Atom {
ident: AtomIdent::Fourcc(*fourcc), ident: AtomIdent::Fourcc(*fourcc),

View file

@ -14,6 +14,9 @@ use crate::util::io::{FileLike, Length, Truncate};
use std::io::{Cursor, Seek, SeekFrom, Write}; use std::io::{Cursor, Seek, SeekFrom, Write};
use crate::mp4::constants::{
BE_SIGNED_INTEGER, BE_UNSIGNED_INTEGER, BMP, JPEG, PNG, RESERVED, UTF16, UTF8,
};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
// A "full" atom is a traditional length + identifier, followed by a version (1) and flags (3) // A "full" atom is a traditional length + identifier, followed by a version (1) and flags (3)
@ -675,12 +678,12 @@ where
{ {
for value in data { for value in data {
match value { match value {
AtomData::UTF8(text) => write_data(1, text.as_bytes(), writer)?, AtomData::UTF8(text) => write_data(UTF8, text.as_bytes(), writer)?,
AtomData::UTF16(text) => write_data(2, text.as_bytes(), writer)?, AtomData::UTF16(text) => write_data(UTF16, text.as_bytes(), writer)?,
AtomData::Picture(ref pic) => write_picture(pic, writer)?, AtomData::Picture(ref pic) => write_picture(pic, writer)?,
AtomData::SignedInteger(int) => write_signed_int(*int, writer)?, AtomData::SignedInteger(int) => write_signed_int(*int, writer)?,
AtomData::UnsignedInteger(uint) => write_unsigned_int(*uint, writer)?, AtomData::UnsignedInteger(uint) => write_unsigned_int(*uint, writer)?,
AtomData::Bool(b) => write_signed_int(i32::from(*b), writer)?, AtomData::Bool(b) => write_bool(*b, writer)?,
AtomData::Unknown { code, ref data } => write_data(*code, data, writer)?, AtomData::Unknown { code, ref data } => write_data(*code, data, writer)?,
}; };
} }
@ -689,7 +692,7 @@ where
} }
fn write_signed_int(int: i32, writer: &mut AtomWriterCompanion<'_>) -> Result<()> { fn write_signed_int(int: i32, writer: &mut AtomWriterCompanion<'_>) -> Result<()> {
write_int(21, int.to_be_bytes(), 4, writer) write_int(BE_SIGNED_INTEGER, int.to_be_bytes(), 4, writer)
} }
fn bytes_to_occupy_uint(uint: u32) -> usize { fn bytes_to_occupy_uint(uint: u32) -> usize {
@ -706,7 +709,12 @@ fn bytes_to_occupy_uint(uint: u32) -> usize {
fn write_unsigned_int(uint: u32, writer: &mut AtomWriterCompanion<'_>) -> Result<()> { fn write_unsigned_int(uint: u32, writer: &mut AtomWriterCompanion<'_>) -> Result<()> {
let bytes_needed = bytes_to_occupy_uint(uint); let bytes_needed = bytes_to_occupy_uint(uint);
write_int(22, uint.to_be_bytes(), bytes_needed, writer) write_int(
BE_UNSIGNED_INTEGER,
uint.to_be_bytes(),
bytes_needed,
writer,
)
} }
fn write_int( fn write_int(
@ -719,15 +727,19 @@ fn write_int(
write_data(flags, &bytes[4 - bytes_needed..], writer) write_data(flags, &bytes[4 - bytes_needed..], writer)
} }
fn write_bool(b: bool, writer: &mut AtomWriterCompanion<'_>) -> Result<()> {
write_int(BE_SIGNED_INTEGER, i32::from(b).to_be_bytes(), 1, writer)
}
fn write_picture(picture: &Picture, writer: &mut AtomWriterCompanion<'_>) -> Result<()> { fn write_picture(picture: &Picture, writer: &mut AtomWriterCompanion<'_>) -> Result<()> {
match picture.mime_type { match picture.mime_type {
// GIF is deprecated // GIF is deprecated
Some(MimeType::Gif) => write_data(12, &picture.data, writer), Some(MimeType::Gif) => write_data(12, &picture.data, writer),
Some(MimeType::Jpeg) => write_data(13, &picture.data, writer), Some(MimeType::Jpeg) => write_data(JPEG, &picture.data, writer),
Some(MimeType::Png) => write_data(14, &picture.data, writer), Some(MimeType::Png) => write_data(PNG, &picture.data, writer),
Some(MimeType::Bmp) => write_data(27, &picture.data, writer), Some(MimeType::Bmp) => write_data(BMP, &picture.data, writer),
// We'll assume implicit (0) was the intended type // We'll assume implicit (0) was the intended type
None => write_data(0, &picture.data, writer), None => write_data(RESERVED, &picture.data, writer),
_ => Err(FileEncodingError::new( _ => Err(FileEncodingError::new(
FileType::Mp4, FileType::Mp4,
"Attempted to write an unsupported picture format", "Attempted to write an unsupported picture format",
@ -766,7 +778,7 @@ fn write_data(flags: u32, data: &[u8], writer: &mut AtomWriterCompanion<'_>) ->
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::mp4::ilst::write::bytes_to_occupy_uint; use super::bytes_to_occupy_uint;
macro_rules! int_test { macro_rules! int_test {
( (