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

时间:2011-10-12 18:06:58

标签: android ffmpeg h.264 rtsp

我正在尝试使用Android上的硬件H264编码器从相机创建视频,并使用FFmpeg来复用音频(所有这些都在Android手机上)

到目前为止我所做的是将H264视频打包成rtsp个数据包,然后使用VLC(UDP)解码,所以我知道视频至少是正确的格式化。但是,我无法以可以理解的格式将视频数据传输到ffmpeg

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

出于延迟和可扩展性的原因,我不能将视频和音频发送到服务器并将其复制到那里,必须以尽可能轻的方式在手机上完成。

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

我可以根据请求提供更多信息,例如如何为Android编译ffmpeg,但我怀疑这是必要的。

哦,我开始ffmpeg的方式是通过命令行,如果可能的话,我宁愿避免与jni混淆。

非常感谢帮助,谢谢。

2 个答案:

答案 0 :(得分:1)

您是否尝试过使用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 :(得分:1)

有点晚了,但我认为这是一个很好的问题,但它还没有一个好的答案。

如果你想从Android设备流式传输相机和麦克风,你有两个主要选择:Java或NDK实现。

  1. Java实现。

    我只想提到这个想法,但基本上它是基于这些标准Real-Time Streaming Protocol Version 2.0RTP Payload Format for H.264 Video在java中实现RTSP服务器和RTP协议。这项任务将是漫长而艰难的。但如果您正在使用PhP,那么为Android安装一个不错的RTSP Java库可能会很不错。

  2. NDK实施。

    这是另类包括各种解决方案。主要思想是在我们的Android应用程序中使用power 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)的直接图像对齐,一个blob分析包({{ 1}}),以及Blobs类中的各种功能。其中一些类还有一个OpenCL和OpenGL对应物,它们的名称以JavaCV结尾或以CL开头,即:GLJavaCVCL等。

  3. 但我们如何使用此解决方案?

    这里我们有一个使用UDP流的基本实现。

    GLCanvasFrame

    这部分代码显示了如何初始化名为recorder的FFmpegFrameRecorder对象。此对象将捕获和编码从摄像机获取的帧和从麦克风获得的样本。

    如果你想在同一个Android应用程序中捕获预览,那么我们需要实现一个CameraPreview类,这个类将转换从Camera提供的原始数据,它将为FFmpegFrameRecorder创建预览和框架。

    请记住将ip_destination替换为要发送流的pc或设备的ip。例如,端口可以是8080。

    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);
    

    此方法显示了从摄像机获取Mat(图片)的@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; } 方法的实现,它被转换为Frame并由FFmpegFrameRecorder对象记录。

    onCameraFrame

    与音频相同,@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对象,将由FFmpegFrameRecorder录制。

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

    ShortBuffer

    ffplay udp://ip_source:port 是正在流式传输相机和麦克风流的智能手机的IP。端口必须相同8080。

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

    祝你好运