我正在尝试使用安卓系统的硬件H264编码器来创建摄像头的视频,并使用FFmpeg来多路传输音频(所有这些都在安卓手机上)
到目前为止,我所做的是将H264视频打包成rtsp数据包,并使用VLC (通过UDP)对其进行解码,因此我知道视频至少是正确格式化的。但是,我很难将视频数据转换成ffmpeg可以理解的格式。
我尝试发送相同的rtsp包到本地主机上的5006端口(通过UDP),然后为ffmpeg提供sdp文件,该文件告诉它视频流是从哪个本地端口进入的,以及如何解码视频,如果我正确理解rtsp流的话。然而,这不起作用,我在诊断原因时遇到了问题,因为ffmpeg只是坐在那里等待输入。
由于延迟和可伸缩性的原因,我不能只是将视频和音频发送到服务器并在那里进行多路复用,它必须在手机上完成,以尽可能轻量级的方式完成。
我想我正在寻找的是关于如何实现这一点的建议。最好的解决方案是通过管道将打包的H264视频发送到ffmpeg,但是我无法向ffmpeg发送解码视频所需的sdp文件参数。
我可以根据要求提供更多信息,比如ffmpeg是如何为安卓编译的,但我怀疑这是否必要。
哦,我启动ffmpeg的方式是通过命令行,如果可能的话,我真的宁愿避免使用jni。
如果能帮上忙我们会很感激,谢谢。
发布于 2012-10-31 11:42:03
你试过使用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读取。它不是管道,但它应该比使用网络接口更好。
发布于 2017-12-06 18:08:47
有点晚了,但我认为这是一个很好的问题,而且还没有一个好的答案。
如果你想从android设备上流式传输摄像头和麦克风,你有两个主要的选择: Java或NDK实现。
Java implementation.的
我只想提一下这个想法,但基本上它是在这些标准Real-Time Streaming Protocol Version 2.0和RTP Payload Format for H.264 Video的基础上用java实现一个RTSP Server和RTP协议。这项任务将非常漫长和艰巨。但是如果你正在做你的PhP,有一个很好的用于安卓的RTSP Java lib可能会很好。
这是一种替代方案,包括各种解决方案。主要思想是在我们的安卓应用程序中使用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,<代码>D23,<代码>D24和<代码>D25),斑点分析包(<代码>D26),以及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);这部分代码展示了如何初始化名为recorder的FFmpegFrameRecorder对象。这个对象将捕获并编码从摄像头获得的帧和从麦克风获得的样本。
如果你想在相同的安卓应用程序中捕获预览,那么我们需要实现一个CameraPreview类,这个类将转换相机提供的原始数据,它将为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 (图片),并将其转换为帧并由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:portip_source是流式传输摄像头和麦克风流的智能手机的ip。端口必须是相同的8080。
我在github存储库中创建了一个解决方案:UDPAVStreamer。
祝好运
https://stackoverflow.com/questions/7744489
复制相似问题