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.
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ć? –
@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
Które urządzenie to jest? –