2014 snapchat source code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

95 lines
3.3 KiB

  1. //
  2. // SCManagedCaptureDeviceSavitzkyGolayZoomHandler.m
  3. // Snapchat
  4. //
  5. // Created by Yu-Kuan Lai on 4/12/17.
  6. // Copyright © 2017 Snapchat, Inc. All rights reserved.
  7. // https://en.wikipedia.org/wiki/Savitzky%E2%80%93Golay_filter
  8. //
  9. #import "SCManagedCaptureDeviceSavitzkyGolayZoomHandler.h"
  10. #import "SCManagedCaptureDevice.h"
  11. #import "SCManagedCaptureDeviceDefaultZoomHandler_Private.h"
  12. #import <SCFoundation/SCQueuePerformer.h>
  13. #import <SCFoundation/SCTraceODPCompatible.h>
  14. static NSUInteger const kSCSavitzkyGolayWindowSize = 9;
  15. static CGFloat const kSCUpperSharpZoomThreshold = 1.15;
  16. @interface SCManagedCaptureDeviceSavitzkyGolayZoomHandler ()
  17. @property (nonatomic, strong) NSMutableArray *zoomFactorHistoryArray;
  18. @end
  19. @implementation SCManagedCaptureDeviceSavitzkyGolayZoomHandler
  20. - (instancetype)initWithCaptureResource:(SCCaptureResource *)captureResource
  21. {
  22. self = [super initWithCaptureResource:captureResource];
  23. if (self) {
  24. _zoomFactorHistoryArray = [[NSMutableArray alloc] init];
  25. }
  26. return self;
  27. }
  28. - (void)setZoomFactor:(CGFloat)zoomFactor forDevice:(SCManagedCaptureDevice *)device immediately:(BOOL)immediately
  29. {
  30. if (self.currentDevice != device) {
  31. // reset if device changed
  32. self.currentDevice = device;
  33. [self _resetZoomFactor:zoomFactor forDevice:self.currentDevice];
  34. return;
  35. }
  36. if (immediately || zoomFactor == 1 || _zoomFactorHistoryArray.count == 0) {
  37. // reset if zoomFactor is 1 or this is the first data point
  38. [self _resetZoomFactor:zoomFactor forDevice:device];
  39. return;
  40. }
  41. CGFloat lastVal = [[_zoomFactorHistoryArray lastObject] floatValue];
  42. CGFloat upperThreshold = lastVal * kSCUpperSharpZoomThreshold;
  43. if (zoomFactor > upperThreshold) {
  44. // sharp change in zoomFactor, reset
  45. [self _resetZoomFactor:zoomFactor forDevice:device];
  46. return;
  47. }
  48. [_zoomFactorHistoryArray addObject:@(zoomFactor)];
  49. if ([_zoomFactorHistoryArray count] > kSCSavitzkyGolayWindowSize) {
  50. [_zoomFactorHistoryArray removeObjectAtIndex:0];
  51. }
  52. float filteredZoomFactor =
  53. SC_CLAMP([self _savitzkyGolayFilteredZoomFactor], kSCMinVideoZoomFactor, kSCMaxVideoZoomFactor);
  54. [self _setZoomFactor:filteredZoomFactor forManagedCaptureDevice:device];
  55. }
  56. - (CGFloat)_savitzkyGolayFilteredZoomFactor
  57. {
  58. if ([_zoomFactorHistoryArray count] == kSCSavitzkyGolayWindowSize) {
  59. CGFloat filteredZoomFactor =
  60. 59 * [_zoomFactorHistoryArray[4] floatValue] +
  61. 54 * ([_zoomFactorHistoryArray[3] floatValue] + [_zoomFactorHistoryArray[5] floatValue]) +
  62. 39 * ([_zoomFactorHistoryArray[2] floatValue] + [_zoomFactorHistoryArray[6] floatValue]) +
  63. 14 * ([_zoomFactorHistoryArray[1] floatValue] + [_zoomFactorHistoryArray[7] floatValue]) -
  64. 21 * ([_zoomFactorHistoryArray[0] floatValue] + [_zoomFactorHistoryArray[8] floatValue]);
  65. filteredZoomFactor /= 231;
  66. return filteredZoomFactor;
  67. } else {
  68. return [[_zoomFactorHistoryArray lastObject] floatValue]; // use zoomFactor directly if we have less than 9
  69. }
  70. }
  71. - (void)_resetZoomFactor:(CGFloat)zoomFactor forDevice:(SCManagedCaptureDevice *)device
  72. {
  73. [_zoomFactorHistoryArray removeAllObjects];
  74. [_zoomFactorHistoryArray addObject:@(zoomFactor)];
  75. [self _setZoomFactor:zoomFactor forManagedCaptureDevice:device];
  76. }
  77. @end