Декодирование видео с камеры H264 с аппаратным кодированием Android с помощью ffmpeg в реальном времени

Я пытаюсь использовать аппаратный кодировщик 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, если это вообще возможно.

И помощь будет очень признательна, спасибо.

28
задан HitOdessit 4 October 2012 в 08:30
поделиться

2 ответа

Вы пытались использовать 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. Это не труба, но это должно быть лучше, чем использование сетевого интерфейса.

1
ответ дан 28 November 2019 в 03:58
поделиться
1136 Немного опоздал, но я думаю, что это хороший вопрос, и на него пока нет хорошего ответа.

Если вы хотите транслировать камеру и микрофон с устройства Android, у вас есть две основные альтернативы: реализации Java или NDK.

  1. Реализация Java.

    Я только собираюсь упомянуть эту идею, но в основном она реализует RTSP-сервер и протокол RTP в Java на основе этих стандартов. Потоковый протокол реального времени версии 2.0 и Формат полезной нагрузки RTP для Видео H.264 . Это задание будет очень долгим и сложным. Но если вы делаете свой PhP, было бы неплохо иметь хорошую RTSP Java lib для Android.

  2. Реализация 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 .

Удачи

1
ответ дан 28 November 2019 в 03:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: