Skip to content

TIKA-4779: Add audio:bitrate, audio:is-variable-bitrate and audio:has-drm#2953

Open
dschmidt wants to merge 1 commit into
apache:mainfrom
dschmidt:audio-bitrate-vbr-drm
Open

TIKA-4779: Add audio:bitrate, audio:is-variable-bitrate and audio:has-drm#2953
dschmidt wants to merge 1 commit into
apache:mainfrom
dschmidt:audio-bitrate-vbr-drm

Conversation

@dschmidt

Copy link
Copy Markdown
Contributor

Part 2 of TIKA-4779, following up on #2947 with the three audio properties that need parser work rather than plain mapping: audio:bitrate (average, bits per second), audio:is-variable-bitrate and audio:has-drm, defined under Tika's own namespace in Audio.java.

MP3: the parser already walks every audio frame for the duration, and since frame duration does not depend on the bitrate, the plain mean over the frames is the exact average and differing frame bitrates are an exact VBR signal. The one special case is the Xing/Info/VBRI tag frame some encoders write first: it is a valid MPEG frame without audio, often at a different bitrate than the stream, so it is detected and excluded (a CBR file with an Info tag would otherwise be misreported as VBR, there is a fixture proving exactly that). I deliberately did not go the usual route of reading the bitrate from the Xing table itself: the full frame walk already happens for the duration, so the exact mean is free and works for files without any tag frame.

Vorbis: the identification header declares upper/nominal/lower rates. Nominal maps to audio:bitrate; a zero-width bracket (upper == lower, no nominal) also pins an exact rate. Fixed rate means all three declared rates agree, or only a zero-width bracket is declared; anything else counts as variable.

MP4/M4A: a TikaMp4SoundHandler (same extension pattern as TIKA-2861) structurally walks the sample description entries. Protected sample entry formats (drms, enca) set audio:has-drm; these markers are readable by design since DRM encrypts the payload, not the metadata. The average bitrate comes from the esds elementary stream descriptor, located as a child box of the entry (honoring the version-dependent entry layout, QuickTime wave wrappers and the optional ES descriptor fields). I deliberately avoided scanning the stsd bytes for fourcc markers: codec private data or a URL field can legally contain the string sinf, and a fixture covers that false positive.

For files with several audio tracks the properties reflect the last sound track's sample description, consistent with how the existing MP4 audio metadata behaves.

Note: the hdlr dispatch hook in TikaMp4BoxHandler overlaps with #2936; whichever merges second has a trivial rebase.

Tests run against real files where the repo has them (testMP4.m4a with a declared average of 256000, the constant bitrate MP3 fixtures, testVORBIS.ogg copied from the integration tests). Synthetic fixtures cover only what no real specimen exercises: a VBR MP3, a CBR MP3 with an Info tag frame, a drms protected M4A and an M4A whose ES descriptor uses the optional fields.

…s-drm

Part 2 of TIKA-4779, covering the audio properties that need parser work
rather than plain mapping.

MP3: the parser already walks every audio frame for the duration, and
frame duration does not depend on the bitrate, so the plain mean over
the frames is the true average bitrate and differing frame bitrates are
an exact variable bitrate signal. The only special case is the leading
Xing/Info/VBRI tag frame some encoders write: it is a valid MPEG frame
that carries no audio and may use a different bitrate, so it is detected
(via a new peek method on MpegStream) and kept out of the statistics.

Vorbis: the identification header declares upper/nominal/lower rates.
The nominal rate is mapped to audio:bitrate (or the shared bound when a
zero-width bracket is declared without a nominal rate), and the stream
counts as fixed rate when all three declared rates agree or when only a
zero-width bracket is declared.

MP4: a TikaMp4SoundHandler (same pattern as the box handler extensions
from TIKA-2861) walks the sound track's sample description entries.
Protected sample entry formats ('drms', 'enca') set audio:has-drm; the
esds elementary stream descriptor is located structurally below the
entry (honoring the version-dependent entry layout, QuickTime 'wave'
wrappers and the optional ES descriptor fields) and its average bitrate
is mapped to audio:bitrate.

Verified against the real files in the repo where they cover the
behavior: testVORBIS.ogg (copied from the integration tests; a real
quality-mode encoding with nominal 80000 and no bounds), the 192 kbps
testMP3lyrics.mp3 and the 128 kbps ID3 fixtures for constant bitrate,
and testMP4.m4a whose esds declares an average bitrate of 256000.
Synthetic fixtures fill only the gaps the repo has no real specimen
for: a variable bitrate MP3 (frames alternating 128/192 kbps), a
constant bitrate MP3 with an 'Info' tag frame at a different rate, a
DRM-protected M4A ('drms' sample entry) and an M4A whose ES descriptor
uses the optional dependency/URL/OCR fields.
@dschmidt dschmidt marked this pull request as ready for review July 14, 2026 14:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant