我正在尝试使用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混淆。
非常感谢帮助,谢谢。
答案 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实现。
Java实现。
我只想提到这个想法,但基本上它是基于这些标准Real-Time Streaming Protocol Version 2.0和RTP Payload Format for H.264 Video在java中实现RTSP服务器和RTP协议。这项任务将是漫长而艰难的。但如果您正在使用PhP,那么为Android安装一个不错的RTSP Java库可能会很不错。
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等,并提供实用程序类,使其功能更易于在Java平台上使用,包括(当然)Android
JavaCV还带有硬件加速的全屏图像显示(CanvasFrame
和GLCanvasFrame
),易于使用的方法在多个核心(Parallel
)上并行执行代码,用户友好的相机和投影仪的几何和颜色校准(GeometricCalibrator
,ProCamGeometricCalibrator
,ProCamColorCalibrator
),特征点的检测和匹配(ObjectFinder
),一组类实现投影仪 - 相机系统(主要是GNImageAligner
,ProjectiveTransformer
,ProjectiveColorTransformer
,ProCamTransformer
和ReflectanceInitializer
)的直接图像对齐,一个blob分析包({{ 1}}),以及Blobs
类中的各种功能。其中一些类还有一个OpenCL和OpenGL对应物,它们的名称以JavaCV
结尾或以CL
开头,即:GL
,JavaCVCL
等。
但我们如何使用此解决方案?
这里我们有一个使用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。
祝你好运