use std::{
alloc::{GlobalAlloc, Layout, System},
cell::Cell,
};
mod support;
use mediadecode::demuxer::Demuxer;
use mediadecode_ffmpeg::{DemuxError, DemuxLimits, FfmpegOwnedDemuxer};
use smol_bytes::{INLINE_CAP, Utf8Bytes};
thread_local! {
static WATCHING: Cell<bool> = const { Cell::new(false) };
static ALLOCATIONS: Cell<usize> = const { Cell::new(0) };
static ALLOCATED_BYTES: Cell<usize> = const { Cell::new(0) };
static LARGEST: Cell<usize> = const { Cell::new(0) };
}
struct Counting;
fn record(size: usize) {
let watching = WATCHING.try_with(Cell::get).unwrap_or(false);
if watching {
let _ = ALLOCATIONS.try_with(|c| c.set(c.get() + 1));
let _ = ALLOCATED_BYTES.try_with(|c| c.set(c.get() + size));
let _ = LARGEST.try_with(|c| c.set(c.get().max(size)));
}
}
unsafe impl GlobalAlloc for Counting {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
record(layout.size());
unsafe { System.alloc(layout) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe { System.dealloc(ptr, layout) }
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
record(new_size);
unsafe { System.realloc(ptr, layout, new_size) }
}
}
#[global_allocator]
static ALLOCATOR: Counting = Counting;
fn measured<T>(body: impl FnOnce() -> T) -> (T, usize, usize) {
let (out, allocations, bytes, _) = measured_with_largest(body);
(out, allocations, bytes)
}
fn measured_with_largest<T>(body: impl FnOnce() -> T) -> (T, usize, usize, usize) {
ALLOCATIONS.set(0);
ALLOCATED_BYTES.set(0);
LARGEST.set(0);
WATCHING.set(true);
let out = body();
WATCHING.set(false);
(out, ALLOCATIONS.get(), ALLOCATED_BYTES.get(), LARGEST.get())
}
fn charged_buffer(len: usize) -> String {
let mut buffer = String::new();
buffer
.try_reserve_exact(len)
.expect("the test's own reservation");
buffer.extend(std::iter::repeat_n('x', len));
assert_eq!(buffer.len(), len);
buffer
}
const HEADER_CEILING: usize = 64;
#[test]
fn a_large_value_reaches_the_carrier_without_allocating() {
let buffer = charged_buffer(65_535);
let (text, allocations, bytes) = measured(|| Utf8Bytes::from(buffer));
assert_eq!(text.as_str().len(), 65_535);
assert_eq!(
allocations, 0,
"the fallibly reserved buffer is moved into the carrier, not copied — {bytes} bytes were \
allocated after the charge",
);
}
#[test]
fn the_first_heap_sized_value_costs_no_copy() {
let buffer = charged_buffer(INLINE_CAP + 1);
let (text, _, bytes) = measured(|| Utf8Bytes::from(buffer));
assert_eq!(text.as_str().len(), INLINE_CAP + 1);
assert!(
bytes <= HEADER_CEILING,
"the heap road starts here; {bytes} bytes were allocated, which is more than a header and \
therefore a copy",
);
}
#[test]
fn a_small_value_is_stored_inline() {
let buffer = charged_buffer(INLINE_CAP);
let (text, allocations, _) = measured(|| Utf8Bytes::from(buffer));
assert_eq!(text.as_str().len(), INLINE_CAP);
assert_eq!(allocations, 0, "inline storage, so no heap at all");
}
#[test]
fn the_copying_carrier_allocated_a_second_time() {
let buffer = charged_buffer(65_535);
let (copy, allocations, bytes) = measured(|| std::sync::Arc::<str>::from(buffer.as_str()));
assert_eq!(copy.len(), 65_535);
assert!(allocations >= 1);
assert!(
bytes >= 65_535,
"only {bytes} bytes were allocated, so this is no longer a full copy and the contrast this \
lane draws has gone stale",
);
}
#[test]
fn a_budgeted_open_makes_no_oversized_or_duplicated_allocation() {
let Some(corpus) = support::Corpus::new() else {
return;
};
let path = corpus.multi_track_mkv();
let (demuxer, allocations, bytes, largest) =
measured_with_largest(|| FfmpegOwnedDemuxer::open(&path));
let demuxer = demuxer.expect("the fixture opens");
assert_eq!(demuxer.tracks().len(), 4);
assert!(
allocations > 0,
"an open that allocated nothing was not an open"
);
assert!(
largest < 256 * 1024,
"the largest single allocation during the open was {largest} bytes; every payload in this \
fixture is tiny, so a block that size means one was staged and copied again",
);
assert!(
bytes < 4 * 1024 * 1024,
"the open allocated {bytes} bytes in total for a fixture whose payloads are a few kilobytes \
— a reservation made against the ceiling rather than against the file",
);
}
#[test]
fn a_refused_chapter_table_is_refused_before_the_tracks_are_built() {
let Some(corpus) = support::Corpus::new() else {
return;
};
let path = corpus.chaptered_mkv();
let (refused, _, refused_bytes, refused_largest) = measured_with_largest(|| {
FfmpegOwnedDemuxer::open_with(&path, DemuxLimits::new().with_max_chapters(1))
});
assert!(
matches!(refused, Err(DemuxError::TooManyChapters(_))),
"the ceiling must refuse this file",
);
let (accepted, _, accepted_bytes, _) = measured_with_largest(|| FfmpegOwnedDemuxer::open(&path));
let accepted = accepted.expect("the same file opens under the default ceiling");
assert_eq!(accepted.chapters().len(), 2);
assert!(
accepted_bytes > 0,
"an open that allocated nothing was not an open",
);
assert!(
refused_bytes * 2 < accepted_bytes,
"the refused open spent {refused_bytes} bytes against the accepted open's {accepted_bytes}: \
the refusal is paying for a table it was always going to throw away",
);
assert!(
refused_largest < 64 * 1024,
"the largest single allocation before the refusal was {refused_largest} bytes — a carrier, \
which means a payload was copied for a file that was never going to open",
);
}
#[test]
fn over_budget_metadata_on_the_last_stream_costs_no_track_material() {
let Some(corpus) = support::Corpus::new() else {
return;
};
let path = corpus.multi_track_mkv();
let (accepted, _, accepted_bytes, _) = measured_with_largest(|| FfmpegOwnedDemuxer::open(&path));
let accepted = accepted.expect("the fixture opens");
let retained: usize = accepted
.tracks()
.iter()
.map(|track| {
let len = |value: Option<&Utf8Bytes>| value.map_or(0, |text| text.len());
len(track.filename()) + len(track.mime_type()) + len(track.language())
})
.sum();
assert!(
retained > 0,
"the fixture must retain some stream metadata for this lane to mean anything",
);
let (refused, _, refused_bytes, refused_largest) = measured_with_largest(|| {
FfmpegOwnedDemuxer::open_with(
&path,
DemuxLimits::new().with_max_total_stream_metadata_bytes(retained - 1),
)
});
match refused {
Err(DemuxError::TrackMetadataBudgetExhausted(_)) => {}
Err(other) => panic!("the budget must be what refuses this file, got {other:?}"),
Ok(_) => panic!("one byte under what the file retains must be refused"),
}
assert!(
refused_bytes * 2 < accepted_bytes,
"the refused open spent {refused_bytes} bytes against the accepted open's {accepted_bytes}: \
the refusal is paying for a table it was always going to throw away",
);
assert!(
refused_largest < 64 * 1024,
"the largest single allocation before the refusal was {refused_largest} bytes — an \
attachment carrier or a parameter mirror, bought for a file that was never going to open",
);
}
#[test]
fn reading_the_descriptor_tables_allocates_nothing() {
use mediadecode_ffmpeg::CodecId;
let ((longest, seen), allocations, bytes) = measured(|| {
let mut longest = 0usize;
let mut seen = 0usize;
for raw in 0..1200i32 {
let id = CodecId::from_raw(raw);
if let Some(name) = id.name() {
longest = longest.max(name.len());
seen += 1;
}
if let Some(long) = id.long_name() {
longest = longest.max(long.len());
}
}
(longest, seen)
});
assert!(
seen > 100,
"the descriptor table should not be nearly empty"
);
assert!(
longest > INLINE_CAP,
"the scan never met a name past the {INLINE_CAP}-byte window, so it cannot speak to the \
case this lane is about; it saw at most {longest} bytes",
);
assert_eq!(
allocations, 0,
"reading names out of a static table must not copy them; the scan allocated {bytes} bytes",
);
}
#[test]
fn reporting_an_unsupported_pixel_format_allocates_nothing() {
use mediadecode_ffmpeg::convert::UnsupportedPixelFormat;
let (named, allocations, bytes) = measured(|| UnsupportedPixelFormat::new(0, Some("yuv420p")));
assert_eq!(
allocations, 0,
"naming a refused format must not need the allocator; it allocated {bytes} bytes",
);
assert_eq!(named.raw(), 0);
assert_eq!(named.name(), Some("yuv420p"));
let (unnamed, allocations, _) = measured(|| UnsupportedPixelFormat::new(-99_999, None));
assert_eq!(allocations, 0);
assert!(unnamed.name().is_none());
}
#[test]
fn producing_a_carrier_costs_one_allocation_and_nothing_after_it() {
let (carrier, allocations, _) = measured(|| {
mediadecode_ffmpeg::FfmpegBytes::try_copy_from_slice(&[7u8; 4096])
.expect("a four-kibibyte carrier")
});
assert_eq!(carrier.len(), 4096);
assert_eq!(
allocations, 1,
"one allocation for the payload, and nothing after it — no staging \
buffer, and no second copy into a refcount",
);
}