Захват веб-камеры для opencv в Android, построенный с помощью ffmpeg и скомпилированный для Android
Я только что приобрел IP-камеру onwave, основная цель заключалась в том, чтобы выполнять обработку и мониторинг изображений с помощью планшета Android. Во время написания кода и при перекрестной компиляции для java, python и C++ с FFMPEG . Класс Videocapture работает с URL-адресом ip-камеры и работает безупречно. Это показывает кадры ipcamera, который использует протокол RTSP для потоковой передачи. например, в C++
Mat frame
Videocapture cap;
cap.open(rtsp:// the url);
while(true)
{
cap.read(frame);
waitkey(1);
}
Код работает безупречно, он дает мне кадры из потока камеры в моей локальной сети практически без задержки. То же самое для python и при компиляции для Java.
Однако проблема возникает при переходе на Android, так как opencv sdk для android изначально не поддерживает ffmpeg. Сначала я не хотел сначала скомпилировать его с ffmpeg для android, а вместо этого пошел на JavaCV, который поставляется с предварительно собранным классом ffmpegframegrabber, а также сохраняет собственный исходный код. коды opencv. Однако framegrabber не помог мне, когда я попытался показать кадры на растровом изображении, и возникла огромная проблема с рендерингом с потерей пакетов, а кадр оказался искаженным, также попытался с классом FrameRecorder и записал файл в фоновом режиме, но с тем же результат. Позже я попытался с помощью Mediaplayer для Android. Прикреплен мой код с помощью медиаплеера.
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 для android. У меня просто есть сомнения, так как ffmpeg, скомпилированный с opencv, работал безупречно в C++ и Python(в linux), давая мне задержку в 0,2 секунды, даст ли мне компиляция ffmpeg с android тот же результат и могу ли я использовать класс Videocapture в Android так же, как я сделал для C++, без использования NDK? Было бы очень полезно, если бы кто-нибудь когда-либо пробовал это на планшетах Android и телефонах с ipcam, используя официальный sdk. Или есть другой способ использования медиаплеера или JavaCV, который дает мне возможность без задержек без искаженных кадров
2 ответа
Я на самом деле решил эту проблему, скомпилировав библиотеки opencv для android (armhf) из исходного кода, а также библиотеки ffmpeg, которые включают libav, libswsscale и т. д. Затем я сначала захватил кадры с помощью классов ffmpegs avframe и преобразовал кадр в Mat OpenCV в отдельном pthread и применил все алгоритмы обработки изображений, прежде чем, наконец, вызвать основную функцию из основной программы через JNI.
Потребуется некоторое время, чтобы настроить все, что вы хотите для ffmpeg, хотя я некоторое время не трогал его, возможно, что-то изменилось. Лучше начать с поиска проекта github, в котором он уже интегрирован, и начать с него, их должно быть много (найдите более свежий). Когда я работал над видеозвонками, около 3 лет назад, не было соответствующего Android Media API, в настоящее время существуют низкоуровневые обратные вызовы, поэтому вы должны успешно реализовать все, что захотите.