Захват веб-камеры для opencv в Android, созданный с помощью ffmpeg и скомпилированный для Android

Я только что купил ip-камеру onwave, основной целью было выполнять обработку и мониторинг изображений с помощью планшета Android. При кодировании изначально и при кросс-компиляции для java, python и C ++ с FFMPEG. Класс Videocapture работает с URL-адресом ip-камеры работает безупречно. Он показывает кадры ip-камеры, которая использует протокол rtsp для потоковой передачи. например, в С++ `

       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. Однако фреймграббер подвел меня, когда я попытался показать кадры на растровом изображении, и возникла огромная проблема с рендерингом с потерей пакетов, и кадр был искажен, также пробовал с классом FrameRecorder и записывал файл в фоновом режиме, но с тем же результат. Позже я попытался использовать медиаплеер для 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 и телефонах с ip-камерой, используя официальный sdk. Или есть ли другой способ, используя медиаплеер или JavaCV, который дает мне небольшую задержку или не дает никаких искаженных кадров?


person rob    schedule 11.07.2017    source источник


Ответы (2)


Потребуется некоторое время, чтобы настроить все, что вы хотите для ffmpeg, правда, я его пока не трогал, может быть, что-то изменилось. Лучше начать с поиска проекта github, в который он уже интегрирован, и начать с этого, их должно быть много (найдите более новый). Когда я работал над видеовызовами, около 3 лет назад, не было подходящего Android-API для мультимедиа, в настоящее время есть низкоуровневые обратные вызовы, поэтому вы должны успешно реализовать все, что хотите.

person user6168651    schedule 11.07.2017

на самом деле я решил проблему, скомпилировав библиотеки opencv для android (armhf) из исходного кода, а также библиотеки ffmpeg, которые включают libav, libswsscale и т. д. Затем я сначала захватил кадры, используя классы ffmpegs avframe, и преобразовал кадр в мат openCV в отдельном pthread и применил все алгоритмы обработки изображений, прежде чем, наконец, вызвать основную функцию из основной программы через JNI.

person rob    schedule 07.03.2018