├── README.md ├── VideoRecord.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── VideoRecord.xccheckout │ └── xcuserdata │ │ └── goodplay.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings └── xcuserdata │ └── goodplay.xcuserdatad │ └── xcschemes │ ├── VideoRecord.xcscheme │ └── xcschememanagement.plist ├── VideoRecord ├── AppDelegate.h ├── AppDelegate.m ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── PlayVideoViewController.h ├── PlayVideoViewController.m ├── ShootVideoViewController.h ├── ShootVideoViewController.m ├── UIView+Tools.h ├── UIView+Tools.m ├── changeCamer.png ├── flashOff.png ├── flashOn.png ├── focusImg.png ├── main.m ├── shootFinish.png └── videoPlay.png ├── VideoRecordTests ├── Info.plist └── VideoRecordTests.m ├── img1.png └── img2.png /README.md: -------------------------------------------------------------------------------- 1 | # VideoRecord 2 | 模仿快手应用的视频录制 10秒1兆左右,清晰度也可以。 3 | ![image](https://github.com/AndyFightting/VideoRecord/blob/master/img1.png) 4 | ![image](https://github.com/AndyFightting/VideoRecord/blob/master/img2.png) 5 | -------------------------------------------------------------------------------- /VideoRecord.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 58FFD66C1B1D6D0000163610 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FFD66B1B1D6D0000163610 /* main.m */; }; 11 | 58FFD6771B1D6D0000163610 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 58FFD6761B1D6D0000163610 /* Images.xcassets */; }; 12 | 58FFD6861B1D6D0000163610 /* VideoRecordTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FFD6851B1D6D0000163610 /* VideoRecordTests.m */; }; 13 | 58FFD6951B1D6D4900163610 /* changeCamer.png in Resources */ = {isa = PBXBuildFile; fileRef = 58FFD68F1B1D6D4900163610 /* changeCamer.png */; }; 14 | 58FFD6961B1D6D4900163610 /* flashOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 58FFD6901B1D6D4900163610 /* flashOff.png */; }; 15 | 58FFD6971B1D6D4900163610 /* flashOn.png in Resources */ = {isa = PBXBuildFile; fileRef = 58FFD6911B1D6D4900163610 /* flashOn.png */; }; 16 | 58FFD6981B1D6D4900163610 /* focusImg.png in Resources */ = {isa = PBXBuildFile; fileRef = 58FFD6921B1D6D4900163610 /* focusImg.png */; }; 17 | 58FFD6991B1D6D4900163610 /* shootFinish.png in Resources */ = {isa = PBXBuildFile; fileRef = 58FFD6931B1D6D4900163610 /* shootFinish.png */; }; 18 | 58FFD69A1B1D6D4900163610 /* videoPlay.png in Resources */ = {isa = PBXBuildFile; fileRef = 58FFD6941B1D6D4900163610 /* videoPlay.png */; }; 19 | 58FFD6A11B1D6D5600163610 /* PlayVideoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FFD69C1B1D6D5600163610 /* PlayVideoViewController.m */; }; 20 | 58FFD6A21B1D6D5600163610 /* ShootVideoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FFD69E1B1D6D5600163610 /* ShootVideoViewController.m */; }; 21 | 58FFD6A31B1D6D5600163610 /* UIView+Tools.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FFD6A01B1D6D5600163610 /* UIView+Tools.m */; }; 22 | 58FFD6A61B1D6D5F00163610 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FFD6A51B1D6D5F00163610 /* AppDelegate.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 58FFD6801B1D6D0000163610 /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 58FFD65E1B1D6D0000163610 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = 58FFD6651B1D6D0000163610; 31 | remoteInfo = VideoRecord; 32 | }; 33 | /* End PBXContainerItemProxy section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 58FFD6661B1D6D0000163610 /* VideoRecord.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VideoRecord.app; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 58FFD66A1B1D6D0000163610 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | 58FFD66B1B1D6D0000163610 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 39 | 58FFD6761B1D6D0000163610 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 40 | 58FFD67F1B1D6D0000163610 /* VideoRecordTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VideoRecordTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 58FFD6841B1D6D0000163610 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 42 | 58FFD6851B1D6D0000163610 /* VideoRecordTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VideoRecordTests.m; sourceTree = ""; }; 43 | 58FFD68F1B1D6D4900163610 /* changeCamer.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = changeCamer.png; sourceTree = ""; }; 44 | 58FFD6901B1D6D4900163610 /* flashOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = flashOff.png; sourceTree = ""; }; 45 | 58FFD6911B1D6D4900163610 /* flashOn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = flashOn.png; sourceTree = ""; }; 46 | 58FFD6921B1D6D4900163610 /* focusImg.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = focusImg.png; sourceTree = ""; }; 47 | 58FFD6931B1D6D4900163610 /* shootFinish.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = shootFinish.png; sourceTree = ""; }; 48 | 58FFD6941B1D6D4900163610 /* videoPlay.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = videoPlay.png; sourceTree = ""; }; 49 | 58FFD69B1B1D6D5600163610 /* PlayVideoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayVideoViewController.h; sourceTree = ""; }; 50 | 58FFD69C1B1D6D5600163610 /* PlayVideoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PlayVideoViewController.m; sourceTree = ""; }; 51 | 58FFD69D1B1D6D5600163610 /* ShootVideoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShootVideoViewController.h; sourceTree = ""; }; 52 | 58FFD69E1B1D6D5600163610 /* ShootVideoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShootVideoViewController.m; sourceTree = ""; }; 53 | 58FFD69F1B1D6D5600163610 /* UIView+Tools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Tools.h"; sourceTree = ""; }; 54 | 58FFD6A01B1D6D5600163610 /* UIView+Tools.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Tools.m"; sourceTree = ""; }; 55 | 58FFD6A41B1D6D5F00163610 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 56 | 58FFD6A51B1D6D5F00163610 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 57 | /* End PBXFileReference section */ 58 | 59 | /* Begin PBXFrameworksBuildPhase section */ 60 | 58FFD6631B1D6D0000163610 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | 58FFD67C1B1D6D0000163610 /* Frameworks */ = { 68 | isa = PBXFrameworksBuildPhase; 69 | buildActionMask = 2147483647; 70 | files = ( 71 | ); 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | /* End PBXFrameworksBuildPhase section */ 75 | 76 | /* Begin PBXGroup section */ 77 | 58FFD65D1B1D6D0000163610 = { 78 | isa = PBXGroup; 79 | children = ( 80 | 58FFD6681B1D6D0000163610 /* VideoRecord */, 81 | 58FFD6821B1D6D0000163610 /* VideoRecordTests */, 82 | 58FFD6671B1D6D0000163610 /* Products */, 83 | ); 84 | sourceTree = ""; 85 | }; 86 | 58FFD6671B1D6D0000163610 /* Products */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 58FFD6661B1D6D0000163610 /* VideoRecord.app */, 90 | 58FFD67F1B1D6D0000163610 /* VideoRecordTests.xctest */, 91 | ); 92 | name = Products; 93 | sourceTree = ""; 94 | }; 95 | 58FFD6681B1D6D0000163610 /* VideoRecord */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 58FFD6A41B1D6D5F00163610 /* AppDelegate.h */, 99 | 58FFD6A51B1D6D5F00163610 /* AppDelegate.m */, 100 | 58FFD69B1B1D6D5600163610 /* PlayVideoViewController.h */, 101 | 58FFD69C1B1D6D5600163610 /* PlayVideoViewController.m */, 102 | 58FFD69D1B1D6D5600163610 /* ShootVideoViewController.h */, 103 | 58FFD69E1B1D6D5600163610 /* ShootVideoViewController.m */, 104 | 58FFD69F1B1D6D5600163610 /* UIView+Tools.h */, 105 | 58FFD6A01B1D6D5600163610 /* UIView+Tools.m */, 106 | 58FFD68F1B1D6D4900163610 /* changeCamer.png */, 107 | 58FFD6901B1D6D4900163610 /* flashOff.png */, 108 | 58FFD6911B1D6D4900163610 /* flashOn.png */, 109 | 58FFD6921B1D6D4900163610 /* focusImg.png */, 110 | 58FFD6931B1D6D4900163610 /* shootFinish.png */, 111 | 58FFD6941B1D6D4900163610 /* videoPlay.png */, 112 | 58FFD6761B1D6D0000163610 /* Images.xcassets */, 113 | 58FFD6691B1D6D0000163610 /* Supporting Files */, 114 | ); 115 | path = VideoRecord; 116 | sourceTree = ""; 117 | }; 118 | 58FFD6691B1D6D0000163610 /* Supporting Files */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 58FFD66A1B1D6D0000163610 /* Info.plist */, 122 | 58FFD66B1B1D6D0000163610 /* main.m */, 123 | ); 124 | name = "Supporting Files"; 125 | sourceTree = ""; 126 | }; 127 | 58FFD6821B1D6D0000163610 /* VideoRecordTests */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 58FFD6851B1D6D0000163610 /* VideoRecordTests.m */, 131 | 58FFD6831B1D6D0000163610 /* Supporting Files */, 132 | ); 133 | path = VideoRecordTests; 134 | sourceTree = ""; 135 | }; 136 | 58FFD6831B1D6D0000163610 /* Supporting Files */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 58FFD6841B1D6D0000163610 /* Info.plist */, 140 | ); 141 | name = "Supporting Files"; 142 | sourceTree = ""; 143 | }; 144 | /* End PBXGroup section */ 145 | 146 | /* Begin PBXNativeTarget section */ 147 | 58FFD6651B1D6D0000163610 /* VideoRecord */ = { 148 | isa = PBXNativeTarget; 149 | buildConfigurationList = 58FFD6891B1D6D0000163610 /* Build configuration list for PBXNativeTarget "VideoRecord" */; 150 | buildPhases = ( 151 | 58FFD6621B1D6D0000163610 /* Sources */, 152 | 58FFD6631B1D6D0000163610 /* Frameworks */, 153 | 58FFD6641B1D6D0000163610 /* Resources */, 154 | ); 155 | buildRules = ( 156 | ); 157 | dependencies = ( 158 | ); 159 | name = VideoRecord; 160 | productName = VideoRecord; 161 | productReference = 58FFD6661B1D6D0000163610 /* VideoRecord.app */; 162 | productType = "com.apple.product-type.application"; 163 | }; 164 | 58FFD67E1B1D6D0000163610 /* VideoRecordTests */ = { 165 | isa = PBXNativeTarget; 166 | buildConfigurationList = 58FFD68C1B1D6D0000163610 /* Build configuration list for PBXNativeTarget "VideoRecordTests" */; 167 | buildPhases = ( 168 | 58FFD67B1B1D6D0000163610 /* Sources */, 169 | 58FFD67C1B1D6D0000163610 /* Frameworks */, 170 | 58FFD67D1B1D6D0000163610 /* Resources */, 171 | ); 172 | buildRules = ( 173 | ); 174 | dependencies = ( 175 | 58FFD6811B1D6D0000163610 /* PBXTargetDependency */, 176 | ); 177 | name = VideoRecordTests; 178 | productName = VideoRecordTests; 179 | productReference = 58FFD67F1B1D6D0000163610 /* VideoRecordTests.xctest */; 180 | productType = "com.apple.product-type.bundle.unit-test"; 181 | }; 182 | /* End PBXNativeTarget section */ 183 | 184 | /* Begin PBXProject section */ 185 | 58FFD65E1B1D6D0000163610 /* Project object */ = { 186 | isa = PBXProject; 187 | attributes = { 188 | LastUpgradeCheck = 0630; 189 | ORGANIZATIONNAME = guimingsu; 190 | TargetAttributes = { 191 | 58FFD6651B1D6D0000163610 = { 192 | CreatedOnToolsVersion = 6.3.1; 193 | }; 194 | 58FFD67E1B1D6D0000163610 = { 195 | CreatedOnToolsVersion = 6.3.1; 196 | TestTargetID = 58FFD6651B1D6D0000163610; 197 | }; 198 | }; 199 | }; 200 | buildConfigurationList = 58FFD6611B1D6D0000163610 /* Build configuration list for PBXProject "VideoRecord" */; 201 | compatibilityVersion = "Xcode 3.2"; 202 | developmentRegion = English; 203 | hasScannedForEncodings = 0; 204 | knownRegions = ( 205 | en, 206 | Base, 207 | ); 208 | mainGroup = 58FFD65D1B1D6D0000163610; 209 | productRefGroup = 58FFD6671B1D6D0000163610 /* Products */; 210 | projectDirPath = ""; 211 | projectRoot = ""; 212 | targets = ( 213 | 58FFD6651B1D6D0000163610 /* VideoRecord */, 214 | 58FFD67E1B1D6D0000163610 /* VideoRecordTests */, 215 | ); 216 | }; 217 | /* End PBXProject section */ 218 | 219 | /* Begin PBXResourcesBuildPhase section */ 220 | 58FFD6641B1D6D0000163610 /* Resources */ = { 221 | isa = PBXResourcesBuildPhase; 222 | buildActionMask = 2147483647; 223 | files = ( 224 | 58FFD69A1B1D6D4900163610 /* videoPlay.png in Resources */, 225 | 58FFD6951B1D6D4900163610 /* changeCamer.png in Resources */, 226 | 58FFD6981B1D6D4900163610 /* focusImg.png in Resources */, 227 | 58FFD6971B1D6D4900163610 /* flashOn.png in Resources */, 228 | 58FFD6961B1D6D4900163610 /* flashOff.png in Resources */, 229 | 58FFD6991B1D6D4900163610 /* shootFinish.png in Resources */, 230 | 58FFD6771B1D6D0000163610 /* Images.xcassets in Resources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | 58FFD67D1B1D6D0000163610 /* Resources */ = { 235 | isa = PBXResourcesBuildPhase; 236 | buildActionMask = 2147483647; 237 | files = ( 238 | ); 239 | runOnlyForDeploymentPostprocessing = 0; 240 | }; 241 | /* End PBXResourcesBuildPhase section */ 242 | 243 | /* Begin PBXSourcesBuildPhase section */ 244 | 58FFD6621B1D6D0000163610 /* Sources */ = { 245 | isa = PBXSourcesBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | 58FFD6A11B1D6D5600163610 /* PlayVideoViewController.m in Sources */, 249 | 58FFD6A21B1D6D5600163610 /* ShootVideoViewController.m in Sources */, 250 | 58FFD6A31B1D6D5600163610 /* UIView+Tools.m in Sources */, 251 | 58FFD66C1B1D6D0000163610 /* main.m in Sources */, 252 | 58FFD6A61B1D6D5F00163610 /* AppDelegate.m in Sources */, 253 | ); 254 | runOnlyForDeploymentPostprocessing = 0; 255 | }; 256 | 58FFD67B1B1D6D0000163610 /* Sources */ = { 257 | isa = PBXSourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | 58FFD6861B1D6D0000163610 /* VideoRecordTests.m in Sources */, 261 | ); 262 | runOnlyForDeploymentPostprocessing = 0; 263 | }; 264 | /* End PBXSourcesBuildPhase section */ 265 | 266 | /* Begin PBXTargetDependency section */ 267 | 58FFD6811B1D6D0000163610 /* PBXTargetDependency */ = { 268 | isa = PBXTargetDependency; 269 | target = 58FFD6651B1D6D0000163610 /* VideoRecord */; 270 | targetProxy = 58FFD6801B1D6D0000163610 /* PBXContainerItemProxy */; 271 | }; 272 | /* End PBXTargetDependency section */ 273 | 274 | /* Begin XCBuildConfiguration section */ 275 | 58FFD6871B1D6D0000163610 /* Debug */ = { 276 | isa = XCBuildConfiguration; 277 | buildSettings = { 278 | ALWAYS_SEARCH_USER_PATHS = NO; 279 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 280 | CLANG_CXX_LIBRARY = "libc++"; 281 | CLANG_ENABLE_MODULES = YES; 282 | CLANG_ENABLE_OBJC_ARC = YES; 283 | CLANG_WARN_BOOL_CONVERSION = YES; 284 | CLANG_WARN_CONSTANT_CONVERSION = YES; 285 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 286 | CLANG_WARN_EMPTY_BODY = YES; 287 | CLANG_WARN_ENUM_CONVERSION = YES; 288 | CLANG_WARN_INT_CONVERSION = YES; 289 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 290 | CLANG_WARN_UNREACHABLE_CODE = YES; 291 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 292 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 293 | COPY_PHASE_STRIP = NO; 294 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 295 | ENABLE_STRICT_OBJC_MSGSEND = YES; 296 | GCC_C_LANGUAGE_STANDARD = gnu99; 297 | GCC_DYNAMIC_NO_PIC = NO; 298 | GCC_NO_COMMON_BLOCKS = YES; 299 | GCC_OPTIMIZATION_LEVEL = 0; 300 | GCC_PREPROCESSOR_DEFINITIONS = ( 301 | "DEBUG=1", 302 | "$(inherited)", 303 | ); 304 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 305 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 306 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 307 | GCC_WARN_UNDECLARED_SELECTOR = YES; 308 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 309 | GCC_WARN_UNUSED_FUNCTION = YES; 310 | GCC_WARN_UNUSED_VARIABLE = YES; 311 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 312 | MTL_ENABLE_DEBUG_INFO = YES; 313 | ONLY_ACTIVE_ARCH = YES; 314 | PROVISIONING_PROFILE = "ed21f08b-fd34-42b1-a762-965662004bf9"; 315 | SDKROOT = iphoneos; 316 | }; 317 | name = Debug; 318 | }; 319 | 58FFD6881B1D6D0000163610 /* Release */ = { 320 | isa = XCBuildConfiguration; 321 | buildSettings = { 322 | ALWAYS_SEARCH_USER_PATHS = NO; 323 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 324 | CLANG_CXX_LIBRARY = "libc++"; 325 | CLANG_ENABLE_MODULES = YES; 326 | CLANG_ENABLE_OBJC_ARC = YES; 327 | CLANG_WARN_BOOL_CONVERSION = YES; 328 | CLANG_WARN_CONSTANT_CONVERSION = YES; 329 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 330 | CLANG_WARN_EMPTY_BODY = YES; 331 | CLANG_WARN_ENUM_CONVERSION = YES; 332 | CLANG_WARN_INT_CONVERSION = YES; 333 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 334 | CLANG_WARN_UNREACHABLE_CODE = YES; 335 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 336 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 337 | COPY_PHASE_STRIP = NO; 338 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 339 | ENABLE_NS_ASSERTIONS = NO; 340 | ENABLE_STRICT_OBJC_MSGSEND = YES; 341 | GCC_C_LANGUAGE_STANDARD = gnu99; 342 | GCC_NO_COMMON_BLOCKS = YES; 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 350 | MTL_ENABLE_DEBUG_INFO = NO; 351 | PROVISIONING_PROFILE = "ed21f08b-fd34-42b1-a762-965662004bf9"; 352 | SDKROOT = iphoneos; 353 | VALIDATE_PRODUCT = YES; 354 | }; 355 | name = Release; 356 | }; 357 | 58FFD68A1B1D6D0000163610 /* Debug */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 361 | INFOPLIST_FILE = VideoRecord/Info.plist; 362 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 363 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 364 | PRODUCT_NAME = "$(TARGET_NAME)"; 365 | PROVISIONING_PROFILE = "ed21f08b-fd34-42b1-a762-965662004bf9"; 366 | }; 367 | name = Debug; 368 | }; 369 | 58FFD68B1B1D6D0000163610 /* Release */ = { 370 | isa = XCBuildConfiguration; 371 | buildSettings = { 372 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 373 | INFOPLIST_FILE = VideoRecord/Info.plist; 374 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 375 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 376 | PRODUCT_NAME = "$(TARGET_NAME)"; 377 | PROVISIONING_PROFILE = "ed21f08b-fd34-42b1-a762-965662004bf9"; 378 | }; 379 | name = Release; 380 | }; 381 | 58FFD68D1B1D6D0000163610 /* Debug */ = { 382 | isa = XCBuildConfiguration; 383 | buildSettings = { 384 | BUNDLE_LOADER = "$(TEST_HOST)"; 385 | FRAMEWORK_SEARCH_PATHS = ( 386 | "$(SDKROOT)/Developer/Library/Frameworks", 387 | "$(inherited)", 388 | ); 389 | GCC_PREPROCESSOR_DEFINITIONS = ( 390 | "DEBUG=1", 391 | "$(inherited)", 392 | ); 393 | INFOPLIST_FILE = VideoRecordTests/Info.plist; 394 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 395 | PRODUCT_NAME = "$(TARGET_NAME)"; 396 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VideoRecord.app/VideoRecord"; 397 | }; 398 | name = Debug; 399 | }; 400 | 58FFD68E1B1D6D0000163610 /* Release */ = { 401 | isa = XCBuildConfiguration; 402 | buildSettings = { 403 | BUNDLE_LOADER = "$(TEST_HOST)"; 404 | FRAMEWORK_SEARCH_PATHS = ( 405 | "$(SDKROOT)/Developer/Library/Frameworks", 406 | "$(inherited)", 407 | ); 408 | INFOPLIST_FILE = VideoRecordTests/Info.plist; 409 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 410 | PRODUCT_NAME = "$(TARGET_NAME)"; 411 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VideoRecord.app/VideoRecord"; 412 | }; 413 | name = Release; 414 | }; 415 | /* End XCBuildConfiguration section */ 416 | 417 | /* Begin XCConfigurationList section */ 418 | 58FFD6611B1D6D0000163610 /* Build configuration list for PBXProject "VideoRecord" */ = { 419 | isa = XCConfigurationList; 420 | buildConfigurations = ( 421 | 58FFD6871B1D6D0000163610 /* Debug */, 422 | 58FFD6881B1D6D0000163610 /* Release */, 423 | ); 424 | defaultConfigurationIsVisible = 0; 425 | defaultConfigurationName = Release; 426 | }; 427 | 58FFD6891B1D6D0000163610 /* Build configuration list for PBXNativeTarget "VideoRecord" */ = { 428 | isa = XCConfigurationList; 429 | buildConfigurations = ( 430 | 58FFD68A1B1D6D0000163610 /* Debug */, 431 | 58FFD68B1B1D6D0000163610 /* Release */, 432 | ); 433 | defaultConfigurationIsVisible = 0; 434 | defaultConfigurationName = Release; 435 | }; 436 | 58FFD68C1B1D6D0000163610 /* Build configuration list for PBXNativeTarget "VideoRecordTests" */ = { 437 | isa = XCConfigurationList; 438 | buildConfigurations = ( 439 | 58FFD68D1B1D6D0000163610 /* Debug */, 440 | 58FFD68E1B1D6D0000163610 /* Release */, 441 | ); 442 | defaultConfigurationIsVisible = 0; 443 | defaultConfigurationName = Release; 444 | }; 445 | /* End XCConfigurationList section */ 446 | }; 447 | rootObject = 58FFD65E1B1D6D0000163610 /* Project object */; 448 | } 449 | -------------------------------------------------------------------------------- /VideoRecord.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /VideoRecord.xcodeproj/project.xcworkspace/xcshareddata/VideoRecord.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 2AF0404D-3294-4949-831E-793B6547B81D 9 | IDESourceControlProjectName 10 | VideoRecord 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | C6DAC2EF68DB7339AE46E91EDD7ADBA197112D94 14 | https://github.com/AndyFightting/VideoRecord.git 15 | 16 | IDESourceControlProjectPath 17 | VideoRecord.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | C6DAC2EF68DB7339AE46E91EDD7ADBA197112D94 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/AndyFightting/VideoRecord.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | C6DAC2EF68DB7339AE46E91EDD7ADBA197112D94 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | C6DAC2EF68DB7339AE46E91EDD7ADBA197112D94 36 | IDESourceControlWCCName 37 | VideoRecord 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /VideoRecord.xcodeproj/project.xcworkspace/xcuserdata/goodplay.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyFightting/VideoRecord/8489187128385b83dbd8545ab4bfe280b5939d0c/VideoRecord.xcodeproj/project.xcworkspace/xcuserdata/goodplay.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /VideoRecord.xcodeproj/project.xcworkspace/xcuserdata/goodplay.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /VideoRecord.xcodeproj/xcuserdata/goodplay.xcuserdatad/xcschemes/VideoRecord.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /VideoRecord.xcodeproj/xcuserdata/goodplay.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | VideoRecord.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 58FFD6651B1D6D0000163610 16 | 17 | primary 18 | 19 | 20 | 58FFD67E1B1D6D0000163610 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /VideoRecord/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // VideoRecord 4 | // 5 | // Created by guimingsu on 15/6/2. 6 | // Copyright (c) 2015年 guimingsu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /VideoRecord/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // VideoRecord 4 | // 5 | // Created by guimingsu on 15/6/2. 6 | // Copyright (c) 2015年 guimingsu. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ShootVideoViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | // Override point for customization after application launch. 21 | 22 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 23 | 24 | ShootVideoViewController* shootVC = [[ShootVideoViewController alloc] init]; 25 | UINavigationController* nav = [[UINavigationController alloc]initWithRootViewController:shootVC]; 26 | 27 | self.window.rootViewController = nav; 28 | [self.window makeKeyAndVisible]; 29 | return YES; 30 | } 31 | 32 | - (void)applicationWillResignActive:(UIApplication *)application { 33 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 34 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 35 | } 36 | 37 | - (void)applicationDidEnterBackground:(UIApplication *)application { 38 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 39 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 40 | } 41 | 42 | - (void)applicationWillEnterForeground:(UIApplication *)application { 43 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 44 | } 45 | 46 | - (void)applicationDidBecomeActive:(UIApplication *)application { 47 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 48 | } 49 | 50 | - (void)applicationWillTerminate:(UIApplication *)application { 51 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /VideoRecord/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /VideoRecord/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.good.studentApp 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /VideoRecord/PlayVideoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PlayVideoViewController.h 3 | // VideoRecord 4 | // 5 | // Created by guimingsu on 15/4/27. 6 | // Copyright (c) 2015年 guimingsu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface PlayVideoViewController : UIViewController 13 | 14 | @property(nonatomic,retain) NSURL * videoURL; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /VideoRecord/PlayVideoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PlayVideoViewController.m 3 | // VideoRecord 4 | // 5 | // Created by guimingsu on 15/4/27. 6 | // Copyright (c) 2015年 guimingsu. All rights reserved. 7 | // 8 | 9 | #import "PlayVideoViewController.h" 10 | #import 11 | 12 | @interface PlayVideoViewController () 13 | 14 | @end 15 | 16 | @implementation PlayVideoViewController 17 | { 18 | 19 | AVPlayer *player; 20 | AVPlayerLayer *playerLayer; 21 | AVPlayerItem *playerItem; 22 | 23 | UIImageView* playImg; 24 | 25 | } 26 | 27 | @synthesize videoURL; 28 | 29 | 30 | - (void)viewDidLoad { 31 | [super viewDidLoad]; 32 | self.view.backgroundColor = [UIColor blackColor]; 33 | self.title = @"预览"; 34 | 35 | float videoWidth = self.view.frame.size.width; 36 | 37 | AVAsset *movieAsset = [AVURLAsset URLAssetWithURL:videoURL options:nil]; 38 | playerItem = [AVPlayerItem playerItemWithAsset:movieAsset]; 39 | player = [AVPlayer playerWithPlayerItem:playerItem]; 40 | 41 | playerLayer = [AVPlayerLayer playerLayerWithPlayer:player]; 42 | playerLayer.frame = CGRectMake(0, 64, videoWidth, videoWidth); 43 | playerLayer.videoGravity = AVLayerVideoGravityResizeAspect; 44 | [self.view.layer addSublayer:playerLayer]; 45 | 46 | UITapGestureRecognizer *playTap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(playOrPause)]; 47 | [self.view addGestureRecognizer:playTap]; 48 | 49 | [self pressPlayButton]; 50 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playingEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil]; 51 | 52 | playImg = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 40, 40)]; 53 | playImg.center = CGPointMake(videoWidth/2, videoWidth/2); 54 | [playImg setImage:[UIImage imageNamed:@"videoPlay"]]; 55 | [playerLayer addSublayer:playImg.layer]; 56 | playImg.hidden = YES; 57 | 58 | } 59 | 60 | -(void)playOrPause{ 61 | if (playImg.isHidden) { 62 | playImg.hidden = NO; 63 | [player pause]; 64 | 65 | }else{ 66 | playImg.hidden = YES; 67 | [player play]; 68 | } 69 | } 70 | 71 | - (void)pressPlayButton 72 | { 73 | [playerItem seekToTime:kCMTimeZero]; 74 | [player play]; 75 | } 76 | 77 | - (void)playingEnd:(NSNotification *)notification 78 | { 79 | if (playImg.isHidden) { 80 | [self pressPlayButton]; 81 | } 82 | } 83 | 84 | - (void)didReceiveMemoryWarning { 85 | [super didReceiveMemoryWarning]; 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /VideoRecord/ShootVideoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ShootVideoViewController.h 3 | // VideoRecord 4 | // 5 | // Created by guimingsu on 15/5/4. 6 | // Copyright (c) 2015年 guimingsu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "UIView+Tools.h" 12 | 13 | #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 14 | #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height 15 | 16 | #define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] 17 | 18 | @interface ShootVideoViewController : UIViewController 19 | 20 | @property float totalTime; //视频总长度 默认10秒 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /VideoRecord/ShootVideoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ShootVideoViewController.m 3 | // VideoRecord 4 | // 5 | // Created by guimingsu on 15/5/4. 6 | // Copyright (c) 2015年 guimingsu. All rights reserved. 7 | // 8 | 9 | #import "ShootVideoViewController.h" 10 | #import "PlayVideoViewController.h" 11 | 12 | #import 13 | #import 14 | 15 | #define TIMER_INTERVAL 0.05 16 | #define VIDEO_FOLDER @"videoFolder" 17 | 18 | typedef void(^PropertyChangeBlock)(AVCaptureDevice *captureDevice); 19 | 20 | @interface ShootVideoViewController ()//视频文件输出代理 21 | 22 | @property (strong,nonatomic) AVCaptureSession *captureSession;//负责输入和输出设置之间的数据传递 23 | @property (strong,nonatomic) AVCaptureDeviceInput *captureDeviceInput;//负责从AVCaptureDevice获得输入数据 24 | @property (strong,nonatomic) AVCaptureMovieFileOutput *captureMovieFileOutput;//视频输出流 25 | @property (strong,nonatomic) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;//相机拍摄预览图层 26 | 27 | @property (strong,nonatomic) UIView *viewContainer;//视频容器 28 | @property (strong,nonatomic) UIImageView *focusCursor; //聚焦光标 29 | 30 | @end 31 | 32 | @implementation ShootVideoViewController{ 33 | 34 | NSMutableArray* urlArray;//保存视频片段的数组 35 | 36 | float currentTime; //当前视频长度 37 | 38 | NSTimer *countTimer; //计时器 39 | UIView* progressPreView; //进度条 40 | float progressStep; //进度条每次变长的最小单位 41 | 42 | float preLayerWidth;//镜头宽 43 | float preLayerHeight;//镜头高 44 | float preLayerHWRate; //高,宽比 45 | 46 | UIButton* shootBt;//录制按钮 47 | UIButton* finishBt;//结束按钮 48 | 49 | UIButton* flashBt;//闪光灯 50 | UIButton* cameraBt;//切换摄像头 51 | 52 | } 53 | @synthesize totalTime; 54 | 55 | - (void)viewDidLoad { 56 | [super viewDidLoad]; 57 | // Do any additional setup after loading the view. 58 | self.view.backgroundColor = UIColorFromRGB(0x1d1e20); 59 | self.title = @"视频录制"; 60 | 61 | //视频最大时长 默认10秒 62 | if (totalTime==0) { 63 | totalTime =10; 64 | } 65 | 66 | urlArray = [[NSMutableArray alloc]init]; 67 | 68 | preLayerWidth = SCREEN_WIDTH; 69 | preLayerHeight = SCREEN_WIDTH; 70 | preLayerHWRate =preLayerHeight/preLayerWidth; 71 | 72 | progressStep = SCREEN_WIDTH*TIMER_INTERVAL/totalTime; 73 | 74 | [self createVideoFolderIfNotExist]; 75 | [self initCapture]; 76 | } 77 | 78 | -(void)initCapture{ 79 | 80 | //视频高度加进度条(10)高度 81 | self.viewContainer = [[UIView alloc]initWithFrame:CGRectMake(0, 64, preLayerWidth, preLayerHeight+10)]; 82 | [self.view addSubview:self.viewContainer]; 83 | 84 | self.focusCursor = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 50, 50)]; 85 | [self.focusCursor setImage:[UIImage imageNamed:@"focusImg"]]; 86 | self.focusCursor.alpha = 0; 87 | [self.viewContainer addSubview:self.focusCursor]; 88 | 89 | 90 | UIView* btView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 86, 86)]; 91 | btView.center = CGPointMake(SCREEN_WIDTH/2, 64+preLayerHeight+20+43); 92 | [btView makeCornerRadius:43 borderColor:nil borderWidth:0]; 93 | btView.backgroundColor = UIColorFromRGB(0xeeeeee); 94 | [self.view addSubview:btView]; 95 | 96 | shootBt = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 76, 76)]; 97 | shootBt.center = CGPointMake(43, 43); 98 | shootBt.backgroundColor = UIColorFromRGB(0xfa5f66); 99 | [shootBt addTarget:self action:@selector(shootButtonClick) forControlEvents:UIControlEventTouchUpInside]; 100 | [shootBt makeCornerRadius:38 borderColor:UIColorFromRGB(0x28292b) borderWidth:3]; 101 | [btView addSubview:shootBt]; 102 | 103 | finishBt = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 60, 60)]; 104 | finishBt.center = CGPointMake(SCREEN_WIDTH-35, 64+preLayerHeight+20+45); 105 | finishBt.adjustsImageWhenHighlighted = NO; 106 | [finishBt setBackgroundImage:[UIImage imageNamed:@"shootFinish"] forState:UIControlStateNormal]; 107 | [finishBt addTarget:self action:@selector(finishBtTap) forControlEvents:UIControlEventTouchUpInside]; 108 | finishBt.hidden = YES; 109 | [self.view addSubview:finishBt]; 110 | 111 | //初始化会话 112 | _captureSession=[[AVCaptureSession alloc]init]; 113 | if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {//设置分辨率 114 | _captureSession.sessionPreset=AVCaptureSessionPreset640x480; 115 | } 116 | 117 | //获得输入设备 118 | AVCaptureDevice *captureDevice=[self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];//取得后置摄像头 119 | //添加一个音频输入设备 120 | AVCaptureDevice *audioCaptureDevice=[[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject]; 121 | 122 | NSError *error=nil; 123 | //根据输入设备初始化设备输入对象,用于获得输入数据 124 | _captureDeviceInput=[[AVCaptureDeviceInput alloc]initWithDevice:captureDevice error:&error]; 125 | 126 | AVCaptureDeviceInput *audioCaptureDeviceInput=[[AVCaptureDeviceInput alloc]initWithDevice:audioCaptureDevice error:&error]; 127 | 128 | //初始化设备输出对象,用于获得输出数据 129 | _captureMovieFileOutput=[[AVCaptureMovieFileOutput alloc]init]; 130 | 131 | //将设备输入添加到会话中 132 | if ([_captureSession canAddInput:_captureDeviceInput]) { 133 | [_captureSession addInput:_captureDeviceInput]; 134 | [_captureSession addInput:audioCaptureDeviceInput]; 135 | AVCaptureConnection *captureConnection=[_captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo]; 136 | if ([captureConnection isVideoStabilizationSupported ]) { 137 | captureConnection.preferredVideoStabilizationMode=AVCaptureVideoStabilizationModeAuto; 138 | } 139 | } 140 | 141 | //将设备输出添加到会话中 142 | if ([_captureSession canAddOutput:_captureMovieFileOutput]) { 143 | [_captureSession addOutput:_captureMovieFileOutput]; 144 | } 145 | 146 | //创建视频预览层,用于实时展示摄像头状态 147 | _captureVideoPreviewLayer=[[AVCaptureVideoPreviewLayer alloc]initWithSession:self.captureSession]; 148 | 149 | CALayer *layer= self.viewContainer.layer; 150 | layer.masksToBounds=YES; 151 | 152 | _captureVideoPreviewLayer.frame= CGRectMake(0, 0, preLayerWidth, preLayerHeight); 153 | _captureVideoPreviewLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//填充模式 154 | [layer insertSublayer:_captureVideoPreviewLayer below:self.focusCursor.layer]; 155 | 156 | [self addGenstureRecognizer]; 157 | 158 | //进度条 159 | progressPreView = [[UIView alloc]initWithFrame:CGRectMake(0, preLayerHeight, 0, 4)]; 160 | progressPreView.backgroundColor = UIColorFromRGB(0xffc738); 161 | [progressPreView makeCornerRadius:2 borderColor:nil borderWidth:0]; 162 | [self.viewContainer addSubview:progressPreView]; 163 | 164 | flashBt = [[UIButton alloc]initWithFrame:CGRectMake(SCREEN_WIDTH-90, 5, 34, 34)]; 165 | [flashBt setBackgroundImage:[UIImage imageNamed:@"flashOn"] forState:UIControlStateNormal]; 166 | [flashBt makeCornerRadius:17 borderColor:nil borderWidth:0]; 167 | [flashBt addTarget:self action:@selector(flashBtTap:) forControlEvents:UIControlEventTouchUpInside]; 168 | [self.viewContainer addSubview:flashBt]; 169 | 170 | cameraBt = [[UIButton alloc]initWithFrame:CGRectMake(SCREEN_WIDTH-40, 5, 34, 34)]; 171 | [cameraBt setBackgroundImage:[UIImage imageNamed:@"changeCamer"] forState:UIControlStateNormal]; 172 | [cameraBt makeCornerRadius:17 borderColor:nil borderWidth:0]; 173 | [cameraBt addTarget:self action:@selector(changeCamera:) forControlEvents:UIControlEventTouchUpInside]; 174 | [self.viewContainer addSubview:cameraBt]; 175 | 176 | } 177 | -(void)flashBtTap:(UIButton*)bt{ 178 | if (bt.selected == YES) { 179 | bt.selected = NO; 180 | //关闭闪光灯 181 | [flashBt setBackgroundImage:[UIImage imageNamed:@"flashOn"] forState:UIControlStateNormal]; 182 | [self setTorchMode:AVCaptureTorchModeOff]; 183 | }else{ 184 | bt.selected = YES; 185 | //开启闪光灯 186 | [flashBt setBackgroundImage:[UIImage imageNamed:@"flashOff"] forState:UIControlStateNormal]; 187 | [self setTorchMode:AVCaptureTorchModeOn]; 188 | } 189 | } 190 | 191 | -(void)startTimer{ 192 | shootBt.backgroundColor = UIColorFromRGB(0xf8ad6a); 193 | 194 | countTimer = [NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(onTimer:) userInfo:nil repeats:YES]; 195 | [countTimer fire]; 196 | } 197 | 198 | -(void)stopTimer{ 199 | shootBt.backgroundColor = UIColorFromRGB(0xfa5f66); 200 | 201 | [countTimer invalidate]; 202 | countTimer = nil; 203 | 204 | } 205 | - (void)onTimer:(NSTimer *)timer 206 | { 207 | currentTime += TIMER_INTERVAL; 208 | float progressWidth = progressPreView.frame.size.width+progressStep; 209 | [progressPreView setFrame:CGRectMake(0, preLayerHeight, progressWidth, 4)]; 210 | if (currentTime>2) { 211 | finishBt.hidden = NO; 212 | } 213 | 214 | //时间到了停止录制视频 215 | if (currentTime>=totalTime) { 216 | [countTimer invalidate]; 217 | countTimer = nil; 218 | [_captureMovieFileOutput stopRecording]; 219 | } 220 | 221 | } 222 | -(void)finishBtTap{ 223 | 224 | currentTime=totalTime+10; 225 | [countTimer invalidate]; 226 | countTimer = nil; 227 | 228 | //正在拍摄 229 | if (_captureMovieFileOutput.isRecording) { 230 | [_captureMovieFileOutput stopRecording]; 231 | }else{//已经暂停了 232 | [self mergeAndExportVideosAtFileURLs:urlArray]; 233 | } 234 | } 235 | 236 | -(void)viewDidAppear:(BOOL)animated{ 237 | [super viewDidAppear:animated]; 238 | [self.captureSession startRunning]; 239 | } 240 | 241 | -(void)viewDidDisappear:(BOOL)animated{ 242 | [super viewDidDisappear:animated]; 243 | [self.captureSession stopRunning]; 244 | 245 | //还原数据----------- 246 | [self deleteAllVideos]; 247 | currentTime = 0; 248 | [progressPreView setFrame:CGRectMake(0, preLayerHeight, 0, 4)]; 249 | shootBt.backgroundColor = UIColorFromRGB(0xfa5f66); 250 | finishBt.hidden = YES; 251 | } 252 | 253 | #pragma mark 视频录制 254 | - (void)shootButtonClick{ 255 | //根据设备输出获得连接 256 | AVCaptureConnection *captureConnection=[self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo]; 257 | 258 | //根据连接取得设备输出的数据 259 | if (![self.captureMovieFileOutput isRecording]) { 260 | shootBt.backgroundColor = UIColorFromRGB(0xfa5f66); 261 | //预览图层和视频方向保持一致 262 | captureConnection.videoOrientation=[self.captureVideoPreviewLayer connection].videoOrientation; 263 | [self.captureMovieFileOutput startRecordingToOutputFileURL:[NSURL fileURLWithPath:[self getVideoSaveFilePathString]] recordingDelegate:self]; 264 | } 265 | else{ 266 | [self stopTimer]; 267 | [self.captureMovieFileOutput stopRecording];//停止录制 268 | } 269 | } 270 | #pragma mark 切换前后摄像头 271 | - (void)changeCamera:(UIButton*)bt { 272 | AVCaptureDevice *currentDevice=[self.captureDeviceInput device]; 273 | AVCaptureDevicePosition currentPosition=[currentDevice position]; 274 | AVCaptureDevice *toChangeDevice; 275 | AVCaptureDevicePosition toChangePosition=AVCaptureDevicePositionFront; 276 | if (currentPosition==AVCaptureDevicePositionUnspecified||currentPosition==AVCaptureDevicePositionFront) { 277 | toChangePosition=AVCaptureDevicePositionBack; 278 | flashBt.hidden = NO; 279 | }else{ 280 | flashBt.hidden = YES; 281 | } 282 | toChangeDevice=[self getCameraDeviceWithPosition:toChangePosition]; 283 | //获得要调整的设备输入对象 284 | AVCaptureDeviceInput *toChangeDeviceInput=[[AVCaptureDeviceInput alloc]initWithDevice:toChangeDevice error:nil]; 285 | 286 | //改变会话的配置前一定要先开启配置,配置完成后提交配置改变 287 | [self.captureSession beginConfiguration]; 288 | //移除原有输入对象 289 | [self.captureSession removeInput:self.captureDeviceInput]; 290 | //添加新的输入对象 291 | if ([self.captureSession canAddInput:toChangeDeviceInput]) { 292 | [self.captureSession addInput:toChangeDeviceInput]; 293 | self.captureDeviceInput=toChangeDeviceInput; 294 | } 295 | //提交会话配置 296 | [self.captureSession commitConfiguration]; 297 | 298 | //关闭闪光灯 299 | flashBt.selected = NO; 300 | [flashBt setBackgroundImage:[UIImage imageNamed:@"flashOn"] forState:UIControlStateNormal]; 301 | [self setTorchMode:AVCaptureTorchModeOff]; 302 | 303 | } 304 | 305 | #pragma mark - 视频输出代理 306 | -(void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections{ 307 | NSLog(@"开始录制..."); 308 | [self startTimer]; 309 | } 310 | -(void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error{ 311 | 312 | [urlArray addObject:outputFileURL]; 313 | //时间到了 314 | if (currentTime>=totalTime) { 315 | [self mergeAndExportVideosAtFileURLs:urlArray]; 316 | } 317 | } 318 | - (void)mergeAndExportVideosAtFileURLs:(NSMutableArray *)fileURLArray 319 | { 320 | NSError *error = nil; 321 | 322 | CGSize renderSize = CGSizeMake(0, 0); 323 | 324 | NSMutableArray *layerInstructionArray = [[NSMutableArray alloc] init]; 325 | 326 | AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init]; 327 | 328 | CMTime totalDuration = kCMTimeZero; 329 | 330 | NSMutableArray *assetTrackArray = [[NSMutableArray alloc] init]; 331 | NSMutableArray *assetArray = [[NSMutableArray alloc] init]; 332 | for (NSURL *fileURL in fileURLArray) { 333 | 334 | AVAsset *asset = [AVAsset assetWithURL:fileURL]; 335 | [assetArray addObject:asset]; 336 | 337 | NSArray* tmpAry =[asset tracksWithMediaType:AVMediaTypeVideo]; 338 | if (tmpAry.count>0) { 339 | AVAssetTrack *assetTrack = [tmpAry objectAtIndex:0]; 340 | [assetTrackArray addObject:assetTrack]; 341 | renderSize.width = MAX(renderSize.width, assetTrack.naturalSize.height); 342 | renderSize.height = MAX(renderSize.height, assetTrack.naturalSize.width); 343 | } 344 | } 345 | 346 | CGFloat renderW = MIN(renderSize.width, renderSize.height); 347 | 348 | for (int i = 0; i < [assetArray count] && i < [assetTrackArray count]; i++) { 349 | 350 | AVAsset *asset = [assetArray objectAtIndex:i]; 351 | AVAssetTrack *assetTrack = [assetTrackArray objectAtIndex:i]; 352 | 353 | AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; 354 | 355 | NSArray*dataSourceArray= [asset tracksWithMediaType:AVMediaTypeAudio]; 356 | [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) 357 | ofTrack:([dataSourceArray count]>0)?[dataSourceArray objectAtIndex:0]:nil 358 | atTime:totalDuration 359 | error:nil]; 360 | 361 | AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 362 | 363 | [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) 364 | ofTrack:assetTrack 365 | atTime:totalDuration 366 | error:&error]; 367 | 368 | AVMutableVideoCompositionLayerInstruction *layerInstruciton = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; 369 | 370 | totalDuration = CMTimeAdd(totalDuration, asset.duration); 371 | 372 | CGFloat rate; 373 | rate = renderW / MIN(assetTrack.naturalSize.width, assetTrack.naturalSize.height); 374 | 375 | CGAffineTransform layerTransform = CGAffineTransformMake(assetTrack.preferredTransform.a, assetTrack.preferredTransform.b, assetTrack.preferredTransform.c, assetTrack.preferredTransform.d, assetTrack.preferredTransform.tx * rate, assetTrack.preferredTransform.ty * rate); 376 | layerTransform = CGAffineTransformConcat(layerTransform, CGAffineTransformMake(1, 0, 0, 1, 0, -(assetTrack.naturalSize.width - assetTrack.naturalSize.height) / 2.0+preLayerHWRate*(preLayerHeight-preLayerWidth)/2)); 377 | layerTransform = CGAffineTransformScale(layerTransform, rate, rate); 378 | 379 | [layerInstruciton setTransform:layerTransform atTime:kCMTimeZero]; 380 | [layerInstruciton setOpacity:0.0 atTime:totalDuration]; 381 | 382 | [layerInstructionArray addObject:layerInstruciton]; 383 | } 384 | 385 | NSString *path = [self getVideoMergeFilePathString]; 386 | NSURL *mergeFileURL = [NSURL fileURLWithPath:path]; 387 | 388 | AVMutableVideoCompositionInstruction *mainInstruciton = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 389 | mainInstruciton.timeRange = CMTimeRangeMake(kCMTimeZero, totalDuration); 390 | mainInstruciton.layerInstructions = layerInstructionArray; 391 | AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition]; 392 | mainCompositionInst.instructions = @[mainInstruciton]; 393 | mainCompositionInst.frameDuration = CMTimeMake(1, 100); 394 | mainCompositionInst.renderSize = CGSizeMake(renderW, renderW*preLayerHWRate); 395 | 396 | AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality]; 397 | exporter.videoComposition = mainCompositionInst; 398 | exporter.outputURL = mergeFileURL; 399 | exporter.outputFileType = AVFileTypeMPEG4; 400 | exporter.shouldOptimizeForNetworkUse = YES; 401 | [exporter exportAsynchronouslyWithCompletionHandler:^{ 402 | dispatch_async(dispatch_get_main_queue(), ^{ 403 | 404 | PlayVideoViewController* view = [[PlayVideoViewController alloc]init]; 405 | view.videoURL =mergeFileURL; 406 | [self.navigationController pushViewController:view animated:YES]; 407 | 408 | }); 409 | }]; 410 | 411 | 412 | } 413 | //最后合成为 mp4 414 | - (NSString *)getVideoMergeFilePathString 415 | { 416 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 417 | NSString *path = [paths objectAtIndex:0]; 418 | 419 | path = [path stringByAppendingPathComponent:VIDEO_FOLDER]; 420 | 421 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 422 | formatter.dateFormat = @"yyyyMMddHHmmss"; 423 | NSString *nowTimeStr = [formatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow:0]]; 424 | 425 | NSString *fileName = [[path stringByAppendingPathComponent:nowTimeStr] stringByAppendingString:@"merge.mp4"]; 426 | 427 | return fileName; 428 | } 429 | 430 | //录制保存的时候要保存为 mov 431 | - (NSString *)getVideoSaveFilePathString 432 | { 433 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 434 | NSString *path = [paths objectAtIndex:0]; 435 | 436 | path = [path stringByAppendingPathComponent:VIDEO_FOLDER]; 437 | 438 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 439 | formatter.dateFormat = @"yyyyMMddHHmmss"; 440 | NSString *nowTimeStr = [formatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow:0]]; 441 | 442 | NSString *fileName = [[path stringByAppendingPathComponent:nowTimeStr] stringByAppendingString:@".mov"]; 443 | 444 | return fileName; 445 | } 446 | 447 | - (void)createVideoFolderIfNotExist 448 | { 449 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 450 | NSString *path = [paths objectAtIndex:0]; 451 | 452 | NSString *folderPath = [path stringByAppendingPathComponent:VIDEO_FOLDER]; 453 | 454 | NSFileManager *fileManager = [NSFileManager defaultManager]; 455 | BOOL isDir = NO; 456 | BOOL isDirExist = [fileManager fileExistsAtPath:folderPath isDirectory:&isDir]; 457 | 458 | if(!(isDirExist && isDir)) 459 | { 460 | BOOL bCreateDir = [fileManager createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:nil]; 461 | if(!bCreateDir){ 462 | NSLog(@"创建保存视频文件夹失败"); 463 | } 464 | } 465 | } 466 | - (void)deleteAllVideos 467 | { 468 | for (NSURL *videoFileURL in urlArray) { 469 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 470 | NSString *filePath = [[videoFileURL absoluteString] stringByReplacingOccurrencesOfString:@"file://" withString:@""]; 471 | NSFileManager *fileManager = [NSFileManager defaultManager]; 472 | if ([fileManager fileExistsAtPath:filePath]) { 473 | NSError *error = nil; 474 | [fileManager removeItemAtPath:filePath error:&error]; 475 | 476 | if (error) { 477 | NSLog(@"delete All Video 删除视频文件出错:%@", error); 478 | } 479 | } 480 | }); 481 | } 482 | [urlArray removeAllObjects]; 483 | } 484 | 485 | #pragma mark - 私有方法 486 | -(AVCaptureDevice *)getCameraDeviceWithPosition:(AVCaptureDevicePosition )position{ 487 | NSArray *cameras= [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; 488 | for (AVCaptureDevice *camera in cameras) { 489 | if ([camera position]==position) { 490 | return camera; 491 | } 492 | } 493 | return nil; 494 | } 495 | 496 | -(void)changeDeviceProperty:(PropertyChangeBlock)propertyChange{ 497 | AVCaptureDevice *captureDevice= [self.captureDeviceInput device]; 498 | NSError *error; 499 | //注意改变设备属性前一定要首先调用lockForConfiguration:调用完之后使用unlockForConfiguration方法解锁 500 | if ([captureDevice lockForConfiguration:&error]) { 501 | propertyChange(captureDevice); 502 | [captureDevice unlockForConfiguration]; 503 | }else{ 504 | NSLog(@"设置设备属性过程发生错误,错误信息:%@",error.localizedDescription); 505 | } 506 | } 507 | 508 | -(void)setTorchMode:(AVCaptureTorchMode )torchMode{ 509 | [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { 510 | if ([captureDevice isTorchModeSupported:torchMode]) { 511 | [captureDevice setTorchMode:torchMode]; 512 | } 513 | }]; 514 | } 515 | 516 | -(void)setFocusMode:(AVCaptureFocusMode )focusMode{ 517 | [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { 518 | if ([captureDevice isFocusModeSupported:focusMode]) { 519 | [captureDevice setFocusMode:focusMode]; 520 | } 521 | }]; 522 | } 523 | 524 | -(void)setExposureMode:(AVCaptureExposureMode)exposureMode{ 525 | [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { 526 | if ([captureDevice isExposureModeSupported:exposureMode]) { 527 | [captureDevice setExposureMode:exposureMode]; 528 | } 529 | }]; 530 | } 531 | 532 | -(void)focusWithMode:(AVCaptureFocusMode)focusMode exposureMode:(AVCaptureExposureMode)exposureMode atPoint:(CGPoint)point{ 533 | [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { 534 | if ([captureDevice isFocusModeSupported:focusMode]) { 535 | [captureDevice setFocusMode:AVCaptureFocusModeAutoFocus]; 536 | } 537 | if ([captureDevice isFocusPointOfInterestSupported]) { 538 | [captureDevice setFocusPointOfInterest:point]; 539 | } 540 | if ([captureDevice isExposureModeSupported:exposureMode]) { 541 | [captureDevice setExposureMode:AVCaptureExposureModeAutoExpose]; 542 | } 543 | if ([captureDevice isExposurePointOfInterestSupported]) { 544 | [captureDevice setExposurePointOfInterest:point]; 545 | } 546 | }]; 547 | } 548 | 549 | -(void)addGenstureRecognizer{ 550 | UITapGestureRecognizer *tapGesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapScreen:)]; 551 | [self.viewContainer addGestureRecognizer:tapGesture]; 552 | } 553 | -(void)tapScreen:(UITapGestureRecognizer *)tapGesture{ 554 | CGPoint point= [tapGesture locationInView:self.viewContainer]; 555 | //将UI坐标转化为摄像头坐标 556 | CGPoint cameraPoint= [self.captureVideoPreviewLayer captureDevicePointOfInterestForPoint:point]; 557 | [self setFocusCursorWithPoint:point]; 558 | [self focusWithMode:AVCaptureFocusModeAutoFocus exposureMode:AVCaptureExposureModeAutoExpose atPoint:cameraPoint]; 559 | } 560 | 561 | -(void)setFocusCursorWithPoint:(CGPoint)point{ 562 | self.focusCursor.center=point; 563 | self.focusCursor.transform=CGAffineTransformMakeScale(1.5, 1.5); 564 | self.focusCursor.alpha=1.0; 565 | [UIView animateWithDuration:1.0 animations:^{ 566 | self.focusCursor.transform=CGAffineTransformIdentity; 567 | } completion:^(BOOL finished) { 568 | self.focusCursor.alpha=0; 569 | 570 | }]; 571 | } 572 | @end 573 | -------------------------------------------------------------------------------- /VideoRecord/UIView+Tools.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Tools.h 3 | // VideoRecord 4 | // 5 | // Created by guimingsu on 14-8-25. 6 | // Copyright (c) 2014年 guimingsu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (Tools) 12 | -(void)makeCornerRadius:(float)radius borderColor:(UIColor*)bColor borderWidth:(float)bWidth; 13 | @end 14 | -------------------------------------------------------------------------------- /VideoRecord/UIView+Tools.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Tools.m 3 | // VideoRecord 4 | // 5 | // Created by guimingsu on 14-8-25. 6 | // Copyright (c) 2014年 guimingsu. All rights reserved. 7 | // 8 | 9 | #import "UIView+Tools.h" 10 | 11 | @implementation UIView (Tools) 12 | -(void)makeCornerRadius:(float)radius borderColor:(UIColor *)bColor borderWidth:(float)bWidth{ 13 | self.layer.borderWidth = bWidth; 14 | 15 | if (bColor != nil) { 16 | self.layer.borderColor = bColor.CGColor; 17 | } 18 | 19 | self.layer.cornerRadius = radius; 20 | self.layer.masksToBounds = YES; 21 | } 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /VideoRecord/changeCamer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyFightting/VideoRecord/8489187128385b83dbd8545ab4bfe280b5939d0c/VideoRecord/changeCamer.png -------------------------------------------------------------------------------- /VideoRecord/flashOff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyFightting/VideoRecord/8489187128385b83dbd8545ab4bfe280b5939d0c/VideoRecord/flashOff.png -------------------------------------------------------------------------------- /VideoRecord/flashOn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyFightting/VideoRecord/8489187128385b83dbd8545ab4bfe280b5939d0c/VideoRecord/flashOn.png -------------------------------------------------------------------------------- /VideoRecord/focusImg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyFightting/VideoRecord/8489187128385b83dbd8545ab4bfe280b5939d0c/VideoRecord/focusImg.png -------------------------------------------------------------------------------- /VideoRecord/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // VideoRecord 4 | // 5 | // Created by guimingsu on 15/6/2. 6 | // Copyright (c) 2015年 guimingsu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /VideoRecord/shootFinish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyFightting/VideoRecord/8489187128385b83dbd8545ab4bfe280b5939d0c/VideoRecord/shootFinish.png -------------------------------------------------------------------------------- /VideoRecord/videoPlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyFightting/VideoRecord/8489187128385b83dbd8545ab4bfe280b5939d0c/VideoRecord/videoPlay.png -------------------------------------------------------------------------------- /VideoRecordTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.good.studentApp 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /VideoRecordTests/VideoRecordTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // VideoRecordTests.m 3 | // VideoRecordTests 4 | // 5 | // Created by guimingsu on 15/6/2. 6 | // Copyright (c) 2015年 guimingsu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface VideoRecordTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation VideoRecordTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyFightting/VideoRecord/8489187128385b83dbd8545ab4bfe280b5939d0c/img1.png -------------------------------------------------------------------------------- /img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndyFightting/VideoRecord/8489187128385b83dbd8545ab4bfe280b5939d0c/img2.png --------------------------------------------------------------------------------