日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Swift - 视频录制教程3(设置拍摄窗口大小,录制正方形视频)

發布時間:2024/3/13 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Swift - 视频录制教程3(设置拍摄窗口大小,录制正方形视频) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在之前的兩篇文章中,我介紹了如何通過? AVFoundation.framework?框架提供的? AVCaptureSession?類來實現視頻的錄制。以及通過? AVMutableComposition?來將多段視頻片段的視頻、音頻軌道進行拼接合成。 Swift - 視頻錄制教程1(調用攝像頭錄像,并保存到系統相冊)
Swift - 視頻錄制教程2(小視頻拍攝,將多段視頻進行合并) 這兩個樣例我們用的都是全屏錄像,拍攝下的視頻是豎的(iPhone6拍攝的分辨率是1080*1920)。

但我們看市面上常見的視頻APP,拍攝的小視頻都是正方形,或者是橫向的矩形。本文演示如何修改視頻拍攝尺寸,這里以實現正方形視頻的拍攝為例。

1,要實現正方形視頻的拍攝要從下面幾方面入手:

(1)預覽窗口( AVCaptureVideoPreviewLayer)尺寸設置為正方矩形(長寬均為屏幕寬度),并在整個屏幕垂直居中。
(2)視頻片段錄制的時候還是使用完整的分辨率尺寸進行錄制。
(3)在將各個視頻片段合并輸出時,我們通過? AVMutableVideoComposition?實現視頻的裁剪,即從視頻的中央位置裁出一個正方形的內容并保存文件。
2,效果圖如下: ? ? ? ? ?
3,樣例代碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 import? UIKit import? AVFoundation import? Photos import? AVKit class? ViewController :? UIViewController? ,? AVCaptureFileOutputRecordingDelegate? { ????? ???? //視頻捕獲會話。它是input和output的橋梁。它協調著intput到output的數據傳輸 ???? let? captureSession =? AVCaptureSession () ???? //視頻輸入設備 ???? let? videoDevice =? AVCaptureDevice .defaultDeviceWithMediaType( AVMediaTypeVideo ) ???? //音頻輸入設備 ???? let? audioDevice =? AVCaptureDevice .defaultDeviceWithMediaType( AVMediaTypeAudio ) ???? //將捕獲到的視頻輸出到文件 ???? let? fileOutput =? AVCaptureMovieFileOutput () ????? ???? //錄制、保存按鈕 ???? var? recordButton, saveButton :? UIButton ! ????? ???? //保存所有的錄像片段數組 ???? var? videoAssets = [ AVAsset ]() ???? //保存所有的錄像片段url數組 ???? var? assetURLs = [ String ]() ???? //單獨錄像片段的index索引 ???? var? appendix:? Int32? = 1 ????? ???? //最大允許的錄制時間(秒) ???? let? totalSeconds:? Float64? = 15.00 ???? //每秒幀數 ???? var? framesPerSecond: Int32? = 30 ???? //剩余時間 ???? var? remainingTime :? NSTimeInterval? = 15.0 ????? ???? //表示是否停止錄像 ???? var? stopRecording:? Bool? =? false ???? //剩余時間計時器 ???? var? timer:? NSTimer ? ???? //進度條計時器 ???? var? progressBarTimer:? NSTimer ? ???? //進度條計時器時間間隔 ???? var? incInterval:? NSTimeInterval? = 0.05 ???? //進度條 ???? var? progressBar:? UIView? =? UIView () ???? //當前進度條終點位置 ???? var? oldX:? CGFloat? = 0 ????? ???? override? func? viewDidLoad() { ???????? super .viewDidLoad() ????????? ???????? //背景色設為黑色 ???????? self .view.backgroundColor =? UIColor .blackColor() ????????? ???????? //添加視頻、音頻輸入設備 ???????? let? videoInput = try!? AVCaptureDeviceInput (device:? self .videoDevice) ???????? self .captureSession.addInput(videoInput) ???????? let? audioInput = try!? AVCaptureDeviceInput (device:? self .audioDevice) ???????? self .captureSession.addInput(audioInput); ????????? ???????? //添加視頻捕獲輸出 ???????? let? maxDuration =? CMTimeMakeWithSeconds (totalSeconds, framesPerSecond) ???????? self .fileOutput.maxRecordedDuration = maxDuration ???????? self .captureSession.addOutput( self .fileOutput) ????????? ???????? //使用AVCaptureVideoPreviewLayer可以將攝像頭的拍攝的實時畫面顯示在ViewController上 ???????? let? videoLayer =? AVCaptureVideoPreviewLayer (session:? self .captureSession) ???????? //預覽窗口是正方形,在屏幕居中(顯示的也是攝像頭拍攝的中心區域) ???????? videoLayer.frame =? CGRectMake (0,? self .view.bounds.height/4, ?????????????????????????????????????? self .view.bounds.width,? self .view.bounds.width) ???????? videoLayer.videoGravity =? AVLayerVideoGravityResizeAspectFill ???????? videoLayer.pointForCaptureDevicePointOfInterest( CGPoint (x: 0, y: 0)) ???????? self .view.layer.addSublayer(videoLayer) ????????? ???????? //創建按鈕 ???????? self .setupButton() ???????? //啟動session會話 ???????? self .captureSession.startRunning() ????????? ???????? //添加進度條 ???????? progressBar.frame =? CGRect (x: 0, y: 0, width:? self .view.bounds.width, ??????????????????????????????????? height:? self .view.bounds.height * 0.1) ???????? progressBar.backgroundColor =? UIColor (red: 4, green: 3, blue: 3, alpha: 0.5) ???????? self .view.addSubview(progressBar) ???? } ????? ???? //創建按鈕 ???? func? setupButton(){ ???????? //創建錄制按鈕 ???????? self .recordButton =? UIButton (frame:? CGRectMake (0,0,120,50)) ???????? self .recordButton.backgroundColor =? UIColor .redColor(); ???????? self .recordButton.layer.masksToBounds =? true ???????? self .recordButton.setTitle( "按住錄像" , forState: . Normal ) ???????? self .recordButton.layer.cornerRadius = 20.0 ???????? self .recordButton.layer.position =? CGPoint (x:? self .view.bounds.width/2, ??????????????????????????????????????????????????? y: self .view.bounds.height-50) ???????? self .recordButton.addTarget( self , action: #selector(onTouchDownRecordButton(_:)), ???????????????????????????????????? forControlEvents: . TouchDown ) ???????? self .recordButton.addTarget( self , action: #selector(onTouchUpRecordButton(_:)), ???????????????????????????????????? forControlEvents: . TouchUpInside ) ????????? ???????? //創建保存按鈕 ???????? self .saveButton =? UIButton (frame:? CGRectMake (0,0,70,50)) ???????? self .saveButton.backgroundColor =? UIColor .grayColor(); ???????? self .saveButton.layer.masksToBounds =? true ???????? self .saveButton.setTitle( "保存" , forState: . Normal ) ???????? self .saveButton.layer.cornerRadius = 20.0 ????????? ???????? self .saveButton.layer.position =? CGPoint (x:? self .view.bounds.width - 60, ????????????????????????????????????????????????? y: self .view.bounds.height-50) ???????? self .saveButton.addTarget( self , action: #selector(onClickStopButton(_:)), ?????????????????????????????????? forControlEvents: . TouchUpInside ) ????????? ???????? //添加按鈕到視圖上 ???????? self .view.addSubview( self .recordButton); ???????? self .view.addSubview( self .saveButton); ???? } ????? ???? //按下錄制按鈕,開始錄制片段 ???? func?? onTouchDownRecordButton(sender:? UIButton ){ ???????? if (!stopRecording) { ???????????? let? paths =? NSSearchPathForDirectoriesInDomains (. DocumentDirectory , ???????????????????????????????????????????????????????????? . UserDomainMask ,? true ) ???????????? let? documentsDirectory = paths[0]? as? String ???????????? let? outputFilePath =? "\(documentsDirectory)/output-\(appendix).mov" ???????????? appendix += 1 ???????????? let? outputURL =? NSURL (fileURLWithPath: outputFilePath) ???????????? let? fileManager =? NSFileManager .defaultManager() ???????????? if (fileManager.fileExistsAtPath(outputFilePath)) { ????????????????? ???????????????? do { ???????????????????? try fileManager.removeItemAtPath(outputFilePath) ???????????????? } catch _ { ???????????????? } ???????????? } ???????????? print ( "開始錄制:\(outputFilePath) " ) ???????????? fileOutput.startRecordingToOutputFileURL(outputURL, recordingDelegate:? self ) ???????? } ???? } ????? ???? //松開錄制按鈕,停止錄制片段 ???? func?? onTouchUpRecordButton(sender:? UIButton ){ ???????? if (!stopRecording) { ???????????? timer?.invalidate() ???????????? progressBarTimer?.invalidate() ???????????? fileOutput.stopRecording() ???????? } ???? } ????? ???? //錄像開始的代理方法 ???? func? captureOutput(captureOutput:? AVCaptureFileOutput !, ??????????????????????? didStartRecordingToOutputFileAtURL fileURL:? NSURL !, ???????????????????????? fromConnections connections: [ AnyObject ]!) { ???????? startProgressBarTimer() ???????? startTimer() ???? } ????? ???? //錄像結束的代理方法 ???? func? captureOutput(captureOutput:? AVCaptureFileOutput !, ??????????????????????? didFinishRecordingToOutputFileAtURL outputFileURL:? NSURL !, ???????????????????????? fromConnections connections: [ AnyObject ]!, error:? NSError !) { ???????? let? asset :? AVURLAsset? =? AVURLAsset ( URL : outputFileURL, options:? nil ) ???????? var? duration :? NSTimeInterval? = 0.0 ???????? duration =? CMTimeGetSeconds (asset.duration) ???????? print ( "生成視頻片段:\(asset)" ) ???????? videoAssets.append(asset) ???????? assetURLs.append(outputFileURL.path!) ???????? remainingTime = remainingTime - duration ????????? ???????? //到達允許最大錄制時間,自動合并視頻 ???????? if? remainingTime <= 0 { ???????????? mergeVideos() ???????? } ???? } ????? ???? //剩余時間計時器 ???? func? startTimer() { ???????? timer =? NSTimer (timeInterval: remainingTime, target:? self , ???????????????????????? selector: #selector( ViewController .timeout), userInfo:? nil , ???????????????????????? repeats: true ) ???????? NSRunLoop .currentRunLoop().addTimer(timer!, forMode:? NSDefaultRunLoopMode ) ???? } ????? ???? //錄制時間達到最大時間 ???? func? timeout() { ???????? stopRecording =? true ???????? print ( "時間到。" ) ???????? fileOutput.stopRecording() ???????? timer?.invalidate() ???????? progressBarTimer?.invalidate() ???? } ????? ???? //進度條計時器 ???? func? startProgressBarTimer() { ???????? progressBarTimer =? NSTimer (timeInterval: incInterval, target:? self , ??????????????????????????????????? selector: #selector( ViewController .progress), ??????????????????????????????????? userInfo:? nil , repeats:? true ) ???????? NSRunLoop .currentRunLoop().addTimer(progressBarTimer!, ???????????????????????????????????????????? forMode:? NSDefaultRunLoopMode ) ???? } ????? ???? //修改進度條進度 ???? func? progress() { ???????? let? progressProportion:? CGFloat? =? CGFloat (incInterval / totalSeconds) ???????? let? progressInc:? UIView? =? UIView () ???????? progressInc.backgroundColor =? UIColor (red: 55/255, green: 186/255, blue: 89/255, ?????????????????????????????????????????????? alpha: 1) ???????? let? newWidth = progressBar.frame.width * progressProportion ???????? progressInc.frame =? CGRect (x: oldX , y: 0, width: newWidth, ??????????????????????????????????? height: progressBar.frame.height) ???????? oldX = oldX + newWidth ???????? progressBar.addSubview(progressInc) ???? } ????? ???? //保存按鈕點擊 ???? func? onClickStopButton(sender:? UIButton ){ ???????? mergeVideos() ???? } ????? ???? //合并視頻片段 ???? func? mergeVideos() { ???????? let? duration = totalSeconds ????????? ???????? let? composition =? AVMutableComposition () ???????? //合并視頻、音頻軌道 ???????? let? firstTrack = composition.addMutableTrackWithMediaType( ???????????? AVMediaTypeVideo , preferredTrackID:? CMPersistentTrackID ()) ???????? let? audioTrack = composition.addMutableTrackWithMediaType( ???????????? AVMediaTypeAudio , preferredTrackID:? CMPersistentTrackID ()) ????????? ???????? var? insertTime:? CMTime? = kCMTimeZero ???????? for? asset? in? videoAssets { ???????????? print ( "合并視頻片段:\(asset)" ) ???????????? do { ???????????????? try firstTrack.insertTimeRange( ???????????????????? CMTimeRangeMake (kCMTimeZero, asset.duration), ???????????????????? ofTrack: asset.tracksWithMediaType( AVMediaTypeVideo )[0] , ???????????????????? atTime: insertTime) ???????????? } catch _ { ???????????? } ???????????? do { ???????????????? try audioTrack.insertTimeRange( ???????????????????? CMTimeRangeMake (kCMTimeZero, asset.duration), ???????????????????? ofTrack: asset.tracksWithMediaType( AVMediaTypeAudio )[0] , ???????????????????? atTime: insertTime) ???????????? } catch _ { ???????????? } ????????????? ???????????? insertTime =? CMTimeAdd (insertTime, asset.duration) ???????? } ???????? //旋轉視頻圖像,防止90度顛倒 ???????? firstTrack.preferredTransform =? CGAffineTransformMakeRotation ( CGFloat ( M_PI_2 )) ????????? ???????? //定義最終生成的視頻尺寸(矩形的) ???????? print ( "視頻原始尺寸:" , firstTrack.naturalSize) ???????? let? renderSize =? CGSizeMake (firstTrack.naturalSize.height, firstTrack.naturalSize.height) ???????? print ( "最終渲染尺寸:" , renderSize) ????????? ???????? //通過AVMutableVideoComposition實現視頻的裁剪(矩形,截取正中心區域視頻) ???????? let? videoComposition =? AVMutableVideoComposition () ???????? videoComposition.frameDuration =? CMTimeMake (1, framesPerSecond) ???????? videoComposition.renderSize = renderSize ????????? ???????? let? instruction =? AVMutableVideoCompositionInstruction () ???????? instruction.timeRange =? CMTimeRangeMake ( ???????????? kCMTimeZero, CMTimeMakeWithSeconds ( Float64 (duration), framesPerSecond)) ????????? ???????? let? transformer:? AVMutableVideoCompositionLayerInstruction? = ???????????? AVMutableVideoCompositionLayerInstruction (assetTrack: firstTrack) ???????? let? t1 =? CGAffineTransformMakeTranslation (firstTrack.naturalSize.height, ???????????????????? -(firstTrack.naturalSize.width-firstTrack.naturalSize.height)/2) ???????? let? t2 =? CGAffineTransformRotate (t1,? CGFloat ( M_PI_2 )) ???????? let? finalTransform:? CGAffineTransform? = t2 ???????? transformer.setTransform(finalTransform, atTime: kCMTimeZero) ????????? ???????? instruction.layerInstructions = [transformer] ???????? videoComposition.instructions = [instruction] ????????? ???????? //獲取合并后的視頻路徑 ???????? let? documentsPath =? NSSearchPathForDirectoriesInDomains (. DocumentDirectory , ???????????????????????????????????????????????????????????????? . UserDomainMask , true )[0] ???????? let? destinationPath = documentsPath +? "/mergeVideo-\(arc4random()%1000).mov" ???????? print ( "合并后的視頻:\(destinationPath)" ) ???????? let? videoPath:? NSURL? =? NSURL (fileURLWithPath: destinationPath? as? String ) ???????? let? exporter =? AVAssetExportSession (asset: composition, ???????????????????????????????????????????? presetName: AVAssetExportPresetHighestQuality )! ???????? exporter.outputURL = videoPath ???????? exporter.outputFileType =? AVFileTypeQuickTimeMovie ???????? exporter.videoComposition = videoComposition? //設置videoComposition ???????? exporter.shouldOptimizeForNetworkUse =? true ???????? exporter.timeRange =? CMTimeRangeMake ( ???????????? kCMTimeZero, CMTimeMakeWithSeconds ( Float64 (duration), framesPerSecond)) ???????? exporter.exportAsynchronouslyWithCompletionHandler({ ???????????? //將合并后的視頻保存到相冊 ???????????? self .exportDidFinish(exporter) ???????? }) ???? } ????? ???? //將合并后的視頻保存到相冊 ???? func? exportDidFinish(session:? AVAssetExportSession ) { ???????? print ( "視頻合并成功!" ) ???????? let? outputURL:? NSURL? = session.outputURL! ???????? //將錄制好的錄像保存到照片庫中 ???????? PHPhotoLibrary .sharedPhotoLibrary().performChanges({ ???????????? PHAssetChangeRequest .creationRequestForAssetFromVideoAtFileURL(outputURL) ???????????? }, completionHandler: { (isSuccess:? Bool , error:? NSError ?)? in ???????????????? dispatch_async(dispatch_get_main_queue(),{ ???????????????????? //重置參數 ???????????????????? self .reset() ????????????????????? ???????????????????? //彈出提示框 ???????????????????? let? alertController =? UIAlertController (title:? "視頻保存成功" , ???????????????????????? message:? "是否需要回看錄像?" , preferredStyle: . Alert ) ???????????????????? let? okAction =? UIAlertAction (title:? "確定" , style: . Default , handler: { ???????????????????????? action? in ???????????????????????? //錄像回看 ???????????????????????? self .reviewRecord(outputURL) ???????????????????? }) ???????????????????? let? cancelAction =? UIAlertAction (title:? "取消" , style: . Cancel , ???????????????????????? handler:? nil ) ???????????????????? alertController.addAction(okAction) ???????????????????? alertController.addAction(cancelAction) ???????????????????? self .presentViewController(alertController, animated:? true , ???????????????????????? completion:? nil ) ???????????????? }) ???????? }) ???? } ????? ???? //視頻保存成功,重置各個參數,準備新視頻錄制 ???? func? reset() { ???????? //刪除視頻片段 ???????? for? assetURL? in? assetURLs { ???????????? if ( NSFileManager .defaultManager().fileExistsAtPath(assetURL)) { ???????????????? do { ???????????????????? try? NSFileManager .defaultManager().removeItemAtPath(assetURL) ???????????????? } catch _ { ???????????????? } ???????????????? print ( "刪除視頻片段: \(assetURL)" ) ???????????? } ???????? } ????????? ???????? //進度條還原 ???????? let? subviews = progressBar.subviews ???????? for? subview? in? subviews { ???????????? subview.removeFromSuperview() ???????? } ????????? ???????? //各個參數還原 ???????? videoAssets.removeAll(keepCapacity:? false ) ???????? assetURLs.removeAll(keepCapacity:? false ) ???????? appendix = 1 ???????? oldX = 0 ???????? stopRecording =? false ???????? remainingTime = totalSeconds ???? } ????? ???? //錄像回看 ???? func? reviewRecord(outputURL:? NSURL ) { ???????? //定義一個視頻播放器,通過本地文件路徑初始化 ???????? let? player =? AVPlayer ( URL : outputURL) ???????? let? playerViewController =? AVPlayerViewController () ???????? playerViewController.player = player ???????? self .presentViewController(playerViewController, animated:? true ) { ???????????? playerViewController.player!.play() ???????? } ???? } }

原文出自: www.hangge.com ??轉載請保留原文鏈接: http://www.hangge.com/blog/cache/detail_1204.html

總結

以上是生活随笔為你收集整理的Swift - 视频录制教程3(设置拍摄窗口大小,录制正方形视频)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。