以编程方式将 iPhone MOV 转换为 Mp4 视频
Posted
技术标签:
【中文标题】以编程方式将 iPhone MOV 转换为 Mp4 视频【英文标题】:MOV to Mp4 video conversion iPhone programmatically 【发布时间】:2012-01-18 11:00:45 【问题描述】:我正在为 iPhone 中的 Play Station 3 开发媒体服务器。
我知道 PS3 不支持 .MOV 文件,所以我必须将其转换为 Mp4 或其他 PS3 支持的转码。
这是我所做的,但如果我设置的文件类型与其源文件不同,它会崩溃。
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality])
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName:AVAssetExportPresetLowQuality];
exportSession.outputURL = [NSURL fileURLWithPath:videoPath];
exportSession.outputFileType = AVFileTypeMPEG4;
CMTime start = CMTimeMakeWithSeconds(1.0, 600);
CMTime duration = CMTimeMakeWithSeconds(3.0, 600);
CMTimeRange range = CMTimeRangeMake(start, duration);
exportSession.timeRange = range;
[exportSession exportAsynchronouslyWithCompletionHandler:^
switch ([exportSession status])
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
break;
default:
break;
[exportSession release];
];
如果我在此处设置 AVFileTypeMPEG4,它会崩溃,并显示“文件类型无效”。所以我必须将它设置为 AVFileTypeQuickTimeMovie 并提供 MOV 文件。
是否可以在 ios 中通过 AVAssetExportSession 将视频从 MOV 转换为 Mp4...或者无需任何第三方库?
【问题讨论】:
你有没有为此找到解决方案? 你有这个转换的解决方案吗??? 您无法在 iOS 上读取任何随机的 .mov 编解码器,AVFoundation 只能读取编码为 .mov/.m4v 的 h.264 视频。 【参考方案1】:这里是代码
func encodeVideo(videoURL: NSURL)
let avAsset = AVURLAsset(URL: videoURL, options: nil)
var startDate = NSDate()
//Create Export session
exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetPassthrough)
// exportSession = AVAssetExportSession(asset: composition, presetName: mp4Quality)
//Creating temp path to save the converted video
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let myDocumentPath = NSURL(fileURLWithPath: documentsDirectory).URLByAppendingPathComponent("temp.mp4").absoluteString
let url = NSURL(fileURLWithPath: myDocumentPath)
let documentsDirectory2 = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
let filePath = documentsDirectory2.URLByAppendingPathComponent("rendered-Video.mp4")
deleteFile(filePath)
//Check if the file already exists then remove the previous file
if NSFileManager.defaultManager().fileExistsAtPath(myDocumentPath)
do
try NSFileManager.defaultManager().removeItemAtPath(myDocumentPath)
catch let error
print(error)
url
exportSession!.outputURL = filePath
exportSession!.outputFileType = AVFileTypeMPEG4
exportSession!.shouldOptimizeForNetworkUse = true
var start = CMTimeMakeWithSeconds(0.0, 0)
var range = CMTimeRangeMake(start, avAsset.duration)
exportSession.timeRange = range
exportSession!.exportAsynchronouslyWithCompletionHandler(() -> Void in
switch self.exportSession!.status
case .Failed:
print("%@",self.exportSession?.error)
case .Cancelled:
print("Export canceled")
case .Completed:
//Video conversion finished
var endDate = NSDate()
var time = endDate.timeIntervalSinceDate(startDate)
print(time)
print("Successful!")
print(self.exportSession.outputURL)
default:
break
)
func deleteFile(filePath:NSURL)
guard NSFileManager.defaultManager().fileExistsAtPath(filePath.path!) else
return
do
try NSFileManager.defaultManager().removeItemAtPath(filePath.path!)
catch
fatalError("Unable to delete file: \(error) : \(__FUNCTION__).")
【讨论】:
【参考方案2】:您可以通过 AVAssets 将视频转换为 mp4。
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
NSArray *compatiblePresets = [AVAssetExportSession
exportPresetsCompatibleWithAsset:avAsset];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName:AVAssetExportPresetLowQuality];
NSString* documentsDirectory=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
exportSession.outputURL = url;
//set the output file format if you want to make it in other file format (ex .3gp)
exportSession.outputFileType = AVFileTypeMPEG4;
exportSession.shouldOptimizeForNetworkUse = YES;
[exportSession exportAsynchronouslyWithCompletionHandler:^
switch ([exportSession status])
case AVAssetExportSessionStatusFailed:
NSLog(@"Export session failed");
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
break;
case AVAssetExportSessionStatusCompleted:
//Video conversion finished
NSLog(@"Successful!");
break;
default:
break;
];
要轻松地将视频转换为 mp4,请使用此 link。
您还可以找到将视频转换为 mp4 的示例项目。
【讨论】:
输出文件是否可以是临时的NSData
对象而不是outputURL
?我不明白我应该将转换后的文件保存在哪里......而且我不想保存它,我只想将它上传到服务器,所以我不需要@987654325 @,我只需要将它输出到一个对象。【参考方案3】:
您需要AVMutableComposition
来执行此操作。因为Asset
在iOS 5.0下无法直接转码为MP4。
- (BOOL)encodeVideo:(NSURL *)videoURL
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
// Create the composition and tracks
AVMutableComposition *composition = [AVMutableComposition composition];
AVMutableCompositionTrack *videoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *audioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
NSArray *assetVideoTracks = [asset tracksWithMediaType:AVMediaTypeVideo];
if (assetVideoTracks.count <= 0)
NSLog(@"Error reading the transformed video track");
return NO;
// Insert the tracks in the composition's tracks
AVAssetTrack *assetVideoTrack = [assetVideoTracks firstObject];
[videoTrack insertTimeRange:assetVideoTrack.timeRange ofTrack:assetVideoTrack atTime:CMTimeMake(0, 1) error:nil];
[videoTrack setPreferredTransform:assetVideoTrack.preferredTransform];
AVAssetTrack *assetAudioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
[audioTrack insertTimeRange:assetAudioTrack.timeRange ofTrack:assetAudioTrack atTime:CMTimeMake(0, 1) error:nil];
// Export to mp4
NSString *mp4Quality = [MGPublic isIOSAbove:@"6.0"] ? AVAssetExportPresetMediumQuality : AVAssetExportPresetPassthrough;
NSString *exportPath = [NSString stringWithFormat:@"%@/%@.mp4",
[NSHomeDirectory() stringByAppendingString:@"/tmp"],
[BSCommon uuidString]];
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:composition presetName:mp4Quality];
exportSession.outputURL = exportUrl;
CMTime start = CMTimeMakeWithSeconds(0.0, 0);
CMTimeRange range = CMTimeRangeMake(start, [asset duration]);
exportSession.timeRange = range;
exportSession.outputFileType = AVFileTypeMPEG4;
[exportSession exportAsynchronouslyWithCompletionHandler:^
switch ([exportSession status])
case AVAssetExportSessionStatusCompleted:
NSLog(@"MP4 Successful!");
break;
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
break;
default:
break;
];
return YES;
【讨论】:
【参考方案4】:使用下面的代码
NSURL * mediaURL = [info objectForKey:UIImagePickerControllerMediaURL];
AVAsset *video = [AVAsset assetWithURL:mediaURL];
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPresetMediumQuality];
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeMPEG4;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
basePath = [basePath stringByAppendingPathComponent:@"videos"];
if (![[NSFileManager defaultManager] fileExistsAtPath:basePath])
[[NSFileManager defaultManager] createDirectoryAtPath:basePath withIntermediateDirectories:YES attributes:nil error:nil];
compressedVideoUrl=nil;
compressedVideoUrl = [NSURL fileURLWithPath:basePath];
long CurrentTime = [[NSDate date] timeIntervalSince1970];
NSString *strImageName = [NSString stringWithFormat:@"%ld",CurrentTime];
compressedVideoUrl=[compressedVideoUrl URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.mp4",strImageName]];
exportSession.outputURL = compressedVideoUrl;
[exportSession exportAsynchronouslyWithCompletionHandler:^
NSLog(@"done processing video!");
NSLog(@"%@",compressedVideoUrl);
if(!dataMovie)
dataMovie = [[NSMutableData alloc] init];
dataMovie = [NSData dataWithContentsOfURL:compressedVideoUrl];
];
【讨论】:
【参考方案5】:只是想说网址不能像
[NSURL URLWithString: [@"~/Documents/movie.mov" stringByExpandingTildeInPath]]
应该是这样的
[NSURL fileURLWithPath: [@"~/Documents/movie.mov" stringByExpandingTildeInPath]]
我花了一段时间才弄明白 :-)
【讨论】:
【参考方案6】:presetName 使用“AVAssetExportPresetPassthrough”而不是“AVAssetExportPresetLowQuality”
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName:AVAssetExportPresetPassthrough];
【讨论】:
【参考方案7】:MOV 与 MP4 非常相似,您也许可以只更改扩展名并让它工作,Windows Phone 无法播放 .MOVS 但可以播放 mp4,我所做的只是将扩展名更改为 .mov到.mp4,它工作正常,这是从iphone上拍摄的视频......如果有什么可以定义的尝试使用AVAssetExporter导出并尝试那里有一个MP4和M4A的文件类型,你可以从文件格式中看到尿路感染here
希望对你有帮助
【讨论】:
Daniel,下面是我所做的,但如果我设置的文件类型与其源文件不同,它会崩溃。 该解决方案不适用于所有地方,例如某些 android 设备无法重现这些视频 更改扩展名可能是 PS3 的一个 hack,但不是一个普遍适用的真正解决方案。 即使更改了扩展名,文件本身仍然是.mov.. mp4 和 mov 之间的差异是微妙的,并且会导致意想不到的问题(例如有时无法播放音频)。 MP4 是一种容器格式。最好做一个合适的 mp4 生成。以上是关于以编程方式将 iPhone MOV 转换为 Mp4 视频的主要内容,如果未能解决你的问题,请参考以下文章