Я пытаюсь использовать аппаратный кодировщик H264
на Android для создания видео с камеры и использовать FFmpeg
для мультиплексирования в аудио (все на самом телефоне Android)
То, что я сделал до сих пор, - это пакетирование видео H264
в пакеты rtsp
и его декодирование с помощью VLC ( over UDP
), поэтому я знаю, что видео по крайней мере правильно отформатировано. Однако у меня возникают проблемы с получением видеоданных в ffmpeg
в формате, который он может понять.
Я попытался отправить те же пакеты rtsp
на порт 5006 на локальном хосте (через UDP), а затем предоставил ffmpeg
файл sdp
, который сообщает это на какой локальный порт поступает видеопоток и как декодировать видео, если я правильно понимаю rtsp
потоковую передачу. Однако это не работает, и мне сложно определить причину, поскольку ffmpeg
просто сидит и ждет ввода.
По причинам задержки и масштабируемости я не могу просто отправить видео и аудио на сервер и мультиплексировать их там, это должно быть сделано на телефоне, как можно более легким способом.
Думаю, я ищу предложения о том, как этого можно достичь.Оптимальным решением было бы отправить пакетное видео H264
на ffmpeg
по каналу, но тогда я не могу отправить ffmpeg
sdp
параметры файла, необходимые для декодирования видео.
Я могу предоставить дополнительную информацию по запросу, например, как ffmpeg
скомпилирован для Android, но я сомневаюсь, что это необходимо.
Да, и способ запуска ffmpeg
- через командную строку, я бы предпочел избегать возиться с jni, если это вообще возможно.
И помощь будет очень признательна, спасибо.
Вы пытались использовать java.lang.Runtime?
String[] parameters = {"ffmpeg", "other", "args"};
Program program Runtime.getRuntime().exec(parameters);
InputStream in = program.getInputStream();
OutputStream out = program.getOutputStream();
InputStream err = program.getErrorStream();
Затем вы пишете в stdout и читаете из stdin и stderr. Это не труба, но это должно быть лучше, чем использование сетевого интерфейса.
Если вы хотите транслировать камеру и микрофон с устройства Android, у вас есть две основные альтернативы: реализации Java или NDK.
Реализация Java.
Я только собираюсь упомянуть эту идею, но в основном она реализует RTSP-сервер и протокол RTP в Java на основе этих стандартов. Потоковый протокол реального времени версии 2.0 и Формат полезной нагрузки RTP для Видео H.264 . Это задание будет очень долгим и сложным. Но если вы делаете свой PhP, было бы неплохо иметь хорошую RTSP Java lib для Android.
Реализация NDK.
Это альтернатива включает в себя различные решения. Основная идея - использовать мощную библиотеку C или C ++ в нашем приложении для Android. Для этого экземпляра FFmpeg. Эта библиотека может быть скомпилирована для Android и может поддерживать различные архитектуры. Проблема этого подхода в том, что вам может потребоваться узнать об Android NDK, C и C ++, чтобы выполнить это.
1142 Но есть альтернатива. Вы можете обернуть библиотеку c и использовать FFmpeg. Но как?
Например, используя FFmpeg Android , который был скомпилирован с x264, libass, fontconfig, freetype и fribidi и поддерживает различные архитектуры. Но все равно сложно запрограммировать, если вы хотите осуществлять потоковую передачу в реальном времени, вам нужно иметь дело с файловыми дескрипторами и входными / выходными потоками.
Лучшая альтернатива, с точки зрения программирования на Java, - это использование JavaCV . JavaCV использует оболочки из обычно используемых библиотек компьютерного зрения, которые включают в себя: ( OpenCV , FFmpeg и т. Д., И предоставляют служебные классы, облегчающие использование их функций на платформе Java, включая ( конечно) Android.
JavaCV также поставляется с аппаратным ускорением полноэкранного отображения изображений (CanvasFrame
и GLCanvasFrame
), простыми в использовании методами для параллельного выполнения кода на нескольких ядрах (Parallel
), удобная геометрическая и цветовая калибровка камер и проекторов (GeometricCalibrator
, ProCamGeometricCalibrator
, ProCamColorCalibrator
), обнаружение и сопоставление характерных точек (ObjectFinder
), набор классов, реализующих прямое выравнивание изображения проектора -камерные системы (в основном GNImageAligner
, ProjectiveTransformer
, ProjectiveColorTransformer
, ProCamTransformer
и ReflectanceInitializer
), пакет анализа BLOB-объектов (Blobs
), а также различные функциональные возможности в классе JavaCV
. из этих классов также есть аналог OpenCL и OpenGL, имена которых заканчиваются на CL
или начинаются с GL
, то есть: JavaCVCL
, GLCanvasFrame
и т. д.
Но как мы можем использовать т его решение?
Здесь у нас есть базовая реализация для потоковой передачи с использованием UDP.
String streamURL = "udp://ip_destination:port";
recorder = new FFmpegFrameRecorder(streamURL, frameWidth, frameHeight, 1);
recorder.setInterleaved(false);
// video options //
recorder.setFormat("mpegts");
recorder.setVideoOption("tune", "zerolatency");
recorder.setVideoOption("preset", "ultrafast");
recorder.setVideoBitrate(5 * 1024 * 1024);
recorder.setFrameRate(30);
recorder.setSampleRate(AUDIO_SAMPLE_RATE);
recorder.setVideoCodec(AV_CODEC_ID_H264);
recorder.setAudioCodec(AV_CODEC_ID_AAC);
В этой части кода показано, как инициализировать объект FFmpegFrameRecorder, называемый рекордером. Этот объект будет захватывать и кодировать кадры, полученные с камеры, и сэмплы, полученные с микрофона.
Если вы хотите захватить предварительный просмотр в том же приложении Android, то нам нужно реализовать класс CameraPreview, этот класс преобразует необработанные данные, передаваемые с камеры, и создаст предварительный просмотр и кадр для FFmpegFrameRecorder.
Не забудьте заменить ip_destination на ip компьютера или устройства, на которое вы хотите отправить поток. Порт может быть 8080 в качестве примера.
@Override
public Mat onCameraFrame(Mat mat)
{
if (audioRecordRunnable == null) {
startTime = System.currentTimeMillis();
return mat;
}
if (recording && mat != null) {
synchronized (semaphore) {
try {
Frame frame = converterToMat.convert(mat);
long t = 1000 * (System.currentTimeMillis() - startTime);
if (t > recorder.getTimestamp()) {
recorder.setTimestamp(t);
}
recorder.record(frame);
} catch (FFmpegFrameRecorder.Exception e) {
LogHelper.i(TAG, e.getMessage());
e.printStackTrace();
}
}
}
return mat;
}
Этот метод показывает реализацию метода onCameraFrame
, который получает мат (изображение) с камеры, и он преобразуется в виде кадра и записывается объектом FFmpegFrameRecorder.
@Override
public void onSampleReady(ShortBuffer audioData)
{
if (recorder == null) return;
if (recording && audioData == null) return;
try {
long t = 1000 * (System.currentTimeMillis() - startTime);
if (t > recorder.getTimestamp()) {
recorder.setTimestamp(t);
}
LogHelper.e(TAG, "audioData: " + audioData);
recorder.recordSamples(audioData);
} catch (FFmpegFrameRecorder.Exception e) {
LogHelper.v(TAG, e.getMessage());
e.printStackTrace();
}
}
Как и в случае со звуком, audioData
является объектом ShortBuffer
, который будет записываться с помощью FFmpegFrameRecorder.
На ПК или на устройстве вы можете запустить следующую команду, чтобы получить поток.
ffplay udp://ip_source:port
ip_source
- это ip-адрес смартфона, который передает потоковую камеру и микрофон. Порт должен быть таким же, как 8080.
Я создал решение в своем репозитории github здесь: UDPAVStreamer .
Удачи