有点晚了,但我认为这是一个好问题,目前还没有很好的答案。
如果你想从Android设备流式传输相机和麦克风,你有两个主要选择:Java或NDK实现。
1. Java实现。
我只会提到这个想法,但基本上它是在Java中实现一个基于这些标准
Real-Time Streaming Protocol Version 2.0和
RTP Payload Format for H.264 Video的RTSP服务器和RTP协议。这项任务将非常漫长和艰难。但如果你正在做你的PhP,那么拥有一个漂亮的Android RTSP Java库可能是不错的。
2. NDK实现。
这是另一种选择,包括各种解决方案。主要思路是在我们的Android应用程序中使用强大的C或C++库。例如,FFmpeg。该库可以编译为Android并支持各种架构。这种方法的问题是你可能需要学习Android NDK、C和C++才能完成这项任务。
但是有一种替代方案。您可以包装c库并使用FFmpeg。但是如何?
例如,使用已编译x264、libass、fontconfig、freetype和fribidi并支持各种体系结构的FFmpeg Android。但是,如果您想要实时流式传输,则仍然很难进行编程,因为您需要处理文件描述符和输入/输出流。
从Java编程角度来看,最好的选择是使用JavaCV。 JavaCV使用常用计算机视觉库的包装器,包括:(OpenCV,FFmpeg等,并提供实用类以使它们在Java平台上更易于使用,包括(当然)Android。
JavaCV还配备了硬件加速的全屏图像显示(
CanvasFrame
和
GLCanvasFrame
)、在多个核上并行执行代码的易于使用的方法(
Parallel
)、用户友好的相机和投影仪几何和颜色校准(
GeometricCalibrator
、
ProCamGeometricCalibrator
、
ProCamColorCalibrator
)、特征点检测和匹配(
ObjectFinder
)、实现投影仪-摄像头系统直接图像对齐的一组类(主要为
GNImageAligner
、
ProjectiveTransformer
、
ProjectiveColorTransformer
、
ProCamTransformer
和
ReflectanceInitializer
)、一个斑点分析包(
Blobs
),以及在
JavaCV
类中的其他杂项功能。其中一些类还具有OpenCL和OpenGL对应物,它们的名称以
CL
结尾或以
GL
开头,例如:
JavaCVCL
、
GLCanvasFrame
等。
但我们如何使用这个解决方案呢?
这里我们有一个基本实现来使用UDP进行流式传输。
String streamURL = "udp://ip_destination:port";
recorder = new FFmpegFrameRecorder(streamURL, frameWidth, frameHeight, 1);
recorder.setInterleaved(false);
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类,该类将转换从摄像机提供的原始数据,并创建预览和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:port
ip_source
是智能手机流媒体摄像头和麦克风的IP地址。端口必须是相同的8080。
我在我的github存储库中创建了一个解决方案,链接在这里:
UDPAVStreamer。
祝好运