| Index: webrtc/sdk/objc/Framework/Classes/avfoundationformatmapper.mm | 
| diff --git a/webrtc/sdk/objc/Framework/Classes/avfoundationformatmapper.mm b/webrtc/sdk/objc/Framework/Classes/avfoundationformatmapper.mm | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..19afa337683bacbeb7b1a14e2cd539cf821b6f09 | 
| --- /dev/null | 
| +++ b/webrtc/sdk/objc/Framework/Classes/avfoundationformatmapper.mm | 
| @@ -0,0 +1,135 @@ | 
| +/* | 
| + *  Copyright 2016 The WebRTC project authors. All Rights Reserved. | 
| + * | 
| + *  Use of this source code is governed by a BSD-style license | 
| + *  that can be found in the LICENSE file in the root of the source | 
| + *  tree. An additional intellectual property rights grant can be found | 
| + *  in the file PATENTS.  All contributing project authors may | 
| + *  be found in the AUTHORS file in the root of the source tree. | 
| + */ | 
| + | 
| +#include "avfoundationformatmapper.h" | 
| + | 
| +#import "WebRTC/RTCLogging.h" | 
| + | 
| +// TODO(denicija): add support for higher frame rates. | 
| +// See http://crbug/webrtc/6355 for more info. | 
| +static const int kFramesPerSecond = 30; | 
| + | 
| +static inline BOOL IsMediaSubTypeSupported(FourCharCode mediaSubType) { | 
| +  return (mediaSubType == kCVPixelFormatType_420YpCbCr8PlanarFullRange || | 
| +          mediaSubType == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange); | 
| +} | 
| + | 
| +static inline BOOL IsFrameRateWithinRange(int fps, AVFrameRateRange* range) { | 
| +  return range.minFrameRate <= fps && range.maxFrameRate >= fps; | 
| +} | 
| + | 
| +// Returns filtered array of device formats based on predefined constraints our | 
| +// stack imposes. | 
| +static NSArray<AVCaptureDeviceFormat*>* GetEligibleDeviceFormats( | 
| +    const AVCaptureDevice* device, | 
| +    int supportedFps) { | 
| +  NSMutableArray<AVCaptureDeviceFormat*>* eligibleDeviceFormats = | 
| +      [NSMutableArray array]; | 
| + | 
| +  for (AVCaptureDeviceFormat* format in device.formats) { | 
| +    // Filter out subTypes that we currently don't support in the stack | 
| +    FourCharCode mediaSubType = | 
| +        CMFormatDescriptionGetMediaSubType(format.formatDescription); | 
| +    if (!IsMediaSubTypeSupported(mediaSubType)) { | 
| +      continue; | 
| +    } | 
| + | 
| +    // Filter out frame rate ranges that we currently don't support in the stack | 
| +    for (AVFrameRateRange* frameRateRange in format.videoSupportedFrameRateRanges) { | 
| +      if (IsFrameRateWithinRange(supportedFps, frameRateRange)) { | 
| +        [eligibleDeviceFormats addObject:format]; | 
| +        break; | 
| +      } | 
| +    } | 
| +  } | 
| + | 
| +  return [eligibleDeviceFormats copy]; | 
| +} | 
| + | 
| +// Mapping from cricket::VideoFormat to AVCaptureDeviceFormat. | 
| +static AVCaptureDeviceFormat* GetDeviceFormatForVideoFormat( | 
| +    const AVCaptureDevice* device, | 
| +    const cricket::VideoFormat& videoFormat) { | 
| +  AVCaptureDeviceFormat* desiredDeviceFormat = nil; | 
| +  NSArray<AVCaptureDeviceFormat*>* eligibleFormats = | 
| +      GetEligibleDeviceFormats(device, videoFormat.framerate()); | 
| + | 
| +  for (AVCaptureDeviceFormat* deviceFormat in eligibleFormats) { | 
| +    CMVideoDimensions dimension = | 
| +        CMVideoFormatDescriptionGetDimensions(deviceFormat.formatDescription); | 
| +    FourCharCode mediaSubType = | 
| +        CMFormatDescriptionGetMediaSubType(deviceFormat.formatDescription); | 
| + | 
| +    if (videoFormat.width == dimension.width && | 
| +        videoFormat.height == dimension.height) { | 
| +      if (mediaSubType == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { | 
| +        // This is the preferred format so no need to wait for better option. | 
| +        return deviceFormat; | 
| +      } else { | 
| +        // This is good candidate, but let's wait for something better. | 
| +        desiredDeviceFormat = deviceFormat; | 
| +      } | 
| +    } | 
| +  } | 
| + | 
| +  return desiredDeviceFormat; | 
| +} | 
| +namespace webrtc { | 
| +std::set<cricket::VideoFormat> GetSupportedVideoFormatsForDevice( | 
| +    AVCaptureDevice* device) { | 
| +  std::set<cricket::VideoFormat> supportedFormats; | 
| + | 
| +  NSArray<AVCaptureDeviceFormat*>* eligibleFormats = | 
| +      GetEligibleDeviceFormats(device, kFramesPerSecond); | 
| + | 
| +  for (AVCaptureDeviceFormat* deviceFormat in eligibleFormats) { | 
| +    CMVideoDimensions dimension = | 
| +        CMVideoFormatDescriptionGetDimensions(deviceFormat.formatDescription); | 
| +    cricket::VideoFormat format = cricket::VideoFormat( | 
| +        dimension.width, dimension.height, | 
| +        cricket::VideoFormat::FpsToInterval(kFramesPerSecond), | 
| +        cricket::FOURCC_NV12); | 
| +    supportedFormats.insert(format); | 
| +  } | 
| + | 
| +  return supportedFormats; | 
| +} | 
| + | 
| +bool SetFormatForCaptureDevice(AVCaptureDevice* device, | 
| +                               AVCaptureSession* session, | 
| +                               const cricket::VideoFormat& format) { | 
| +  AVCaptureDeviceFormat* deviceFormat = | 
| +      GetDeviceFormatForVideoFormat(device, format); | 
| +  const int fps = cricket::VideoFormat::IntervalToFps(format.interval); | 
| + | 
| +  NSError* error = nil; | 
| +  bool success = true; | 
| +  [session beginConfiguration]; | 
| +  if ([device lockForConfiguration:&error]) { | 
| +    @try { | 
| +      device.activeFormat = deviceFormat; | 
| +      device.activeVideoMinFrameDuration = CMTimeMake(1, fps); | 
| +    } @catch (NSException* exception) { | 
| +      RTCLogError(@"Failed to set active format!\n User info:%@", | 
| +                  exception.userInfo); | 
| +      success = false; | 
| +    } | 
| + | 
| +    [device unlockForConfiguration]; | 
| +  } else { | 
| +    RTCLogError(@"Failed to lock device %@. Error: %@", device, error.userInfo); | 
| +    success = false; | 
| +  } | 
| +  [session commitConfiguration]; | 
| + | 
| +  return success; | 
| +} | 
| + | 
| +}  // namespace webrtc | 
|  |