在Android上录制视频时拍照

mac*_*ery 7 android android-camera android-mediarecorder

我编写了下面显示的Android服务,用于在后台录制前置摄像头.这非常有效.但现在我想在录制的同时每隔5秒拍一张照片.这有点可能吗?当我尝试打开第二台相机(在另一项服务中)时,我收到了错误消息.

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; }
}
Run Code Online (Sandbox Code Playgroud)

编辑:我现在写了一个帖子PictureThread.该RecorderService视频录制时,该线程启动并尝试拍照.

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");
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

不幸的是jpegCallback永远不会被调用(即永远不会打印日志消息).当我打开平板电脑的相机应用程序时,我可以在视频录制时拍照,所以这应该是可能的.

我也曾尝试Camera2 API例如由Alex科恩(所建议https://github.com/mobapptuts/android_camera2_api_video_app).录制视频可以正常工作并拍摄照片但是当我在录制时尝试拍照时,不会创建图片(但也没有错误).不过,我发现这个示例应用程序工作不太可靠(也许还有另一个示例应用程序).

编辑2:该shutterCallbackrawCallbacktakePicture被调用,但的数据rawCallback为空.在jpegCallback得到从来没有所谓.任何想法,为什么和这可怎么解决呢?我还尝试在线程中等待一段时间来给出被调用的回调时间,并且我试图在我的主活动中使回调静态(这样它就不会被垃圾回收).没有任何效果.

Edd*_*ala 5

编辑:

澄清:

老相机API支持调用takePicture()正在录制的视频,如果Camera.Parameters.isVideoSnapshotSupported设备上的报告是真实的问题.

只需按住您传入MediaRecorder的相同实例,并在其上调用Camera.takePicture().

通过同时创建具有预览,录制和JPEG输出的会话,Camera2还可以更灵活地支持此功能.

原始答案:

如果您的意思是使用后置摄像头拍照,则使用前置摄像头进行录制 - 这取决于设备.有些设备有足够的硬件资源可以同时运行多个摄像头,但大多数设备不会(它们共享两个摄像头之间的处理硬件).

判断是否可以同时使用多个摄像头的唯一方法是尝试打开第二个摄像头.如果它有效,你应该好好去; 如果没有,该设备不会同时支持多个摄像头.