Iphone 如何使用AVFoundation修剪视频
我可以使用AVFoundation或UIImagePickerController录制视频。但我无法将视频从一秒剪辑到另一秒。有人能帮我吗 谢谢,Iphone 如何使用AVFoundation修剪视频,iphone,video,Iphone,Video,我可以使用AVFoundation或UIImagePickerController录制视频。但我无法将视频从一秒剪辑到另一秒。有人能帮我吗 谢谢, 湿婆奎师那。您可以让UIImagePickerController启用修剪 UIImagePickerController *videoRecorder = [[UIImagePickerController alloc]init]; NSArray *sourceTypes = [UIImagePickerCont
湿婆奎师那。您可以让UIImagePickerController启用修剪
UIImagePickerController *videoRecorder = [[UIImagePickerController alloc]init];
NSArray *sourceTypes = [UIImagePickerController availableMediaTypesForSourceType:videoRecorder.sourceType];
NSLog(@"Available types for source as camera = %@", sourceTypes);
if (![sourceTypes containsObject:(NSString*)kUTTypeMovie] ) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:@"Device Not Supported for video Recording." delegate:self
cancelButtonTitle:@"Yes"
otherButtonTitles:@"No",nil];
[alert show];
[alert release];
return;
}
videoRecorder.allowsEditing = YES;
不幸的是,从imagePickerController返回后,您不得不手动转换视频
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
if ([self.popoverLibraryBrowser isPopoverVisible])
{
[self.popoverLibraryBrowser dismissPopoverAnimated:YES];
}
NSString *type = [info objectForKey:UIImagePickerControllerMediaType];
if ([type isEqualToString:(NSString *)kUTTypeVideo] ||
[type isEqualToString:(NSString *)kUTTypeMovie]) { // movie != video
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSNumber *start = [info objectForKey:@"_UIImagePickerControllerVideoEditingStart"];
NSNumber *end = [info objectForKey:@"_UIImagePickerControllerVideoEditingEnd"];
// if start and end are nil then clipping was not used.
// You should use the entire video.
int startMilliseconds = ([start doubleValue] * 1000);
int endMilliseconds = ([end doubleValue] * 1000);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *manager = [NSFileManager defaultManager];
NSString *outputURL = [documentsDirectory stringByAppendingPathComponent:@"output"] ;
[manager createDirectoryAtPath:outputURL withIntermediateDirectories:YES attributes:nil error:nil];
outputURL = [outputURL stringByAppendingPathComponent:@"output.mp4"];
// Remove Existing File
[manager removeItemAtPath:outputURL error:nil];
//[self loadAssetFromFile:videoURL];
[self.recorder dismissModalViewControllerAnimated:YES];
AVURLAsset *videoAsset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:videoAsset presetName:AVAssetExportPresetHighestQuality];
exportSession.outputURL = [NSURL fileURLWithPath:outputURL];
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTimeRange timeRange = CMTimeRangeMake(CMTimeMake(startMilliseconds, 1000), CMTimeMake(endMilliseconds - startMilliseconds, 1000));
exportSession.timeRange = timeRange;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch (exportSession.status) {
case AVAssetExportSessionStatusCompleted:
// Custom method to import the Exported Video
[self loadAssetFromFile:exportSession.outputURL];
break;
case AVAssetExportSessionStatusFailed:
//
NSLog(@"Failed:%@",exportSession.error);
break;
case AVAssetExportSessionStatusCancelled:
//
NSLog(@"Canceled:%@",exportSession.error);
break;
default:
break;
}
}];
//NSData *videoData = [NSData dataWithContentsOfURL:videoURL];
//NSString *videoStoragePath;//Set your video storage path to this variable
//[videoData writeToFile:videoStoragePath atomically:YES];
//You can store the path of the saved video file in sqlite/coredata here.
}
}
您应该在setMediaTypes数组中添加kUTTypeMovie,它将起作用。以上的Swift版本
import UIKit
import AVFoundation
import MobileCoreServices
func pickVideo(){
if UIImagePickerController.isSourceTypeAvailable(.Camera) {
let videoRecorder = UIImagePickerController()
videoRecorder.sourceType = .Camera
videoRecorder.mediaTypes = [kUTTypeMovie as String]
videoRecorder.allowsEditing = true
videoRecorder.delegate = self
presentViewController(videoRecorder, animated: true, completion: nil)
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
picker.dismissViewControllerAnimated(true, completion: nil)
let manager = NSFileManager.defaultManager()
guard let documentDirectory = try? manager.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true) else {return}
guard let mediaType = info[UIImagePickerControllerMediaType] as? String else {return}
guard let url = info[UIImagePickerControllerMediaURL] as? NSURL else {return}
if mediaType == kUTTypeMovie as String || mediaType == kUTTypeVideo as String {
let asset = AVAsset(URL: url)
let length = Float(asset.duration.value) / Float(asset.duration.timescale)
print("video length: \(length) seconds")
let start = info["_UIImagePickerControllerVideoEditingStart"] as? Float
let end = info["_UIImagePickerControllerVideoEditingEnd"] as? Float
var outputURL = documentDirectory.URLByAppendingPathComponent("output")
do {
try manager.createDirectoryAtURL(outputURL, withIntermediateDirectories: true, attributes: nil)
outputURL = outputURL.URLByAppendingPathComponent("output.mp4")
}catch let error {
print(error)
}
//Remove existing file
_ = try? manager.removeItemAtURL(outputURL)
guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) else {return}
exportSession.outputURL = outputURL
exportSession.outputFileType = AVFileTypeMPEG4
let startTime = CMTime(seconds: Double(start ?? 0), preferredTimescale: 1000)
let endTime = CMTime(seconds: Double(end ?? length), preferredTimescale: 1000)
let timeRange = CMTimeRange(start: startTime, end: endTime)
exportSession.timeRange = timeRange
exportSession.exportAsynchronouslyWithCompletionHandler{
switch exportSession.status {
case .Completed:
print("exported at \(outputURL)")
case .Failed:
print("failed \(exportSession.error)")
case .Cancelled:
print("cancelled \(exportSession.error)")
default: break
}
}
}
}
我找到了swift 4的最佳解决方案。我确实根据自己的需要修复了它,但它非常清晰和方便 守则:
import-AVFoundation
进口基金会
扩展文件管理器{
func removefileifneeded(在url:url处)引发{
保护文件存在(atPath:url.path)或其他{
返回
}
做{
尝试删除项目(位于:url)
}
捕捉错误{
抛出TrimError(“无法删除现有目标文件:\(错误)”)
}
}
}
结构TrimError:错误{
let description:字符串
让我们看看错误:错误?
初始化(uu说明:字符串,underyingError:错误?=nil){
self.description=“TrimVideo:+说明
self.underyingerror=underyingerror
}
}
扩展可变合成{
便利初始化(资产:AVAsset){
self.init()
对于asset.tracks中的track{
addMutableTrack(withMediaType:track.mediaType,preferredTrackID:track.trackID)
}
}
func微调(timeOffStart:Double){
let duration=CMTime(秒:timeOffStart,首选时间刻度:1)
let timeRange=CMTimeRange(开始:kCMTimeZero,持续时间:持续时间)
轨道中的轨道{
track.removeTimeRange(时间范围)
}
removeTimeRange(时间范围)
}
}
扩展AVAsset{
func assetByTrimming(timeOffStart:Double)抛出->AVAsset{
let duration=CMTime(秒:timeOffStart,首选时间刻度:1)
let timeRange=CMTimeRange(开始:kCMTimeZero,持续时间:持续时间)
let composition=AVMutableComposition()
做{
轨道中的轨道{
让compositionTrack=composition.addMutableTrack(withMediaType:track.mediaType,preferredTrackID:track.trackID)
尝试compositionTrack?.insertTimeRange(时间范围,of:track,at:kCMTimeZero)
}
}捕捉错误{
抛出TrimError(“合成过程中的错误”,参考错误:错误)
}
返回组合
}
func导出(到目标:URL)抛出{
guard let exportSession=AVAssetExportSession(资产:self,预设名称:AVAssetExportPresetPassthrough)else{
抛出错误(“无法创建导出会话”)
}
exportSession.outputURL=目的地
exportSession.outputFileType=AVFileType.m4v
exportSession.shouldOptimizationForNetworkUse=true
let group=DispatchGroup()
group.enter()
请尝试FileManager.default.RemoveFileIf必要时(在:目标)
exportSession.exportAsynchronously{
小组请假()
}
组。等待()
如果let error=exportSession.error{
抛出TrimError(“导出期间出错”,参考错误:错误)
}
}
}
函数时间(u操作:()抛出->())重试{
让我们开始=日期()
尝试操作()
让end=Date().timeIntervalSince(开始)
列印(完)
让sourceURL=URL(fileURLWithPath:CommandLine.arguments[1])
让destinationURL=URL(fileURLWithPath:CommandLine.arguments[2])
做{
试一试{
let asset=avurlaste(url:sourceURL)
让trimmedAsset=try asset.assetByTrimming(timeOffStart:1.0)
尝试trimmedAsset.export(到:destinationURL)
}
}捕捉错误{
print(“在查找用于修剪现有视频的内容时发现此问题。修剪捕获的视频相对简单。但是,让修剪窗口显示出来似乎让我难以理解。我希望下面的答案能有所帮助。感谢您提供的源代码。当我使用“*sourceTypes”作为“UIImagePickerController源类型摄影机”时,我得到了”*开始和结束时间。但当我使用“*sourceTypes”作为“UIImagePickerControllerSourceTypeSavedPhotosAlbum”时,我没有获得“开始和结束”时间。问题是什么?我如何获得“开始和结束”时间?你给了他们“剪辑”的能力吗"视频?填充编辑开始和结束的部分是剪辑。如果不剪辑视频,则这些值保留为零,这意味着应跳过剪辑并使用整个视频。请参阅此处的日志。我允许用户从缩略图中选择帧。如果我编辑,则没有问题“摄像机录制的视频”和问题发生在我尝试从相册中加载的视频中选择帧时。@karthi使用UIImagePickerControllerSourceTypeSavedPhotosAlbum
时,您从[info objectForKey:UIImagePickerControllerDiaUrl]获得的url;
引用了一个修剪过的视频文件,因此不需要开始和结束时间。我知道这一点,因为我从[info objectForKey:uiimagepickercontrollermediaaurl]获取url的持续时间;
并将其与原始视频持续时间进行比较。不应检查电影或视频,而应检查类型是否符合电影:uttypeconformisto((uu-bridge CFStringRef)mediaType,kuttypeMoine)!=0
。电影和视频也是如此。对于某些视频,此解决方案失败。有什么建议吗?作为程序员,您应该知道“失败”这不是描述错误/问题的合适方式。云视频失败了,我调试并解决了。我告诉失败了,因为我无法得到一个场景,所以想问你,如果你遇到任何像这样奇怪的问题。无论如何,我已经解决了这个问题。下次请和任何人好好谈谈