繁体   English   中英

在Android上录制视频时拍照

[英]Taking picture while recording video on Android

我编写了下面显示的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; }
}

编辑 :我现在写了一个线程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");
        }
    };
}

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

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

编辑2: shutterCallbackrawCallbacktakePicture被调用,但数据rawCallback为空。 jpegCallback永远不会被调用..任何想法为什么以及如何解决这个问题? 我还尝试在线程中等待一段时间来给出被调用的回调时间,并且我试图在我的主活动中使回调静态(这样它就不会被垃圾回收)。 没有任何效果。

编辑:

澄清:

旧的相机API支持在录制视频时调用takePicture(),如果Camera.Parameters.isVideoSnapshotSupported在设备上报告为true则是问题。

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

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

原始答案:

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

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

不,您无法打开单独的相机实例进行视频录制和静止拍摄。 不推荐使用的Camera API对于此类任务不可靠(例如,请参阅Android相机参数IsVideoSnapshotSupported错误地将其设置为关于Samsung S4的错误 )。

您可以使用camera2 API(在支持此类模式的设备上)从同一个摄像头实例捕获不同的格式和分辨率。 这是一个视频教程: https//www.nigeapptuts.com/android-video-app-still-capture-recording/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM