我刚刚购买了一台 onwave ip 摄像头,主要目的是使用 Android 平板电脑进行图像处理和监控。在本机编码以及使用 FFMPEG 为 java、python 和 C++ 交叉编译时。Videocapture 类与 ip camera url 完美配合。它显示了使用 rtsp 协议进行流式传输的 ipcamera 的帧。例如在 C++ 中
Mat frame
Videocapture cap;
cap.open(rtsp:// the url);
while(true)
{
cap.read(frame);
waitkey(1);
}
该代码完美无缺,它为我提供了局域网上摄像机流中的帧,几乎没有延迟。python 和为 Java 编译时也是如此。
然而,当来到android时问题就来了,因为android的opencv sdk本身并不支持ffmpeg。起初我不想用ffmpeg for android重新编译它,而是选择了JavaCV,它带有预构建的ffmpegframegrabber类并且还保留了本机源代码opencv 的代码。但是当我尝试它时,我无法使用帧抓取器在位图上显示帧,并且存在丢包的巨大渲染问题,并且帧都出现乱码,还尝试使用 FrameRecorder 类并在后台记录文件但相同结果。后来我尝试使用适用于 Android 的 Mediaplayer。附加的是我使用媒体播放器的代码。
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 秒的延迟,这在监控中根本不可接受。
所以我想我回到了为 android 编译 ffmpeg 的问题上。我只是有疑问,因为用 opencv 编译的 ffmpeg 在 C++ 和 Python(在 linux 上)中完美地工作给了我 0.2 秒的延迟,无论用 android 编译 ffmpeg 是否会给我相同的结果以及我是否可以像使用 C++ 一样在 android 中使用 Videocapture 类,而不使用 NDK?如果有人曾经使用官方 sdk 在带有 ipcam 的 Android 平板电脑和手机上尝试过这一点,那将非常有帮助。或者是否有其他方法可以使用媒体播放器或 JavaCV 让我几乎没有延迟或没有任何乱码帧