-[AVCapturePhotoBracketSettings setLivePhotoMovieMetadata:] Unsupported when doing a bracketed capture

AVCapturePhotoSettings @property livePhotoMovieMetadata is marked as null_resettable:


@property(nonatomic, copy, null_resettable) NSArray<AVMetadataItem *> *livePhotoMovieMetadata;


However, assigning nil to livePhotoMovieMetadata subsequently calling AVCapturePhotoOutput setPreparedPhotoSettingsArray: with an AVCapturePhotoBracketSettings instance will always throw the following exception (in iOS 10 beta7):


*** -[AVCapturePhotoBracketSettings setLivePhotoMovieMetadata:] Unsupported when doing a bracketed capture


Code example:


@property (nonatomic) AVCaptureSession* captureSession;
@property (nonatomic) AVCapturePhotoOutput* capturePhotoOutput;
@property (nonatomic) AVCaptureDevice* videoDevice;

- (void)configureCaptureSession;
{
    self.captureSession = [[AVCaptureSession alloc] init];
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    self.videoDevice = devices[[devices indexOfObjectPassingTest:^BOOL(AVCaptureDevice* device, NSUInteger idx, BOOL *stop) {
        if(device.position == AVCaptureDevicePositionBack) {
            *stop = TRUE; return(YES);
        }
        return(NO);
    }]];
    assert(self.videoDevice);

    [self.captureSession beginConfiguration];
    NSError* error;
    AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:self.videoDevice error:&error];
    assert(videoDeviceInput && [self.captureSession canAddInput:videoDeviceInput]);
    [self.captureSession addInput:videoDeviceInput];

    self.captureSession.sessionPreset = AVCaptureSessionPresetPhoto;

    self.capturePhotoOutput = [[AVCapturePhotoOutput alloc] init];
    assert(self.capturePhotoOutput && [self.captureSession canAddOutput:self.capturePhotoOutput]);


    [self.captureSession addOutput:self.capturePhotoOutput];
    self.capturePhotoOutput.highResolutionCaptureEnabled = YES;
    self.capturePhotoOutput.livePhotoCaptureEnabled = NO; // <--- NOTE!

    // Let's assume we're running this on a device that actually supports RAW capture.
    assert(self.capturePhotoOutput.availableRawPhotoPixelFormatTypes.count > 0);
     
    OSType rawPixelFormatType = [self.capturePhotoOutput.availableRawPhotoPixelFormatTypes.firstObject unsignedIntValue];

    NSArray<AVCaptureBracketedStillImageSettings *>* bracketedSettings = @[ [AVCaptureAutoExposureBracketedStillImageSettings autoExposureSettingsWithExposureTargetBias:(-2.0f)], [AVCaptureAutoExposureBracketedStillImageSettings autoExposureSettingsWithExposureTargetBias:(-1.0f)], [AVCaptureAutoExposureBracketedStillImageSettings autoExposureSettingsWithExposureTargetBias:(0.0f)], [AVCaptureAutoExposureBracketedStillImageSettings autoExposureSettingsWithExposureTargetBias:(+1.0f)] ];
  
    assert(bracketedSettings.count <= self.capturePhotoOutput.maxBracketedCapturePhotoCount);
  
    AVCapturePhotoBracketSettings* capturePhotoSettings = [AVCapturePhotoBracketSettings photoBracketSettingsWithRawPixelFormatType:rawPixelFormatType processedFormat:nil bracketedSettings:bracketedSettings];


    capturePhotoSettings.livePhotoMovieMetadata = nil; // <--- NOTE!

    @try
    {
        [self.capturePhotoOutput setPreparedPhotoSettingsArray:@[capturePhotoSettings] completionHandler:nil];
    }
    @catch (NSException *exception)
    {
        NSLog(@"%@", exception.description);
        // The following exception SHOULD NOT be thown here:
        // *** -[AVCapturePhotoBracketSettings setLivePhotoMovieMetadata:] Unsupported when doing a bracketed capture
        assert(false);
    }

    [self.captureSession commitConfiguration];
}


The exception (Line 51) will always be thrown.

Note that Live Photo Capture is disabled (Line 31).


Is this a bug or am I missing something?

Accepted Reply

Thanks for filing this bug report. This is an actual framework bug, not anything you're doing wrong. The bug affects AVCapturePhotoBracketSettings on which photoSettingsFromPhotoSettings is called. The workaround for the time being is to not call photoSettingsFromPhotoSettings: on instances of AVCapturePhotoBracketSettings. Just make a new, fresh bracket settings instance each time you want to capture or prepare a bracket. Also, this code:


capturePhotoSettings.livePhotoMovieMetadata = nil;


is unnecessary and should be omitted, since AVCapturePhotoBracketSettings default to livePhotoMovieMetadata being nil (note that since it's a null-resettable property, if you query it, it will always give you a nonnull value, which in this property's case is an empty dictionary).

Replies

By the way, this exception is also thrown by AVCapturePhotoOutput -capturePhotoWithSettings: delegate: (regardless of the settings and whether or not setPreparedPhotoSettingsArray: was called beforehand), so I guess that bracketed captures don't work in general on iOS 10 beta 7.

Filed as Bug #27933956 under https://bugreport.apple.com

Thanks for filing this bug report. This is an actual framework bug, not anything you're doing wrong. The bug affects AVCapturePhotoBracketSettings on which photoSettingsFromPhotoSettings is called. The workaround for the time being is to not call photoSettingsFromPhotoSettings: on instances of AVCapturePhotoBracketSettings. Just make a new, fresh bracket settings instance each time you want to capture or prepare a bracket. Also, this code:


capturePhotoSettings.livePhotoMovieMetadata = nil;


is unnecessary and should be omitted, since AVCapturePhotoBracketSettings default to livePhotoMovieMetadata being nil (note that since it's a null-resettable property, if you query it, it will always give you a nonnull value, which in this property's case is an empty dictionary).

Thanks for sharing the workaround!