【发布时间】:2017-12-15 16:39:03
【问题描述】:
我刚刚购买了一台 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);
}
代码完美运行,它为我提供了 LAN 上摄像头流中的帧,几乎没有延迟。python 和 Java 编译时也是如此。
然而,当来到 android 时问题就来了,因为 android 的 opencv sdk 本身并不支持 ffmpeg。起初我不想用 ffmpeg for android 重新编译它,而是选择了 JavaCV,它带有预构建的 ffmpegframegrabber 类并且还保留opencv 的本机源代码。但是当我尝试使用它在位图上显示帧时,framegrabber 失败了,并且丢包存在巨大的渲染问题,并且帧全部乱码,还尝试使用 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 让我在没有任何乱码帧的情况下几乎没有延迟
【问题讨论】:
标签: android opencv android-mediaplayer javacv android-ffmpeg