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

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

到目前为止我所做的是将H264video打包成rtsp数据包,并使用VLC(通过UDP )对其进行解码,因此我知道video的格式至少是正确的。 但是,我无法以可以理解的格式将video数据发送到ffmpeg

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

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

我想我正在寻找的是关于如何实现这一点的建议。 最佳解决方案是将分组化的H264video通过管道发送到ffmpeg ,但是我无法向ffmpeg发送解码video所需的sdp文件参数。

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

哦,我开始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实现。

    我只想提一下这个想法,但基本上它是基于这些标准的实时流协议版本2.0和H.264video的RTP有效载荷格式在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使用常用的计算机视觉库包装器,包括:( OpenCV , FFmpeg等),并提供实用程序类,使其function更易于在Java平台上使用,包括(当然)Android。

    JavaCV还带有硬件加速全屏图像显示( CanvasFrameGLCanvasFrame ),易于使用的方法在多个内核上Parallel执行代码( Parallel ),用户友好的相机和投影仪几何和颜色校准( GeometricCalibratorProCamGeometricCalibratorProCamColorCalibrator ),特征点的检测和匹配( ObjectFinder ),一组实现投影仪 – 相机系统(主要是GNImageAlignerProjectiveTransformerProjectiveColorTransformerProCamTransformerReflectanceInitializer )直接图像对齐的类,一个blob分析包( Blobs ),以及JavaCV类中的各种function。 其中一些类还具有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); 

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

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

请记住将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 。

祝你好运