【问题标题】:MOV to Mp4 video conversion iPhone programmatically以编程方式将 iPhone MOV 转换为 Mp4 视频
【发布时间】: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 视频。

标签: iphone ios video-processing


【解决方案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 生成。
            猜你喜欢
            • 2023-01-17
            • 1970-01-01
            • 2016-05-19
            • 1970-01-01
            • 2017-09-26
            • 1970-01-01
            • 2010-10-04
            • 2011-12-05
            • 1970-01-01
            相关资源
            最近更新 更多