2017-07-26 28 views
5

Napisałem poniżej opisaną usługę Android do nagrywania przedniej kamery w tle. Działa to bardzo dobrze. Ale teraz chciałbym również zrobić zdjęcie co 5 sekund podczas nagrywania. Czy to jakoś możliwe? Kiedy próbuję otworzyć drugą kamerę (w innej usłudze) pojawia się błąd.Robienie zdjęć podczas nagrywania wideo na Androidzie

public class RecorderService extends Service implements SurfaceHolder.Callback { 

    private WindowManager windowManager; 
    private SurfaceView surfaceView; 
    private Camera camera = null; 
    private MediaRecorder mediaRecorder = null; 

    @Override 
    public void onCreate() { 
     // Create new SurfaceView, set its size to 1x1, move it to the top left corner and set this service as a callback 
     windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE); 
     surfaceView = new SurfaceView(this); 
     WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
       1, 1, 
       WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, 
       WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, 
       PixelFormat.TRANSLUCENT 
     ); 
     layoutParams.gravity = Gravity.LEFT | Gravity.TOP; 
     windowManager.addView(surfaceView, layoutParams); 
     surfaceView.getHolder().addCallback(this); 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     Intent notificationIntent = new Intent(this, MainActivity.class); 

     PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, 
       notificationIntent, 0); 

     Notification notification = new NotificationCompat.Builder(this) 
       //.setSmallIcon(R.mipmap.app_icon) 
       .setContentTitle("Background Video Recorder") 
       .setContentText("") 
       .setContentIntent(pendingIntent).build(); 

     startForeground(MainActivity.NOTIFICATION_ID_RECORDER_SERVICE, notification); 
     return Service.START_NOT_STICKY; 
    } 

    // Method called right after Surface created (initializing and starting MediaRecorder) 
    @Override 
    public void surfaceCreated(SurfaceHolder surfaceHolder) { 
     camera = Camera.open(1); 
     mediaRecorder = new MediaRecorder(); 
     camera.unlock(); 

     mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface()); 
     mediaRecorder.setCamera(camera); 
     mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); 
     mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 
     mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_720P)); 

     FileUtil.createDir("/storage/emulated/0/Study/Camera"); 
     mediaRecorder.setOutputFile("/storage/emulated/0/Study/Camera/" + Long.toString(System.currentTimeMillis()) + ".mp4"); 

     try { mediaRecorder.prepare(); } catch (Exception e) {} 
     mediaRecorder.start(); 

     try { 
      camera.setPreviewDisplay(surfaceHolder); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     Runnable runnable = new PictureThread(camera); 
     Thread thread = new Thread(runnable); 
     thread.start(); 
    } 

    // Stop recording and remove SurfaceView 
    @Override 
    public void onDestroy() { 
     mediaRecorder.stop(); 
     mediaRecorder.reset(); 
     mediaRecorder.release(); 

     camera.lock(); 
     camera.release(); 

     windowManager.removeView(surfaceView); 
    } 

    @Override 
    public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {} 

    @Override 
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {} 

    @Override 
    public IBinder onBind(Intent intent) { return null; } 
} 

Edit: Mam już napisany wątek PictureThread. Ten wątek rozpoczyna się od RecorderService i próbuje zrobić zdjęcie podczas nagrywania wideo.

public class PictureThread implements Runnable { 
    private final static String TAG = PictureThread.class.getSimpleName(); 

    private Camera camera; 

    PictureThread(Camera camera) { 
     this.camera = camera; 
    } 

    @Override 
    public void run() { 
     camera.startPreview(); 
     camera.takePicture(shutterCallback, rawCallback, jpegCallback); 
    } 

    Camera.ShutterCallback shutterCallback = new Camera.ShutterCallback() { 
     public void onShutter() { 
     } 
    }; 

    Camera.PictureCallback rawCallback = new Camera.PictureCallback() { 
     public void onPictureTaken(byte[] data, Camera camera) { 
     } 
    }; 

    Camera.PictureCallback jpegCallback = new Camera.PictureCallback() { 
     public void onPictureTaken(byte[] data, Camera camera) { 
      Log.i(TAG, "onPictureTaken - jpeg"); 
     } 
    }; 
} 

Niestety jpegCallback nigdy nie jest wywoływany (tzn. Komunikat dziennika nigdy nie jest drukowany). Kiedy otwieram aplikację aparatu w moim tablecie, mogę robić zdjęcia podczas nagrywania wideo, więc powinno to być możliwe.

Próbowałem również przykład Camera2 API, jak sugeruje Alex Cohn (https://github.com/mobapptuts/android_camera2_api_video_app). Nagrywanie filmu działa, a także robi zdjęcie, ale gdy próbuję zrobić zdjęcie podczas nagrywania, nie jest tworzony żaden obraz (ale także brak błędu). Niemniej jednak stwierdziłem, że ta przykładowa aplikacja nie działa niezawodnie (być może jest inna przykładowa aplikacja).

Edycja 2: The shutterCallback i rawCallback z takePicture pobiera nazywane ale dane o rawCallback jest null. jpegCallback nigdy nie jest wywoływany .. Jakieś pojęcie dlaczego i jak można to rozwiązać? Próbowałem również czekać w wątku przez pewien czas, aby dać czas oddzwaniania do wywołania i próbowałem uczynić wywołania zwrotne statyczne w mojej głównej aktywności (tak, że nie pobiera się śmieci). Nic nie działało.

+0

Dane o rawCallback są zerowe, nawet bez zapisu. W ciągu ostatnich 10 lat nie widziałem jednego urządzenia, które dostarczyłoby sensownych danych na temat tego wywołania zwrotnego. Jeśli chodzi o jpegCallback, co sprawia, że ​​uważasz, że to powinno działać? –

+0

@AlexCohn Dlaczego funkcja jpegCallback nie działa? Czy popełniłem błąd? Dzięki aplikacji kamery Android mogę robić zdjęcia podczas nagrywania, więc uważam, że powinno działać ... – machinery

+0

Które urządzenie to jest? –

Odpowiedz

4

Edit:

Z wyjaśnień:

Stary aparat API obsługuje wywołanie takePicture(), gdy film jest nagrany, jeśli Camera.Parameters.isVideoSnapshotSupported raporty prawda na urządzenie pytanie.

Po prostu przytrzymaj tę samą instancję kamery, którą przechodzisz do MediaRecorder, i wywołaj na nim Camera.takePicture().

Kamera 2 obsługuje również większą elastyczność, tworząc sesję z podglądem, nagrywaniem i wyjściami JPEG w tym samym czasie.

Oryginalny odpowiedź:

Jeśli masz na myśli robienie zdjęć z tyłu aparatu, podczas nagrywania z przodu kamery - to urządzenie zależne. Niektóre urządzenia mają wystarczającą ilość zasobów sprzętowych do jednoczesnego uruchomienia wielu kamer, ale większość z nich nie będzie (współużytkują sprzęt do przetwarzania między tymi dwoma kamerami).

Jedynym sposobem na stwierdzenie, czy można użyć wielu kamer naraz, jest próba otwarcia drugiej kamery, gdy jest już otwarta. Jeśli to działa, powinieneś być dobry, aby iść; jeśli nie, to urządzenie nie obsługuje jednocześnie wielu kamer.

+0

Chcę nagrać wideo z przedniego aparatu i jednocześnie robić zdjęcie z przedniej kamery. – machinery

+0

Dokonałem edycji mojego oryginalnego wpisu. Używanie funkcji Camera.takePicture() nie działa, mimo że moje urządzenie powinno przechwytywać obrazy podczas nagrywania. – machinery

1

Nie, nie można otworzyć oddzielnych instancji kamery do nagrywania wideo i robienia zdjęć. Nieaktualny interfejs API aparatu nie jest niezawodny w przypadku takich zadań (patrz np. Android camera parameter IsVideoSnapshotSupported incorrectly set to false na temat Samsung S4).

Możesz użyć interfejsu API camera2 (na urządzeniach obsługujących taki tryb), aby przechwytywać różne formaty i rozdzielczości z tej samej instancji kamery. Tutaj jest tutorial wideo: https://www.nigeapptuts.com/android-video-app-still-capture-recording/

+0

Camera2 API brzmi interesująco. Jeśli dobrze Cię rozumiem, mogę utworzyć instancję kamery, a następnie użyć tej instancji do nagrywania wideo z przedniej kamery i robienia zdjęć z przedniej kamery. Czy możesz podać przykład kodu, jak można to osiągnąć? To byłoby bardzo miłe. – machinery

+0

https://www.nigeapptuts.com/android-video-app-still-capture-recording/ –

+0

Dokonałem edycji mojego oryginalnego wpisu z moim nowym podejściem. – machinery