Streaming sample getters read each selected sample separately

perfloop-oss/mp4ff · Under-Batching

https://perfloop.ai/t/oss/case_5efpe3ks0y

Verdict

VALIDATED BY A DIFFERENT CHANGE · settled 2026-11-12

What happened: The check passes with this change.

Hypothesis

Streaming multi-sample getters read selected samples individually even when their bytes form contiguous runs. On a fresh, unbuffered file reader, this creates repeated underlying file reads. The existing append APIs demonstrate a grouped route, but customer latency and savings remain unmeasured. Confidence is medium.

GetSampleRange calls ReadData inside its selected-sample loop; GetSamples does likewise at stream.go:443-458. Each reached lazy ReadData call seeks, allocates, and uses io.ReadFull. InitDecodeStream passes its input directly to BoxSeekReader. That reader caches bytes already consumed but does not read ahead to coalesce first-pass sample reads. In contrast, appendSamples reads a selected trun range in one operation.

TestPerfloopStreamBoundaryAudit opened the committed mp4/testdata/v300_multiple_segments.mp4 afresh for each API mode and counted actual os.File.Read calls only during sample access. Successful full extraction covered 240 samples in four truns across four fragments. GetSamples and GetSampleRange each made 240 underlying reads. AppendSamples and AppendSampleRange each made four. Every mode returned 134386 payload bytes with the same SHA-256 digest. These counts exclude parsing, do not cover cached rereads or early errors, and are not elapsed-time measurements.

The append APIs are already shipped, as recorded in CHANGELOG.md:250-253. This proposal is distinct from adding them: existing GetSamples/GetSampleRange callers still take the per-sample route. It must not silently trade independent sample-buffer use for unsafe cross-sample appends or unexamined retention of an entire track buffer.

The Case's first useful check is an instrumented file-reader differential on that fixture, followed by a bounded sweep of samples per trun and payload sizes. Measure read counts, elapsed time, and allocations for fresh and already-buffered readers. Compare sample bytes, metadata, ordering, partial ranges, multiple truns/tracks, and failures from invalid offsets or truncated input. Any grouped read must retain the getters' failure behavior; reduced dispatch count alone does not establish an end-to-end gain.

The refreshed open PR https://github.com/Eyevinn/mp4ff/pull/657 implements AAC configuration support and does not route these getters through grouped media reads.

Change to test: Batch contiguous selected bytes per trun in GetSamples and GetSampleRange, using the existing append implementation where compatible rather than requiring callers to change APIs. Preserve ordering, bounds and error behavior, and independent sample-buffer use; account for any added copying or whole-run buffer retention.

Where it lives

perfloop-oss/mp4ff

Evidence

The check passes with this change: `For full-track extraction from mp4/testdata/v300_multiple_segments.mp4 through InitDecodeStream with a fresh os.File per API, GetSamples, GetSampleRange, AppendSamples and AppendSampleRange return the same 240 ordered samples and metadata and 134386 payload bytes with SHA-256 3449633b656952612c827c0232a94ee21713a14c1460ca982bda9ef147c42a57; their sample-access os.File.Read counts are 240, 240, 4 and 4 respectively.`

Verification: no defect found.

Timeline