繁体   English   中英

使用ffmpeg实时解码android的硬件编码的H264相机feed

[英]Decode android's hardware encoded H264 camera feed using ffmpeg in real time

我正在尝试使用Android上的硬件H264编码器从相机创建视频,并使用FFmpeg音频(全部在Android手机本身上)

到目前为止,我已经完成的工作是将H264视频打包为rtsp数据包,并使用VLC(通过UDP )对其进行解码,因此我知道视频的格式至少正确。 但是,我无法以可以理解的格式将视频数据传输到ffmpeg

我试过将相同的rtsp数据包发送到本地主机上的端口5006(通过UDP),然后为ffmpeg提供sdp文件,该文件告诉它视频流进入哪个本地端口以及如何解码视频(如果我理解) rtsp正确流式传输。 但是,这是行不通的,由于ffmpeg只是坐在那里等待输入,因此我无法诊断原因。

出于延迟和可伸缩性的考虑,我不能仅将视频和音频发送到服务器并在服务器上进行复用,而必须在电话中以尽可能轻便的方式完成。

我猜我正在寻找有关如何实现此目标的建议。 最佳解决方案是通过管道将打包的H264视频发送到ffmpeg ,但随后我无法将解码视频所需的sdp文件参数发送给ffmpeg

我可以根据要求提供更多信息,例如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实现。

  1. Java实现。

    我只想提一下这个想法,但基本上,它是基于这些标准的H.264 Video 实时流协议2.0版RTP有效负载格式在Java中实现RTSP服务器和RTP协议。 这项任务将非常漫长而艰巨。 但是,如果您正在做PhP,那么拥有一个适用于Android的RTSP Java库可能会很好。

  2. NDK实现。

    这是备选方案,包括各种解决方案。 主要思想是在我们的Android应用程序中使用功能强大的C或C ++库。 对于此实例,FFmpeg。 该库可以针对Android进行编译,并且可以支持各种架构。 这种方法的问题是您可能需要了解Android NDK,C和C ++才能完成此任务。

    但是还有另一种选择。 您可以包装c库并使用FFmpeg。 但是如何?

    例如,使用FFmpeg Android ,它已与x264,libass,fontconfig,freetype和fribidi一起编译,并支持各种体系结构。 但是,如果要实时流式传输,仍然很难编程,就需要处理文件描述符和输入/输出流。

    从Java编程的角度来看,最好的选择是使用JavaCV JavaCV使用来自常用计算机视觉库的包装器,这些包装器包括:( OpenCVFFmpeg等),并提供实用程序类以使其功能更易于在Java平台(当然包括Android)上使用。

    JavaCV还具有硬件加速的全屏图像显示( CanvasFrameGLCanvasFrame ),易于使用的方法以在多核上并行执行代码( Parallel ),相机和投影仪的用户友好型几何和颜色校准( GeometricCalibratorProCamGeometricCalibratorProCamColorCalibrator ),特征点的检测和匹配( ObjectFinder ),实现投影仪与相机系统直接图像对齐的一组类(主要是GNImageAlignerProjectiveTransformerProjectiveColorTransformerProCamTransformerReflectanceInitializer ),斑点分析包( Blobs ),以及JavaCV类中的其他功能。 其中一些类还具有OpenCL和OpenGL对应类,它们的名称以CL结尾或以GL开头,即: JavaCVCLGLCanvasFrame等。

但是我们如何使用该解决方案?

在这里,我们有一个使用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类,该类将转换从Camera提供的原始数据,并将为FFmpegFrameRecorder创建Preview和Frame。

切记将ip_destination替换为要向其发送流的PC或设备的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方法的实现,该方法从相机获取Mat(图片),并将其转换为Frame并由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记录。

在PC或设备目标中,您可以运行以下命令以获取流。

ffplay udp://ip_source:port

ip_source是正在传输摄像头和麦克风流的智能手机的ip。 端口必须与8080相同。

我在github存储库中创建了一个解决方案: UDPAVStreamer

祝好运

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM