安卓中opencv的网络摄像头捕获,使用ffmpeg构建并为Android编译



我刚刚购买了一个onwave网络摄像机,主要目的是使用Android平板电脑进行图像处理和监控。在本机编码时,当使用 FFMPEG 为 java、python 和 C++ 进行交叉编译时。视频捕获类与网络摄像机网址完美地工作。它显示了使用RTSP协议进行流式传输的IPcamera的帧。 例如在C++ `

Mat frame
Videocapture cap;
cap.open(rtsp:// the url);
while(true)
{
cap.read(frame);
waitkey(1);
} 

该代码完美运行,它为我提供了来自 LAN 上相机流的帧,几乎没有延迟。对于python和为Java编译时也是如此。

然而,当来到Android时,问题就来了,因为适用于Android的opencv sdk本身并不支持ffmpeg。起初,我不想再次使用适用于android的ffmpeg编译它,而是选择了JavaCV,它带有预构建的ffmpeg帧抓取器类,并且还保留了opencv的本机源代码。然而,当我尝试在位图上显示帧时,图像采集卡让我失败了,并且存在巨大的渲染问题,数据包丢失并且帧全部乱码,还尝试使用 FrameRecorder 类并在后台录制文件,但结果相同。 后来我尝试使用安卓媒体播放器。附上我使用媒体播放器的代码。

package com.example.rob.androidipcamera4;
import android.app.Activity;
import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends Activity implements        MediaPlayer.OnPreparedListener,SurfaceHolder.Callback {
final static String RTSP_URL="rtsp://192.168.1.7:554/onvif1";
private static String USERNAME="";
private static String PASSWORD="";
private MediaPlayer mediaplayer;
private  SurfaceHolder surfaceholder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
Window window=getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
window.setBackgroundDrawableResource(android.R.color.black);
setContentView(R.layout.activity_main);
//Configuring the surfaceview
SurfaceView surfaceView=(SurfaceView)findViewById(R.id.surfaceView);
surfaceholder = surfaceView.getHolder();
surfaceholder.addCallback(this);
surfaceholder.setFixedSize(320,320);
}
@Override
public void onPrepared(MediaPlayer mp) {
mediaplayer.start();
}
@Override
public void surfaceCreated(SurfaceHolder sh)  {
mediaplayer=new MediaPlayer();
mediaplayer.setDisplay(surfaceholder);
Context context=getApplicationContext();
Map<String,String>headers=getRTSPHeaders();
Uri source=Uri.parse(RTSP_URL);
try{
mediaplayer.setDataSource(context,source,headers);
mediaplayer.setOnPreparedListener(this);
mediaplayer.prepareAsync();
}
catch (Exception e){
System.out.println("Sorry no media ");
};
}
@Override
public void surfaceChanged(SurfaceHolder sh, int f, int w, int h) {}
@Override
public void surfaceDestroyed(SurfaceHolder sh) {
mediaplayer.release();
}
private  Map<String,String>getRTSPHeaders() {
Map<String,String>headers=new HashMap<String, String>();
String basicAuthValue=getBasicAuthValue(USERNAME,PASSWORD);
headers.put("Authorisation",basicAuthValue);
return headers;
}
private String getBasicAuthValue(String usr,String pwd){
String credientials=usr+":"+pwd;
int flags= Base64.URL_SAFE|Base64.NO_WRAP;
byte[]bytes=credientials.getBytes();
return "Basic" + Base64.encodeToString(bytes,flags) ;
}
}

虽然帧的分辨率很好,也让我可以选择拍摄每一帧并进行一些运动检测,但是实时流中大约有 7 秒的延迟,这在监控中是完全不可接受的。

所以我想我又回到了原点,为安卓编译 ffmpeg .我只是有疑问,因为使用 opencv 编译的 ffmpeg 在 C++ 和 Python(在 Linux 上(中完美运行,给了我 0.2 秒的延迟,使用 android 编译 ffmpeg 是否会给我相同的结果,以及我是否可以像我在 C++ 中一样使用 android 中的视频捕获类,而无需使用 NDK?如果有人曾经使用官方 SDK 在带有 ipcam 的 Android 平板电脑和手机上尝试过这个,那将非常有帮助。或者是否有另一种使用媒体播放器或 JavaCV 的方法,它可以让我轻松或没有延迟,没有任何乱码

为ffmpeg 配置您想要的所有内容需要一些时间,尽管我有一段时间没有碰它,但也许有什么变化。更好的开始是寻找一个已经集成的 github 项目,并从那里开始,应该有很多这样的项目(找到一个更新的项目(。当我在做视频通话的时候,大约 3 年前,没有合适的 Android 媒体 API,目前有低级回调,所以你应该成功实现任何你想要的东西。

我实际上已经通过从源代码编译适用于Android的OpenCV库(ARMHF(以及包括libav,libswsscale等的FFMPEG库来解决这个问题。然后,我首先使用 ffmpegs avframe 类捕获帧,并在单独的 pthread 中将帧转换为 openCV 的 Mat 并应用所有图像处理算法,最后通过 JNI 从主程序调用主函数。

最新更新