Files
SDR-Rover/docs/video/VIDEO_001.md

253 lines
28 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VIDEO-001: программный предел видеотракта
16 сентября 2026 года. Ветка `video-development`, исходный HEAD `af7c05f`.
`RF TX = 0`. SDR, камеры и экран не запускались. Основной `main`, старые результаты
и исходные IQ не менялись. Таблицы ниже относятся к этому компьютеру и одному
ролику; они не доказывают работу живого видео через радио.
## Что уже работает
| Узел | Файл и назначение | Зависимости и измеренное состояние |
|---|---|---|
| Подготовка JPEG | `experiments/lab047_jpeg_object_transport.py`, `experiments/lab050_video_stream.py`: уменьшение, RGB, JPEG | Pillow; Lab047: 320×240 q35, 8724 байта. Lab050: 128×96 q25, 1740–1893 байта на искусственных сдвигах фотографии. |
| Кодирование видео | `experiments/lab026_video_bitrate_benchmark.py` и `protocol/video_packet.py`: исследование сжатия и отдельный формат BASE/ROI | Это не подключённый к Lab045/Lab053 H.264 видеотракт. В VIDEO-001 добавлен автономный измеритель `tools/video_compare.py`, PyAV/libx264. |
| Фрагменты объекта | `experiments/lab046_bpsk_object_transport.py`, `protocol/image_fragments.py` | 12 байт метаданных и 244 байта JPEG на пакет. Сборка требует все фрагменты; отдельного замера CPU только для фрагментации нет. |
| Сигнал | `experiments/lab045_hackrf_bpsk_fec.py`, `experiments/lab049_bpsk_symbol_rate.py` | BPSK, свёрточный код 1/2, RRC; один пакет при 500 ксимв/с занимает 11,532 мс до паузы. Видео с H.264 в генератор не подаётся. |
| Приём потока | `experiments/lab053_streaming_receiver.py`, `experiments/lab053_pipeline.py` | NumPy, SciPy, Numba. Lab053: программный источник 6,044416 с, 240/240 CRC-пакетов, 30/30 JPEG, 5 свежих изображений/с в стенде. Камеры и экрана там нет. |
| Сборка и показ | `ImageSink` в `experiments/lab051_receiver_performance.py`; модель показа в `lab050_video_stream.py` | В Lab053 на 30 изображений сборка заняла 5,967 мс, JPEG decode 5,977 мс суммарно. Физический экран не реализован и не измерен. |
**MEASURED:** Lab047 передала по эфиру один JPEG 8724 байта за 10,3788 с на
20 ксимв/с. Первоначальный независимый приём остановился по вычислительному
пределу; повторный анализ той же RX-записи после сеанса восстановил 36/36
фрагментов и точный JPEG. Lab050–052 сначала не достигали реального времени:
например, Lab050 обработала 0,323745 с IQ за 55,157553 с при 500 ксимв/с.
Lab053 ускорила только программный конвейер: измеренные 5 кадров/с относятся к
заданному файлу IQ, не к аппаратному видео. Ориентир 5 кадров/с для полной
системы остаётся непроверенным.
**MEASURED:** Lab066 выполнила один аппаратно валидный сеанс 500 ксимв/с с
16 пакетами по 256 байт и 5 мс между ними. Строгие legacy и T2 получили
10/16 точных пакетов, шесть остановились на PHY-заголовке. Lab067 связала эти
отказы с локальным качеством принятого сигнала и не нашла основания для малой
правки приёмника. 10/16 не считается постоянной вероятностью доставки.
## Радиобюджет
**CALCULATED по генератору Lab045/Lab066:** 256 байт нагрузки содержат 12 байт
заголовка фрагмента и 244 байта изображения. Пакет протокола имеет ещё 8 байт
заголовка и 4 байта CRC, всего 268 байт. Код 1/2 с шестью хвостовыми битами
даёт `(268×8+6)×2 = 4300` кодированных бит. Преамбула PRBS7 занимает
1280 символов, троекратный PHY-заголовок 144, вместе с кодированным телом это
5724 BPSK-символа. Две защитные области и хвост RRC добавляют 42 интервала:
5766 интервалов, 92 256 IQ-отсчётов и 11,532 мс на пакет при 500 ксимв/с.
| Условие | Полезная скорость JPEG, бит/с | Смысл |
|---|---:|---|
| Без потерь и пауз | 169 268 | `244×8 / 0,011532`; верхняя граница формата. |
| Без потерь, с паузой 5 мс после пакета | 118 074 | `244×8 / 0,016532`; около 60,49 пакета/с. |
| Один сеанс Lab066, 10 принятых пакетов, с двумя 100-мс защитными интервалами | 42 480 | `10×244×8 / 0,459512`; видеоэквивалент, потому что Lab066 передавала не JPEG. Не измерение длительной видеодоставки. |
При 5/10/15 кадрах/с без потерь и с паузой помещаются соответственно не более
12/6/4 целых пакетов за период кадра: 2928/1464/976 байт изображения. Это
только длительность эфира; опорный H.264 кадр и потери могут заполнить очередь.
Текущий формат и сборщик понимают JPEG, поэтому H.264 требует отдельного
видеотранспорта. Его оценка в таблицах учитывает `ceil(размер/244)` пакетов на
кадр, но не означает готовую передачу H.264.
**MEASURED, сохранённый IQ Lab053:** 386 842 624 байта complex64 равны
6,044416 с при 8 Мвыб/с. Новый `tools/video_iq_replay.py` читает их блоками,
вызывает штатный независимый PHY/FEC/CRC-приёмник и сборщик, без графиков,
истории по блокам и сверки с TX во время замера. Первый проход: JIT-разогрев
0,496044 с, затем 4,099045 с обработки, или 1,475 с IQ/с обработки.
Повторный проход: разогрев 0,000135 с, обработка 4,238388 с, или 1,426.
Оба дали 240/240 пакетов и 30/30 точных JPEG. Первый и повторный проходы не
образуют статистической гарантии для другого ноутбука, а профиль всё ещё
содержит внутренние счётчики приёмника.
## Программное сравнение кодеков
**MEASURED:** один исходный файл `data/raw/video001/udacity_project_video.mp4`,
взятый из [открытого проекта Udacity по обнаружению автомобилей](https://github.com/udacity/CarND-Vehicle-Detection/blob/master/project_video.mp4).
Размер 25 268 015 байт, SHA-256
`651949922042c223375d40bf8929def97dbb62c6ade651d1f5b08eea47127d5f`;
1280×720, 25 кадров/с, 50,4 с. Это реальная съёмка с движущегося автомобиля.
В окне 7–13 с белая машина проходит справа, в окне 33–39 с появляются и
меняют положение чёрная и белая машины. В обоих окнах исходные выбранные кадры
различались. При изменении разрешения пропорции сохранены чёрными полями.
Предыдущая проба на пустой дороге сохранена отдельно в
`data/processed/video001/camera_only/` и не входит в таблицу ниже.
JPEG повторяет профиль проекта: q35, 4:2:0, независимые кадры. H.264 использует
PyAV 16.0.1 и доступный `libx264` из FFmpeg: `preset=veryfast`, `tune=zerolatency`,
без B-кадров и lookahead, один поток кодировщика, закрытый GOP с опорным кадром раз в секунду,
`crf=28`, VBV maxrate/buffer 160 или 320 кбит/с. Есть отдельные пробы с 40 кбит/с.
Настройка maxrate не считается фактическим битрейтом: ниже приведены размеры
полученных пакетов. Время кодирования и декодирования не включает чтение MP4.
Отдельный `end_to_end_file_pipeline_latency_s` измерен прямым проходом: чтение
очередного кадра MP4 с пропуском промежуточных, изменение размера, кодирование,
декодирование и получение RGB. Открытие файла, эфир, очередь показа и экран в
него не входят. Пик за 1 с рассчитан скользящим окном из `fps` кадров.
В таблице для каждого режима взято большее из двух окон значение среднего
и пикового потока, а также большее среднее время обработки кадра. Единицы:
кбит/с и мс/кадр. `FITS` сопоставляет пакетную пиковую нагрузку с 21,76
принятого пакета/с в одном сеансе Lab066. Для всех строк это `НЕТ`; длительный
рабочий предел радио остаётся **NOT_RUN**. По контрольным кадрам оценены
различимость машин и полос, направление и потеря деталей. Мелких препятствий
в этих двух участках нет; проверка с оператором ровера **NOT_RUN**.
| Разрешение | FPS | Кодек | Средний поток | Пик 1 с | Кодирование | Декодирование | Качество для оператора | FITS CURRENT RADIO BUDGET |
|---|---:|---|---:|---:|---:|---:|---|---|
| 320×240 | 5 | JPEG q35 | 245 | 280 | 0,6 | 0,5 | Ближние машины и полоса видны; дальние предметы мелки | НЕТ |
| 320×240 | 5 | H.264 160k | 117 | 172 | 1,2 | 0,3 | Ближние машины и направление видны; мелкие детали ограничены | НЕТ |
| 320×240 | 5 | H.264 320k | 117 | 172 | 1,2 | 0,3 | Почти тот же вид, что при 160k | НЕТ |
| 320×240 | 10 | JPEG q35 | 491 | 563 | 0,3 | 0,4 | Ближние машины и полоса видны; дальние предметы мелки | НЕТ |
| 320×240 | 10 | H.264 160k | 140 | 213 | 1,0 | 0,2 | Ближние машины и направление видны; мелкие детали ограничены | НЕТ |
| 320×240 | 10 | H.264 320k | 140 | 213 | 1,0 | 0,2 | Почти тот же вид, что при 160k | НЕТ |
| 320×240 | 15 | JPEG q35 | 738 | 850 | 0,2 | 0,3 | Ближние машины и полоса видны; дальние предметы мелки | НЕТ |
| 320×240 | 15 | H.264 160k | 151 | 238 | 0,9 | 0,2 | Ближние машины и направление видны; мелкие детали ограничены | НЕТ |
| 320×240 | 15 | H.264 320k | 151 | 238 | 0,9 | 0,2 | Почти тот же вид, что при 160k | НЕТ |
| 640×360 | 5 | JPEG q35 | 580 | 726 | 0,8 | 1,7 | Машины и разметка видны; крупный поток | НЕТ |
| 640×360 | 5 | H.264 160k | 174 | 230 | 3,2 | 0,7 | Машины видны; текстура дороги размыта при движении | НЕТ |
| 640×360 | 5 | H.264 320k | 342 | 437 | 3,8 | 1,0 | Машины, полоса и направление различимы | НЕТ |
| 640×360 | 10 | JPEG q35 | 1165 | 1470 | 0,6 | 0,8 | Машины и разметка видны; крупный поток | НЕТ |
| 640×360 | 10 | H.264 160k | 178 | 250 | 2,5 | 0,5 | Машины видны; текстура дороги размыта при движении | НЕТ |
| 640×360 | 10 | H.264 320k | 354 | 376 | 3,0 | 0,7 | Машины, полоса и направление различимы | НЕТ |
| 640×360 | 15 | JPEG q35 | 1752 | 2226 | 0,6 | 1,3 | Машины и разметка видны; крупный поток | НЕТ |
| 640×360 | 15 | H.264 160k | 180 | 250 | 2,3 | 0,4 | Машины видны; текстура дороги размыта при движении | НЕТ |
| 640×360 | 15 | H.264 320k | 355 | 375 | 2,6 | 0,5 | Машины, полоса и направление различимы | НЕТ |
| 640×480 | 5 | JPEG q35 | 699 | 841 | 1,3 | 1,4 | Машины видны; чёрные поля 60 пикселей | НЕТ |
| 640×480 | 5 | H.264 160k | 171 | 221 | 3,7 | 0,7 | Машины видны; поля и размытие деталей | НЕТ |
| 640×480 | 5 | H.264 320k | 347 | 412 | 4,1 | 1,0 | Машины видны; полезная область как 640×360 | НЕТ |
| 640×480 | 10 | JPEG q35 | 1402 | 1701 | 1,0 | 1,4 | Машины видны; чёрные поля 60 пикселей | НЕТ |
| 640×480 | 10 | H.264 160k | 178 | 252 | 2,9 | 0,5 | Машины видны; поля и размытие деталей | НЕТ |
| 640×480 | 10 | H.264 320k | 355 | 381 | 3,3 | 0,7 | Машины видны; полезная область как 640×360 | НЕТ |
| 854×480 | 5 | JPEG q35 | 911 | 1142 | 1,3 | 2,1 | Машины и разметка чётче; крупный поток | НЕТ |
| 854×480 | 5 | H.264 160k | 172 | 223 | 5,2 | 0,8 | Ближние машины видны; дальние детали размыты | НЕТ |
| 854×480 | 5 | H.264 320k | 347 | 378 | 6,3 | 1,3 | Машины, полосы и направление хорошо различимы | НЕТ |
| 854×480 | 10 | JPEG q35 | 1828 | 2318 | 1,4 | 2,2 | Машины и разметка чётче; крупный поток | НЕТ |
| 854×480 | 10 | H.264 160k | 179 | 265 | 4,3 | 0,6 | Ближние машины видны; дальние детали размыты | НЕТ |
| 854×480 | 10 | H.264 320k | 357 | 456 | 5,1 | 0,8 | Машины, полосы и направление хорошо различимы | НЕТ |
| 1280×720 | 5 | JPEG q35 | 1745 | 2247 | 2,7 | 4,9 | Машины и разметка подробны; поток велик | НЕТ |
| 1280×720 | 5 | H.264 160k | 173 | 217 | 9,8 | 1,2 | Машины видны; разрешение не даёт ожидаемой детализации | НЕТ |
| 1280×720 | 5 | H.264 320k | 346 | 441 | 11,5 | 1,7 | Машины и разметка видны; дальние надписи не проверены | НЕТ |
Полные размеры каждого кадра, включая опорные, фактическая скорость кодирования,
оба замера задержки, RSS всего процесса, PSNR и число уникальных кадров сохранены
в `data/processed/video001/comparison_traffic_160k.json` и
`comparison_traffic_320k.json`. RSS в общем процессе достиг 240,9 МиБ в первом
наборе и 241,7 МиБ во втором; это наблюдаемый пик при двух проходах на случай,
не отдельная память кодека. В сценарии заранее загружены все выбранные кадры,
поэтому RSS завышает память будущего поштучного видеотракта. У программных
кандидатов максимальная задержка
прямого файлового прохода составила 26,0 мс для HIGH QUALITY, 10,2 мс для
NORMAL и 11,5 мс для ROBUST на этом ПК.
Все 88 проходов этих двух наборов дали столько же уникальных декодированных
кадров, сколько входных. Повторного кадра под новым номером не было в
файловом декодировании; поведение экрана не проверено. Полученная частота
кодирования выше заданной FPS на этом ПК, но это не частота доставки через радио.
**MEASURED, проверка малого потока:** при настройке 40 кбит/с фактический
H.264 поток на `320×240 / 5` достигал 43,0 кбит/с в среднем и 56,0 кбит/с
в худшую секунду; опорный кадр до 2709 байт. Ближние автомобили узнаваемы,
но их края и дорожная текстура сильно размываются. На `640×360 / 10` получено
44,8/67,6 кбит/с. Проверены все 11 сочетаний при 40 кбит/с, оба участка;
во всех 44 проходах JPEG и H.264 число уникальных кадров равно входному.
Даже наименьший пик среди всех этих проходов составил 29 пакетных мест за
секунду, больше 21,76 принятого пакета/с в измеренном сеансе Lab066. Подробности:
`comparison_traffic_40k.json`; пик RSS этого набора — 240,5 МиБ.
**MEASURED, потеря данных в файле:** в каждом H.264 проходе удаляли первый
опорный пакет и, отдельно, первый промежуточный пакет. Точное совпадение с
неповреждённым декодированием возвращалось на следующем опорном кадре через
1 секунду исходного времени. Промежуточные изображения до него могут быть
испорчены или отсутствовать. У независимого JPEG потеря одного изображения
не мешает декодировать следующее. Это программная проба потери пакета кодека,
а не проверка нашего радиопротокола или реального показа без зависаний.
## Выбор режимов и граница вывода
Три **кандидата для следующей программной работы**, выбранные после замеров:
| Назначение | Режим | Причина | Радио сейчас |
|---|---|---|---|
| HIGH QUALITY | 854×480, 10 кадров/с, H.264 320k | Машины и полосы различимы; 357 кбит/с средний, 456 кбит/с пик, кодирование 5,1 мс/кадр | НЕТ |
| NORMAL | 640×360, 10 кадров/с, H.264 320k | Машины и направление различимы; 354/376 кбит/с, кодирование 3,0 мс/кадр | НЕТ |
| ROBUST | 320×240, 5 кадров/с, H.264 160k | Ближние машины видны при меньшей нагрузке; 117/172 кбит/с, кодирование 1,2 мс/кадр | НЕТ |
Названия описывают исследуемые программные профили, а не пригодность для
управления ровером. Вариант 40 кбит/с не выбран даже как ROBUST: потеря мелких
деталей и всплеск пакетов слишком велики. Для будущего видеотранспорта нужны
номер изображения, номер фрагмента, время создания и срок актуальности;
ожидающая очередь не больше одного нового изображения, сброс просроченного,
сброс зависимого H.264 потока после потери опорных данных до следующего IDR.
Имеющиеся PHY, FEC, CRC, заголовки и модуляция не менялись.
Для `1280×720 / 5` H.264 320k потребовал 346 кбит/с в среднем, 441 кбит/с
в худшую секунду и до 228 пакетных мест за секунду. Кодирование заняло в
среднем до 11,5 мс/кадр, декодирование до 1,7 мс/кадр, прямой файловый путь
до 32,0 мс для отдельного кадра; фактически кодировалось около 87 кадров/с.
Текущие 5-мс паузы ограничивают эфир примерно 60,49 пакета/с без потерь.
Крупнейший опорный кадр 12 593 байта требует 52 фрагмента и 0,860 с их
сериализации; наибольший кадр вообще — 14 550 байт, 60 фрагментов и 0,992 с.
Чтобы передать этот кадр в период 0,2 с, потребовалось бы не менее 300
пакетов/с без учёта управления, ошибок и защитного запаса. JPEG q35 при
том же режиме дал 1745/2247 кбит/с. Для 720p нужны иной радиобюджет или
существенно меньшие кадры, а также ограничение пиков, потерь и срока
актуальности; одной скорости кодировщика недостаточно.
## Очереди и наблюдаемые ограничения
В Lab053 очереди ограничены: 8 IQ-блоков, 4 строгих кандидата и 16 выходных
пакетов. В программном стенде переполнений не было. У экспериментального
`lab053_pipeline.py` растут списки истории блоков, пакетов и кадров: они нужны
для отчёта, но не должны попадать в рабочий процесс ноутбука. Новый повтор
IQ не собирает эту историю и не строит графики. Штатный приёмник всё же
сохраняет внутренние счётчики и двойное IQ-кольцо; в Lab053 выделение кольца
составило 6 797 824 байта. Это измеренная стоимость текущей реализации,
а не основание менять PHY в VIDEO-001.
`ImageSink` держит один собираемый JPEG. Недостающие фрагменты старого
изображения задерживают его завершение до появления следующего ID; в текущем
формате нет времени создания и срока годности. Отдельной H.264 очереди ещё
нет. В автономном сравнении создан один экземпляр libx264 на весь участок,
не новый процесс на каждый кадр. Основные измеренные ограничения для 10/15
кадров/с: пакетная и пиковая битовая нагрузка, потери Lab066, крупные опорные
изображения и отсутствие транспорта с правилами свежести и восстановления.
Одной достаточной скорости CPU-кодирования для решения этих вопросов мало.
**NOT_RUN:** независимые генераторы, передача H.264 или непрерывного видео по
эфиру, живой USB-приём, камера, экран, операторская проверка препятствий,
ноутбук и длительное подтверждение полезной скорости радиоканала. Следующая
практическая задача: сделать программный видеотранспорт с ограничением очереди,
дедлайном изображения и восстановлением по IDR, затем проверить его на
сохранённом IQ без доступа к SDR.
**Проверки:** `video_validate_results.py` сверил 132 прохода в трёх наборах:
матрицу режимов, SHA исходника, размеры кадров, поток, пакетные места,
уникальность и восстановление. Целевые тесты VIDEO-001: 4 пройдены. Общие
тесты: 1022 пройдены, один исторический тест исключён, поскольку в отдельном
рабочем дереве нет исходного `data/raw/lab064/tx_metadata.json`. Полный
`quick_gate.py` в этом дереве не завершён. На радио тесты не запускались.
## Воспроизведение
Из ветки `video-development` после установки `requirements-video.txt`. Исходный
ролик берётся по ссылке выше и сверяется с указанным SHA-256. Окна по умолчанию:
7–13 и 33–39 с; для другого ролика доступны повторяемые параметры `--window`.
```powershell
New-Item -ItemType Directory -Force data\raw\video001
Invoke-WebRequest https://raw.githubusercontent.com/udacity/CarND-Vehicle-Detection/master/project_video.mp4 -OutFile data\raw\video001\udacity_project_video.mp4
(Get-FileHash -Algorithm SHA256 data\raw\video001\udacity_project_video.mp4).Hash
python -B tools/video_compare.py --source data\raw\video001\udacity_project_video.mp4 --output data\processed\video001\comparison_traffic_160k.json --h264-maxrate-bps 160000
python -B tools/video_compare.py --source data\raw\video001\udacity_project_video.mp4 --output data\processed\video001\comparison_traffic_320k.json --h264-maxrate-bps 320000
python -B tools/video_compare.py --source data\raw\video001\udacity_project_video.mp4 --output data\processed\video001\comparison_traffic_40k.json --h264-maxrate-bps 40000
python -B tools/video_validate_results.py --source data\raw\video001\udacity_project_video.mp4 data\processed\video001\comparison_traffic_160k.json data\processed\video001\comparison_traffic_320k.json data\processed\video001\comparison_traffic_40k.json
python -B tools/video_report_table.py --comparison-160k data\processed\video001\comparison_traffic_160k.json --comparison-320k data\processed\video001\comparison_traffic_320k.json --report docs\video\VIDEO_001.md
python -B -m pytest tests\test_video_001_compare.py -q -p no:cacheprovider --basetemp data\processed\video001\pytest_temp_target
```
Повтор IQ описан в `SECOND_COMPUTER_SETUP.md`; он требует сохранённый файл
и исходную ведомость SHA только для послерезультатной сверки.