Intereting Posts
Фильтровать строки из курсора, чтобы они не отображались в ListView Можем ли мы обновить APK в Google Play Store без изменения версии APP Jarsigner: невозможно подписать jar: java.util.zip.ZipException: недействительный размер записи сжат (ожидается 463, но получил 465 байт) Установить / удалить APK программно (PackageManager vs Intents) Вид ресайклера, показывающий отдельный элемент Android: ошибка libGL.so: невозможно открыть файл общих объектов: нет такого файла или каталога Проблемы с альфа-тестированием OpenGL ES2 Firebase Cloud Messaging заменила ключи сервера на токены для отправки уведомлений / сообщений Android Studio, как запустить градиентную синхронизацию вручную? Android – Как получить выбранное имя файла из документа Ошибка нескольких файлов dex при компиляции с помощью ant или Eclipse Обновить вкладки из активности вкладки в Android TabHost Как реализовать журнал изменений в android? Файл конфигурации Android Не удалось выделить память: 8

Почему я получаю ошибки «Неподдерживаемый формат», считывая потоки rtsp, закодированные H.264, с помощью Android MediaPlayer?

Я пытаюсь показать кодированное rtsp видео H.264 на устройстве Android. Поток идет от малины Pi, используя vlc для кодирования /dev/video1 который является «Pi NoIR Camera Board».

 vlc-wrapper -vvv v4l2:///dev/video1 --v4l2-width $WIDTH --v4l2-height $HEIGHT --v4l2-fps ${FPS}.0 --v4l2-chroma h264 --no-audio --no-osd --sout "#rtp{sdp=rtsp://:8000/pi.sdp}" :demux=h264 > /tmp/vlc-wrapper.log 2>&1 

Я использую очень минимальный код Android прямо сейчас:

 final MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setDisplay(holder); try { mediaPlayer.setDataSource(url); mediaPlayer.prepare(); 

И получить сообщение «Подготовить не удалось: status = 0x1» IOException . Когда я смотрю на журналы, я вижу такие строки, как

 06-02 16:28:05.566 W/APacketSource( 316): Format:video 0 RTP/AVP 96 / MIME-Type:H264/90000 06-02 16:28:05.566 W/MyHandler( 316): Unsupported format. Ignoring track #1. 06-02 16:28:05.566 I/MyHandler( 316): SETUP(1) completed with result -1010 (Unknown error 1010) 

Исходя из системного процесса. Grepping для этих сообщений указывает на источники libstagefright/rtsp и, похоже, означает, что ASessionDescription::getDimensions в конструкторе APacketSource::APacketSource не работает. Это не похоже, что это должно произойти, потому что VLC, конечно, знает, какие размеры выводят:

 [0x1c993a8] v4l2 demux debug: trying specified size 800x600 [0x1c993a8] v4l2 demux debug: Driver requires at most 262144 bytes to store a complete image [0x1c993a8] v4l2 demux debug: Interlacing setting: progressive [0x1c993a8] v4l2 demux debug: added new video es h264 800x600 

Похоже, что ASessionDescription::getDimensions ищет атрибут framesize в (казалось бы, правильно сформированном) DESCRIBE результате

 06-02 16:28:05.566 I/MyHandler( 316): DESCRIBE completed with result 0 (Success) 06-02 16:28:05.566 I/ASessionDescription( 316): v=0 06-02 16:28:05.566 I/ASessionDescription( 316): o=- 15508012299902503225 15508012299902503225 IN IP4 pimple 06-02 16:28:05.566 I/ASessionDescription( 316): s=Unnamed 06-02 16:28:05.566 I/ASessionDescription( 316): i=N/A 06-02 16:28:05.566 I/ASessionDescription( 316): c=IN IP4 0.0.0.0 06-02 16:28:05.566 I/ASessionDescription( 316): t=0 0 06-02 16:28:05.566 I/ASessionDescription( 316): a=tool:vlc 2.0.3 06-02 16:28:05.566 I/ASessionDescription( 316): a=recvonly 06-02 16:28:05.566 I/ASessionDescription( 316): a=type:broadcast 06-02 16:28:05.566 I/ASessionDescription( 316): a=charset:UTF-8 06-02 16:28:05.566 I/ASessionDescription( 316): a=control:rtsp://192.168.1.35:8000/pi.sdp 06-02 16:28:05.566 I/ASessionDescription( 316): m=video 0 RTP/AVP 96 06-02 16:28:05.566 I/ASessionDescription( 316): b=RR:0 06-02 16:28:05.566 I/ASessionDescription( 316): a=rtpmap:96 H264/90000 

Похоже, что это может быть ошибка Stagefright: он знает (или должен знать), что у него есть кодированный поток H.264, но, похоже, он ожидает атрибут framesize H.263. Отсюда мои вопросы:

  1. Я правильно читаю источники? Является ли проблема в ASessionDescription::getDimensions ? (Действительно ли stagefright поддерживает потоки H.263?)
  2. Или неправильный код Pi-side?
  3. Или я просто пропустил один или два ключа в своем клиентском коде?

Обновление, 20140606:

Документы MediaPlayer говорят, что -1010 MEDIA_ERROR_UNSUPPORTED : «Битовый поток соответствует соответствующему стандарту кодирования или спецификации файла, но среда мультимедиа не поддерживает эту функцию». Это заставляет меня задаться вопросом, является ли проблема «стандартной» проблемой прогрессивной загрузки. То есть, поддерживаемые форматы носителей говорят

Для видеоконтента, транслируемого через HTTP или RTSP [в] MPEG-4 [контейнер], атом moov должен предшествовать любым атомам mdat , но должен преуспеть в атоме ftyp

В то время как большинство потоков помещают атом moov .

Хотя я совсем не уверен, как это проверить!

  • Я не moov атомов moov или ftyp в источнике vlc. (Мне сказали, что vlc просто потоковая передача здесь, что фактический контент H264 выходит из драйвера камеры.)
  • Я не moov атомов moov или ftyp в ветвях https://github.com/raspberrypi linux или userland. (Может быть, я просто готовлюсь к неправильным вещам.)
  • Когда у меня есть vlc, сохраните поток, я получаю файл mp4 с moov до mdat , но, конечно же, vlc может выполнять некоторую перекодировку.

Обновление, 20140610:

Игрок GPAC «Osmo4» может отображать поток на планшете Android 4.3. Плохо (больше лаги, чем VLC на ноутбуке, и склонны к блокировкам), но он может отображать его.

Обновление, 20140616:

Когда я снова попытался повторно использовать источники VLC (без учета регистра и без слов), я нашел макросы FOURCC, определяющие moov и ftyp в modules/mux/mp4.c , что быстро привело к --sout-mp4-faststart--no-sout-mp4-faststart ), которые не имеют никакого значения.

Таким образом, похоже, что на самом деле это не проблема с упорядочением атомов. Хорошо бы знать, если он закрывает целый класс тупиков, но он оставляет меня, ударяя головой о стену (которая, как всегда, приносит больше урона голове, чем стене) без подсказки.

Обновление, 20140702:

Я собрал VLC для Android, и он может отображать поток, созданный VLC на пи. Он помещает изображение в верхнем левом углу экрана; Я попробовал написать свою собственную шкуру для их .so, и не мог найти никаких «ручек», которые позволяли бы мне масштабировать поверхность или что-то еще. (Плюс к .apk пришел к 12M!)

Итак, я нашел соответствующие RFC и написал свой собственный клиент RTSP. Или попытался: я могу разобрать SDP и создать достаточный допустимый RTSP для получения датаграмм RTP и RTCP, и я могу анализировать заголовки RTP и RTCP. Но даже несмотря на то, что SDP утверждает, что доставляет m = видео 0 RTP / AVP 96 и a = rtpmap: 96 H264 / 90000, MediaCodec не будет отображать видео на моей поверхности, независимо от того, какой из трех кодеков H264 на моем планшете я прохожу В MediaCodec.createByCodecName () , и когда я смотрю на полезные ресурсы RTP, я не слишком удивлен: я не вижу шаблон синхронизации NAL в любом из пакетов.

Вместо этого все они начинаются либо с 21 9A __ 22 FF (обычно), либо изредка 3C 81 9A __ 22 FF , где __ всегда будет четным числом, которое увеличивается на 2 каждого пакета. Я не признаю этот образец – не так ли?

Обновление, 20140711:

Оказывается, что пакеты H264 не должны начинаться с шаблона синхронизации NAL – это необходимо только там, где блоки NAL могут быть встроены в больший поток данных. Мои пакеты RTP находятся в формате RFC 6184 .

Solutions Collecting From Web of "Почему я получаю ошибки «Неподдерживаемый формат», считывая потоки rtsp, закодированные H.264, с помощью Android MediaPlayer?"

После невероятного количества тупиков я могу показать поток H264 RTSP на Android SurfaceView . Этот ответ – это всего лишь ответ, потому что я все еще не могу ответить на мои первоначальные три вопроса, но даже полный ошибок и ярлыков, как это, мой 75K apk намного лучше, чем Vlc для Android или osmo4-плеер: -средняя задержка (по крайней мере, когда отправитель и получатель находятся на одном и том же Wi-Fi маршрутизаторе!) И заполняет SurfaceView .

Несколько выводов, чтобы помочь любому, кто пытается сделать что-то подобное:

  • Все входные буферы, которые вы передаете MediaCodec.queueInputBuffer() должны начинаться с шаблона синхронизации 00 00 01.
  • Вы можете сразу configure() и start() кодек, но не ставить в очередь никаких «нормальных» входных буферов, пока не увидите пакет SPS (NALU код 7) и PPS (NALU code 8). (Это могут быть не 0x67 и 0x68 – бит nal_ref_idc должен быть отличным от нуля, но необязательно равен 11. Fwiw, vlc кажется, всегда дает мне 01.)
  • Передавайте пакеты SPS / PPS почти нормально – передайте флаг queueInputBuffer() в queueInputBuffer() . В частности, не пытайтесь помещать их в буфер «csd-0», прикрепленный к MediaFormat !
  • Когда вы видите (а) пропущенные рамки ( т. codec.flush() Вы видите прыжок в порядковом номере RTP) , не вызывайте codec.flush() ! Просто пропустите частичный кадр и не ставьте очередь в буфер до следующего полного кадра.