Skip to content

Auro-3D: Detect in 24-bit PCM - #2531

Open
almirus wants to merge 5 commits into
MediaArea:masterfrom
almirus:master
Open

almirus wants to merge 5 commits into
MediaArea:masterfrom
almirus:master

Conversation

@almirus

@almirus almirus commented Feb 16, 2026

Copy link
Copy Markdown
Contributor

Hello! This is the first version of support for displaying the Auro-3D format with channel layout. It was implemented by me based on reverse engineering; my detector is available here: https://github.com/almirus/Orua-D3

Auro is embedded in the PCM stream, so it can be contained in FLAC and DTS HD MA, and those must be decoded first.

The documentation is here, and the test files are here.

@JeromeMartinez

Copy link
Copy Markdown
Member

Great to have that.
We could use the FFmpeg plugin for decoding, in the future.
We can manage project files.

I'll force-push an update with the updated project files.

@almirus

almirus commented Feb 16, 2026

Copy link
Copy Markdown
Contributor Author

Currently (this PR), only WAV files and MKV files containing WAV are supported.

@JeromeMartinez

Copy link
Copy Markdown
Member

Currently (this PR), only WAV files and MKV files containing WAV are supported.

I understand, the compressed streams will require a decoder, a totally other story, for later.

@almirus

almirus commented Feb 16, 2026

Copy link
Copy Markdown
Contributor Author

A silly solution — using a user ffmpeg application (if available).

@JeromeMartinez

Copy link
Copy Markdown
Member

using a user ffmpeg application (if available).

It is the idea with "We could use the FFmpeg plugin for decoding" (we have already it for some other things).

@cjee21

cjee21 commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

Related issue: #1471

@cinema-ONE

Copy link
Copy Markdown

Offering something for the part that was deliberately deferred here — @JeromeMartinez's "the compressed streams will require a decoder, a totally other story, for later". No suggestion that it belongs in this PR; this is for whenever that later comes.

I have a working decode path for Auro-3D inside DTS-HD MA and Blu-ray LPCM, using ffmpeg exactly as the FFmpeg-plugin route would, plus a corpus to validate it against. It reads .m2ts straight out of BDMV/STREAM, so no remux step.

What might be worth knowing before that work starts:

  • ~2 seconds of decoded audio is enough. Measured 0.13 s wall clock including the ffmpeg call. The decode requirement is real but the duration is small, which may make it cheaper than it sounded earlier in Auro-3D audio detection #1471.
  • Block size varies per stream — 800, 960, 1000 and 1024 all occur, and 1000 and 1024 each appear at both 48 and 96 kHz. It does not follow the sample rate. Reading it from the header (as @almirus does) is the only safe route; anything hard-coded passes the common case and silently misses the rest.
  • The CRC does all the work on false positives. Sync alone is not enough: one DTS:X control produced 5,149 chance 16-runs on its LFE. Every one fails the CRC. On my corpus, 400 of 400 candidate blocks validate on each Auro file and 0 on each control.

The offer: ground truth from an Auro-3D-certified hardware decoder (StormAudio ISP Elite MK2 over its TCP API) rather than from another software implementation. I've run @almirus's method against it — 7 of 7, both negatives included, reported in #1471. Corpus is two Auro-3D demonstration Blu-rays swept track-by-track (175 streams), two commercial remuxes and a demo-trailer set, spanning 8.0, 9.1, 10.1, 11.1, 11.1 (7+4) and 13.1, at 48 and 96 kHz, in both DTS-HD MA and LPCM.

If a compressed-carrier implementation lands and you want it checked against real hardware before merging, say the word and I'll run whatever set is useful. Happy to supply per-stream expected results too.

For reference, my own port of @almirus's method (CRC, header parse, ADOL walk to opcode 0x1E) is at https://github.com/cinema-ONE/auro3d-detector — Python, MIT, ffmpeg the only dependency. It exists to test the method, not to compete with this PR.

@cjee21

cjee21 commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

The decode requirement is real but the duration is small

Then will just be enabling DTS-HD MA decoder in MediaArea's FFmpeg build (size and patent licensing consideration) and implementing the decoding with FFmpeg and passing the decoded to the detector (code complexity; is temp file needed? etc.).

@cinema-ONE

Copy link
Copy Markdown

@cjee21 Two of those I can answer with measurements rather than opinion.

The lossless extension is mandatory — core-only gets you nothing

I wondered whether the DTS core would be enough, since that would change the size and licensing calculus considerably. It is not. Same 4-second window from the same DTS-HD MA track, decoded two ways:

ffmpeg ... -c:a pcm_s24le                    -> Auro-3D, carrier 5.1, layout Auro 11.1
ffmpeg ... -core_only 1 -c:a pcm_s24le       -> nothing; no block passes CRC

That is by construction rather than bad luck: the payload lives in the least-significant bits of the lossless reconstruction, and the lossy core does not preserve them. So for DTS-HD MA carriers it is XLL or nothing — there is no cheaper decoder that yields a partial answer. Whether that is worth the build size and the licensing is entirely your and @JeromeMartinez's call, but at least the technical half is settled: there is no middle option to trade down to.

Worth adding that LPCM carriers need no decoder at all beyond what MediaInfo already does, which is what this PR covers today.

No temp file needed

Pipe it. ffmpeg writes WAV to stdout, the detector parses the header and reads samples straight from the buffer:

ffmpeg -v error -ss <n> -i <file> -map 0:<stream> -t 2 -c:a pcm_s32le -f wav -

That is what my implementation does — no intermediate file, no seek-back. Two further properties that keep it cheap:

  • Peak memory is the decoded window, and the window is small. 2 seconds is enough (the marker repeats ~48×/second). Worst realistic case, 8 channels at 96 kHz, is 5.9 MB; a 5.1 track at 48 kHz is about 1.5 MB.
  • You can stop early. Detection needs only a handful of CRC-valid blocks; there is no need to decode to the end, or to hold more than the current window.

One caveat from experience: read the channel count and sample rate from the decoder's WAV header, not from the container. On Blu-ray .m2ts, ffprobe frequently reports channels=0 because it cannot resolve the layout from the container alone — five of the streams in my corpus did exactly that, and trusting the container value would have produced a divide-by-zero or a wrong stride.

Happy to run any build against the hardware-labelled corpus if that would help de-risk the decision.

v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 17, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer has been written into the low bits of
the 24-bit PCM samples, so every field a demuxer or parser can read says
plain DTS-HD MA and nothing in the container or the bitstream names Auro. The
side channel only becomes legible once the samples have been reconstructed.
MediaInfoLib reaches the same conclusion from the other direction: its Auro
detection, MediaArea/MediaInfoLib#2531, runs on WAV and raw PCM only, because
those are the cases where it has samples without having to decode.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, and a
few lines above is already where the DTS:X syncword is turned into a profile.
Putting the probe there costs the scan and nothing else - no second decode,
no buffering the caller did not already pay for, no extra pass.

Getting the answer before playback starts took a second change. The probe in
avformat_find_stream_info() does reach this code - sample_fmt and
bits_per_raw_sample are set nowhere else in the DCA parser or decoder, and
ffprobe reports both after find_stream_info alone, even at analyzeduration=0
- but it stops at the first decoded frame, and one frame is 512 samples where
the scan needs up to 4096. Measured, that is the whole difference between
"DTS-HD MA" and "DTS-HD MA + Auro-3D" on all six samples below.
has_codec_parameters() already carries a DTS clause for a similar reason
("no decodable DTS frames"), but widening it would make a stream that ends
before the budget report missing parameters, so try_decode_frame() and the
outer read loop each get one condition instead and what a stream reports at
the end is untouched. Only DTS-HD MA pays: anything that is not DTS, or whose
first frame already named DTS:X, drops out there. That is what reaches
passthrough users and the library scanner, neither of which ever decodes a
frame of its own.

The scan follows the Auro-Codec block framing. A block opens with sixteen
consecutive samples whose bit 0 is set, its length is spread through bits 1
and 2 of the first eight of those, and a CRC16-CCITT over all three bytes of
every sample in the block is stored a couple of bits at a time across the low
half of the same sixteen. Sync alone is not evidence - any channel throws
long runs of set low bits by chance - so a block is believed only once its
stored CRC matches. One valid block is the whole test; the verdict is then
latched for the stream and no later frame pays anything.

Measured on seven carriers: the six Auro-3D demo titles available here and
the reference carrier from the Orua-D3 pair, a 96 kHz file whose two active
channels carry Auro and whose third is silent. All six titles are reported as
"DTS-HD MA + Auro-3D" by ffprobe after find_stream_info alone, with no
decoding by the caller. All seven validate a block in the first carrying
channel, each on the first candidate the scan reaches, because blocks tile
the stream and the first sync found is a real block head. The latest a first
block completes is 4096 samples in, hence the 8192 budget and the sixteen
frames. A full 8192-sample scan costs 0.04ms, and 0.01ms on material with no
Auro layer, which does not offer it a single candidate. Probing an Auro title
costs 0.5ms more than before; a DTS-HD MA title that is not Auro, which runs
the whole budget, costs 1.9ms more.

Negative controls reject on every channel. The sharpest is the other half of
that same pair - the 5.1 original of the same programme, 24-bit 96 kHz,
correlating 0.87 to 0.93 against the carrier's channels, with bit 0 set in
47% of its samples. Its low bits are fully exercised, which makes it the
hardest realistic false positive; its six channels offer between four and
twelve chance sync runs across ten seconds and not one survives its CRC. The
rest also reject: the carrier with bit 0 randomised, the carrier with its low
byte cleared, white noise over the full 24-bit range, digital silence and a
ramp. The candidate ceiling bounds the one input that is expensive rather
than wrong - a channel whose low bit is set almost everywhere offers a
candidate at nearly every sample - at 2.5ms instead of 117ms, and latches a
negative verdict rather than repeating the work next frame. Streams truncated
to between 4 KB and 2 MB were checked against an unpatched build: same
warnings, same parameters, no new "Could not find codec parameters", and a
stream cut too short to finish the scan simply stays "DTS-HD MA".

The scan is skipped unless the samples are stored unshifted: a carrier whose
low bits have been moved is not one Auro could have been written into.

Like the DTS:X detection alongside it, this is reverse engineering rather
than specification. AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree;
upstream has assigned no value for it. Built and run as ffprobe on x86_64
against ffmpeg 8.1.2 with 0005 and 0008 applied first; not built for the
device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 17, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer has been written into the low bits of
the 24-bit PCM samples, so every field a demuxer or parser can read says
plain DTS-HD MA and nothing in the container or the bitstream names Auro. The
side channel only becomes legible once the samples have been reconstructed.
MediaInfoLib reaches the same conclusion from the other direction: its Auro
detection, MediaArea/MediaInfoLib#2531, runs on WAV and raw PCM only, because
those are the cases where it has samples without having to decode.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, and a
few lines above is already where the DTS:X syncword is turned into a profile.
Putting the probe there costs the scan and nothing else - no second decode,
no buffering the caller did not already pay for, no extra pass.

Getting the answer before playback starts took a second change. The probe in
avformat_find_stream_info() does reach this code - sample_fmt and
bits_per_raw_sample are set nowhere else in the DCA parser or decoder, and
ffprobe reports both after find_stream_info alone, even at analyzeduration=0
- but it stops at the first decoded frame, and one frame is 512 samples where
the scan needs several thousand. Measured, that is the whole difference
between "DTS-HD MA" and "DTS-HD MA + Auro-3D" on all six samples below.
has_codec_parameters() already carries a DTS clause for a similar reason
("no decodable DTS frames"), but widening it would make a stream that ends
before the budget report missing parameters, so try_decode_frame() and the
outer read loop each get one condition instead and what a stream reports at
the end is untouched. Only DTS-HD MA pays: anything that is not DTS, or whose
first frame already named DTS:X, drops out there. That is what reaches
passthrough users and the library scanner, neither of which ever decodes a
frame of its own.

The scan follows the Auro-Codec block framing. A block opens with sixteen
consecutive samples whose bit 0 is set; three bit planes of those sixteen
carry the whole header - bit 0 the sync, bit 1 a CRC16-CCITT over all three
bytes of every sample in the block, bit 2 the block length and the number of
low bits borrowed per sample. Sync alone is not evidence, since any channel
throws long runs of set low bits by chance, so a block is believed only once
its stored CRC matches. One valid block is the whole test; the verdict is
then latched for the stream and no later frame pays anything.

Nothing range-checks the length. All 256 codes name a length, 16 to 4096 in
steps of 16 with one code reserved for 1000, and the reference implementation
accepts every one of them; a plausible-looking length is not evidence and an
implausible one is not disqualifying, because the CRC settles it either way.
Sizing follows from the same fact: blocks tile the stream, so a buffer of two
maximum-length blocks holds one whole block whatever phase it starts at. That
is 8192 samples, which is also what the reference detector gives its ring,
~170 ms at 48 kHz, and sixteen frames of the usual 512 - hence the probe
budget.

Both extractions were checked against the reference rather than trusted. The
length code and the stored CRC are read here in the form the commercial
decoder uses, which carries bit 1 through the length arithmetic and masks it
off a step later; over all 65536 inputs that form agrees exactly with reading
the two as the plain bit planes they are.

Measured on seven carriers: the six Auro-3D demo titles available here and
the reference carrier from the Orua-D3 pair, a 96 kHz file whose two active
channels carry Auro and whose third is silent. All six titles are reported as
"DTS-HD MA + Auro-3D" by ffprobe after find_stream_info alone, with no
decoding by the caller; the reference carrier is not in a container and went
through the scan directly. All seven validate a block in the first carrying
channel, each on the first candidate the scan reaches, because blocks tile
the stream and the first sync found is a real block head. Synthetic blocks
built to the framing above are found at every length from 16 to 4096 and at
every phase within the buffer, including a 4096-sample block beginning at
sample 4095 and ending on the buffer's last sample. A full 8192-sample scan
costs 0.04ms, and 0.01ms on material with no Auro layer, which does not offer
it a single candidate. Probing an Auro title costs 0.5ms more than before; a
DTS-HD MA title that is not Auro, which runs the whole budget, costs 1.9ms
more.

Negative controls reject on every channel. The sharpest is the other half of
that same pair - the 5.1 original of the same programme, 24-bit 96 kHz,
correlating 0.87 to 0.93 against the carrier's channels, with bit 0 set in
47% of its samples. Its low bits are fully exercised, which makes it the
hardest realistic false positive; its six channels offer between four and
twelve chance sync runs across ten seconds and not one survives its CRC. The
rest also reject: the carrier with bit 0 randomised, the carrier with its low
byte cleared, white noise over the full 24-bit range, digital silence and a
ramp. The candidate ceiling bounds the one input that is expensive rather
than wrong - a channel whose low bit is set almost everywhere offers a
candidate at nearly every sample - at 4.2ms, and latches a negative verdict
rather than repeating the work next frame. Streams truncated to between 4 KB
and 2 MB were checked against an unpatched build: same warnings, same
parameters, no new "Could not find codec parameters", and a stream cut too
short to finish the scan simply stays "DTS-HD MA".

The scan is skipped unless the samples are stored unshifted: a carrier whose
low bits have been moved is not one Auro could have been written into.

Like the DTS:X detection alongside it, this is reverse engineering rather
than specification. AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree;
upstream has assigned no value for it. Built and run as ffprobe on x86_64
against ffmpeg 8.1.2 with 0005 and 0008 applied first; not built for the
device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 17, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer has been written into the low bits of
the 24-bit PCM samples, so every field a demuxer or parser can read says
plain DTS-HD MA and nothing in the container or the bitstream names Auro. The
side channel only becomes legible once the samples have been reconstructed.
MediaInfoLib reaches the same conclusion from the other direction: its Auro
detection, MediaArea/MediaInfoLib#2531, runs on WAV and raw PCM only, because
those are the cases where it has samples without having to decode.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, and a
few lines above is already where the DTS:X syncword is turned into a profile.
Putting the probe there costs the scan and nothing else - no second decode,
no buffering the caller did not already pay for, no extra pass.

Getting the answer before playback starts took a second change. The probe in
avformat_find_stream_info() does reach this code - sample_fmt and
bits_per_raw_sample are set nowhere else in the DCA parser or decoder, and
ffprobe reports both after find_stream_info alone, even at analyzeduration=0
- but it stops at the first decoded frame, and one frame is 512 samples where
the scan needs several thousand. Measured, that is the whole difference
between "DTS-HD MA" and "DTS-HD MA + Auro-3D" on all six samples below.
has_codec_parameters() already carries a DTS clause for a similar reason
("no decodable DTS frames"), but widening it would make a stream that ends
before the budget report missing parameters, so try_decode_frame() and the
outer read loop each get one condition instead and what a stream reports at
the end is untouched. Only DTS-HD MA pays: anything that is not DTS, or whose
first frame already named DTS:X, drops out there. That is what reaches
passthrough users and the library scanner, neither of which ever decodes a
frame of its own.

The scan follows the Auro-Codec block framing. A block opens with sixteen
consecutive samples whose bit 0 is set; three bit planes of those sixteen
carry the whole header - bit 0 the sync, bit 1 a CRC16-CCITT over all three
bytes of every sample in the block, bit 2 the block length and the number of
low bits borrowed per sample. Sync alone is not evidence, since any channel
throws long runs of set low bits by chance, so a block is believed only once
its stored CRC matches. One valid block is the whole test; the verdict is
then latched for the stream and no later frame pays anything.

Nothing range-checks the length. All 256 codes name a length, 16 to 4096 in
steps of 16 with one code reserved for 1000, and the reference implementation
accepts every one of them; a plausible-looking length is not evidence and an
implausible one is not disqualifying, because the CRC settles it either way.
Sizing follows from the same fact: blocks tile the stream, so a buffer of two
maximum-length blocks holds one whole block whatever phase it starts at. That
is 8192 samples, which is also what the reference detector gives its ring,
~170 ms at 48 kHz, and sixteen frames of the usual 512 - hence the probe
budget.

Both extractions were checked against the reference rather than trusted. The
length code and the stored CRC are read here in the form the commercial
decoder uses, which carries bit 1 through the length arithmetic and masks it
off a step later; over all 65536 inputs that form agrees exactly with reading
the two as the plain bit planes they are.

Measured on seven carriers: the six Auro-3D demo titles available here and
the reference carrier from the Orua-D3 pair, a 96 kHz file whose two active
channels carry Auro and whose third is silent. All six titles are reported as
"DTS-HD MA + Auro-3D" by ffprobe after find_stream_info alone, with no
decoding by the caller; the reference carrier is not in a container and went
through the scan directly. All seven validate a block in the first carrying
channel, each on the first candidate the scan reaches, because blocks tile
the stream and the first sync found is a real block head. Synthetic blocks
built to the framing above are found at every length from 16 to 4096 and at
every phase within the buffer, including a 4096-sample block beginning at
sample 4095 and ending on the buffer's last sample. A full 8192-sample scan
costs 0.04ms, and 0.01ms on material with no Auro layer, which does not offer
it a single candidate. Probing an Auro title costs 0.5ms more than before; a
DTS-HD MA title that is not Auro, which runs the whole budget, costs 1.9ms
more.

Negative controls reject on every channel. The sharpest is the other half of
that same pair - the 5.1 original of the same programme, 24-bit 96 kHz,
correlating 0.87 to 0.93 against the carrier's channels, with bit 0 set in
47% of its samples. Its low bits are fully exercised, which makes it the
hardest realistic false positive; its six channels offer between four and
twelve chance sync runs across ten seconds and not one survives its CRC. The
rest also reject: the carrier with bit 0 randomised, the carrier with its low
byte cleared, white noise over the full 24-bit range, digital silence and a
ramp. The candidate ceiling bounds the one input that is expensive rather
than wrong - a channel whose low bit is set almost everywhere offers a
candidate at nearly every sample - at 4.2ms, and latches a negative verdict
rather than repeating the work next frame. Streams truncated to between 4 KB
and 2 MB were checked against an unpatched build: same warnings, same
parameters, no new "Could not find codec parameters", and a stream cut too
short to finish the scan simply stays "DTS-HD MA".

The scan is skipped unless the samples are stored unshifted: a carrier whose
low bits have been moved is not one Auro could have been written into.

Like the DTS:X detection alongside it, this is reverse engineering rather
than specification. AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree;
upstream has assigned no value for it. Built and run as ffprobe on x86_64
against ffmpeg 8.1.2 with 0005 and 0008 applied first; not built for the
device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 17, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer has been written into the low bits of
the 24-bit PCM samples, so every field a demuxer or parser can read says
plain DTS-HD MA and nothing in the container or the bitstream names Auro. The
side channel only becomes legible once the samples have been reconstructed.
MediaInfoLib reaches the same conclusion from the other direction: its Auro
detection, MediaArea/MediaInfoLib#2531, runs on WAV and raw PCM only, because
those are the cases where it has samples without having to decode.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, and a
few lines above is already where the DTS:X syncword is turned into a profile.
Putting the probe there costs the scan and nothing else - no second decode,
no buffering the caller did not already pay for, no extra pass.

Getting the answer before playback starts took a second change. The probe in
avformat_find_stream_info() does reach this code - sample_fmt and
bits_per_raw_sample are set nowhere else in the DCA parser or decoder, and
ffprobe reports both after find_stream_info alone, even at analyzeduration=0
- but it stops at the first decoded frame, and one frame is 512 samples where
the scan needs several thousand. Measured, that is the whole difference
between "DTS-HD MA" and "DTS-HD MA + Auro-3D" on all six samples below.
has_codec_parameters() already carries a DTS clause for a similar reason
("no decodable DTS frames"), but widening it would make a stream that ends
before the budget report missing parameters, so try_decode_frame() and the
outer read loop each get one condition instead and what a stream reports at
the end is untouched. Only DTS-HD MA pays: anything that is not DTS, or whose
first frame already named DTS:X, drops out there. That is what reaches
passthrough users and the library scanner, neither of which ever decodes a
frame of its own.

The scan follows the Auro-Codec block framing. A block opens with sixteen
consecutive samples whose bit 0 is set; three bit planes of those sixteen
carry the whole header - bit 0 the sync, bit 1 a CRC16-CCITT over all three
bytes of every sample in the block, bit 2 the block length and the number of
low bits borrowed per sample. Sync alone is not evidence, since any channel
throws long runs of set low bits by chance, so a block is believed only once
its stored CRC matches. One valid block is the whole test; the verdict is
then latched for the stream and no later frame pays anything.

Nothing range-checks the length. All 256 codes name a length, 16 to 4096 in
steps of 16 with one code reserved for 1000, and the reference implementation
accepts every one of them; a plausible-looking length is not evidence and an
implausible one is not disqualifying, because the CRC settles it either way.
Sizing follows from the same fact: blocks tile the stream, so a buffer of two
maximum-length blocks holds one whole block whatever phase it starts at. That
is 8192 samples, which is also what the reference detector gives its ring,
~170 ms at 48 kHz, and sixteen frames of the usual 512 - hence the probe
budget.

Both extractions were checked against the reference rather than trusted. The
length code and the stored CRC are read here in the form the commercial
decoder uses, which carries bit 1 through the length arithmetic and masks it
off a step later; over all 65536 inputs that form agrees exactly with reading
the two as the plain bit planes they are.

Measured on seven carriers: the six Auro-3D demo titles available here and
the reference carrier from the Orua-D3 pair, a 96 kHz file whose two active
channels carry Auro and whose third is silent. All six titles are reported as
"DTS-HD MA + Auro-3D" by ffprobe after find_stream_info alone, with no
decoding by the caller; the reference carrier is not in a container and went
through the scan directly. All seven validate a block in the first carrying
channel, each on the first candidate the scan reaches, because blocks tile
the stream and the first sync found is a real block head. Synthetic blocks
built to the framing above are found at every length from 16 to 4096 and at
every phase within the buffer, including a 4096-sample block beginning at
sample 4095 and ending on the buffer's last sample. A full 8192-sample scan
costs 0.04ms, and 0.01ms on material with no Auro layer, which does not offer
it a single candidate. Probing an Auro title costs 0.5ms more than before; a
DTS-HD MA title that is not Auro, which runs the whole budget, costs 1.9ms
more.

Negative controls reject on every channel. The sharpest is the other half of
that same pair - the 5.1 original of the same programme, 24-bit 96 kHz,
correlating 0.87 to 0.93 against the carrier's channels, with bit 0 set in
47% of its samples. Its low bits are fully exercised, which makes it the
hardest realistic false positive; its six channels offer between four and
twelve chance sync runs across ten seconds and not one survives its CRC. The
rest also reject: the carrier with bit 0 randomised, the carrier with its low
byte cleared, white noise over the full 24-bit range, digital silence and a
ramp. The candidate ceiling bounds the one input that is expensive rather
than wrong - a channel whose low bit is set almost everywhere offers a
candidate at nearly every sample - at 4.2ms, and latches a negative verdict
rather than repeating the work next frame. Streams truncated to between 4 KB
and 2 MB were checked against an unpatched build: same warnings, same
parameters, no new "Could not find codec parameters", and a stream cut too
short to finish the scan simply stays "DTS-HD MA".

The scan is skipped unless the samples are stored unshifted: a carrier whose
low bits have been moved is not one Auro could have been written into.

Like the DTS:X detection alongside it, this is reverse engineering rather
than specification. AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree;
upstream has assigned no value for it. Built and run as ffprobe on x86_64
against ffmpeg 8.1.2 with 0005 and 0008 applied first; not built for the
device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 18, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer has been written into the low bits of
the 24-bit PCM samples, so every field a demuxer or parser can read says
plain DTS-HD MA and nothing in the container or the bitstream names Auro. The
side channel only becomes legible once the samples have been reconstructed.
MediaInfoLib reaches the same conclusion from the other direction: its Auro
detection, MediaArea/MediaInfoLib#2531, runs on WAV and raw PCM only, because
those are the cases where it has samples without having to decode.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, and a
few lines above is already where the DTS:X syncword is turned into a profile.
Putting the probe there costs the scan and nothing else - no second decode,
no buffering the caller did not already pay for, no extra pass.

Getting the answer before playback starts took a second change. The probe in
avformat_find_stream_info() does reach this code - sample_fmt and
bits_per_raw_sample are set nowhere else in the DCA parser or decoder, and
ffprobe reports both after find_stream_info alone, even at analyzeduration=0
- but it stops at the first decoded frame, and one frame is 512 samples where
the scan needs several thousand. Measured, that is the whole difference
between "DTS-HD MA" and "DTS-HD MA + Auro-3D" on all six samples below.
has_codec_parameters() already carries a DTS clause for a similar reason
("no decodable DTS frames"), but widening it would make a stream that ends
before the budget report missing parameters, so try_decode_frame() and the
outer read loop each get one condition instead and what a stream reports at
the end is untouched. Only DTS-HD MA pays: anything that is not DTS, or whose
first frame already named DTS:X, drops out there. That is what reaches
passthrough users and the library scanner, neither of which ever decodes a
frame of its own.

The scan follows the Auro-Codec block framing. A block opens with sixteen
consecutive samples whose bit 0 is set; three bit planes of those sixteen
carry the whole header - bit 0 the sync, bit 1 a CRC16-CCITT over all three
bytes of every sample in the block, bit 2 the block length and the number of
low bits borrowed per sample. Sync alone is not evidence, since any channel
throws long runs of set low bits by chance, so a block is believed only once
its stored CRC matches. One valid block is the whole test; the verdict is
then latched for the stream and no later frame pays anything.

Nothing range-checks the length. All 256 codes name a length, 16 to 4096 in
steps of 16 with one code reserved for 1000, and the reference implementation
accepts every one of them; a plausible-looking length is not evidence and an
implausible one is not disqualifying, because the CRC settles it either way.
Sizing follows from the same fact: blocks tile the stream, so a buffer of two
maximum-length blocks holds one whole block whatever phase it starts at. That
is 8192 samples, which is also what the reference detector gives its ring,
~170 ms at 48 kHz, and sixteen frames of the usual 512 - hence the probe
budget.

Both extractions were checked against the reference rather than trusted. The
length code and the stored CRC are read here in the form the commercial
decoder uses, which carries bit 1 through the length arithmetic and masks it
off a step later; over all 65536 inputs that form agrees exactly with reading
the two as the plain bit planes they are.

Measured on seven carriers: the six Auro-3D demo titles available here and
the reference carrier from the Orua-D3 pair, a 96 kHz file whose two active
channels carry Auro and whose third is silent. All six titles are reported as
"DTS-HD MA + Auro-3D" by ffprobe after find_stream_info alone, with no
decoding by the caller; the reference carrier is not in a container and went
through the scan directly. All seven validate a block in the first carrying
channel, each on the first candidate the scan reaches, because blocks tile
the stream and the first sync found is a real block head. Synthetic blocks
built to the framing above are found at every length from 16 to 4096 and at
every phase within the buffer, including a 4096-sample block beginning at
sample 4095 and ending on the buffer's last sample. A full 8192-sample scan
costs 0.04ms, and 0.01ms on material with no Auro layer, which does not offer
it a single candidate. Probing an Auro title costs 0.5ms more than before; a
DTS-HD MA title that is not Auro, which runs the whole budget, costs 1.9ms
more.

Negative controls reject on every channel. The sharpest is the other half of
that same pair - the 5.1 original of the same programme, 24-bit 96 kHz,
correlating 0.87 to 0.93 against the carrier's channels, with bit 0 set in
47% of its samples. Its low bits are fully exercised, which makes it the
hardest realistic false positive; its six channels offer between four and
twelve chance sync runs across ten seconds and not one survives its CRC. The
rest also reject: the carrier with bit 0 randomised, the carrier with its low
byte cleared, white noise over the full 24-bit range, digital silence and a
ramp. The candidate ceiling bounds the one input that is expensive rather
than wrong - a channel whose low bit is set almost everywhere offers a
candidate at nearly every sample - at 4.2ms, and latches a negative verdict
rather than repeating the work next frame. Streams truncated to between 4 KB
and 2 MB were checked against an unpatched build: same warnings, same
parameters, no new "Could not find codec parameters", and a stream cut too
short to finish the scan simply stays "DTS-HD MA".

The scan is skipped unless the samples are stored unshifted: a carrier whose
low bits have been moved is not one Auro could have been written into.

Like the DTS:X detection alongside it, this is reverse engineering rather
than specification. AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree;
upstream has assigned no value for it. Built and run as ffprobe on x86_64
against ffmpeg 8.1.2 with 0005 and 0008 applied first; not built for the
device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 18, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer has been written into the low bits of
the 24-bit PCM samples, so every field a demuxer or parser can read says
plain DTS-HD MA and nothing in the container or the bitstream names Auro. The
side channel only becomes legible once the samples have been reconstructed.
MediaInfoLib reaches the same conclusion from the other direction: its Auro
detection, MediaArea/MediaInfoLib#2531, runs on WAV and raw PCM only, because
those are the cases where it has samples without having to decode.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, and a
few lines above is already where the DTS:X syncword is turned into a profile.
Putting the probe there costs the scan and nothing else - no second decode,
no buffering the caller did not already pay for, no extra pass.

Getting the answer before playback starts took a second change. The probe in
avformat_find_stream_info() does reach this code - sample_fmt and
bits_per_raw_sample are set nowhere else in the DCA parser or decoder, and
ffprobe reports both after find_stream_info alone, even at analyzeduration=0
- but it stops at the first decoded frame, and one frame is 512 samples where
the scan needs several thousand. Measured, that is the whole difference
between "DTS-HD MA" and "DTS-HD MA + Auro-3D" on all six samples below.
has_codec_parameters() already carries a DTS clause for a similar reason
("no decodable DTS frames"), but widening it would make a stream that ends
before the budget report missing parameters, so try_decode_frame() and the
outer read loop each get one condition instead and what a stream reports at
the end is untouched. Only DTS-HD MA pays: anything that is not DTS, or whose
first frame already named DTS:X, drops out there. That is what reaches
passthrough users and the library scanner, neither of which ever decodes a
frame of its own.

The scan follows the Auro-Codec block framing. A block opens with sixteen
consecutive samples whose bit 0 is set; three bit planes of those sixteen
carry the whole header - bit 0 the sync, bit 1 a CRC16-CCITT over all three
bytes of every sample in the block, bit 2 the block length and the number of
low bits borrowed per sample. Sync alone is not evidence, since any channel
throws long runs of set low bits by chance, so a block is believed only once
its stored CRC matches. One valid block is the whole test; the verdict is
then latched for the stream and no later frame pays anything.

Nothing range-checks the length. All 256 codes name a length, 16 to 4096 in
steps of 16 with one code reserved for 1000, and the reference implementation
accepts every one of them; a plausible-looking length is not evidence and an
implausible one is not disqualifying, because the CRC settles it either way.
Sizing follows from the same fact: blocks tile the stream, so a buffer of two
maximum-length blocks holds one whole block whatever phase it starts at. That
is 8192 samples, which is also what the reference detector gives its ring,
~170 ms at 48 kHz, and sixteen frames of the usual 512 - hence the probe
budget.

Both extractions were checked against the reference rather than trusted. The
length code and the stored CRC are read here in the form the commercial
decoder uses, which carries bit 1 through the length arithmetic and masks it
off a step later; over all 65536 inputs that form agrees exactly with reading
the two as the plain bit planes they are.

Measured on seven carriers: the six Auro-3D demo titles available here and
the reference carrier from the Orua-D3 pair, a 96 kHz file whose two active
channels carry Auro and whose third is silent. All six titles are reported as
"DTS-HD MA + Auro-3D" by ffprobe after find_stream_info alone, with no
decoding by the caller; the reference carrier is not in a container and went
through the scan directly. All seven validate a block in the first carrying
channel, each on the first candidate the scan reaches, because blocks tile
the stream and the first sync found is a real block head. Synthetic blocks
built to the framing above are found at every length from 16 to 4096 and at
every phase within the buffer, including a 4096-sample block beginning at
sample 4095 and ending on the buffer's last sample. A full 8192-sample scan
costs 0.04ms, and 0.01ms on material with no Auro layer, which does not offer
it a single candidate. Probing an Auro title costs 0.5ms more than before; a
DTS-HD MA title that is not Auro, which runs the whole budget, costs 1.9ms
more.

Negative controls reject on every channel. The sharpest is the other half of
that same pair - the 5.1 original of the same programme, 24-bit 96 kHz,
correlating 0.87 to 0.93 against the carrier's channels, with bit 0 set in
47% of its samples. Its low bits are fully exercised, which makes it the
hardest realistic false positive; its six channels offer between four and
twelve chance sync runs across ten seconds and not one survives its CRC. The
rest also reject: the carrier with bit 0 randomised, the carrier with its low
byte cleared, white noise over the full 24-bit range, digital silence and a
ramp. The candidate ceiling bounds the one input that is expensive rather
than wrong - a channel whose low bit is set almost everywhere offers a
candidate at nearly every sample - at 4.2ms, and latches a negative verdict
rather than repeating the work next frame. Streams truncated to between 4 KB
and 2 MB were checked against an unpatched build: same warnings, same
parameters, no new "Could not find codec parameters", and a stream cut too
short to finish the scan simply stays "DTS-HD MA".

The scan is skipped unless the samples are stored unshifted: a carrier whose
low bits have been moved is not one Auro could have been written into.

Like the DTS:X detection alongside it, this is reverse engineering rather
than specification. AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree;
upstream has assigned no value for it. Built and run as ffprobe on x86_64
against ffmpeg 8.1.2 with 0005 and 0008 applied first; not built for the
device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 18, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer has been written into the low bits of
the 24-bit PCM samples, so every field a demuxer or parser can read says
plain DTS-HD MA and nothing in the container or the bitstream names Auro. The
side channel only becomes legible once the samples have been reconstructed.
MediaInfoLib reaches the same conclusion from the other direction: its Auro
detection, MediaArea/MediaInfoLib#2531, runs on WAV and raw PCM only, because
those are the cases where it has samples without having to decode.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, and a
few lines above is already where the DTS:X syncword is turned into a profile.
Putting the probe there costs the scan and nothing else - no second decode,
no buffering the caller did not already pay for, no extra pass.

Getting the answer before playback starts took a second change. The probe in
avformat_find_stream_info() does reach this code - sample_fmt and
bits_per_raw_sample are set nowhere else in the DCA parser or decoder, and
ffprobe reports both after find_stream_info alone, even at analyzeduration=0
- but it stops at the first decoded frame, and one frame is 512 samples where
the scan needs several thousand. Measured, that is the whole difference
between "DTS-HD MA" and "DTS-HD MA + Auro-3D" on all six samples below.
has_codec_parameters() already carries a DTS clause for a similar reason
("no decodable DTS frames"), but widening it would make a stream that ends
before the budget report missing parameters, so try_decode_frame() and the
outer read loop each get one condition instead and what a stream reports at
the end is untouched. Only DTS-HD MA pays: anything that is not DTS, or whose
first frame already named DTS:X, drops out there. That is what reaches
passthrough users and the library scanner, neither of which ever decodes a
frame of its own.

The scan follows the Auro-Codec block framing. A block opens with sixteen
consecutive samples whose bit 0 is set; three bit planes of those sixteen
carry the whole header - bit 0 the sync, bit 1 a CRC16-CCITT over all three
bytes of every sample in the block, bit 2 the block length and the number of
low bits borrowed per sample. Sync alone is not evidence, since any channel
throws long runs of set low bits by chance, so a block is believed only once
its stored CRC matches. One valid block is the whole test; the verdict is
then latched for the stream and no later frame pays anything.

Nothing range-checks the length. All 256 codes name a length, 16 to 4096 in
steps of 16 with one code reserved for 1000, and the reference implementation
accepts every one of them; a plausible-looking length is not evidence and an
implausible one is not disqualifying, because the CRC settles it either way.
Sizing follows from the same fact: blocks tile the stream, so a buffer of two
maximum-length blocks holds one whole block whatever phase it starts at. That
is 8192 samples, which is also what the reference detector gives its ring,
~170 ms at 48 kHz, and sixteen frames of the usual 512 - hence the probe
budget.

Both extractions were checked against the reference rather than trusted. The
length code and the stored CRC are read here in the form the commercial
decoder uses, which carries bit 1 through the length arithmetic and masks it
off a step later; over all 65536 inputs that form agrees exactly with reading
the two as the plain bit planes they are.

Measured on seven carriers: the six Auro-3D demo titles available here and
the reference carrier from the Orua-D3 pair, a 96 kHz file whose two active
channels carry Auro and whose third is silent. All six titles are reported as
"DTS-HD MA + Auro-3D" by ffprobe after find_stream_info alone, with no
decoding by the caller; the reference carrier is not in a container and went
through the scan directly. All seven validate a block in the first carrying
channel, each on the first candidate the scan reaches, because blocks tile
the stream and the first sync found is a real block head. Synthetic blocks
built to the framing above are found at every length from 16 to 4096 and at
every phase within the buffer, including a 4096-sample block beginning at
sample 4095 and ending on the buffer's last sample. A full 8192-sample scan
costs 0.04ms, and 0.01ms on material with no Auro layer, which does not offer
it a single candidate. Probing an Auro title costs 0.5ms more than before; a
DTS-HD MA title that is not Auro, which runs the whole budget, costs 1.9ms
more.

Negative controls reject on every channel. The sharpest is the other half of
that same pair - the 5.1 original of the same programme, 24-bit 96 kHz,
correlating 0.87 to 0.93 against the carrier's channels, with bit 0 set in
47% of its samples. Its low bits are fully exercised, which makes it the
hardest realistic false positive; its six channels offer between four and
twelve chance sync runs across ten seconds and not one survives its CRC. The
rest also reject: the carrier with bit 0 randomised, the carrier with its low
byte cleared, white noise over the full 24-bit range, digital silence and a
ramp. The candidate ceiling bounds the one input that is expensive rather
than wrong - a channel whose low bit is set almost everywhere offers a
candidate at nearly every sample - at 4.2ms, and latches a negative verdict
rather than repeating the work next frame. Streams truncated to between 4 KB
and 2 MB were checked against an unpatched build: same warnings, same
parameters, no new "Could not find codec parameters", and a stream cut too
short to finish the scan simply stays "DTS-HD MA".

The scan is skipped unless the samples are stored unshifted: a carrier whose
low bits have been moved is not one Auro could have been written into.

Like the DTS:X detection alongside it, this is reverse engineering rather
than specification. AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree;
upstream has assigned no value for it. Built and run as ffprobe on x86_64
against ffmpeg 8.1.2 with 0005 and 0008 applied first; not built for the
device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 18, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer is written into the low bits of the
24-bit PCM samples, so every field a demuxer can read says plain DTS-HD MA and
the side channel is only legible once the samples are reconstructed. That is
also why MediaInfoLib's own Auro detection, MediaArea/MediaInfoLib#2531, runs
on WAV and raw PCM only.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, a few
lines below where the DTS:X syncword becomes a profile, so the probe costs the
scan and nothing else. Getting the answer before playback took a second
change: find_stream_info() reaches this code but stops at the first decoded
frame, and one frame is 512 samples where the scan needs several thousand.
Widening has_codec_parameters() would make a stream that ends early report
missing parameters, so try_decode_frame() and the outer read loop each get one
condition instead. Only DTS-HD MA pays, and that is what reaches passthrough
users and the library scanner, neither of which decodes a frame.

A block opens with sixteen samples whose bit 0 is set, and three bit planes of
those sixteen are its header: bit 0 the sync, bit 1 a CRC16-CCITT over the
block, bit 2 its length and the low bits per sample the side channel borrows.
Sync alone is not evidence, so a block is believed only once its stored CRC
matches; one valid block is the whole test and the verdict is then latched.

The layout goes in the level, where 0008 already puts the DTS:X object count
and for the same reason: it says which variant of a codec, not which codec, so
every consumer that enumerates the DTS-HD MA family by profile goes on seeing
what it saw. Reading it walks the payload bit planes to ADOL instruction 0x1E,
which announces the channel-input configuration, after checking the reserved
bit every 16*m positions is clear. What lands in the level is the mask of
streams that configuration places - bit 3 the LFE, bits 9 to 14 the heights,
the rest the floor - so its population count is the channel count and the name
a listener uses is arithmetic on the same mask. Neither is derived here.

Measured on seven carriers: six Auro-3D demo titles and the reference carrier
from the Orua-D3 pair. All six titles report "DTS-HD MA + Auro-3D" after
find_stream_info alone with nothing decoded by the caller, all seven validate
on the first candidate reached, and every recovered layout matches the
independent reference parser - 32319 for the four 11.1 titles, 26175 for the
two 9.1 ones, and 63 for the reference carrier, which wraps a 5.1 original
with no height layer and so names no presentation.

Negative controls reject on every channel: the 5.1 original of the same
programme as that carrier (24-bit 96 kHz, bit 0 set in 47% of its samples, and
not one of its chance sync runs survives its CRC), the carrier with bit 0
randomised, the carrier with its low byte cleared, white noise, digital
silence and a ramp. Streams truncated between 4 KB and 2 MB were checked
against an unpatched build: no new warnings, and a stream too short to finish
the scan stays "DTS-HD MA".

Like the DTS:X detection alongside it this is reverse engineering rather than
specification, and AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree. Built
and run as ffprobe on x86_64 against ffmpeg 8.1.2 with 0005 and 0008 applied
first; not built for the device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 18, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer is written into the low bits of the
24-bit PCM samples, so every field a demuxer can read says plain DTS-HD MA and
the side channel is only legible once the samples are reconstructed. That is
also why MediaInfoLib's own Auro detection, MediaArea/MediaInfoLib#2531, runs
on WAV and raw PCM only.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, a few
lines below where the DTS:X syncword becomes a profile, so the probe costs the
scan and nothing else. Getting the answer before playback took a second
change: find_stream_info() reaches this code but stops at the first decoded
frame, and one frame is 512 samples where the scan needs several thousand.
Widening has_codec_parameters() would make a stream that ends early report
missing parameters, so try_decode_frame() and the outer read loop each get one
condition instead. Only DTS-HD MA pays, and that is what reaches passthrough
users and the library scanner, neither of which decodes a frame.

A block opens with sixteen samples whose bit 0 is set, and three bit planes of
those sixteen are its header: bit 0 the sync, bit 1 a CRC16-CCITT over the
block, bit 2 its length and the low bits per sample the side channel borrows.
Sync alone is not evidence, so a block is believed only once its stored CRC
matches; one valid block is the whole test and the verdict is then latched.

The layout goes in the level, where 0008 already puts the DTS:X object count
and for the same reason: it says which variant of a codec, not which codec, so
every consumer that enumerates the DTS-HD MA family by profile goes on seeing
what it saw. Reading it walks the payload bit planes to ADOL instruction 0x1E,
which announces the channel-input configuration, after checking the reserved
bit every 16*m positions is clear. What lands in the level is the mask of
streams that configuration places - bit 3 the LFE, bits 9 to 14 the heights,
the rest the floor - so its population count is the channel count and the name
a listener uses is arithmetic on the same mask. Neither is derived here.

Measured on seven carriers: six Auro-3D demo titles and the reference carrier
from the Orua-D3 pair. All six titles report "DTS-HD MA + Auro-3D" after
find_stream_info alone with nothing decoded by the caller, all seven validate
on the first candidate reached, and every recovered layout matches the
independent reference parser - 32319 for the four 11.1 titles, 26175 for the
two 9.1 ones, and 63 for the reference carrier, which wraps a 5.1 original
with no height layer and so names no presentation.

Negative controls reject on every channel: the 5.1 original of the same
programme as that carrier (24-bit 96 kHz, bit 0 set in 47% of its samples, and
not one of its chance sync runs survives its CRC), the carrier with bit 0
randomised, the carrier with its low byte cleared, white noise, digital
silence and a ramp. Streams truncated between 4 KB and 2 MB were checked
against an unpatched build: no new warnings, and a stream too short to finish
the scan stays "DTS-HD MA".

Like the DTS:X detection alongside it this is reverse engineering rather than
specification, and AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree. Built
and run as ffprobe on x86_64 against ffmpeg 8.1.2 with 0005 and 0008 applied
first; not built for the device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 18, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer is written into the low bits of the
24-bit PCM samples, so every field a demuxer can read says plain DTS-HD MA and
the side channel is only legible once the samples are reconstructed. That is
also why MediaInfoLib's own Auro detection, MediaArea/MediaInfoLib#2531, runs
on WAV and raw PCM only.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, a few
lines below where the DTS:X syncword becomes a profile, so the probe costs the
scan and nothing else. Getting the answer before playback took a second
change: find_stream_info() reaches this code but stops at the first decoded
frame, and one frame is 512 samples where the scan needs several thousand.
Widening has_codec_parameters() would make a stream that ends early report
missing parameters, so try_decode_frame() and the outer read loop each get one
condition instead. Only DTS-HD MA pays, and that is what reaches passthrough
users and the library scanner, neither of which decodes a frame.

A block opens with sixteen samples whose bit 0 is set, and three bit planes of
those sixteen are its header: bit 0 the sync, bit 1 a CRC16-CCITT over the
block, bit 2 its length and the low bits per sample the side channel borrows.
Sync alone is not evidence and neither is the CRC behind it - sixteen bits
each, which a long enough run of candidates satisfies by chance - so a block is
believed only once it also reads as one: CRC matched and bytecode walked to its
end. One such block is the whole test and the verdict is then latched.

The layout goes in the level, where 0008 already puts the DTS:X object count
and for the same reason: it says which variant of a codec, not which codec, so
every consumer that enumerates the DTS-HD MA family by profile goes on seeing
what it saw. Reading it walks the payload bit planes to ADOL instruction 0x1E,
which announces the channel-input configuration, after checking the reserved
bit every 16*m positions is clear. What lands in the level is the mask of
streams that configuration places - bit 3 the LFE, bits 9 to 14 the heights,
the rest the floor - so its population count is the channel count and the name
a listener uses is arithmetic on the same mask. Neither is derived here.

Measured on seven carriers: six Auro-3D demo titles and the reference carrier
from the Orua-D3 pair. All six titles report "DTS-HD MA + Auro-3D" after
find_stream_info alone with nothing decoded by the caller, all seven validate
on the first candidate reached, and every recovered layout matches the
independent reference parser - 32319 for the four 11.1 titles, 26175 for the
two 9.1 ones, and 63 for the reference carrier, which wraps a 5.1 original
with no height layer and so names no presentation.

Negative controls reject on every channel: the 5.1 original of the same
programme as that carrier (24-bit 96 kHz, bit 0 set in 47% of its samples, and
not one of its chance sync runs survives its CRC), the carrier with bit 0
randomised, the carrier with its low byte cleared, white noise, digital
silence, a ramp, and the constant -8354511 - the one input here whose sixteen
sample window satisfies both the sync and the CRC, and which the walk then
rejects. 20000 random buffers with bit 0 set throughout were swept as well, and
none is accepted. Streams truncated between 4 KB and 2 MB were checked
against an unpatched build: no new warnings, and a stream too short to finish
the scan stays "DTS-HD MA".

Like the DTS:X detection alongside it this is reverse engineering rather than
specification, and AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree. Built
and run as ffprobe on x86_64 against ffmpeg 8.1.2 with 0005 and 0008 applied
first; not built for the device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 18, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer is written into the low bits of the
24-bit PCM samples, so every field a demuxer can read says plain DTS-HD MA and
the side channel is only legible once the samples are reconstructed. That is
also why MediaInfoLib's own Auro detection, MediaArea/MediaInfoLib#2531, runs
on WAV and raw PCM only.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, a few
lines below where the DTS:X syncword becomes a profile, so the probe costs the
scan and nothing else. Getting the answer before playback took a second
change: find_stream_info() reaches this code but stops at the first decoded
frame, and one frame is 512 samples where the scan needs several thousand.
Widening has_codec_parameters() would make a stream that ends early report
missing parameters, so try_decode_frame() and the outer read loop each get one
condition instead. Only DTS-HD MA pays, and that is what reaches passthrough
users and the library scanner, neither of which decodes a frame.

A block opens with sixteen samples whose bit 0 is set, and three bit planes of
those sixteen are its header: bit 0 the sync, bit 1 a CRC16-CCITT over the
block, bit 2 its length and the low bits per sample the side channel borrows.
Sync alone is not evidence and neither is the CRC behind it - sixteen bits
each, which a long enough run of candidates satisfies by chance - so a block is
believed only once it also reads as one: CRC matched and bytecode walked to its
end. One such block is the whole test and the verdict is then latched.

The layout goes in the level, where 0008 already puts the DTS:X object count
and for the same reason: it says which variant of a codec, not which codec, so
every consumer that enumerates the DTS-HD MA family by profile goes on seeing
what it saw. Reading it walks the payload bit planes to ADOL instruction 0x1E,
which announces the channel-input configuration, after checking the reserved
bit every 16*m positions is clear. What lands in the level is the mask of
streams that configuration places - bit 3 the LFE, bits 9 to 14 the heights,
the rest the floor - so its population count is the channel count and the name
a listener uses is arithmetic on the same mask. Neither is derived here.

Measured on seven carriers: six Auro-3D demo titles and the reference carrier
from the Orua-D3 pair. All six titles report "DTS-HD MA + Auro-3D" after
find_stream_info alone with nothing decoded by the caller, all seven validate
on the first candidate reached, and every recovered layout matches the
independent reference parser - 32319 for the four 11.1 titles, 26175 for the
two 9.1 ones, and 63 for the reference carrier, which wraps a 5.1 original
with no height layer and so names no presentation.

Negative controls reject on every channel: the 5.1 original of the same
programme as that carrier (24-bit 96 kHz, bit 0 set in 47% of its samples, and
not one of its chance sync runs survives its CRC), the carrier with bit 0
randomised, the carrier with its low byte cleared, white noise, digital
silence, a ramp, and the constant -8354511 - the one input here whose sixteen
sample window satisfies both the sync and the CRC, and which the walk then
rejects. 20000 random buffers with bit 0 set throughout were swept as well, and
none is accepted. Streams truncated between 4 KB and 2 MB were checked
against an unpatched build: no new warnings, and a stream too short to finish
the scan stays "DTS-HD MA".

Like the DTS:X detection alongside it this is reverse engineering rather than
specification, and AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree. Built
and run as ffprobe on x86_64 against ffmpeg 8.1.2 with 0005 and 0008 applied
first; not built for the device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 24, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer is written into the low bits of the
24-bit PCM samples, so every field a demuxer can read says plain DTS-HD MA and
the side channel is only legible once the samples are reconstructed. That is
also why MediaInfoLib's own Auro detection, MediaArea/MediaInfoLib#2531, runs
on WAV and raw PCM only.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, a few
lines below where the DTS:X syncword becomes a profile, so the probe costs the
scan and nothing else. Getting the answer before playback took a second
change: find_stream_info() reaches this code but stops at the first decoded
frame, and one frame is 512 samples where the scan needs several thousand.
Widening has_codec_parameters() would make a stream that ends early report
missing parameters, so try_decode_frame() and the outer read loop each get one
condition instead. Only DTS-HD MA pays, and that is what reaches passthrough
users and the library scanner, neither of which decodes a frame.

A block opens with sixteen samples whose bit 0 is set, and three bit planes of
those sixteen are its header: bit 0 the sync, bit 1 a CRC16-CCITT over the
block, bit 2 its length and the low bits per sample the side channel borrows.
Sync alone is not evidence and neither is the CRC behind it - sixteen bits
each, which a long enough run of candidates satisfies by chance - so a block is
believed only once it also reads as one: CRC matched and bytecode walked to its
end. One such block is the whole test and the verdict is then latched.

The layout goes in the level, where 0008 already puts the DTS:X object count
and for the same reason: it says which variant of a codec, not which codec, so
every consumer that enumerates the DTS-HD MA family by profile goes on seeing
what it saw. Reading it walks the payload bit planes to ADOL instruction 0x1E,
which announces the channel-input configuration, after checking the reserved
bit every 16*m positions is clear. What lands in the level is the mask of
streams that configuration places - bit 3 the LFE, bits 9 to 14 the heights,
the rest the floor - so its population count is the channel count and the name
a listener uses is arithmetic on the same mask. Neither is derived here.

Measured on seven carriers: six Auro-3D demo titles and the reference carrier
from the Orua-D3 pair. All six titles report "DTS-HD MA + Auro-3D" after
find_stream_info alone with nothing decoded by the caller, all seven validate
on the first candidate reached, and every recovered layout matches the
independent reference parser - 32319 for the four 11.1 titles, 26175 for the
two 9.1 ones, and 63 for the reference carrier, which wraps a 5.1 original
with no height layer and so names no presentation.

Negative controls reject on every channel: the 5.1 original of the same
programme as that carrier (24-bit 96 kHz, bit 0 set in 47% of its samples, and
not one of its chance sync runs survives its CRC), the carrier with bit 0
randomised, the carrier with its low byte cleared, white noise, digital
silence, a ramp, and the constant -8354511 - the one input here whose sixteen
sample window satisfies both the sync and the CRC, and which the walk then
rejects. 20000 random buffers with bit 0 set throughout were swept as well, and
none is accepted. Streams truncated between 4 KB and 2 MB were checked
against an unpatched build: no new warnings, and a stream too short to finish
the scan stays "DTS-HD MA".

Like the DTS:X detection alongside it this is reverse engineering rather than
specification, and AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree. Built
and run as ffprobe on x86_64 against ffmpeg 8.1.2 with 0005 and 0008 applied
first; not built for the device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 24, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer is written into the low bits of the
24-bit PCM samples, so every field a demuxer can read says plain DTS-HD MA and
the side channel is only legible once the samples are reconstructed. That is
also why MediaInfoLib's own Auro detection, MediaArea/MediaInfoLib#2531, runs
on WAV and raw PCM only.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, a few
lines below where the DTS:X syncword becomes a profile, so the probe costs the
scan and nothing else. Getting the answer before playback took a second
change: find_stream_info() reaches this code but stops at the first decoded
frame, and one frame is 512 samples where the scan needs several thousand.
Widening has_codec_parameters() would make a stream that ends early report
missing parameters, so try_decode_frame() and the outer read loop each get one
condition instead. Only DTS-HD MA pays, and that is what reaches passthrough
users and the library scanner, neither of which decodes a frame.

A block opens with sixteen samples whose bit 0 is set, and three bit planes of
those sixteen are its header: bit 0 the sync, bit 1 a CRC16-CCITT over the
block, bit 2 its length and the low bits per sample the side channel borrows.
Sync alone is not evidence and neither is the CRC behind it - sixteen bits
each, which a long enough run of candidates satisfies by chance - so a block is
believed only once it also reads as one: CRC matched and bytecode walked to its
end. One such block is the whole test and the verdict is then latched.

The layout goes in the level, where 0008 already puts the DTS:X object count
and for the same reason: it says which variant of a codec, not which codec, so
every consumer that enumerates the DTS-HD MA family by profile goes on seeing
what it saw. Reading it walks the payload bit planes to ADOL instruction 0x1E,
which announces the channel-input configuration, after checking the reserved
bit every 16*m positions is clear. What lands in the level is the mask of
streams that configuration places - bit 3 the LFE, bits 9 to 14 the heights,
the rest the floor - so its population count is the channel count and the name
a listener uses is arithmetic on the same mask. Neither is derived here.

Measured on seven carriers: six Auro-3D demo titles and the reference carrier
from the Orua-D3 pair. All six titles report "DTS-HD MA + Auro-3D" after
find_stream_info alone with nothing decoded by the caller, all seven validate
on the first candidate reached, and every recovered layout matches the
independent reference parser - 32319 for the four 11.1 titles, 26175 for the
two 9.1 ones, and 63 for the reference carrier, which wraps a 5.1 original
with no height layer and so names no presentation.

Negative controls reject on every channel: the 5.1 original of the same
programme as that carrier (24-bit 96 kHz, bit 0 set in 47% of its samples, and
not one of its chance sync runs survives its CRC), the carrier with bit 0
randomised, the carrier with its low byte cleared, white noise, digital
silence, a ramp, and the constant -8354511 - the one input here whose sixteen
sample window satisfies both the sync and the CRC, and which the walk then
rejects. 20000 random buffers with bit 0 set throughout were swept as well, and
none is accepted. Streams truncated between 4 KB and 2 MB were checked
against an unpatched build: no new warnings, and a stream too short to finish
the scan stays "DTS-HD MA".

Like the DTS:X detection alongside it this is reverse engineering rather than
specification, and AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree. Built
and run as ffprobe on x86_64 against ffmpeg 8.1.2 with 0005 and 0008 applied
first; not built for the device.
v-lix added a commit to v-lix/CoreELEC that referenced this pull request Sep 24, 2026
Auro-3D does not extend the bitstream. An Auro title is an ordinary 5.1 or
7.1 DTS-HD MA stream whose height layer is written into the low bits of the
24-bit PCM samples, so every field a demuxer can read says plain DTS-HD MA and
the side channel is only legible once the samples are reconstructed. That is
also why MediaInfoLib's own Auro detection, MediaArea/MediaInfoLib#2531, runs
on WAV and raw PCM only.

Reconstructed samples are what ff_dca_xll_filter_frame() already holds, a few
lines below where the DTS:X syncword becomes a profile, so the probe costs the
scan and nothing else. Getting the answer before playback took a second
change: find_stream_info() reaches this code but stops at the first decoded
frame, and one frame is 512 samples where the scan needs several thousand.
Widening has_codec_parameters() would make a stream that ends early report
missing parameters, so try_decode_frame() and the outer read loop each get one
condition instead. Only DTS-HD MA pays, and that is what reaches passthrough
users and the library scanner, neither of which decodes a frame.

A block opens with sixteen samples whose bit 0 is set, and three bit planes of
those sixteen are its header: bit 0 the sync, bit 1 a CRC16-CCITT over the
block, bit 2 its length and the low bits per sample the side channel borrows.
Sync alone is not evidence and neither is the CRC behind it - sixteen bits
each, which a long enough run of candidates satisfies by chance - so a block is
believed only once it also reads as one: CRC matched and bytecode walked to its
end. One such block is the whole test and the verdict is then latched.

The layout goes in the level, where 0008 already puts the DTS:X object count
and for the same reason: it says which variant of a codec, not which codec, so
every consumer that enumerates the DTS-HD MA family by profile goes on seeing
what it saw. Reading it walks the payload bit planes to ADOL instruction 0x1E,
which announces the channel-input configuration, after checking the reserved
bit every 16*m positions is clear. What lands in the level is the mask of
streams that configuration places - bit 3 the LFE, bits 9 to 14 the heights,
the rest the floor - so its population count is the channel count and the name
a listener uses is arithmetic on the same mask. Neither is derived here.

Measured on seven carriers: six Auro-3D demo titles and the reference carrier
from the Orua-D3 pair. All six titles report "DTS-HD MA + Auro-3D" after
find_stream_info alone with nothing decoded by the caller, all seven validate
on the first candidate reached, and every recovered layout matches the
independent reference parser - 32319 for the four 11.1 titles, 26175 for the
two 9.1 ones, and 63 for the reference carrier, which wraps a 5.1 original
with no height layer and so names no presentation.

Negative controls reject on every channel: the 5.1 original of the same
programme as that carrier (24-bit 96 kHz, bit 0 set in 47% of its samples, and
not one of its chance sync runs survives its CRC), the carrier with bit 0
randomised, the carrier with its low byte cleared, white noise, digital
silence, a ramp, and the constant -8354511 - the one input here whose sixteen
sample window satisfies both the sync and the CRC, and which the walk then
rejects. 20000 random buffers with bit 0 set throughout were swept as well, and
none is accepted. Streams truncated between 4 KB and 2 MB were checked
against an unpatched build: no new warnings, and a stream too short to finish
the scan stays "DTS-HD MA".

Like the DTS:X detection alongside it this is reverse engineering rather than
specification, and AV_PROFILE_DTS_HD_MA_AURO3D is local to this tree. Built
and run as ffprobe on x86_64 against ffmpeg 8.1.2 with 0005 and 0008 applied
first; not built for the device.
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.

4 participants