如何将UIImage数组导出为电影?

如何将UIImage数组导出为电影?

我有一个严重的问题:我有一个NSArray有几个UIImage物品。我现在想做的是用那些UIImages..但我不知道该怎么做。

我希望有人能帮我,或者给我发一个代码片段,做一些我想做的事情。

编辑:供今后参考-在应用解决方案后,如果视频看起来失真,请确保所捕获的图像/区域的宽度为16倍。在此经过几个小时的挣扎后发现:
为什么我的电影“UIImage”会被歪曲?

以下是完整的解决方案(只需确保宽度为16的倍数)
http:/codeThink.no-ip.org/WordPress/files/673


墨色风雨
浏览 594回答 3
3回答

jeck猫

注:这是一个SWIFT 2.1解决方案(iOS 8+,XCode 7.2).上周,我开始编写iOS代码,从图像生成视频。我有一点AVFoundation的经验,但从未听说过CVPixelBuffer。我在这页上看到了答案这里..花了几天的时间来解剖所有的东西,然后用斯威夫特的方法把它们重新组合在一起,这对我的大脑是有意义的。下面是我想出来的。注意:如果您将下面的所有代码复制/粘贴到一个SWIFT文件中,它应该会编译。你只需要调整一下loadImages()而RenderSettings价值。第1部分:设置在这里,我将所有与导出相关的设置分组为一个RenderSettings结构。import&nbsp;AVFoundationimport&nbsp;UIKitimport&nbsp;Photosstruct&nbsp;RenderSettings&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;width:&nbsp;CGFloat&nbsp;=&nbsp;1280 &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;height:&nbsp;CGFloat&nbsp;=&nbsp;720 &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;fps:&nbsp;Int32&nbsp;=&nbsp;2&nbsp;&nbsp;&nbsp;//&nbsp;2&nbsp;frames&nbsp;per&nbsp;second &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;avCodecKey&nbsp;=&nbsp;AVVideoCodecH264 &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;videoFilename&nbsp;=&nbsp;"render" &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;videoFilenameExt&nbsp;=&nbsp;"mp4" &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;size:&nbsp;CGSize&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;CGSize(width:&nbsp;width,&nbsp;height:&nbsp;height) &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;outputURL:&nbsp;NSURL&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Use&nbsp;the&nbsp;CachesDirectory&nbsp;so&nbsp;the&nbsp;rendered&nbsp;video&nbsp;file&nbsp;sticks&nbsp;around&nbsp;as&nbsp;long&nbsp;as&nbsp;we&nbsp;need&nbsp;it&nbsp;to. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Using&nbsp;the&nbsp;CachesDirectory&nbsp;ensures&nbsp;the&nbsp;file&nbsp;won't&nbsp;be&nbsp;included&nbsp;in&nbsp;a&nbsp;backup&nbsp;of&nbsp;the&nbsp;app. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;fileManager&nbsp;=&nbsp;NSFileManager.defaultManager() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;let&nbsp;tmpDirURL&nbsp;=&nbsp;try?&nbsp;fileManager.URLForDirectory(.CachesDirectory,&nbsp;inDomain:&nbsp;.UserDomainMask,&nbsp;appropriateForURL: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil,&nbsp;create:&nbsp;true)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;tmpDirURL.URLByAppendingPathComponent(videoFilename).URLByAppendingPathExtension(videoFilenameExt) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fatalError("URLForDirectory()&nbsp;failed") &nbsp;&nbsp;&nbsp;&nbsp;}}第二部分:图像动画这个ImageAnimator类知道您的图像,并使用VideoWriter类来执行呈现。其想法是将视频内容代码与低级AVFoundation代码分开。我还补充说saveToLibrary()这里是一个类函数,它在链的末尾被调用,以便将视频保存到照片库。class&nbsp;ImageAnimator&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Apple&nbsp;suggests&nbsp;a&nbsp;timescale&nbsp;of&nbsp;600&nbsp;because&nbsp;it's&nbsp;a&nbsp;multiple&nbsp;of&nbsp;standard&nbsp;video&nbsp;rates&nbsp;24,&nbsp;25,&nbsp;30,&nbsp;60&nbsp;fps&nbsp;etc. &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;let&nbsp;kTimescale:&nbsp;Int32&nbsp;=&nbsp;600 &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;settings:&nbsp;RenderSettings &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;videoWriter:&nbsp;VideoWriter &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;images:&nbsp;[UIImage]! &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;frameNum&nbsp;=&nbsp;0 &nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;func&nbsp;saveToLibrary(videoURL:&nbsp;NSURL)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PHPhotoLibrary.requestAuthorization&nbsp;{&nbsp;status&nbsp;in &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;guard&nbsp;status&nbsp;==&nbsp;.Authorized&nbsp;else&nbsp;{&nbsp;return&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PHPhotoLibrary.sharedPhotoLibrary().performChanges({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL(videoURL) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;})&nbsp;{&nbsp;success,&nbsp;error&nbsp;in &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;!success&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("Could&nbsp;not&nbsp;save&nbsp;video&nbsp;to&nbsp;photo&nbsp;library:",&nbsp;error) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;func&nbsp;removeFileAtURL(fileURL:&nbsp;NSURL)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;NSFileManager.defaultManager().removeItemAtPath(fileURL.path!) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch&nbsp;_&nbsp;as&nbsp;NSError&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Assume&nbsp;file&nbsp;doesn't&nbsp;exist. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;init(renderSettings:&nbsp;RenderSettings)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;settings&nbsp;=&nbsp;renderSettings &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;videoWriter&nbsp;=&nbsp;VideoWriter(renderSettings:&nbsp;settings) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;images&nbsp;=&nbsp;loadImages() &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;render(completion:&nbsp;()->Void)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;The&nbsp;VideoWriter&nbsp;will&nbsp;fail&nbsp;if&nbsp;a&nbsp;file&nbsp;exists&nbsp;at&nbsp;the&nbsp;URL,&nbsp;so&nbsp;clear&nbsp;it&nbsp;out&nbsp;first. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ImageAnimator.removeFileAtURL(settings.outputURL) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;videoWriter.start() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;videoWriter.render(appendPixelBuffers)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ImageAnimator.saveToLibrary(self.settings.outputURL) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;completion() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Replace&nbsp;this&nbsp;logic&nbsp;with&nbsp;your&nbsp;own. &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;loadImages()&nbsp;->&nbsp;[UIImage]&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;images&nbsp;=&nbsp;[UIImage]() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;index&nbsp;in&nbsp;1...10&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;filename&nbsp;=&nbsp;"\(index).jpg" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;images.append(UIImage(named:&nbsp;filename)!) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;images&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;This&nbsp;is&nbsp;the&nbsp;callback&nbsp;function&nbsp;for&nbsp;VideoWriter.render() &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;appendPixelBuffers(writer:&nbsp;VideoWriter)&nbsp;->&nbsp;Bool&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;frameDuration&nbsp;=&nbsp;CMTimeMake(Int64(ImageAnimator.kTimescale&nbsp;/&nbsp;settings.fps),&nbsp;ImageAnimator.kTimescale) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;!images.isEmpty&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;writer.isReadyForData&nbsp;==&nbsp;false&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Inform&nbsp;writer&nbsp;we&nbsp;have&nbsp;more&nbsp;buffers&nbsp;to&nbsp;write. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;image&nbsp;=&nbsp;images.removeFirst() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;presentationTime&nbsp;=&nbsp;CMTimeMultiply(frameDuration,&nbsp;Int32(frameNum)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;success&nbsp;=&nbsp;videoWriter.addImage(image,&nbsp;withPresentationTime:&nbsp;presentationTime) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;success&nbsp;==&nbsp;false&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fatalError("addImage()&nbsp;failed") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;frameNum++ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Inform&nbsp;writer&nbsp;all&nbsp;buffers&nbsp;have&nbsp;been&nbsp;written. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true &nbsp;&nbsp;&nbsp;&nbsp;}}第3部分:录影作家这个VideoWriter全班做所有AVFoundation重举。它主要是一个包装器AVAssetWriter和AVAssetWriterInput..它还包含一些花哨的代码,不是我编写的,它知道如何将图像转换为CVPixelBuffer.class&nbsp;VideoWriter&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;renderSettings:&nbsp;RenderSettings &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;videoWriter:&nbsp;AVAssetWriter! &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;videoWriterInput:&nbsp;AVAssetWriterInput! &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;pixelBufferAdaptor:&nbsp;AVAssetWriterInputPixelBufferAdaptor! &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;isReadyForData:&nbsp;Bool&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;videoWriterInput?.readyForMoreMediaData&nbsp;??&nbsp;false &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;func&nbsp;pixelBufferFromImage(image:&nbsp;UIImage,&nbsp;pixelBufferPool:&nbsp;CVPixelBufferPool,&nbsp;size:&nbsp;CGSize)&nbsp;->&nbsp;CVPixelBuffer&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;pixelBufferOut:&nbsp;CVPixelBuffer? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;status&nbsp;=&nbsp;CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault,&nbsp;pixelBufferPool,&nbsp;&pixelBufferOut) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;status&nbsp;!=&nbsp;kCVReturnSuccess&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fatalError("CVPixelBufferPoolCreatePixelBuffer()&nbsp;failed") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;pixelBuffer&nbsp;=&nbsp;pixelBufferOut! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CVPixelBufferLockBaseAddress(pixelBuffer,&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;data&nbsp;=&nbsp;CVPixelBufferGetBaseAddress(pixelBuffer) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;rgbColorSpace&nbsp;=&nbsp;CGColorSpaceCreateDeviceRGB() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;context&nbsp;=&nbsp;CGBitmapContextCreate(data,&nbsp;Int(size.width),&nbsp;Int(size.height), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8,&nbsp;CVPixelBufferGetBytesPerRow(pixelBuffer),&nbsp;rgbColorSpace,&nbsp;CGImageAlphaInfo.PremultipliedFirst.rawValue) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CGContextClearRect(context,&nbsp;CGRectMake(0,&nbsp;0,&nbsp;size.width,&nbsp;size.height)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;horizontalRatio&nbsp;=&nbsp;size.width&nbsp;/&nbsp;image.size.width&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;verticalRatio&nbsp;=&nbsp;size.height&nbsp;/&nbsp;image.size.height&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//aspectRatio&nbsp;=&nbsp;max(horizontalRatio,&nbsp;verticalRatio)&nbsp;//&nbsp;ScaleAspectFill &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;aspectRatio&nbsp;=&nbsp;min(horizontalRatio,&nbsp;verticalRatio)&nbsp;//&nbsp;ScaleAspectFit &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;newSize&nbsp;=&nbsp;CGSize(width:&nbsp;image.size.width&nbsp;*&nbsp;aspectRatio,&nbsp;height:&nbsp;image.size.height&nbsp;*&nbsp;aspectRatio) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;x&nbsp;=&nbsp;newSize.width&nbsp;<&nbsp;size.width&nbsp;?&nbsp;(size.width&nbsp;-&nbsp;newSize.width)&nbsp;/&nbsp;2&nbsp;:&nbsp;0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;y&nbsp;=&nbsp;newSize.height&nbsp;<&nbsp;size.height&nbsp;?&nbsp;(size.height&nbsp;-&nbsp;newSize.height)&nbsp;/&nbsp;2&nbsp;:&nbsp;0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CGContextDrawImage(context,&nbsp;CGRectMake(x,&nbsp;y,&nbsp;newSize.width,&nbsp;newSize.height),&nbsp;image.CGImage) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CVPixelBufferUnlockBaseAddress(pixelBuffer,&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;pixelBuffer&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;init(renderSettings:&nbsp;RenderSettings)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.renderSettings&nbsp;=&nbsp;renderSettings&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;start()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;avOutputSettings:&nbsp;[String:&nbsp;AnyObject]&nbsp;=&nbsp;[ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AVVideoCodecKey:&nbsp;renderSettings.avCodecKey, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AVVideoWidthKey:&nbsp;NSNumber(float:&nbsp;Float(renderSettings.width)), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AVVideoHeightKey:&nbsp;NSNumber(float:&nbsp;Float(renderSettings.height)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;createPixelBufferAdaptor()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;sourcePixelBufferAttributesDictionary&nbsp;=&nbsp;[ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kCVPixelBufferPixelFormatTypeKey&nbsp;as&nbsp;String:&nbsp;NSNumber(unsignedInt:&nbsp;kCVPixelFormatType_32ARGB), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kCVPixelBufferWidthKey&nbsp;as&nbsp;String:&nbsp;NSNumber(float:&nbsp;Float(renderSettings.width)), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kCVPixelBufferHeightKey&nbsp;as&nbsp;String:&nbsp;NSNumber(float:&nbsp;Float(renderSettings.height)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pixelBufferAdaptor&nbsp;=&nbsp;AVAssetWriterInputPixelBufferAdaptor(assetWriterInput:&nbsp;videoWriterInput, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sourcePixelBufferAttributes:&nbsp;sourcePixelBufferAttributesDictionary) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;createAssetWriter(outputURL:&nbsp;NSURL)&nbsp;->&nbsp;AVAssetWriter&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;guard&nbsp;let&nbsp;assetWriter&nbsp;=&nbsp;try?&nbsp;AVAssetWriter(URL:&nbsp;outputURL,&nbsp;fileType:&nbsp;AVFileTypeMPEG4)&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fatalError("AVAssetWriter()&nbsp;failed") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;guard&nbsp;assetWriter.canApplyOutputSettings(avOutputSettings,&nbsp;forMediaType:&nbsp;AVMediaTypeVideo)&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fatalError("canApplyOutputSettings()&nbsp;failed") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;assetWriter&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;videoWriter&nbsp;=&nbsp;createAssetWriter(renderSettings.outputURL) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;videoWriterInput&nbsp;=&nbsp;AVAssetWriterInput(mediaType:&nbsp;AVMediaTypeVideo,&nbsp;outputSettings:&nbsp;avOutputSettings) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;videoWriter.canAddInput(videoWriterInput)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;videoWriter.addInput(videoWriterInput) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fatalError("canAddInput()&nbsp;returned&nbsp;false") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;The&nbsp;pixel&nbsp;buffer&nbsp;adaptor&nbsp;must&nbsp;be&nbsp;created&nbsp;before&nbsp;we&nbsp;start&nbsp;writing. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;createPixelBufferAdaptor() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;videoWriter.startWriting()&nbsp;==&nbsp;false&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fatalError("startWriting()&nbsp;failed") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;videoWriter.startSessionAtSourceTime(kCMTimeZero) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;precondition(pixelBufferAdaptor.pixelBufferPool&nbsp;!=&nbsp;nil,&nbsp;"nil&nbsp;pixelBufferPool") &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;render(appendPixelBuffers:&nbsp;(VideoWriter)->Bool,&nbsp;completion:&nbsp;()->Void)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;precondition(videoWriter&nbsp;!=&nbsp;nil,&nbsp;"Call&nbsp;start()&nbsp;to&nbsp;initialze&nbsp;the&nbsp;writer") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;queue&nbsp;=&nbsp;dispatch_queue_create("mediaInputQueue",&nbsp;nil) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;videoWriterInput.requestMediaDataWhenReadyOnQueue(queue)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;isFinished&nbsp;=&nbsp;appendPixelBuffers(self) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;isFinished&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.videoWriterInput.markAsFinished() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.videoWriter.finishWritingWithCompletionHandler()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dispatch_async(dispatch_get_main_queue())&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;completion() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Fall&nbsp;through.&nbsp;The&nbsp;closure&nbsp;will&nbsp;be&nbsp;called&nbsp;again&nbsp;when&nbsp;the&nbsp;writer&nbsp;is&nbsp;ready. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;addImage(image:&nbsp;UIImage,&nbsp;withPresentationTime&nbsp;presentationTime:&nbsp;CMTime)&nbsp;->&nbsp;Bool&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;precondition(pixelBufferAdaptor&nbsp;!=&nbsp;nil,&nbsp;"Call&nbsp;start()&nbsp;to&nbsp;initialze&nbsp;the&nbsp;writer") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;pixelBuffer&nbsp;=&nbsp;VideoWriter.pixelBufferFromImage(image,&nbsp;pixelBufferPool:&nbsp;pixelBufferAdaptor.pixelBufferPool!,&nbsp;size:&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;renderSettings.size) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;pixelBufferAdaptor.appendPixelBuffer(pixelBuffer,&nbsp;withPresentationTime:&nbsp;presentationTime) &nbsp;&nbsp;&nbsp;&nbsp;}}第4部分:使之成为现实一旦一切就绪,以下是你的三条魔法线:let&nbsp;settings&nbsp;=&nbsp;RenderSettings()let&nbsp;imageAnimator&nbsp;=&nbsp;ImageAnimator(renderSettings:&nbsp;settings)imageAnimator.render()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;print("yes")}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

iOS