Skip to content

Latest commit

 

History

History
318 lines (237 loc) · 45.1 KB

README.ru.md

File metadata and controls

318 lines (237 loc) · 45.1 KB

OpenIPC logo

OpenIPC Decoder

English | Русский | 简体中文

Build Release License Platform

Компактное приложение для Android: показывает RTSP-потоки с IP-камер и декодирует H.264/H.265 аппаратно. Создано для камер с прошивкой OpenIPC. Работает на телефонах, планшетах, телевизорах, ТВ-приставках и автомобильных устройствах.

Мультивид: восемь камер и меню

Скачать

Готовые сборки лежат в релизе latest:

Файл Что это
decoder-v2.apk Текущая версия, рекомендуется
decoder.apk Старая версия из ветки basic

У каждой версии 2.xx есть и свой релиз — v2.01 и далее, на странице релизов — с APK этой версии и списком изменений после предыдущей.

Есть бета-канал в Google Play. Чтобы попасть в него, пришлите свой e-mail через Telegram-каналы OpenIPC.

Возможности

  • Видео: воспроизведение RTSP, аппаратное декодирование H.264/H.265 через MediaCodec, MJPEG по RTSP (RTP/JPEG) и по HTTP (multipart/x-mixed-replace) в одиночном режиме и в мультивиде, автоматическое восстановление декодера, поток UDP с потерями показывается с замаскированными повреждениями вместо чёрного экрана, предупреждение, если видеодекодер устройства перестал отвечать, картинка вписывается в экран любой формы
  • Звук: AAC (RFC 3640 mpeg4-generic, ADTS, MP4A-LATM), Opus, G.711 μ-law/A-law, L16 PCM (моно и стерео); в мультивиде — звук выбранной ячейки
  • Режимы: одна камера или мультивид (Quad) — до 8 камер и ячейка U (камера, которая сама шлёт RTP) сеткой 2×2 или 3×3; адаптивное декодирование (все кадры или только ключевые для каждой ячейки, предел определяется на устройстве); S: только ключевые кадры — и в мультивиде, и в одиночном режиме
  • Управление: масштаб двумя пальцами, перемещение, сброс двойным касанием, пульт Android TV (Leanback)
  • Сеть: RTSP поверх TCP или UDP (Auto, режим по умолчанию, переходит на TCP, если UDP отклонён, видео не приходит или ключевые кадры теряются), фактический транспорт показывается при подключении, RTSP multicast, приём RTP, который камера сама шлёт по UDP (unicast или multicast), авторизация Basic и Digest, RTSP keepalive, автоматическое переподключение с растущей задержкой, индикатор качества связи
  • WebUI: встроенный браузер для веб-интерфейса камеры
  • Прочее: 8 слотов для камер, адреса хранятся в зашифрованном виде, скриншот долгим нажатием, приём ссылок из других приложений

Требования

  • Android 5.0 (API 21) или новее
  • IP-камера с RTSP или камера, которая сама отправляет RTP по UDP (OpenIPC Majestic outgoing), см. Транспорты
  • Сервисы Google (GAPPS) не нужны: приложение работает и на AOSP-сборках без них. WebUI использует системный WebView, поэтому ему нужен рабочий пакет WebView (на некоторых устройствах это Android System WebView от Google); его отключение затрагивает только WebUI — #15

Быстрый старт

  1. Установите APK из релиза latest и запустите приложение.
  2. Коснитесь экрана или нажмите OK на пульте, чтобы открыть меню.
  3. Выберите номер камеры (1–8), нажмите Settings и введите адрес камеры:
    rtsp://username:password@ip_address:554/stream=0
    Под адресом можно выбрать транспорт; у нового слота по умолчанию Auto (UDP с откатом на TCP).
  4. Нажмите Save. Приложение сразу подключится и само переподключится, если поток прервётся.

Управление

Меню

Меню — это сетка: восемь слотов сверху, ниже два ряда по четыре кнопки.

[ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ]
[ Settings | WebUI  | Grid   | Slides ]
[ Exit     | Reset  | Debug  | UDP    ]

Меню на телефоне WebUI на телефоне: страница прокручивает поле над клавиатурой

Пункт Действие
1–8 Переключиться на слот камеры. Цвет номера активного слота показывает качество связи: зелёный — джиттер меньше 100 мс, жёлтый — 100–300 мс, красный — больше 300 мс. Серый номер — пустой слот.
Settings Изменить адрес и транспорт активного слота (только в режиме одной камеры; в остальных — серая)
WebUI Открыть веб-интерфейс камеры; логин и пароль берутся из RTSP-адреса (только в режиме одной камеры; в остальных — серая)
Grid Вид: мультивид (2×2 или 3×3) или одна камера. Grid не меняет режим воспроизведения (Slides)
Slides Режим воспроизведения: все кадры или только ключевые (картинка обновляется раз в интервал ключевых кадров, MJPEG — раз в секунду), минимальная нагрузка на декодер. Работает и в мультивиде, и в одиночном режиме, вид не меняет
Exit Закрыть приложение. Мелкий текст под ним — версия приложения и хеш сборки.
Reset Очистить все настройки после подтверждения (фокус на Cancel), чтобы настроить приложение с чистого листа: удаляются слоты камер, транспорты и остальные настройки, приложение открывается как сразу после установки. Сами камеры не меняются
Debug Текст в углу каждой ячейки мультивида (разрешение, кодек, декодировано/получено кадр/с, ключевые кадры, состояние) или ни в одной
UDP Ячейка U на весь экран: камера, которая сама шлёт RTP по UDP на порт 5600

Включённые пункты — Grid, Slides, Debug, UDP и активный слот — залиты оранжевым; пункт, на котором стоит пульт, обведён голубой рамкой.

Жесты и кнопки

Ввод Действие
Касание / OK / Enter Открыть или закрыть меню
Back / Esc Закрыть меню
Щипок, затем перетаскивание Увеличение (до 5×) и перемещение, в режиме одной камеры
Двойное касание Сбросить масштаб
Долгое нажатие Одна камера: скриншот в Pictures/OpenIPC. Мультивид: звук этой ячейки

Открытие камеры из другого приложения

Приложение принимает текст через «Поделиться» (ACTION_SEND, text/plain). Если поделиться ссылкой rtsp://, udp:// или http:// из другого приложения, например из OpenIPC Network, она запишется в активный слот. Необязательный параметр transport (tcp, udp, auto, multicast) задаёт транспорт слота:

adb shell am start -a android.intent.action.SEND -t text/plain \
  --es android.intent.extra.TEXT 'rtsp://user:pass@192.168.1.10/stream=0' \
  --es transport udp -n com.openipc.decoder/.Decoder

Мультивид (Quad)

Показывает настроенные слоты сеткой 2×2, а если занят хотя бы один из слотов 5–8 — сеткой 3×3. Девятая ячейка сетки 3×3, ячейка U, показывает камеру, которая сама отправляет RTP по UDP на порт 5600 устройства (udp://@:5600, см. слоты udp://); пока поток не пришёл, в ней перечислены все адреса устройства, куда его слать. Кнопка UDP в меню открывает её на весь экран. Другие порты и multicast-группы указываются в слоте адресом udp://. У каждой ячейки своё подключение и свой декодер, а у видеодекодера устройства постоянный бюджет: тестовая приставка AG-216, например, декодирует в полном темпе примерно два потока 1080p30. Поэтому сетка подстраивается: ячейки стартуют на ключевых кадрах, затем по приоритету (ячейка U, пока в неё идёт поток, ячейка со звуком, потом по номеру слота) переходят на все кадры, пока декодер успевает. Остальные остаются на ключевых кадрах — картинка обновляется раз в интервал между ключевыми кадрами (в тексте в углу — key frames, меню Debug). Предел определяется замером на каждом устройстве. Дополнительные потоки камер (substream), если они есть, позволяют показать в полном темпе больше ячеек. Ячейка на ключевых кадрах сверх лимита экземпляров аппаратного декодера (у AG-216 — 4 × H.265) работает на программном декодере (· software в углу); только сверх и этого бюджета она показывает Decoder limit: N × H.265. Если не справляются даже ключевые кадры, ячейка с наименьшим приоритетом ставится на паузу (Paused: decoder overloaded) и после спокойного периода пробуется снова; потери в первые секунды после запуска сетки, когда все декодеры стартуют разом, не учитываются. Ячейка, у которой поток UDP теряет кусок каждого ключевого кадра, показывает кадры с замаскированными повреждениями (· damaged), а не чёрный экран. Некоторые камеры допускают только одно RTSP-подключение одновременно. Долгое нажатие на ячейку включает её звук (повторное — выключает); у выбранной ячейки виден значок AUDIO, выбор запоминается. Коснитесь любой ячейки, чтобы открыть меню.

Транспорты

У каждого слота свой транспорт: он выбирается под адресом в Settings (или параметром transport в присланной ссылке).

Транспорт Как приходит видео Примечание
TCP RTP внутри RTSP-соединения Работает везде, в том числе через NAT и межсетевые экраны
UDP RTP по UDP, пара портов на дорожку Меньше задержка в локальной сети. Потерянные пакеты пропускаются, а не запрашиваются заново. На TCP не переходит
Auto (по умолчанию) UDP, а если UDP не работает — TCP Переходит на TCP, если камера отказала в UDP или видео не пришло за 3 с, и остаётся на TCP, пока слот не изменят
Multicast RTSP multicast (Android 8.0+), при отказе — TCP Для серверов с RTSP multicast. OpenIPC Majestic и камеры XM его не поддерживают: отвечают 400 или 451, и слот играет по TCP в том же соединении

Фактический транспорт показывается при запуске потока в одиночном режиме (Connected • UDP • H.265 …), на отладочной странице и в /stats.json (transport; настройка слота — transport_mode). После отката там будет, например, TCP (auto).

Одиночный режим сразу после подключения: транспорт, кодеки и битрейт

Слоты UDP (Majestic outgoing)

Слот может принимать и RTP, который камера отправляет сама, без RTSP. Для этого вместо rtsp:// укажите адрес udp://:

Адрес Значение
udp://@:5600 Слушать порт 5600
udp://@239.1.2.3:5600 Войти в multicast-группу 239.1.2.3 на порту 5600
udp://192.168.1.10@239.1.2.3:5600 То же, но принимать пакеты только от этого отправителя
udp://@:5600?codec=h265&pt=97 Задать кодек или тип нагрузки видео, если значения по умолчанию не подходят

Кодек определяется по типу нагрузки RTP (96 → H.264, 97 → H.265), если не задан codec=; смену кодека на камере приложение подхватывает на лету. Только видео. Два слота не могут слушать один и тот же порт.

На камере добавьте устройство в адресаты outgoing в /etc/majestic.yaml (затем перезапустите Majestic):

outgoing:
  servers:
    - udp://192.168.1.20:5600

/api/v1/outgoing.json на камере показывает, идёт ли отправка. Majestic умеет слать и в multicast-группу (udp://239.1.2.3:5600), тогда одну камеру могут смотреть несколько устройств. В Wi‑Fi приложение держит multicast lock, пока состоит в группе.

Слоты HTTP MJPEG

Слот принимает и адрес HTTP MJPEG, например у Majestic http://user:password@<камера>/mjpeg: поток multipart/x-mixed-replace, по одному JPEG в каждой части, с chunked-кодированием или без. Учётные данные Basic отправляются сразу, Digest — после запроса камеры; поток переподключается так же, как RTSP. Работает в одиночном режиме и в мультивиде, транспорт показывается как HTTP. Звука в этом режиме нет.

Отладочная страница (порт 8085)

Пока приложение работает, оно отдаёт отладочную информацию по HTTP на порту 8085 — для браузера или curl из той же сети:

  • http://<приставка>:8085/ — снимок на всю страницу, поверх каждой ячейки камера, размер, fps и потери (красным); в шапке версия, время приставки и аптайм. Переключатель Info On / Off в шапке убирает текст поверх ячеек (и список под ними на узком экране), остаётся только картинка; по умолчанию Off, выбор запоминается в браузере. Красная пометка в шапке сообщает, что видеодекодер устройства перестал отвечать (decoder_stuck);
  • http://<приставка>:8085/snapshot.jpg (?labels=0 — только кадры) — картинка с раскладкой экрана в разрешении экрана (не больше 1920×1080) из кадров, которые приложение показывает сейчас; ячейка без видео — чёрная с её статусом. Снимается только по запросу; страница обновляет её раз в 3, 5 (по умолчанию) или 10 с, пока вкладка видна;
  • http://<приставка>:8085/stats.json — то же в JSON, для скриптов;
  • В одиночном виде страница и снимок всё равно показывают всю сетку (#100): камера на экране обведена синей рамкой, а каждый другой настроенный слот, пока страница открыта, примерно раз в 45 с получает короткую проверку потока (подключение, несколько секунд пакетов, без декодирования); в его ячейке — результат, например Stream OK · H.265 · 25 fps · 3.1 Mbit/s · checked 12 s ago, или ошибка. Слот с камерой, которая на экране, не проверяется (некоторые камеры принимают только одного клиента), как и слоты udp://. В stats.json эти ячейки — в поле slots;
  • http://<приставка>:8085/log — последние 500 строк лога приложения.

Отвечает только клиентам из локальной сети (loopback, 10/8, 172.16/12, 192.168/16, link-local, IPv6 fc00::/7), остальным — 403. Логины и пароли не показываются.

Отладочная страница: снимок с текстом каждой ячейки
/stats.json /log

Известные ограничения

Important

На каждый пункт заведён issue — комментарии, результаты проверок и pull request приветствуются.

  • RTSP multicast требует Android 8.0+ и сервера, который его поддерживает; камеры OpenIPC его не поддерживают — #69
  • Не поддерживаются звук G.726 и MP4A-LATM с конфигурацией внутри потока (cpresent=1). OpenIPC Majestic их не использует, а камеры с G.726 обычно умеют отдавать G.711 или AAC — #14
  • MJPEG декодируется программно на устройствах без рабочего JPEG-декодера (AG-216 его объявляет, но создать не может); аппаратное декодирование используется, если устройство предоставляет video/jpeg — #132
  • Видеодекодер AG-216 может перестать отвечать до перезагрузки устройства: кадры приходят, но ни один не декодируется; приложение сообщает об этом на экране и на отладочной странице, причина пока неизвестна — #145
  • Переключение между мультивидом и одиночным режимом может на несколько секунд заморозить картинку на некоторых ТВ-приставках (замечено на AG-216) — #76
  • Логин и пароль передаются в открытом виде по RTSP/HTTP без шифрования (Basic, если камера не запросила Digest); RTSPS не поддерживается и не планируется — #16

Известные ошибки собраны отдельно, под меткой bug.

Ветки

Ветка Назначение
v2 Основная ветка разработки (по умолчанию). Модульный код в android/. Сборки публикуются как decoder-v2.apk.
basic Старая версия 1.0x в одном файле, сохранена для справки и для старых установок. Сборки публикуются как decoder.apk.

Pull request делайте от ветки v2.

Сборка

Нужны JDK 17 и Android SDK (platform 36). Путь к SDK задаётся через ANDROID_HOME или android/local.properties.

cd android
./gradlew assembleDebug        # отладочная сборка, ключи подписи не нужны
# → app/build/outputs/apk/debug/app-debug.apk

Для релизной сборки нужно хранилище ключей android/key.jks и переменные окружения:

export KEYSTORE_PASS=your_password
export KEY_ALIAS=your_alias
export KEY_PASS=your_key_password
./gradlew assembleRelease      # → app/build/outputs/apk/release/app-release.apk

Отладочная и релизная сборки подписаны разными ключами. Чтобы перейти с одной на другую, сначала удалите приложение; сохранённые адреса камер удалятся вместе с ним.

CI: GitHub Actions собирает каждый push. Push в v2 и basic обновляет релиз latest и отправляет уведомление в Telegram-канал OpenIPC. Для остальных веток APK прикладывается только как артефакт на странице запуска.

Архитектура

Класс Назначение
Decoder Главная activity: интерфейс, жизненный цикл, настройки, декодирование видео одной камеры, сетка мультивида
RtspClient Поток одной камеры: RTSP-сессия, сборка NAL, звук, качество связи
RtspSession Одна RTSP-сессия поверх TCP, UDP или multicast: рукопожатие, приём RTP, keepalive, сторожевой таймер, переподключение с растущей задержкой
RtspAuth, Sdp Авторизация Basic и Digest; разбор описания сессии камеры
Transport, UdpReceiver, RtpReorder Согласование транспорта; приём по UDP и multicast с фильтром отправителя; восстановление порядка пакетов
RtpListener Слоты udp://: RTP, который камера отправляет сама
HttpMjpeg Слоты http://: MJPEG по HTTP (multipart/x-mixed-replace, chunked или нет)
NalAssembler Сборка NAL-блоков H.264/H.265 из RTP-пакетов, отбрасывание блоков, повреждённых потерями
JpegAssembler MJPEG: сборка целых JPEG-кадров из RTP/JPEG (RFC 2435)
JpegCodec, JpegRenderer MJPEG на экране: JPEG-декодер устройства, если он есть, иначе BitmapFactory
DecodePlanner Мультивид: какие ячейки декодируют все кадры, а какие только ключевые, в пределах выученной ёмкости декодера
MediaCodecManager, DecoderRetry Жизненный цикл аппаратного видеодекодера и восстановление после ошибок
AudioManager, AudioConfig Звук: преобразование G.711/L16, декодирование AAC/Opus, вывод через AudioTrack
QuadCell Одна ячейка мультивида: своя сессия, декодер и звук по выбору
MenuManager Всплывающее меню, редактор адреса, браузер WebUI
CredentialStore, KeystoreCipher Зашифрованное хранение адресов камер (Android Keystore)
FramePool, Frame Пул буферов, снижает нагрузку на сборщик мусора
App, Crash Обработчик необработанных исключений и экран отчёта о сбое
DebugServer, NetInfo, Snapshots Отладочная страница на порту 8085 (только локальная сеть), адреса устройства, снимки экрана

Сеть, декодирование видео и звук работают в отдельных потоках, поэтому медленный декодер не блокирует сокет.

Безопасность

  • Логин и пароль берутся из адреса и передаются в заголовке Authorization: сначала Basic, Digest — если камера его запросит. В строку RTSP-запроса они не попадают.
  • RTSP, RTP по UDP и HTTP без шифрования, RTSPS не поддерживается. Если камера ждёт логин и пароль прямо в пути или параметрах адреса (например, user=…_password=…), они уходят с каждым запросом. Используйте приложение только в доверенных сетях, см. #16.
  • Адреса камер вместе с паролями хранятся в закрытом хранилище приложения в зашифрованном виде (AES-256-GCM, ключ в Android Keystore, Android 6.0+). На Android 5.x или если Keystore недоступен — в открытом виде. Резервное копирование отключено (allowBackup="false").
  • Отладочная страница на порту 8085 без шифрования и пароля; она отвечает только клиентам из локальной сети и не показывает логины и пароли.

Совместимость с устройствами

Проверили приложение на своём устройстве? Отправьте Device report — это займёт минуту и поможет другим пользователям. Проверили камеру? Отправьте Camera report: производитель, модель, адрес RTSP (без пароля), кодеки и что работает.

Проверенные устройства

Большинство отчётов ниже получено для старой версии 1.0x (ветка basic); в столбце Версия указано, какая версия проверялась. В новых отчётах указывайте версию приложения.

Тип Устройство Android Ядро Версия Примечание
Телефон Asus ZC553KL 8.1 3.18.71 1.0x
Телефон Blackview BV4900Pro 12 4.19.191 1.0x
Телефон Oppo 5X ColorOS 15.0 5.15.149 1.0x
Телефон Oppo A17 ColorOS 12.1 4.19.191 1.0x
Телефон Samsung Galaxy A51 13 4.14.113 1.0x
Телефон Samsung Galaxy M21 (SM-M215F/DSN) 12 4.14.113 1.0x
Телефон Samsung Galaxy S25 15 6.6.30 1.0x
Телефон Samsung A55 5G 14 6.1.93 1.0x
Телефон Samsung Galaxy J7 10 3.18.150 1.0x
Телефон Samsung S8 9 4.4.153 1.0x
Телефон Samsung S23 Ultra 15 5.15.153 1.0x
Телефон TECNO KM4 15 5.15.194 v2 2.04 Сенсорное устройство лаборатории: WebUI с экранной клавиатурой проверен (#159, #160); Close под строкой состояния (#169)
Телефон Xiaomi Redmi 7A 10 4.9.261 1.0x
Телефон Xiaomi Redmi Note 7 (M1901F7G) 10 4.4.192 1.0x
Телефон Xiaomi Redmi Note 13 4G 13 5.15.94 1.0x
Планшет Lenovo TB-8504X 8.1.0 3.18.71 v2 2.00 H.265 и мультивью работают; ввод в WebUI исправлен в 2.02 (#159)
Планшет Lenovo TB-X304L 8.1.0 3.18.71 1.0x Изображение обрезано в 1.0x, исправлено в v2 (#17)
Планшет Lenovo TB-X606F 10 — 1.0x Изображение обрезано в 1.0x, исправлено в v2 (#17)
Планшет Lenovo Tab P11 11 4.19.157-perf+ 1.0x Изображение обрезано в 1.0x, исправлено в v2 (#17)
Планшет Samsung Galaxy Tab A 7.1.1 3.10.49 1.0x
Планшет Samsung Galaxy Tab A 11 4.9.227 1.0x
Планшет Samsung Tab A7 (SM-T505) 12 4.19.157-perf- 1.0x
ТВ-приставка A95X F3 AIR 9 (SlimBOXtv AOSP 9.14, без GAPPS) 4.9.113 1.0x
ТВ-приставка IE X3 Air 9 (SlimBOXtv AOSP 9.14, без GAPPS) 4.9.113 1.0x
ТВ-приставка AG-216 10 4.9.170 v2 2.00 Тестовое устройство v2; бюджет декодера по замеру ≈ 1080p60 суммарно (два 1080p30 в полном темпе)
ТВ-приставка SberBox SBDV-00001 своя 4.9.228 1.0x
ТВ-приставка X96Q (Allwinner H313) 10 4.9.170 1.0x
Проектор SIBIRLINK HY300 / HY320 11 4.19.323 v2 2.02 1080p H.264 / H.265 работает; 2304×1296 и 2560×1440 не запускаются (#165, #166)
Телевизор Haier Candy Android TV 2K 11 4.9.243+ 1.0x Нет значка в списке приложений
Телевизор Yandex TV Novex NVX-55U169TSY 7.1.1 4.4.3 1.0x
Авто Медиацентр JCAC10003 (ac8227/ac8229) 12 3.18.79+ 1.0x
Авто Зеркало Z55 8.1.0 4.4.83 1.0x

Не работает

Тип Устройство Android Ядро Версия Примечание
ТВ-приставка ТВ-приставка без названия 5.1.1 3.14.29 1.0x Нет видео

История версий

Изменения описаны на странице релизов и в истории коммитов. История версий 1.0x — в README ветки basic.

Лицензия

The Prosperity Public License 3.0.0: бесплатно для некоммерческого использования; для коммерческого — пробный период 30 дней. Полный текст — в LICENSE.md.

Поддержка

Telegram