touch MAX

получи максимум — личный блог "тыж программиста"

DTS изнутри: где в DTS-HD MA спрятаны высотные каналы и объекты

Когда MediaInfo показывает у дорожки DTS:X:

C L R LFE Lb Rb Lss Rss Objects

легко представить обычные восемь каналов и ещё один таинственный канал Objects.

Но никакого девятого PCM-канала Objects в потоке нет.

Обычный DTS-HD-декодер действительно получает совместимый 5.1/7.1. Современный ресивер из той же самой дорожки способен собрать 7.1.4 с отдельными верхними каналами. А слово Objects в MediaInfo — прежде всего признак того, что внутри DTS-потока обнаружено расширение DTS:X, а не количество объектов и не отдельная звуковая дорожка.

Тогда возникают три вопроса:

  • где физически лежат четыре высотных канала;
  • как динамический объект узнаёт, куда ему двигаться;
  • почему старый ресивер не теряет эту часть фонограммы, хотя ничего не знает о DTS:X.

Я уже разбирал похожий трюк у Auro-3D, где классический Auro-Codec использует младшие биты 24-битного PCM как side-channel. У DTS:X архитектура принципиально другая.

Здесь есть DTS Core, поверх него ExSS/XLL — тот самый тракт DTS-HD Master Audio, — а внутри расширений находятся дополнительные lossless-waveforms, матрицы сведения, приватная навигация, presentations и пространственные метаданные.

Официальной публичной спецификации, полностью описывающей consumer DTS:X object layer, практически нет. Есть ETSI-документы по DTS Core/Extensions и отдельно по DTS-UHD, маркетинговые материалы и сторонние реконструкции.

Поэтому путь исследования получился таким:

тестовые DTS:X / Blu-ray дорожки
        ↓
MediaInfo / FFmpeg
        ↓
разбор Core / ExSS / XLL
        ↓
декомпиляция libdtsx
        ↓
сверка с ETSI
        ↓
собственный C++ decoder / renderer

Ниже — устройство legacy DTS:X, то есть варианта, который обычно встречается на Blu-ray, в MKV/M2TS и .dtshd как DTS-HD MA + DTS:X.

Более новый DTS-UHD / ACE / P2, часто встречающийся в MP4, использует другую framing-модель и здесь подробно не рассматривается.


DTS:X — не просто «объектный кодек»

На диске DTS:X не заменяет DTS-HD Master Audio, а идет поверх него.

Упрощённо структура выглядит так:

DTS Core
  └─ базовый совместимый звук

ExSS (Extension Substream)
  ├─ DTS-HD / XLL: lossless channel bed
  ├─ дополнительные XLL waveforms
  ├─ combined-mix / downmix matrices
  ├─ private navigation
  └─ presentations + spatial object metadata

Core обеспечивает обратную совместимость с совсем старыми DTS-декодерами.

ExSS добавляет расширения.

XLL — DTS-HD Lossless — восстанавливает PCM без потерь.

DTS:X использует эту уже существующую матрёшку и добавляет внутрь неё собственный пространственный слой.

Поэтому формулировка «DTS:X — объектный кодек» слишком упрощённая.

В одном потоке одновременно могут находиться:

  1. совместимое канальное представление;
  2. основной channel bed, например 7.1;
  3. дополнительные аудио-waveforms;
  4. фиксированные высотные назначения;
  5. динамические объекты;
  6. их координаты и gain;
  7. правила сведения в конкретный speaker layout.

Типичные домашние раскладки:

5.1.2
5.1.4
7.1.2
7.1.4

Что на самом деле означает Objects в MediaInfo

Типичная строка:

C L R LFE Lb Rb Lss Rss Objects

не означает:

  • восемь bed-каналов плюс девятый PCM-канал;
  • один объект;
  • четыре height-канала;
  • наличие доступных object stems;
  • конкретный выходной layout.

В исследованных legacy-файлах основной XLL bed выглядел как два channel set:

6 + 2

то есть восемь декодированных каналов.

Activity mask:

0x84B

соответствует:

C L R LFE Lb Rb Lss Rss

и сам по себе физических height-каналов не содержит.

MediaInfo сейчас добавляет Objects (даже если их там нет), когда распознаёт внутренние признаки DTS:X — например сигнатуры семейства:

0x02000850
0xF14000D0
0xF14000D1
0xF14000D4

Но это эвристика наличия расширения.

Поэтому запись, которую пользователь воспринимает как «DTS:X 7.1.4», физически может выглядеть примерно так:

совместимый DTS-HD MA 7.1 bed
        +
supplemental / object data внутри ExSS
        ↓
DTS:X decoder
        ↓
7.1.4

Без правильного DTS:X parser/renderer виден только нижний совместимый слой.


Ложный след: 02 00 08 50

Одной из первых зацепок при разборе была последовательность байтов:

02 00 08 50

Она встречается в DTS:X-потоках и используется некоторыми анализаторами как один из признаков формата.

Естественная первая гипотеза: перед нами sync word отдельного object extension.

Она оказалась неправильной.

В тестовом первом ExSS-кадре:

  • XLL начинался примерно на offset 40;
  • его размер составлял 132 байта;
  • последовательность находилась на offset 84 внутри области XLL.

Разбор private navigation показал, что:

02 00 08 50 28

— это короткий embedded raw metadata chunk: element header, payload и CRC.

То есть это не новый аудиоканал и не самостоятельная структурная граница после XLL.

Декомпилированный native parser дополнительно показал интересную особенность: descriptor содержит размеры и типы associated chunks, а код при разборе некоторых navigation fields временно читает данные дальше формальной границы descriptor, после чего возвращает bit cursor назад.

Если буквально соблюдать только очевидную границу descriptor, дополнительные channel set остаются невидимыми.

Это хороший пример того, почему reverse engineering бинарных форматов нельзя строить только на поиске «магических байтов»:

нашли похожую сигнатуру
        ≠
нашли начало самостоятельного блока

Сначала нужно восстановить границы ExSS asset, XLL frame, navigation и association table — и только затем интерпретировать payload.


Где физически находятся высотные каналы

В стандартном исследованном legacy DTS:X 7.1.4 основной XLL asset содержит только 7.1 bed.

Четыре недостающих канала нашлись в associated private data ExSS.

Внутри находятся полноценные дополнительные XLL channel-set bitstreams, которые декодируются отдельно от основного 6+2 bed.

Их порядок:

TFL  TFR  TBL  TBR

То есть:

  • Top Front Left;
  • Top Front Right;
  • Top Back Left;
  • Top Back Right.

Статические направления, восстановленные из нативного тракта:

КаналAzimuthElevation
TFL−45°45°
TFR+45°45°
TBL−135°45°
TBR+135°45°

Внутренний associated chunk этого пути имеет тип 69.

Для пользователя число 69 само по себе ничего не значит. Для parser это важная навигационная метка: здесь находится не случайный payload, а дополнительный XLL bitstream.

На тестовом DTS-X 7.1.4.mkv было найдено около 3977 supplemental XLL channel-set headers/frames.

Они:

  • проходили native CRC;
  • описывали четыре канала @ 48 kHz;
  • декодировались независимо от основного 7.1;
  • содержали реальные последовательные height callout’ы.

Иными словами, в таком legacy DTS:X высота не угадывается апмиксером.

Она существует как отдельный lossless waveform внутри расширения DTS-HD.


Почему старый ресивер всё равно слышит высотные звуки

Здесь начинается наиболее интересная инженерная часть DTS:X.

Представим, что height-сигнал хранился бы исключительно внутри расширения.

Тогда DTS-HD-ресивер без поддержки DTS:X просто потерял бы часть фонограммы.

Поэтому энкодер заранее создаёт совместимый bed, куда дополнительный материал уже подмешан.

То есть аппарат без DTS:X получает нормальный 7.1 и слышит всю программу, но без точного вертикального разделения.

Схема:

без DTS:X decoder
        ↓
DTS-HD MA 7.1
с уже подмешанным height/object content

А DTS:X-декодер делает дополнительную работу:

compatible bed с fold-down
        +
supplemental waveforms
        +
authored mix matrix
        ↓
очищенный floor bed
        +
дискретный upper/object layer

Это принципиально.

Нельзя просто:

  1. декодировать DTS-HD в 7.1 через обычный FFmpeg;
  2. найти похожий сигнал;
  3. скопировать его в TFL/TFR/TBL/TBR.

В таком случае высотный материал останется и в нижних колонках, и в верхних одновременно.

DTS:X decoder должен не только получить дополнительный waveform, но и отменить его исходный fold-down в bed.


Combined-mix matrix: как высота была спрятана в 7.1

Рядом с дополнительными waveforms находится authored combined-mix metadata.

В исследованном потоке это путь с matrix chunk type 2.

Он сообщает декодеру, как дополнительный сигнал был встроен в совместимое представление.

Для тестового 7.1.4 коэффициент fold-down высоты в соответствующий bed-канал составил примерно:

0.707092

то есть около:

−3.01 dB

Схематично энкодер может сделать:

compatible_FL =
    original_FL
    + 0.707092 × TFL

А DTS:X decoder выполняет обратную операцию:

original_FL =
    compatible_FL
    − 0.707092 × TFL

В реальном потоке всё, разумеется, многоканальное:

bed_ref_j += Σ g_ij × height_i

а при декодировании:

bed_j =
    compatible_bed_j
    − Σ g_ij × decoded_height_i

Таким образом, DTS:X передаёт одновременно:

  • дополнительный waveform;
  • информацию о том, куда он был подмешан;
  • коэффициенты этого подмешивания.



После правильного unmix нижний слой очищался, а отдельные height-каналы оставались независимыми.

Именно поэтому этот механизм нельзя путать с обычным matrix upmix.

Decoder не пытается статистически решить, «какая часть сигнала, вероятно, относится к потолку».

У него уже есть authored waveform и authored matrix.


А где же настоящие объекты

Фиксированные TFL/TFR/TBL/TBR — это ещё не вся DTS:X.

В других потоках, в частности в исследованных материалах DTS:X Pro / Trinnov, существует полноценный object path.

В associated data встречаются вложенные object-XLL bitstreams.

В разных вариантах reverse-engineered path обнаруживаются association/chunk types семейства 65/68; в исследованных Trinnov-потоках основной nested object-XLL path использовал type 68.

А metadata/presentation blocks, в том числе type 241, связывают:

object ID
    ↓
waveform ID
    ↓
spatial metadata

То есть объект — это не просто координата.

У него есть собственный аудиосигнал и временная пространственная траектория.

В metadata удалось восстановить:

  • azimuth;
  • elevation;
  • distance;
  • gain;
  • point / extended source;
  • width;
  • height;
  • rotation;
  • snap;
  • coherent / non-coherent rendering;
  • обновления параметров во времени.

Координаты в native code представлены довольно компактно.

Для azimuth и elevation используется преобразование порядка:

angle = code × 0.5°

Distance масштабируется в единицах:

1 / 64

при этом stored code 1 используется как специальное представление нулевой дистанции.

В одном из внутренних режимов из-за кодирования metadata фактический шаг между соседними передаваемыми направлениями может получаться крупнее базового полуградусного unit.


Как объект превращается в звук колонок

Сам waveform обычно монофонический.

Рядом с ним существует timeline пространственных параметров:

object waveform
        +
position / extent / gain timeline
        ↓
renderer
        ↓
speaker gain matrix
        ↓
FL FR C ... TFL TFR TBL TBR

Renderer определяет вклад объекта в каждую destination speaker.

Gain плавно интерполируется между metadata updates, поэтому движущийся объект не прыгает ступенями от колонки к колонке.

В исследованных Trinnov-потоках удалось восстановить:

  • пять динамических объектов;
  • девять вложенных XLL waveforms на ExSS frame.

Waveforms можно сохранять отдельно как mono WAV, а координаты — в JSONL.

Это уже принципиально отличается от попыток «выделить объект» из готового PCM с помощью source separation.

Здесь звуковой сигнал извлекается до object renderer.


Reverse-render: почему объект нельзя просто добавить к bed

У динамических объектов возникает та же проблема обратной совместимости, что и у фиксированных heights.

Если объект должен быть слышен на старом DTS-HD decoder, его вклад уже может присутствовать в compatible bed.

Поэтому native object path перед финальным рендером способен выполнять reverse-render:

compatible bed
        −
запечённый contribution объекта
        ↓
clean bed

После этого объект заново отправляется в нужные колонки:

object waveform
        +
current coordinates
        ↓
forward render

Без reverse-render объект мог бы одновременно остаться в совместимом нижнем миксе и появиться повторно в своей новой позиции.


Point source и extended source

Простейший объект — point source.

Для него достаточно направления, distance и gain.

Например, условный вертолёт может двигаться:

−40° спереди слева
        ↓
верх сцены
        ↓
+120° сзади справа

Но DTS:X умеет описывать и extended source.

У него дополнительно есть:

width
height
rotation

То есть звук существует не как идеальная точка, а как пространственная область.

Такое представление естественно для:

  • дождя;
  • толпы;
  • атмосферы помещения;
  • широких музыкальных источников;
  • эффектов, которые не должны схлопываться в одну колонку.

Что происходит при выборе меньшего layout

Допустим, исходный материал позволяет собрать 7.1.4, а пользователь запросил только 5.1.2.

Неправильный подход:

отрендерить 7.1.4
→ удалить лишние каналы

Правильный путь должен учитывать authored hierarchy и downmix rules.

Например, передние heights могут остаться дискретными, а материал отсутствующего заднего upper layer возвращается в доступные каналы с использованием предусмотренной энкодером матрицы.

Поэтому:

7.1.4 → 5.1.2

— это не просто обрезка четырёх каналов до двух.


Иерархический XLL

DTS-HD/XLL сам по себе поддерживает иерархию channel sets.

Первый набор каналов может содержать готовое меньшее представление, а следующие channel set позволяют выполнить inverse downmix и восстановить более полный layout.

Условно:

базовый channel set
        ↓
совместимый layout

+ дополнительные channel sets
        ↓
inverse downmix
        ↓
расширенный layout

Поэтому корректный decoder должен учитывать authored hierarchy.

Если в потоке уже существует подходящее представление для нужного layout, правильнее восстановить именно его, а не всегда получать максимум каналов и затем выбрасывать лишние.


Полный decode pipeline

Полный путь текущего декодера можно представить так:

MKV / MP4 / M2TS / .dts / .dtshd
        │
        ▼
FFmpeg copy-demux
(для .dts/.dtshd не нужен)
        │
        ▼
DTS elementary stream
        │
        ▼
Core + ExSS frame scanner
        │
        ▼
Core decode
        │
        ▼
XLL decode
  ├─ основной bed
  ├─ hierarchical inverse downmix
  └─ supplemental/object channel sets
        │
        ▼
private DTS:X navigation
  ├─ type-69 height XLL
  ├─ nested object XLL
  ├─ presentations
  ├─ combined-mix matrix
  └─ spatial metadata
        │
        ▼
reconstruction
  ├─ height unmix из compatible bed
  ├─ reverse-render объектов
  └─ layout mapping
        │
        ▼
object renderer
  ├─ coordinates
  ├─ extent
  ├─ gain interpolation
  └─ speaker panning
        │
        ▼
limiter
        │
        ▼
PCM24 WAV / W64
  ├─ final render
  ├─ optional mono stems
  └─ JSONL metadata

Lossless ли DTS:X

Ответ зависит от того, что именно сравнивать.

XLL waveforms

XLL — lossless.

То есть отдельный закодированный waveform восстанавливается без потерь в рамках формата.

Compatible bed

Это уже authored representation, куда могут быть заранее подмешаны дополнительные сигналы.

Поэтому compatible 7.1 и clean floor 7.1 после DTS:X unmix — не одно и то же.

Финальный render

Object renderer выполняет:

  • panning;
  • gain interpolation;
  • downmix/upmix для другого layout;
  • суммирование;
  • limiter.

Поэтому финальный PCM для разных layouts закономерно будет различаться.

Удобнее сформулировать так:

Что сравниваемРезультат
XLL waveform vs исходный waveformLossless
Compatible bed без DTS:XАвторский fold-down
Floor после корректного unmixВосстановленный bed
Render в другой layoutНовый детерминированный PCM
Blind PARMAПараметрическая реконструкция

На стандартном тестовом 7.1.4 собственный decoder получил:

  • восемь корректных нижних каналов;
  • четыре непустых верхних канала;
  • правильный порядок TFL/TFR/TBL/TBR;
  • точное удаление height fold-down;
  • корреляцию fold-down порядка 1.0;
  • отсутствие clipped samples;
  • одинаковый итог для raw .dtshd и copy-demux той же дорожки из контейнера.

В тестах нижний reference bed после соответствующей реконструкции совпадал sample-for-sample.


Ограничения

При всей привлекательности результата DTS:X не даёт магического доступа к бесконечному набору изолированных студийных объектов.

Если отдельный object waveform отсутствует в доступном bitstream, честный isolated stem получить не из чего.

Также нужно учитывать:

  • некоторые representations могут требовать parametric reconstruction;
  • authored object gains могут быть выше unity;
  • native renderer использует limiter chain;
  • DTS-UHD/P2 — отдельная архитектура;
  • редкие DTS:X profiles требуют отдельной проверки;
  • arbitrary room geometry не следует объявлять поддержанной только потому, что доступны object coordinates.

DTS:X, Dolby Atmos и Auro-3D

У всех трёх форматов задача похожа: сохранить совместимость со старым воспроизведением и одновременно дать современному decoder больше пространственной информации.

Но технически способы очень разные.

ПараметрDolby AtmosDTS:XAuro-3D
РазработчикDolby LaboratoriesDTS / XperiAuro Technologies
Основной принципBed + objectsBed + supplemental heights/objectsКанальные слои, Auro-Cx для объектов
Blu-ray transportTrueHD + AtmosDTS-HD MA + DTS:XPCM / DTS-HD MA
Совместимый слойTrueHD/DD+ bedDTS-HD bed с fold-downPCM/DTS bed
Где дополнительная информацияAtmos extensionExSS/XLL + private chunksLSB side-channel в классическом Auro-Codec
ВысотыObject/bed renderingSupplemental XLL и object renderDematrix carrier
Типичные home layouts5.1.2 … 7.1.6+5.1.2 … 7.1.4, Pro9.1 / 11.1 / 13.1
АпмиксерDolby SurroundNeural:X / PARMAAuro-Matic
Сильная сторонаЭкосистемаГибкий lossless object/bed pathКанальная height-сцена
ОграничениеЗависит от микса и rendererМеньше контента, закрытая object-частьМало native-контента

У классического Auro-Codec дополнительная информация живёт в младших битах PCM, поэтому определённая обработка PCM способна её разрушить.

Legacy DTS:X устроен иначе: дополнительные waveforms и metadata находятся внутри структурированных расширений сжатого DTS bitstream до PCM decode.

С Atmos DTS:X концептуально похож:

compatible representation
        +
additional audio
        +
renderer metadata

но framing, containers, waveform association и правила rendering у форматов разные.

Самого слова object недостаточно, чтобы считать их внутреннее устройство одинаковым.


dtsx-decode

По результатам исследования получился dtsx-decode — консольный C++ decoder/renderer, повторяющий необходимую часть native DTS:X path.

Проект пока исследовательский, это alpha версия:

0.1.3 alpha

На проверенном legacy-корпусе уже работают:

  • Core/ExSS parsing;
  • XLL bed;
  • hierarchical reconstruction;
  • type-69 supplemental heights;
  • nested object waveforms;
  • combined-mix unmix;
  • presentations;
  • spatial metadata;
  • object renderer;
  • PCM24 output;
  • mono stems;
  • coordinate JSONL.


Минимальный запуск

dtsx-decode -i clip.mkv

Явный layout:

dtsx-decode -i film.mkv --layout 7.1.4

Ограничить фрагмент:

dtsx-decode -i film.mkv --layout 7.1.4 --duration 30s

Probe без финального рендера

dtsx-decode -i film.m2ts --probe -v

Полная инспекция потока:

dtsx-decode -i film.mkv --full-probe

Экспорт объектов

Сохранить доступные object waveforms:

dtsx-decode -i film.mkv \
  --objects-output-dir objects

Объекты плюс bed:

dtsx-decode -i film.mkv \
  --layout 7.1.4 \
  --objects-output-dir objects \
  --objects-output-bed \
  --metadata-output metadata.jsonl

Только объектный слой без bed:

dtsx-decode -i film.mkv --render objects-only

Основные параметры

Вход и выход

ПараметрОписание
-i, --input.mkv, .mp4, .m2ts, .dts, .dtshd
-o, --outputПуть выходного PCM
--output-formatwav или w64
--audio-track NНомер DTS-аудиодорожки
--duration TIMEНапример 10s, 10m, 1h2m5s
--overwriteРазрешить перезапись
--mono-tracksЗаписать каждый выходной канал отдельно
--dolby-outputАльтернативный channel order для 7.1.x

Layout и render

ПараметрОписание
--layout NAMEЦелевой speaker layout
--channels NПроверка числа каналов
--sample-rate HZЧастота выходного PCM
--render objectsBed + objects/heights
--render objects-onlyТолько object/height layer
--render bedТолько channel bed

Диагностика и stems

ПараметрОписание
--probeБыстрая инспекция
--full-probeПолный проход
--metadata-output PATHJSONL с headers/presentations/object metadata
--objects-output-dir PATHMono WAV объектов + coordinate sidecar
--objects-output-bedДополнительно сохранить bed
-v, --verboseРасширенная диагностика

Object viewer

Так же написал веб проигрыватель объектов object-viewer.

Он позволяет:

  • синхронно проигрывать extracted stems;
  • отображать object trajectories;
  • читать координаты из JSONL;
  • показывать интервалы с coordinateStatus: "decoded";
  • прослушивать bed в упрощённом stereo representation.

Это удобно уже не только для проверки decoder, но и для визуального анализа DTS:X scene.


Вместо вывода

После анализа сотен видеороликов и фильмов, получил такую статистику, 99% коммерческие фильмы имеют формат кодирования DTS:X с канальным кодированием, то есть там нет (вообще нет) объектов. Некоторые фильмы (их мало) DTS:X закодированы только в конфигурации 7.1 (без верхних каналов).

Настоящие объекты есть в роликах Trinnov, в фильме IP MAN 3 китайская дорожка (только шумовые эффекты)

Даже на демо дисках от самой DTS звук записан в канальном режиме, исключение DTS Blu-Ray Demo Disc 19 2015 — где есть пару роликов с объектами.


Источники

Нормативные документы, использованные как база терминологии и структуры DTS:

Получившийся dtsx-decode можно использовать бесплатно для некоммерческого использования с указанием автора @almirus.


Поблагодарить автора:

Мой публичный адрес для получения ETH 0x5AA8B619B4a1C598b48F370F48602E8E327c9E3D

Произведите оплату через Trust Wallet: https://link.trustwallet.com/send?coin=60&address=0x5AA8B619B4a1C598b48F370F48602E8E327c9E3D

Мой публичный адрес для получения USDT 0x5AA8B619B4a1C598b48F370F48602E8E327c9E3D

Произведите оплату через Trust Wallet: https://link.trustwallet.com/send?coin=10042221&address=0x5AA8B619B4a1C598b48F370F48602E8E327c9E3D&token_id=0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9

Мира!


DTS, DTS-HD, DTS:X и связанные обозначения принадлежат их правообладателям. Материал описывает результаты независимого исследования совместимости и внутреннего устройства формата.

,