From 83cc34628cf0f9ee15dec48f8635e3f3d96859e2 Mon Sep 17 00:00:00 2001 From: Taksh Date: Sat, 15 Aug 2026 17:54:11 +0530 Subject: [PATCH 1/4] feat(media): recognise audio-only ISO-BMFF containers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `looks_like_iso_bmff` answers "is this an `ftyp` container", which is true of an MP4 video and of an M4A voice memo alike. Nothing could tell the two apart: `looks_like_mp4_iso_bmff` consults the compatible-brand list, and an Apple Voice Memo carries `isom` and `mp42` there, so it reads as MP4. Add `looks_like_audio_iso_bmff`, which reads the *major* brand — the one field that actually declares the container's content — against the Apple and Flash audio brands. Pure predicate, no caller yet. Signed-off-by: Taksh --- crates/buzz-media/src/lib.rs | 4 +- crates/buzz-media/src/validation.rs | 82 +++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/crates/buzz-media/src/lib.rs b/crates/buzz-media/src/lib.rs index b2ff12c16e..669c1ae595 100644 --- a/crates/buzz-media/src/lib.rs +++ b/crates/buzz-media/src/lib.rs @@ -27,4 +27,6 @@ pub use upload_record::{ parse_port, parse_public_ip, upload_record_key, UploadAttribution, UploadNetworkInfo, UploadRecord, UPLOAD_RECORD_VERSION, }; -pub use validation::{looks_like_iso_bmff, serve_inline, validate_video_file, VideoMeta}; +pub use validation::{ + looks_like_audio_iso_bmff, looks_like_iso_bmff, serve_inline, validate_video_file, VideoMeta, +}; diff --git a/crates/buzz-media/src/validation.rs b/crates/buzz-media/src/validation.rs index dfc61c4275..2ab2739444 100644 --- a/crates/buzz-media/src/validation.rs +++ b/crates/buzz-media/src/validation.rs @@ -19,6 +19,15 @@ const MP4_BRANDS: &[[u8; 4]] = &[ *b"mp41", *b"mp42", *b"avc1", *b"dash", *b"M4V ", ]; +/// ISO-BMFF major brands that declare an audio-only container. +/// +/// An Apple Voice Memo is `M4A ` with `isom`/`mp42` among its *compatible* +/// brands, so the compatible-brand list cannot distinguish it from video — +/// only the major brand can. +const AUDIO_ONLY_BRANDS: &[[u8; 4]] = &[ + *b"M4A ", *b"M4B ", *b"M4P ", *b"M4R ", *b"F4A ", *b"F4B ", *b"mp4a", +]; + fn iso_bmff_ftyp_payload(bytes: &[u8]) -> Option<&[u8]> { if bytes.len() < 16 || &bytes[4..8] != b"ftyp" { return None; @@ -49,6 +58,21 @@ pub fn looks_like_iso_bmff(bytes: &[u8]) -> bool { iso_bmff_ftyp_payload(bytes).is_some() } +/// Return whether the leading bytes are an ISO-BMFF container whose *major* +/// brand declares audio-only content (`M4A `, `M4B `, …). +/// +/// Such a file has no video track, so putting it through the video validator +/// can only fail — and fails with a message about the moov atom that says +/// nothing about the real problem. +pub fn looks_like_audio_iso_bmff(bytes: &[u8]) -> bool { + let Some(payload) = iso_bmff_ftyp_payload(bytes) else { + return false; + }; + payload[..4] + .try_into() + .is_ok_and(|brand: [u8; 4]| AUDIO_ONLY_BRANDS.contains(&brand)) +} + pub(crate) fn looks_like_mp4_iso_bmff(bytes: &[u8]) -> bool { let Some(payload) = iso_bmff_ftyp_payload(bytes) else { return false; @@ -1531,6 +1555,7 @@ mod tests { assert!(infer::get(proprietary_major).is_none()); assert!(looks_like_iso_bmff(proprietary_major)); assert!(looks_like_mp4_iso_bmff(proprietary_major)); + assert!(!looks_like_audio_iso_bmff(proprietary_major)); assert!( matches!(validate_file_content(proprietary_major, &config), Err(MediaError::DisallowedContentType(m)) if m == "application/iso-bmff") ); @@ -2684,3 +2709,60 @@ mod tests { assert!(!serve_inline("text/plain")); } } + +#[cfg(test)] +mod audio_iso_bmff_tests { + use super::{looks_like_audio_iso_bmff, looks_like_iso_bmff}; + + /// `ftyp` box: size, "ftyp", major brand, minor version, compatible brands. + fn ftyp(major: &[u8; 4], compatible: &[&[u8; 4]]) -> Vec { + let size = 16 + 4 * compatible.len(); + let mut bytes = (size as u32).to_be_bytes().to_vec(); + bytes.extend_from_slice(b"ftyp"); + bytes.extend_from_slice(major); + bytes.extend_from_slice(&0u32.to_be_bytes()); + for brand in compatible { + bytes.extend_from_slice(*brand); + } + bytes + } + + #[test] + fn an_apple_voice_memo_is_recognised_as_audio() { + // A Voice Memo carries isom/mp42 as *compatible* brands, so only the + // major brand tells it apart from video. + let memo = ftyp(b"M4A ", &[b"M4A ", b"mp42", b"isom"]); + assert!(looks_like_iso_bmff(&memo)); + assert!(looks_like_audio_iso_bmff(&memo)); + } + + #[test] + fn the_other_apple_audio_brands_are_recognised_too() { + for major in [b"M4B ", b"M4P ", b"M4R ", b"F4A ", b"F4B ", b"mp4a"] { + let bytes = ftyp(major, &[b"isom"]); + assert!( + looks_like_audio_iso_bmff(&bytes), + "{}", + String::from_utf8_lossy(major) + ); + } + } + + #[test] + fn an_mp4_video_is_not_audio() { + for major in [b"isom", b"mp42", b"avc1", b"M4V "] { + let bytes = ftyp(major, &[b"isom", b"mp42"]); + assert!( + !looks_like_audio_iso_bmff(&bytes), + "{}", + String::from_utf8_lossy(major) + ); + } + } + + #[test] + fn a_non_iso_bmff_file_is_not_audio() { + assert!(!looks_like_audio_iso_bmff(b"\x89PNG\r\n\x1a\n")); + assert!(!looks_like_audio_iso_bmff(&[])); + } +} From 9291503328efdee3099bce20bd2423875b0a405e Mon Sep 17 00:00:00 2001 From: Taksh Date: Sat, 15 Aug 2026 18:02:35 +0530 Subject: [PATCH 2/4] fix(relay): stop routing audio containers through the video validator `should_stream_as_video` sent every ISO-BMFF container down the streaming video path. An M4A voice memo is ISO-BMFF, so an Apple Voice Memo reached `validate_video_file`, where a normal (non-fast-start) recording fails `check_moov_before_mdat` with 422 moov atom not at front of file (not fast-start) That message describes an internal layout detail the user cannot act on, and it is not even the real obstacle: the same validator goes on to require a video track, which an audio-only file will never have. Rewriting the file to put moov first would move the failure, not fix it (#5752). Route audio-branded containers to the generic path instead, which already refuses audio explicitly and answers 415 disallowed content type: audio/m4a That is what "Buzz has no audio pipeline yet" honestly looks like, and 415 is the right status for it. Video routing is unchanged, including the proprietary-brand case the existing test pins. Signed-off-by: Taksh --- crates/buzz-relay/src/api/media.rs | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/crates/buzz-relay/src/api/media.rs b/crates/buzz-relay/src/api/media.rs index 3b6e07bad6..e6c995c06c 100644 --- a/crates/buzz-relay/src/api/media.rs +++ b/crates/buzz-relay/src/api/media.rs @@ -46,7 +46,18 @@ enum UploadRouteMode { LegacyMedia, } +/// Whether an upload should take the streaming video path. +/// +/// An audio-only container is excluded even though it is ISO-BMFF: it has no +/// video track, so the video validator can only reject it — and it rejects a +/// normal (non-fast-start) voice memo with "moov atom not at front of file", +/// a 422 about a detail the user cannot act on. Sending it down the generic +/// path instead produces the honest answer, `415 disallowed content type: +/// audio/m4a`, which is what audio support actually being absent looks like. fn should_stream_as_video(sniff: &[u8]) -> bool { + if buzz_media::looks_like_audio_iso_bmff(sniff) { + return false; + } infer::get(sniff).is_some_and(|kind| kind.mime_type() == "video/mp4") || buzz_media::looks_like_iso_bmff(sniff) } @@ -979,6 +990,34 @@ mod tests { )); } + /// `ftyp` box: size, "ftyp", major brand, minor version, compatible brands. + fn ftyp(major: &[u8; 4], compatible: &[&[u8; 4]]) -> Vec { + let size = 16 + 4 * compatible.len(); + let mut bytes = (size as u32).to_be_bytes().to_vec(); + bytes.extend_from_slice(b"ftyp"); + bytes.extend_from_slice(major); + bytes.extend_from_slice(&0u32.to_be_bytes()); + for brand in compatible { + bytes.extend_from_slice(*brand); + } + bytes + } + + #[test] + fn audio_only_container_does_not_use_video_pipeline() { + // An Apple Voice Memo: major brand M4A, but isom/mp42 among its + // compatible brands, which is why it used to read as video. + let memo = ftyp(b"M4A ", &[b"M4A ", b"mp42", b"isom"]); + assert!(buzz_media::looks_like_iso_bmff(&memo)); + assert!(!should_stream_as_video(&memo)); + } + + #[test] + fn mp4_video_still_uses_video_pipeline() { + let video = ftyp(b"isom", &[b"isom", b"mp42", b"avc1"]); + assert!(should_stream_as_video(&video)); + } + #[test] fn proprietary_iso_bmff_brand_still_uses_video_pipeline() { let bytes = b"\x00\x00\x00\x18ftypPRIV\x00\x00\x00\x00isommp42"; From 2000e062f5e8cdc32bddb8afc00f3182d2231484 Mon Sep 17 00:00:00 2001 From: Taksh Date: Sun, 16 Aug 2026 18:25:26 +0530 Subject: [PATCH 3/4] fix(media): classify a container from its tracks before demanding fast-start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review is right that a major-brand shortcut is not a sound proxy for track contents. MP4RA registers `M4A ` as an iTunes MPEG-4 audio brand that may still carry audio, video, 3G text and chapter tracks, and `M4B ` likewise. A brand is a compatibility declaration, not an inventory. The validator already knew how to answer this correctly — the track loop returns `DisallowedContentType("audio/mp4")` (a 415) when it finds audio and no video. What went wrong is ordering: `check_moov_before_mdat` ran as the very first statement, so a Voice Memo, which is never written fast-start, failed there with "moov atom not at front of file" and never reached the classification. That is a 422 about a requirement which does not apply to a file with no video in it. Classification now runs first, from the parsed track types, and the two video-only requirements — fast-start and metadata-free — run after it. The mp4 crate parses the whole file regardless of atom order, so an mdat-first container reaches the track scan fine; the size guard still bounds the parse. An `M4A `-branded file that really does contain video is unaffected: it classifies as video, is validated as one, and still has to be fast-start. Verified the regression fails on the old ordering: reinstating the leading `check_moov_before_mdat` turns the new test's result into `Err(MoovNotAtFront)`. - `cargo test -p buzz-media --lib` — 121 passed - `cargo fmt --all -- --check` Signed-off-by: Taksh --- crates/buzz-media/src/validation.rs | 244 +++++++++++++++++----------- 1 file changed, 148 insertions(+), 96 deletions(-) diff --git a/crates/buzz-media/src/validation.rs b/crates/buzz-media/src/validation.rs index 2ab2739444..d10743a48b 100644 --- a/crates/buzz-media/src/validation.rs +++ b/crates/buzz-media/src/validation.rs @@ -19,15 +19,6 @@ const MP4_BRANDS: &[[u8; 4]] = &[ *b"mp41", *b"mp42", *b"avc1", *b"dash", *b"M4V ", ]; -/// ISO-BMFF major brands that declare an audio-only container. -/// -/// An Apple Voice Memo is `M4A ` with `isom`/`mp42` among its *compatible* -/// brands, so the compatible-brand list cannot distinguish it from video — -/// only the major brand can. -const AUDIO_ONLY_BRANDS: &[[u8; 4]] = &[ - *b"M4A ", *b"M4B ", *b"M4P ", *b"M4R ", *b"F4A ", *b"F4B ", *b"mp4a", -]; - fn iso_bmff_ftyp_payload(bytes: &[u8]) -> Option<&[u8]> { if bytes.len() < 16 || &bytes[4..8] != b"ftyp" { return None; @@ -58,21 +49,6 @@ pub fn looks_like_iso_bmff(bytes: &[u8]) -> bool { iso_bmff_ftyp_payload(bytes).is_some() } -/// Return whether the leading bytes are an ISO-BMFF container whose *major* -/// brand declares audio-only content (`M4A `, `M4B `, …). -/// -/// Such a file has no video track, so putting it through the video validator -/// can only fail — and fails with a message about the moov atom that says -/// nothing about the real problem. -pub fn looks_like_audio_iso_bmff(bytes: &[u8]) -> bool { - let Some(payload) = iso_bmff_ftyp_payload(bytes) else { - return false; - }; - payload[..4] - .try_into() - .is_ok_and(|brand: [u8; 4]| AUDIO_ONLY_BRANDS.contains(&brand)) -} - pub(crate) fn looks_like_mp4_iso_bmff(bytes: &[u8]) -> bool { let Some(payload) = iso_bmff_ftyp_payload(bytes) else { return false; @@ -323,11 +299,6 @@ pub fn validate_content(bytes: &[u8], config: &MediaConfig) -> Result Result { - // --- moov-before-mdat check (raw byte scan) --- - // We scan the top-level atom sequence before handing off to the mp4 crate, - // because the mp4 crate parses the whole file regardless of atom order. - check_moov_before_mdat(path)?; - let file = std::fs::File::open(path).map_err(|e| MediaError::Io(e.to_string()))?; let size = file .metadata() @@ -342,8 +313,6 @@ pub fn validate_video_file(path: &Path, config: &MediaConfig) -> Result Result has_video = true, + mp4::TrackType::Audio => has_audio_track = true, + _ => {} + } + } + if !has_video { + return Err(if has_audio_track { + MediaError::DisallowedContentType("audio/mp4".to_string()) + } else { + MediaError::InvalidVideo + }); + } + + // --- Video-only requirements --- + // The moov scan reads the top-level atom sequence directly, because the mp4 + // crate parses the whole file regardless of atom order. + check_moov_before_mdat(path)?; + validate_mp4_metadata_free(path)?; + // --- Track inspection --- let mut video_meta: Option = None; let mut has_audio = false; @@ -425,13 +429,9 @@ pub fn validate_video_file(path: &Path, config: &MediaConfig) -> Result, brand: &[u8; 4]) -> Vec { + bytes[8..12].copy_from_slice(brand); + bytes + } + + /// Build an audio-only MP4: one AAC track, no video track. + /// + /// `fast_start == false` reproduces an Apple Voice Memo, which writes mdat + /// before moov. + fn build_audio_only_mp4(fast_start: bool) -> Vec { + let timescale: u32 = 1000; + let duration: u32 = 1_000; + + let ftyp = { + let mut b = Vec::new(); + b.extend_from_slice(&20u32.to_be_bytes()); + b.extend_from_slice(b"ftyp"); + b.extend_from_slice(b"M4A "); + b.extend_from_slice(&0u32.to_be_bytes()); + b.extend_from_slice(b"isom"); + b + }; + let mdat = { + let mut b = Vec::new(); + b.extend_from_slice(&8u32.to_be_bytes()); + b.extend_from_slice(b"mdat"); + b + }; + + // Same mvhd as build_moov, then an audio trak and nothing else. + let full = build_mp4_bytes(true, b"avc1", duration, 320, 240, false); + let mvhd = { + const FTYP_SIZE: usize = 20; + let moov_start = FTYP_SIZE + 8; + let mvhd_size = + u32::from_be_bytes(full[moov_start..moov_start + 4].try_into().unwrap()) as usize; + full[moov_start..moov_start + mvhd_size].to_vec() + }; + + let mut moov_payload = mvhd; + moov_payload.extend_from_slice(&build_audio_trak(1, duration, timescale)); + let moov = box_wrap(b"moov", &moov_payload); + + let mut out = ftyp; + if fast_start { + out.extend_from_slice(&moov); + out.extend_from_slice(&mdat); + } else { + out.extend_from_slice(&mdat); + out.extend_from_slice(&moov); + } + out + } + /// Insert a child box at the end of the top-level `moov` box. fn append_box_to_moov(mut bytes: Vec, child: &[u8]) -> Vec { const FTYP_SIZE: usize = 20; @@ -2357,6 +2411,61 @@ mod tests { assert!(validate_video_file(tmp.path(), &test_config()).is_ok()); } + #[test] + fn an_audio_only_container_is_reported_as_audio_not_as_a_moov_problem() { + // An Apple Voice Memo: one AAC track, no video, and mdat before moov + // because it was never written fast-start. The fast-start check used to + // run first and answered "moov atom not at front of file" — a detail + // about a requirement that does not apply to a file with no video in + // it. Classifying from the parsed tracks first gives the real answer. + let tmp = tempfile::NamedTempFile::new().unwrap(); + std::fs::write(tmp.path(), build_audio_only_mp4(false)).unwrap(); + assert!( + matches!( + validate_video_file(tmp.path(), &test_config()), + Err(MediaError::DisallowedContentType(ref m)) if m == "audio/mp4" + ), + "got {:?}", + validate_video_file(tmp.path(), &test_config()) + ); + } + + #[test] + fn a_fast_start_audio_only_container_is_also_reported_as_audio() { + let tmp = tempfile::NamedTempFile::new().unwrap(); + std::fs::write(tmp.path(), build_audio_only_mp4(true)).unwrap(); + assert!(matches!( + validate_video_file(tmp.path(), &test_config()), + Err(MediaError::DisallowedContentType(ref m)) if m == "audio/mp4" + )); + } + + #[test] + fn an_audio_branded_file_that_holds_video_is_still_accepted() { + // MP4RA registers `M4A ` as an iTunes audio brand, but the brand is a + // compatibility declaration and does not forbid a video track. Rejecting + // on the brand would throw away a valid video. + let bytes = with_major_brand(build_minimal_mp4_moov_first(), b"M4A "); + let tmp = tempfile::NamedTempFile::new().unwrap(); + std::fs::write(tmp.path(), bytes).unwrap(); + let meta = validate_video_file(tmp.path(), &test_config()) + .expect("an M4A-branded file with a video track is a video"); + assert_eq!((meta.width, meta.height), (320, 240)); + } + + #[test] + fn an_audio_branded_file_that_holds_video_still_needs_fast_start() { + // The video-only requirements are not skipped for such a file — they + // are only deferred until the tracks say it is a video. + let bytes = with_major_brand(build_minimal_mp4_mdat_first(), b"M4A "); + let tmp = tempfile::NamedTempFile::new().unwrap(); + std::fs::write(tmp.path(), bytes).unwrap(); + assert!(matches!( + validate_video_file(tmp.path(), &test_config()), + Err(MediaError::MoovNotAtFront) + )); + } + #[test] fn test_accepts_exact_empty_ffmpeg_udta() { let empty_ffmpeg_udta = hex::decode( @@ -2709,60 +2818,3 @@ mod tests { assert!(!serve_inline("text/plain")); } } - -#[cfg(test)] -mod audio_iso_bmff_tests { - use super::{looks_like_audio_iso_bmff, looks_like_iso_bmff}; - - /// `ftyp` box: size, "ftyp", major brand, minor version, compatible brands. - fn ftyp(major: &[u8; 4], compatible: &[&[u8; 4]]) -> Vec { - let size = 16 + 4 * compatible.len(); - let mut bytes = (size as u32).to_be_bytes().to_vec(); - bytes.extend_from_slice(b"ftyp"); - bytes.extend_from_slice(major); - bytes.extend_from_slice(&0u32.to_be_bytes()); - for brand in compatible { - bytes.extend_from_slice(*brand); - } - bytes - } - - #[test] - fn an_apple_voice_memo_is_recognised_as_audio() { - // A Voice Memo carries isom/mp42 as *compatible* brands, so only the - // major brand tells it apart from video. - let memo = ftyp(b"M4A ", &[b"M4A ", b"mp42", b"isom"]); - assert!(looks_like_iso_bmff(&memo)); - assert!(looks_like_audio_iso_bmff(&memo)); - } - - #[test] - fn the_other_apple_audio_brands_are_recognised_too() { - for major in [b"M4B ", b"M4P ", b"M4R ", b"F4A ", b"F4B ", b"mp4a"] { - let bytes = ftyp(major, &[b"isom"]); - assert!( - looks_like_audio_iso_bmff(&bytes), - "{}", - String::from_utf8_lossy(major) - ); - } - } - - #[test] - fn an_mp4_video_is_not_audio() { - for major in [b"isom", b"mp42", b"avc1", b"M4V "] { - let bytes = ftyp(major, &[b"isom", b"mp42"]); - assert!( - !looks_like_audio_iso_bmff(&bytes), - "{}", - String::from_utf8_lossy(major) - ); - } - } - - #[test] - fn a_non_iso_bmff_file_is_not_audio() { - assert!(!looks_like_audio_iso_bmff(b"\x89PNG\r\n\x1a\n")); - assert!(!looks_like_audio_iso_bmff(&[])); - } -} From 005904dba2ff7ea91302a7686f0a9ea7b01aab89 Mon Sep 17 00:00:00 2001 From: Taksh Date: Sun, 16 Aug 2026 18:25:26 +0530 Subject: [PATCH 4/4] fix(relay): keep every ISO-BMFF upload on the bounded video path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review: routing audio-branded containers away from the streaming path rejects a genuine video on its compatibility declaration alone. Any valid video-bearing file with an `M4A `/`M4B ` major brand would have skipped video validation and then been refused by the generic path as audio — a regression against files that are accepted today. `should_stream_as_video` goes back to admitting every ISO-BMFF container. With the previous commit the validator classifies from parsed tracks, so an audio-only container still gets the honest `415 audio/mp4` and a video-bearing one is still validated as video. The routing layer no longer needs to guess. The brand list itself is gone along with its public helper: several of its entries (`M4P `, `M4R `, `F4A `, `F4B `, `mp4a`) are not registered ISO-BMFF brands at all, and the registered ones do not mean what the list claimed. - `cargo test -p buzz-media --lib` — 121 passed - relay media module — 29 passed; the same 6 DB-backed tests cannot run here, the local Postgres has no `buzz` role (pre-existing, unrelated to this diff) - `cargo clippy -p buzz-media -p buzz-relay --lib -- -D warnings` - `cargo fmt --all -- --check` Signed-off-by: Taksh --- crates/buzz-media/src/lib.rs | 4 +--- crates/buzz-relay/src/api/media.rs | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/crates/buzz-media/src/lib.rs b/crates/buzz-media/src/lib.rs index 669c1ae595..b2ff12c16e 100644 --- a/crates/buzz-media/src/lib.rs +++ b/crates/buzz-media/src/lib.rs @@ -27,6 +27,4 @@ pub use upload_record::{ parse_port, parse_public_ip, upload_record_key, UploadAttribution, UploadNetworkInfo, UploadRecord, UPLOAD_RECORD_VERSION, }; -pub use validation::{ - looks_like_audio_iso_bmff, looks_like_iso_bmff, serve_inline, validate_video_file, VideoMeta, -}; +pub use validation::{looks_like_iso_bmff, serve_inline, validate_video_file, VideoMeta}; diff --git a/crates/buzz-relay/src/api/media.rs b/crates/buzz-relay/src/api/media.rs index e6c995c06c..8962e0c1de 100644 --- a/crates/buzz-relay/src/api/media.rs +++ b/crates/buzz-relay/src/api/media.rs @@ -48,16 +48,14 @@ enum UploadRouteMode { /// Whether an upload should take the streaming video path. /// -/// An audio-only container is excluded even though it is ISO-BMFF: it has no -/// video track, so the video validator can only reject it — and it rejects a -/// normal (non-fast-start) voice memo with "moov atom not at front of file", -/// a 422 about a detail the user cannot act on. Sending it down the generic -/// path instead produces the honest answer, `415 disallowed content type: -/// audio/m4a`, which is what audio support actually being absent looks like. +/// Every ISO-BMFF container does, including one whose major brand says audio. +/// A brand is a compatibility declaration, not an inventory: MP4RA registers +/// `M4A `/`M4B ` as iTunes audio brands that may still carry video, chapter +/// and text tracks. Routing on the brand would send a genuine video down the +/// generic path to be rejected as audio. The validator classifies from parsed +/// track types instead, and answers `415 audio/mp4` for a container that turns +/// out to hold no video. fn should_stream_as_video(sniff: &[u8]) -> bool { - if buzz_media::looks_like_audio_iso_bmff(sniff) { - return false; - } infer::get(sniff).is_some_and(|kind| kind.mime_type() == "video/mp4") || buzz_media::looks_like_iso_bmff(sniff) } @@ -1004,12 +1002,14 @@ mod tests { } #[test] - fn audio_only_container_does_not_use_video_pipeline() { - // An Apple Voice Memo: major brand M4A, but isom/mp42 among its - // compatible brands, which is why it used to read as video. + fn an_audio_branded_container_stays_on_the_bounded_video_path() { + // An Apple Voice Memo is major brand `M4A `. It must still reach the + // validator: the brand does not rule out a video track, and only the + // parsed tracks can say. Routing it away here would reject a + // video-bearing `M4A ` file on its compatibility declaration alone. let memo = ftyp(b"M4A ", &[b"M4A ", b"mp42", b"isom"]); assert!(buzz_media::looks_like_iso_bmff(&memo)); - assert!(!should_stream_as_video(&memo)); + assert!(should_stream_as_video(&memo)); } #[test]