Browse Source

Document audiovisual stream format and Android ownership contracts

master
evgeny 1 week ago
parent
commit
ef76ca5de3
  1. 80
      doc/stream.txt

80
doc/stream.txt

@ -703,3 +703,83 @@ END, принятый от первого поставщика, сообщает
Restart в той же source_epoch сохраняет consumer cursor: bootstrap от отстающего поставщика не повторяет уже выданные DATA.
Повтор restart до отложенного GAP сохраняет предыдущую, ещё не сообщённую приложению границу; пропуск сообщается одним GAP.
Инструкция и параметры стенда: tests/stream_netns/README.md.
8. Live media и Android
Транспортный wire v3 не меняется. stream_publish_block публикует одну непустую FEC-пачку
немедленно, с сохранением границ. Первая запись выбирает режим источника: byte write или block write;
смешивание отвергается до изменения данных. stream_publish_finish не освобождает буфер источника.
Медиаблок uAV1 находится целиком внутри входа RS, поэтому header восстанавливается вместе с данными.
При штатных 6+2 полный медиаблок <=7080 байт. Раскладка big-endian, без packed-структур:
fixed header (32 байта):
magic="uAV1":4, video_codec:1, audio_codec:1, video_count:1, audio_count:1,
width:2, height:2, rotation:2, header_size:2, video_size:4, audio_size:4,
first_video_frame_offset:4, config_revision=1:4.
Далее video_count описаний по 32 байта, audio_count описаний по 16 байт,
затем video_size видеобайтов и audio_size аудиобайтов. Описания задают последовательные
неперекрывающиеся диапазоны внутри соответствующего трека; сумма длин должна совпадать с header.
video descriptor:
frame_id:8, PTS_us:8, frame_size:4, fragment_offset:4, fragment_length:4, flags:1, reserved=0:3.
audio descriptor:
PTS_us:8, packet_length:4, samples:2, reserved=0:2.
first_video_frame_offset относительно начала video bytes: UINT32_MAX — начала нет,
иначе это смещение первого фрагмента с fragment_offset=0. Начал может быть несколько,
таблица описывает каждое. Данные конфигурации не являются отдельным кадром.
KEY=bit0 video flags; остальные биты запрещены. frame_id>0, <=16 описаний каждого трека.
Один H.264 кадр <=2MiB. Общий формат допускает медиаблок <=64KiB; реальный максимум дополнительно
ограничен входом RS. Конфигурация, разрешение, поворот и набор треков фиксированы на source_epoch.
video_codec=1: AVC/H.264 Annex B, без B-кадров. Каждый KEY содержит SPS, PPS и IDR в одном
логическом кадре; это позволяет позднему viewer настроить декодер после получения полного KEY.
audio_codec=0: нет аудио; audio_codec=1: Opus, 48000Hz mono, 960 samples (20ms), packet<=1275 bytes.
Opus-пакеты между медиаблоками не разрезаются. Размеры треков не включают header/описания.
stream_media проверяет весь блок до изменения view. Receiver собирает один последовательный кадр.
При GAP, потере продолжения или конфликте metadata недособранный кадр удаляется, видео ждёт KEY.
Аудио обрабатывается независимо; неверный формат/длины не передаются платформенным декодерам.
Ретрансляторы не разбирают uAV1 и не пересоздают подписи источника.
Android:
- Один foreground publisher на процесс, один viewer. Каждая операция имеет новый session ID.
- StreamService владеет камерой, микрофоном и PARTIAL_WAKE_LOCK; пересоздание Activity не завершает источник.
Сервис camera|microphone запускается из видимого приложения после runtime-разрешений; без микрофона — camera.
- Camera2 TEMPLATE_RECORD пишет в Surface AVC encoder. Выбирается совместимое разрешение <=1280x720,
30fps, AVC baseline, 1–2Mbit/s, I-frame interval=1s. Выход нормализуется в Annex B;
partial output собирается в access unit. Codec config передаётся с каждым IDR.
- Camera MediaCodec Surface timestamps и AudioTimestamp.TIMEBASE_MONOTONIC приводятся к общему
origin System.nanoTime; время callback/получения блока не заменяет capture PTS.
- Camera/codec callbacks — HandlerThread, Opus encoder — audio capture thread, decoder/AudioTrack — viewer worker.
- Native bridge держит pthread mutex, ограниченные очереди и один pending post либо timer.
attach/detach выполняются в uasync вне callbacks. detach отменяет post/timer, закрывает handles,
очищает media, snapshots и запрещает producers до уничтожения instance/ua.
UI не сохраняет borrowed inst/ua. Idle без pending data не будит мобильное ядро.
- TX<=2MiB/128 records, не более 250ms ожидания. Actor публикует <=2 пачек за вызов,
неполную пачку объединяет с аудио/видео до 20ms; продолжение работы через timer 5ms.
При video pressure отбрасываются целые ожидающие кадры, P-кадры запрещены до нового KEY.
Кодировщик получает отказ admission и запрашивает KEY с ограничением частоты 500ms.
- RX<=4MiB/256 records. Pressure очищает media, сохраняет control results и сообщает GAP.
Kotlin viewer дополнительно ограничивает video queue 12 кадрами/2MiB, audio queue 16 пакетами.
Нельзя выбросить reference P-кадр и продолжить с зависимыми: переполнение сбрасывает декодер до KEY.
Просроченный кадр при нормальной последовательности декодируется без показа.
- После prebuffer 150ms AudioTrack clock определяет время показа видео; видео без аудио использует
монотонные часы. Короткие audio gaps заполняются Opus PLC, большой разрыв сбрасывает timeline.
Локальный preview использует обычную подписку на собственный источник с отключённым воспроизведением
своего микрофона, чтобы исключить акустическую обратную связь. Камера при закрытии preview продолжает работать.
- Source list строится в uasync по stream_member_load и stream_member_online, выдаётся UI копией JSON.
Свежий snapshot содержит source ID, epoch, self и экранированное имя. Увиденный источник не создаёт подписку.
- Stop сначала завершает capture producers и encoder EOS (максимум 1s), затем FIN.
Publisher сохраняет конечный буфер ещё 2s для сетевой выдачи, затем закрывается.
Это ограниченный drain, не подтверждение воспроизведения всеми viewers. Abort/core restart очищает очередь сразу.
Поздние команды старого session ID не меняют новый запуск.
- Звонок, рация и voice recording не начинают новый capture во время трансляции;
трансляция также отвергается при активном звонке/рации/voice recording.
Логи: stream — epoch/owners, очереди, GAP и teardown; video — codec/config, KEY, PTS и декодер.
Kotlin progress — DEBUG раз в секунду; C packet-level диагностика — TRACE по запросу.
Проверки: test_stream_media (все пары потерь 6+2, parser/границы/GAP), test_android_stream
(живое ядро, preview, verified snapshots, FIN/cancel, concurrent producer/detach и leak count),
Android H264AnnexBTest (Annex B/length-prefixed NAL, SPS/PPS/IDR и усечённые данные).

Loading…
Cancel
Save