Исправить файл 3GP после потоковой передачи с Android Media Recorder

Я пытаюсь потоковое видео с камеры Android через локальный сокет Unix и записать файл из потока на SDCard. Все работает нормально, за исключением того, что файл не воспроизводится ни на одном плеере. Это потому, что Android не заполняет некоторые пробелы в файле, потому что сокет не доступен для поиска. Как я понимаю, мне нужно внести некоторые изменения после окончания видеопотока. Я прочитал несколько статей здесь, здесь и здесь, но ни одна из них не помогла мне. Я играю с шестнадцатеричным редактором, чтобы научиться делать это вручную, поэтому после этого будет тривиально сделать то же самое в коде Android.

Вот пример файла, который был сохранен из потока: https://dl.dropbox.com/u/17510473/sample_not_playable.3gp

Может кто-нибудь исправить, чтобы сделать его играбельным и рассказать как он это сделал?

РЕДАКТИРОВАТЬ: я удаляю заголовок 3gp файла и пишу новый следующим образом:

00 00 00 18 66 74 79 70 33 67 70 34 00 00 03 00 33 67 70 34 33 67 70 36 00 00 00 00

Затем я нахожу начальное местоположение атомов mdat и moov с помощью следующей команды:

grep -aobE "ftyp|mdat|moov" sample_not_playable.3gp

И это дает мне следующий вывод:

4:ftyp
28:mdat
1414676:moov

Тогда сделай 1414676 - 28 = 1,414,648 = 0x1595F8

Затем я пишу 0x1595F8 как 25-28 байт, как раз перед атомом mdat. Так что мой заголовок теперь выглядит так:

00 00 00 18 66 74 79 70 33 67 70 34 00 00 03 00 33 67 70 34 33 67 70 36 00 15 95 F8

И когда я пытаюсь воспроизвести его с помощью mplayer, я получаю несколько поврежденных видео и аудио выходов. Вот некоторая часть из вывода mplayer:

[amrwb @ 0x7f72ad652380]Frame too small (33 bytes). Truncated file?
[amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame
[amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame
[amrwb @ 0x7f72ad652380]Frame too small (33 bytes). Truncated file?
[amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame
[amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame
[amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame
A:  11.0 V:   1.4 A-V:  9.650 ct:  0.023   0/  0 10%  1%  1.6% 0 0                                                        
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f72adeafc40]stream 1, offset 0x15e62b: partial file
[h263 @ 0x7f72ad652380]Bad picture start code
[h263 @ 0x7f72ad652380]header damaged
Error while decoding frame!
[h263 @ 0x7f72ad652380]Bad picture start code
[h263 @ 0x7f72ad652380]header damaged
Error while decoding frame!
[h263 @ 0x7f72ad652380]Bad picture start code
[h263 @ 0x7f72ad652380]header damaged
Error while decoding frame!
A:  11.1 V:   1.5 A-V:  9.558 ct:  0.027   0/  0  9%  1%  1.4% 0 0                                                        
[h263 @ 0x7f72ad652380]Bad picture start code
[h263 @ 0x7f72ad652380]header damaged
Error while decoding frame!

Что я делаю не так?

2 ответа

Решение

Что вам нужно понять, так это то, что mp4 не является живым форматом. следовательно, вы никак не сможете взломать все вокруг, чтобы сделать его живым. Заголовок [moov atom] написан в конце. Android создает в памяти таблицу размеров фреймов и других параметров, которые затем записывает в начале файла в конце записи, из-за чего ему требуется возможность поиска дескриптора файла. [который не является сокетом]

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

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

Нет никакого способа, которым вы можете осуществлять потоковую трансляцию файлов mp4 в Android. Я видел множество людей, пытающихся сделать это напрасно, и если вы понимаете видео / форматы, вы не сможете это сделать. mp4 не предназначен для прямой трансляции. Если вы не знаете заранее размеры вашего кадра [которого вы не знаете] и точную длину кодирования [который вы, скорее всего, не знаете; t), вы не можете предварительно создать заголовок.

пс. mp4 и 3gp - двоюродные братья и сестры, поэтому применяется то же самое.

Многие люди путают потоковую трансляцию с http pd и псевдопотоковой трансляцией. Прямая трансляция означает, что у меня нет целого файла, он создается и также транслируется на лету. http pd и псевдопоток осуществляются с полностью доступными файлами.

РЕДАКТИРОВАТЬ:

Если ваша цель - зашифровать записанный файл перед сохранением в SDCard, вам нужна поддержка кодировщика. Это подразумевает получение вашего собственного кодера. Возьми ffmpeg, скомпилируй его на андроид. Напишите небольшой интерфейс JNI для вашего приложения. Получите это первым без шифрования. После этого, когда ffmpeg записывает поток, добавьте свой модуль шифрования. То же самое при декодировании. Y3ng создание. Это самый чистый способ сделать это.

РЕДАКТИРОВАТЬ 2: См Spydroid, чтобы получить некоторые функции для вас. Там есть похожие.

РЕДАКТИРОВАТЬ 3: Чтобы улучшить качество ответа, я объясняю несовершенный обходной путь, который также дают другие ответы:

Можно по-прежнему выполнять потоковую передачу AV, анализируя mp4, когда он генерируется, и отправляя элементарные потоки отдельно через сокет. Единственная проблема, с которой вы столкнетесь, заключается в том, что вы не получите идеальную синхронизацию AV, поскольку вы не знаете точные временные метки AV-сэмпла. Только андроид знает об этом и пишет в конце в заголовке mp4. Так что не годится для тебя. Вы должны сделать предположение об идеальной частоте дискретизации видеокадров, и ваш звук должен быть amr, чтобы принять 20 мс пакетов. В других аудио случаях вы начнете видеть дрейф в долгосрочной перспективе [особенно, когда у вас начнутся сцены с высоким движением]. Это связано с тем, что каждый сгенерированный аудиопакет не соответствует фиксированной длительности [за исключением amr и других речевых кодеков]

Прежде всего, не очень понятно, что вы пытаетесь сделать.

Вы хотите просто сохранить видео программно в воспроизводимый файл? Если это так, вам просто нужно использовать дескриптор файла вместо сокета Unix. Этот API MediaRecord был разработан для работы с файлом (не с сокетом Unix), именно по причине произвольного доступа. Итак, мой первый совет - использовать дескриптор файла, и вы получите правильный файл в конце записи.

Вы можете получить примеры здесь: Как я могу сделать запись видео на Android?

В случае, если вы пытаетесь написать приложение, которое передает потоковое видео с устройства, вам нужно будет проанализировать поток в реальном времени, разделить его на кадры и отправить кадры отдельно. И самая сложная часть - это анализ потока (некоторые видеокодеки, как, например, H263, могут быть проанализированы, а другие - нет, особенно если данные чередуются со звуком).

Я полагаю, что один из этих двух проектов реализует такую ​​функциональность: http://sipdroid.org/ http://code.google.com/p/imsdroid/

Другие вопросы по тегам