在 Android 上录制视频时拍照

Posted

技术标签:

【中文标题】在 Android 上录制视频时拍照【英文标题】:Taking picture while recording video on Android 【发布时间】:2018-01-02 00:49:00 【问题描述】:

我编写了如下所示的 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 示例。录制视频和拍照都可以,但是当我在录制时尝试拍照时,没有创建图片(但也没有错误)。尽管如此,我发现这个示例应用程序运行起来不是很可靠(也许还有另一个示例应用程序)。

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

【问题讨论】:

rawCallback 上的数据即使没有记录也是空的。在过去的 10 年中,我没有看到任何一种设备能够在此回调中提供有意义的数据。至于 jpegCallback,是什么让你相信它应该可以工作? @AlexCohn 为什么 jpegCallback 不能工作?我犯错了吗?使用 Android 库存相机应用程序,我可以在录制时拍照,所以我相信它应该可以工作...... 那是什么设备? @AlexCohn 这是华为 MediaPad M2 平板电脑(10")。 你试过Open Camera吗? 【参考方案1】:

编辑:

澄清:

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

只需保持您传递给 MediaRecorder 的同一个相机实例,并在其上调用 Camera.takePicture()。

Camera2 还通过同时创建具有预览、录制和 JPEG 输出的会话来更灵活地支持这一点。

原答案:

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

判断是否可以同时使用多个摄像头的唯一方法是在一个摄像头已经打开时尝试打开第二个摄像头。如果它有效,你应该很高兴;如果不是,则该设备不支持同时支持多个摄像头。

【讨论】:

我想用前置摄像头录制视频,同时用前置摄像头拍照。 我对我的原始帖子进行了编辑。使用 Camera.takePicture() 不起作用,虽然我的设备应该能够在录制时拍摄照片。【参考方案2】:

不,您不能打开单独的相机实例进行视频录制和静止图像捕捉。对于此类任务,已弃用的 Camera API 不可靠(例如,请参阅关于三星​​ S4 的 Android camera parameter IsVideoSnapshotSupported incorrectly set to false)。

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

【讨论】:

camera2 API 听起来很有趣。如果我理解正确,我可以创建一个相机实例,然后使用这个实例从前置摄像头录制视频,同时从前置摄像头拍照。您能否提供一些代码示例如何实现?那就太好了。 我用我的新方法对我的原始帖子进行了编辑。 谢谢,通过您的回答,我找到了一个带有项目的示例存储库! github.com/mobapptuts/android_camera2_api_video_app你对我帮助很大!

以上是关于在 Android 上录制视频时拍照的主要内容,如果未能解决你的问题,请参考以下文章

Android20.3 拍照和视频录制

有没有办法打开相机并在屏幕上查看它并使其无法拍照或录制视频。

Android拍照,录制视频,相机简单功能实现

Android拍照丶录制视频功能实现

Android CameraX实现摄像头预览拍照录制视频

Android 11 拍照+录制视频保存到外部共享区域