We once had an issue similar to what you are describing (sometime after the release of iOS 8) but were able to resolve it by following the proper procedure, as outlined in WWDC 2014 Session 508.
Let's assume you know the manual settings (exposure duration, ISO, white balance gains, lens position) for your specific test environment.
You can lock the camera to those specific settings as follows:
AVCaptureDevice* device = [ ... your capture device ... ];
[device lockForConfiguration:nil];
CMTime manualExposureDuration = [...];
float manualISO = [...];
AVCaptureWhiteBalanceGains manualWhiteBalanceGains = [...];
float manualLensPosition = [...];
CMTime __block nextValidSampleBufferTime = kCMTimeZero;
[device setExposureModeCustomWithDuration:manualExposureDuration ISO:manualISO completionHandler:^(CMTime syncTime) {
nextValidSampleBufferTime = CMTimeMaximum(nextValidSampleBufferTime, syncTime);
}];
[device setWhiteBalanceModeLockedWithDeviceWhiteBalanceGains:manualWhiteBalanceGains completionHandler:^(CMTime syncTime) {
nextValidSampleBufferTime = CMTimeMaximum(nextValidSampleBufferTime, syncTime);
}];
[device setFocusModeLockedWithLensPosition:manualLensPosition completionHandler:^(CMTime syncTime) {
nextValidSampleBufferTime = CMTimeMaximum(nextValidSampleBufferTime, syncTime);
}];
[device unlockForConfiguration];
// (... later ...)
AVCaptureSession* captureSession = [... your capture session ...];
CMSampleBufferRef photoSampleBuffer = [ ... from AVCaptureVideoDataOutput/AVCapturePhotoOutput/... ]
CMTime sampleBufferTime = CMSyncConvertTime(CMSampleBufferGetPresentationTimeStamp(photoSampleBuffer), captureSession.masterClock, CMClockGetHostTimeClock());
if(CMTimeCompare(sampleBufferTime, nextValidSampleBufferTime) >= 0)
{
// We have a buffer to which the manual settings have been applied.
}
In our application, we started with auto-exposure/white balance/focus (AVCaptureExposureModeContinuousAutoExposure, AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance, AVCaptureFocusModeContinuousAutoFocus) and stored the current settings for a specific test environment. Later, we would use the code above to restore the those exact settings.
This worked for us and produced consistent, repeatable results.