Расшифруйте аппаратно-закодированный канал Android-камеры с помощью ffmpeg в реальном времени - PullRequest
28 голосов
/ 12 октября 2011

Я пытаюсь использовать аппаратный кодер H264 на Android для создания видео с камеры и использовать FFmpeg для воспроизведения звука (все на самом телефоне Android)

What I 'До сих пор мы делали пакетирование видео H264 в пакеты rtsp и декодирование его с использованием VLC (более UDP), поэтому я знаю, что видео по крайней мере правильно отформатировано.Однако у меня возникают проблемы с получением видеоданных до ffmpeg в формате, который он может понять.

Я попытался отправить те же самые rtsp пакеты в порт 5006 на локальном хосте (через UDP),затем предоставив ffmpeg файл sdp, который сообщает ему, на какой локальный порт поступает видеопоток и как декодировать видео, если я правильно понимаю rtsp потоковую передачу.Однако это не работает, и у меня возникают проблемы с диагностикой почему, поскольку ffmpeg просто сидит и ждет ввода.

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

То, что я думаю, я ищу, это предложения о том, как это можно сделать.Оптимальным решением будет отправка пакетированного H264 видео в ffmpeg по каналу, но тогда я не смогу отправить ffmpeg sdp параметров файла, необходимых для декодирования видео.

Iможет предоставить более подробную информацию по запросу, например, как ffmpeg скомпилировано для Android, но я сомневаюсь, что это необходимо.

О, и способ запуска ffmpeg через командную строку, я бы действительно предпочел избежать взломас JNI, если это вообще возможно.

И помощь будет высоко ценится, спасибо.

Ответы [ 2 ]

1 голос
/ 06 декабря 2017

Немного поздно, но я думаю, что это хороший вопрос, и на него пока нет хорошего ответа.

Если вы хотите транслировать камеру и микрофон с устройства 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 ++, чтобы выполнить это.

    Но есть альтернатива. Вы можете обернуть библиотеку 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 голос
/ 31 октября 2012

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

...