64 lines
2.3 KiB
Rust
64 lines
2.3 KiB
Rust
//! A check of the first bytes of a file against the audio containers voice
|
|
//! memos come in, before anything decodes it.
|
|
//!
|
|
//! The audio comes from matrix rooms with outside people, so the decoder only
|
|
//! ever sees files that start like an audio container. A file that claims to
|
|
//! be anything else (a playlist, an image, a script) stops here, which keeps
|
|
//! most of `ffmpeg`'s demuxers out of reach.
|
|
|
|
/// `true` when `bytes` start like Ogg (Opus, Vorbis), WAV, FLAC, MP3 (with or
|
|
/// without an `ID3` tag), AMR, `MP4` or `M4A`, Matroska or `WebM`.
|
|
#[must_use]
|
|
pub fn is_audio(bytes: &[u8]) -> bool {
|
|
let starts = |magic: &[u8]| bytes.starts_with(magic);
|
|
starts(b"OggS")
|
|
|| (starts(b"RIFF") && bytes.get(8..12) == Some(b"WAVE"))
|
|
|| starts(b"fLaC")
|
|
|| starts(b"ID3")
|
|
|| starts(b"#!AMR")
|
|
// An MPEG audio frame: eleven set bits of sync.
|
|
|| matches!(bytes, [0xFF, second, ..] if second & 0xE0 == 0xE0)
|
|
// The `ftyp` box of an ISO base media file (MP4, M4A, 3GP).
|
|
|| bytes.get(4..8) == Some(b"ftyp")
|
|
// The EBML header of Matroska and WebM.
|
|
|| starts(&[0x1A, 0x45, 0xDF, 0xA3])
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::is_audio;
|
|
|
|
#[test]
|
|
fn the_containers_voice_memos_come_in_pass() {
|
|
for (name, head) in [
|
|
("ogg", &b"OggS\0\x02"[..]),
|
|
("wav", b"RIFF\x24\0\0\0WAVEfmt "),
|
|
("flac", b"fLaC\0"),
|
|
("mp3 with a tag", b"ID3\x04\0"),
|
|
("mp3 frame", &[0xFF, 0xFB, 0x90, 0x00]),
|
|
("amr", b"#!AMR\n"),
|
|
("m4a", b"\0\0\0\x20ftypM4A "),
|
|
("webm", &[0x1A, 0x45, 0xDF, 0xA3, 0x9F]),
|
|
] {
|
|
assert!(is_audio(head), "{name} was refused");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn files_that_are_not_audio_containers_are_refused() {
|
|
for (name, head) in [
|
|
("an HLS playlist", &b"#EXTM3U\n#EXT-X-VERSION:3\n"[..]),
|
|
("a png", b"\x89PNG\r\n\x1a\n"),
|
|
("a script", b"#!/bin/sh\nid\n"),
|
|
(
|
|
"a concat list",
|
|
b"ffconcat version 1.0\nfile '/etc/passwd'\n",
|
|
),
|
|
("a wave-less riff (avi)", b"RIFF\x24\0\0\0AVI LIST"),
|
|
("empty", b""),
|
|
("one byte", &[0xFF]),
|
|
] {
|
|
assert!(!is_audio(head), "{name} was accepted");
|
|
}
|
|
}
|
|
}
|