在同一个AVCaptureSession中使用多个AVCaptureVideoDataOutput

7
我想知道是否可以在单个相机设备输入中向AVCaptureSession添加多个AVCaptureVideoDataOutput
我的实验表明,添加第二个VideoDataOutput将导致canAddOutput返回NO。但是我在苹果的文档中没有找到任何地方说明不允许多个数据输出。
1个回答

7
我们不能使用单个AVCaptureSession对象来处理多个AVCaptureVideoDataOutput对象。
你可以创建多个AVCaptureSession对象和多个AVCaptureVideoDataOutput对象。你可以创建两种不同的AVCaptureVideoDataOutputAVCaptureSession设置,然后在应用程序中一个接一个地使用它们,这样你就能够实现目标。
在我的情况下,我需要同时捕获前后摄像头的图像。
我按照以下方式为AVCaptureVideoDataOutputAVCaptureSession创建了两个不同的对象。
/* 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;

现在,在视图加载时,我首先设置了后置摄像头,并为两个会话设置了开始录制或未开始录制的标志。

- (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];

}

现在,无论何时用户开始进行照片捕捉,我们将使用以下代码捕获前置摄像头的照片。

- (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;

    }

}

一旦后置图像被捕获,我们将使用 setupFrontAVCapture 方法设置会话以捕获前置图像,然后使用 takeFrontPhoto 方法捕获前置图像,如下所示。
- (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;

    }

}

通过这种方式,您可以使用两个不同的AVCaptureSessionAVCaptureStillImageOutput对象,从而实现您的目标。

如果您有任何疑问,请告诉我。


谢谢你提供信息,Jayesh。你知道这种方法是否适用于单个输入设备吗?我的目标是使用同一后置摄像头,并在不同分辨率下获得两个输出。 - xuguo
不,您不能同时使用单个输入设备。在您的情况下,您可以从原始输出创建另一个分辨率文件。这可能是您的一个选择。或者您可以使用两个不同的会话,一个接一个地使用。但这将需要一两秒钟的间隔。 - Jayeshkumar Sojitra
谢谢!这与我的实验结果一致。我现在接受你的解决方案作为答案。但是,你知道苹果有没有说过这是不允许的地方吗? - xuguo
嗨@xuguo, 我和你处于同样的情况。我有一个需要同时录制视频和流视频的应用程序。我需要以4k的分辨率进行录制,但对于流媒体,我可以使用较低的分辨率。现在我正在使用CoreImage调整4k图像的大小,但如果您有更有效的解决方案,我很乐意听取。谢谢。 - Arkader

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接