录制视频时在前后摄像头之间切换

Posted

技术标签:

【中文标题】录制视频时在前后摄像头之间切换【英文标题】:Switch between front and back camera while recording a video 【发布时间】:2017-12-26 20:50:17 【问题描述】:

我创建了一个自定义摄像头,并尝试添加一个功能,用户可以在。我现在的方法是在他们切换相机时停止并开始一个新视频,但它会切断一点视频,我不知道为什么。我怎样才能让它像 snapchat 一样,以便它获得完整的视频,并且在他们切换相机时不会切断任何东西。到目前为止,这是我的代码

@objc func switchCameraInput() 
        self.captureSession.beginConfiguration()
        var existingConnection:AVCaptureDeviceInput!

        for connection in self.captureSession.inputs 
            let input = connection as! AVCaptureDeviceInput
            if input.device.hasMediaType(AVMediaType.video) 
                existingConnection = input
            
        

        self.captureSession.removeInput(existingConnection)
        turnFlashOff()

        var newCamera:AVCaptureDevice!
        if let oldCamera = existingConnection 
            if oldCamera.device.position == .back 
                newCamera = self.cameraWithPosition(position: .front)
             else 
                newCamera = self.cameraWithPosition(position: .back)
            
        

        var newInput:AVCaptureDeviceInput!

        do 
            newInput = try AVCaptureDeviceInput(device: newCamera)
            self.captureSession.addInput(newInput)

         catch 
            ProgressHUD.showError(error.localizedDescription)
        


        self.captureSession.commitConfiguration()

    // This is where i handle switching while recording
    if self.movieFileOutput.isRecording 
        hasSwappedCamera = true
        turnFlashOff()
        //self.movieFileOutput.stopRecording()
        self.movieFileOutput.connection(with: AVMediaType.video)?.videoOrientation = self.videoOrientation()
        self.movieFileOutput.maxRecordedDuration = self.maxRecordedDuration()
        self.movieFileOutput.startRecording(to: URL(fileURLWithPath:self.videoFileLocation()), recordingDelegate: self)
        turnOnFlash()
    

【问题讨论】:

看来这个问题可以帮到你...***.com/questions/44577331/… @BHendricks 这是在目标 c 中,你有没有机会帮我快速解决? 【参考方案1】:

由于 the question 我认为这将有助于回答您在 Objective-C 中的问题,并且您更喜欢 Swift,我已经“翻译”了下面的所有代码。

请注意,我没有编译这个,并且知道一些东西不会编译启动。像 AVMediaTypeVideo 这样的枚举值在 Swift 中通常只是 .video。另外,我很确定答案有一些不正确的代码,主要是围绕将isFrontRecordingisBackRecording 布尔值设置回false。我认为这些应该发生在completionHandler 中,但正如我所提到的,我没有编译这个,所以请谨慎对待。我包含了该问题(Objective-C)中的所有代码以及我对 Swift 的快速而肮脏的翻译。

我希望这会有所帮助:)

目标-C:

/* Front camera settings */
@property bool isFrontRecording;
@property (strong, nonatomic) AVCaptureDeviceInput *videoInputBack;
@property (strong, nonatomic) AVCaptureStillImageOutput *imageOutputBack;
@property (strong, nonatomic) AVCaptureSession *sessionBack;

/* Back camera settings */
@property bool isBackRecording;
@property (strong, nonatomic) AVCaptureDeviceInput *videoInputFront;
@property (strong, nonatomic) AVCaptureStillImageOutput *imageOutputFront;
@property (strong, nonatomic) AVCaptureSession *sessionFront;

斯威夫特:

var isFrontRecording: Bool
var videoInputBack: AVCaptureDeviceInput
var imageOutputBack: AVCaptureStillImageOutput
var sessionBack: AVCaptureSession

var isBackRecording: Bool
var videoInputFront: AVCaptureDeviceInput
var imageOutputFront: AVCaptureStillImageOutput
var sessionFront: AVCaptureSession

目标-C

- (void)viewDidLoad 
    [super viewDidLoad];

    [self setupBackAVCapture];

    self.isFrontRecording = NO;
    self.isBackRecording = NO;


- (void)setupBackAVCapture

    NSError *error = nil;

    self.sessionBack = [[AVCaptureSession alloc] init];
    self.sessionBack.sessionPreset = AVCaptureSessionPresetPhoto;

    AVCaptureDevice *camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    self.videoInputBack = [[AVCaptureDeviceInput alloc] initWithDevice:camera error:&error];
    [self.sessionBack addInput:self.videoInputBack];

    self.imageOutputBack = [[AVCaptureStillImageOutput alloc] init];
    [self.sessionBack addOutput:self.imageOutputBack];


斯威夫特:

override func viewDidLoad() 
    super.viewDidLoad()
    setupBackAVCapture()

    isFrontRecording = false
    isBackRecording = false


func setupBackAVCapture() 
    var error: NSError = nil
    sessionBack = AVCaptureSession()
    sessionBack.sessionPreset = AVCaptureSessionPresetPhoto

    let camera: AVCaptureDevice = AVCaptureDevice(defaultDeviceWithMediaType: AVMediaTypeVideo) 
    videoInputBack = AVCaptureDeviceInput(withDevice: camera, error: error)
    sessionBack.addInput(videoInputBack)

    imageOutputBack = AVCaptureStillImageOutput()
    sessionBack.addOutput(imageOutputBack)

目标-C:

- (IBAction)buttonCapture:(id)sender 
    [self takeBackPhoto];


- (void)takeBackPhoto

    [self.sessionBack startRunning];
    if (!self.isFrontRecording) 

        self.isFrontRecording = YES;

        AudioservicesPlaySystemSound(kSystemSoundID_Vibrate);
        AVCaptureConnection *videoConnection = [self.imageOutputBack connectionWithMediaType:AVMediaTypeVideo];

        if (videoConnection == nil) 
            return;
        


        [self.imageOutputBack
         captureStillImageAsynchronouslyFromConnection:videoConnection
         completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) 

             if (imageDataSampleBuffer == NULL) 
                 return;
             

             NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];

             UIImage *image = [[UIImage alloc] initWithData:imageData];

             UIImageWriteToSavedPhotosAlbum(image, self, nil, nil);

             [self.imageView setImage:image];

             [self.sessionBack stopRunning];

             // Set up front camera setting and capture photo.
             [self setupFrontAVCapture];
             [self takeFrontPhoto];

         ];

        self.isFrontRecording = NO;
    

斯威夫特:

@IBOutlet func buttonCapture(sender: Any) 
    takeBackPhoto()


func takeBackPhoto() 
    sessionBack.startRunning()
    if !isFrontRecording 
        isFrontRecording = true

        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
        let videoConnection: AVCaptureConnection = imageOutputBack.connectionWithMediaType(AVMediaTypeVideo)

        guard let videoConnection = videoConnection else 
            return
        

        imageOutputBack.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: 
            imageDataSampleBuffer: CMSSampleBufferRef, error: NSError in

            guard let imageDataSampleBuffer = imageDataSampleBuffer else 
                return
            

            let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)
            let image = UIImage(data: imageData)
            UIImageWriteToSavedPhotosAlbum(image, self, nil, nil)
            self.imageView.setImage(image)
            self.sessionback.stopRunning()

            // Set up front camera setting and capture photo.
            self.setupFronAVCapture()
            self.takeFrontPhoto()
        )

        isFrontRecording = false
    

目标-C

- (void)setupFrontAVCapture

    NSError *error = nil;

    self.sessionFront = [[AVCaptureSession alloc] init];
    self.sessionFront.sessionPreset = AVCaptureSessionPresetPhoto;

    AVCaptureDevice *camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    camera = [self cameraWithPosition:AVCaptureDevicePositionFront];

    self.videoInputFront = [[AVCaptureDeviceInput alloc] initWithDevice:camera error:&error];
    [self.sessionFront addInput:self.videoInputFront];

    self.imageOutputFront = [[AVCaptureStillImageOutput alloc] init];
    [self.sessionFront addOutput:self.imageOutputFront];


- (void)takeFrontPhoto

    [self.sessionFront startRunning];
    if (!self.isBackRecording) 

        self.isBackRecording = YES;

        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
        AVCaptureConnection *videoConnection = [self.imageOutputFront connectionWithMediaType:AVMediaTypeVideo];

        if (videoConnection == nil) 
            return;
        


        [self.imageOutputFront
         captureStillImageAsynchronouslyFromConnection:videoConnection
         completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) 

             if (imageDataSampleBuffer == NULL) 
                 return;
             

             NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];

             UIImage *image = [[UIImage alloc] initWithData:imageData];

             UIImageWriteToSavedPhotosAlbum(image, self, nil, nil);
             [self.imageViewBack setImage:image];

             [self.sessionFront stopRunning];


         ];

        self.isBackRecording = NO;

    


斯威夫特:

func setupFrontAVCapture() 
    let error: NSError = nil
    sessionFront = AVCaptureSession()
    sessionFront.sessionPreset = AVCaptureSessionPresentPhoto

    var camera: AVCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    camera = camera.cameraWithPosition(AVCaptureDevicePositionFront)

    videoInputFront = AVCaptureDeviceInput(withDevice: camera, error: error)
    sessionFront.addInput(videoInputFront)

    imageOutputFront = AVCaptureStillImageOutput()
    sessionFront.addOutput(imageOutputFront)


func takeFrontPhoto() 
    sessionFront.startRunning()

    if !isBackRecording 
        isBackRecording = true

        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
        let videoConnection: AVCaptureConnection = imageOutputFront.connectionWithMediaType(AVMediaTypeVideo)

        guard let videoConnection = videoConnection else 
            return
        

        imageOutputFront.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: 
            imageDataSampleBuffer: CMSampleBufferRef, error: NSError in

            guard let imageDataSampleBuffer = imageDataSampleBuffer else 
                return
            

            let imageData: NSData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)
            let image = UIImage(data: imageData)

            UIImageWriteToSavedPhotosAlbum(image, self, nil, nil)
            self.imageViewBack.setImage(image)
            self.sessionFront.stopRunning()
        )

        isBackRecording = false
    

祝你好运,让你的项目开始工作!

【讨论】:

它适用于静止图像,但在视频录制时切换相机仍然不清楚。【参考方案2】:

我为这个完全相同的问题找到了一个合适的解决方案,而不是用一个捕获会话和一个输出来切换输入,您必须为每个输入(相机)创建一个会话,然后在它们之间切换输出。

您可以在这里找到更多详细信息:https://***.com/a/54770398/2448590

【讨论】:

以上是关于录制视频时在前后摄像头之间切换的主要内容,如果未能解决你的问题,请参考以下文章

如何在iOS中一次录制前后摄像头的视频

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

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

同时录制视频和播放音频文件

切换相机后音频/视频不同步

Android 使用CameraX实现预览/拍照/录制视频/图片分析/对焦/缩放/切换摄像头等操作