我将我的应用创建的.mov
文件从文档文件夹移动到相机胶卷时遇到了一个奇怪的问题。一点背景:
该应用程序制作延时电影。它专门用于具有1200万像素4032x3024传感器的设备。它在应用程序的文档文件夹中创建了电影。电影可以保存为4k或HD。它们也可以保存为整个传感器的4:3宽高比电影,或传感器的16:9裁剪。如果用户希望将电影存储在设备的相机胶卷中,则可以设置该选项。 尝试将全尺寸电影(4032x3024)从应用的文档文件夹移动到相机胶卷时,我的问题存在。我收到这个错误:
错误域= NSCocoaErrorDomain代码= -1“(null)”
电影很好,它仍然位于文档的文件夹中。它无法复制到相机胶卷。如果我通过相同的代码执行相同的操作与任何其他大小,没有问题。一个4:3高清(1440x1080)工作正常,16:9高清(1920x1080)工作正常,16:9 4k(3880x2160)工作正常。这只是4:3 4k(4032x3024),当我试图移动它时会产生这个错误。
这是移动的代码:
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: cameraRollURL!)
网址正常,因为它适用于其他尺寸。
答案 0 :(得分:0)
当我从拉动方式切换为推入方式时,确实做到了这一点(从扭弯机一侧看)。
拉方法是当我有一个UIImage数组(从相机捕获)时,当准备好处理下一个图像时,它是feed writer。 推入方法是当我一个接一个UIImage(从相机捕获),并准备好处理下一个图像时供稿器。
不确定是什么原因。也许正在处理AVWritter调用之间的消息循环。
优势:如果捕获更长的视频,则您不会在UIImage数组中随时分配GB内存。
缺点:如果捕获速度太快,编写器可能没有准备好编写样本,因为可以实时处理,因此可以丢弃帧。
迅速4:
func initVideo(videoSettings: [String: Any]) -> (assetWriter: AVAssetWriter, writeInput: AVAssetWriterInput, bufferAdapter:AVAssetWriterInputPixelBufferAdaptor)? {
if(FileManager.default.fileExists(atPath: ImagesToVideoUtils.tempPath)){
guard (try? FileManager.default.removeItem(atPath: ImagesToVideoUtils.tempPath)) != nil else {
print("remove path failed")
return nil
}
}
let assetWriter = try! AVAssetWriter(url: ImagesToVideoUtils.fileURL, fileType: AVFileType.mov)
let writeInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoSettings)
assert(assetWriter.canAdd(writeInput), "add failed")
assetWriter.add(writeInput)
let bufferAttributes:[String: Any] = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32ARGB)]
let bufferAdapter = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: writeInput, sourcePixelBufferAttributes: bufferAttributes)
return (assetWriter, writeInput, bufferAdapter)
}
func exportVideo_start(assetWriter: AVAssetWriter) -> (DispatchQueue) {
assetWriter.startWriting()
assetWriter.startSession(atSourceTime: CMTime.zero)
let mediaInputQueue = DispatchQueue(label: "mediaInputQueue")
return (mediaInputQueue)
}
func exportVideo_write(videoSettings: [String: Any], img: UIImage, assetWriter: AVAssetWriter, writeInput: AVAssetWriterInput, bufferAdapter:AVAssetWriterInputPixelBufferAdaptor, mediaInputQueue: DispatchQueue, timestamp: CMTime) {
if (writeInput.isReadyForMoreMediaData){
var sampleBuffer:CVPixelBuffer?
autoreleasepool{
sampleBuffer = self.newPixelBufferFrom(cgImage: img.cgImage!, videoSettings: videoSettings)
}
bufferAdapter.append(sampleBuffer!, withPresentationTime: timestamp)
print("Adding frame at \(timestamp)")
}
}
func exportVideo_end( assetWriter: AVAssetWriter, writeInput: AVAssetWriterInput) {
writeInput.markAsFinished()
assetWriter.finishWriting {
DispatchQueue.main.sync {
print("Finished writting")
ImagesToVideoUtils.saveToCameraRoll(videoURL: ImagesToVideoUtils.fileURL)
}
}
}
答案 1 :(得分:0)
- (void)saveVideoPath:(NSString *)videoPath {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
NSURL *url = [NSURL fileURLWithPath:videoPath];
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (success) {
NSLog(@"succ");
}
if (error) {
NSLog(@"%@",error);
}
}];
});
}