22

I am developing media server for Play station 3 in iPhone.

I came to know that PS3 doesn't support .MOV file so I have to convert it into Mp4 or something other transcode which PS3 support.

This is what I have done but it crashes if I set different file type than its source files.

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];
    }];
}

If I set AVFileTypeMPEG4 here then it crashes, saying "Invalid file type". So I have to set it to AVFileTypeQuickTimeMovie and it gives MOV file.

Is it possible in iOS to convert video from MOV to Mp4 through AVAssetExportSession...OR without any Thirdparty libraries?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Elegant Microweb
  • 476
  • 2
  • 4
  • 12

7 Answers7

10

presetName use "AVAssetExportPresetPassthrough" instead "AVAssetExportPresetLowQuality"

 AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName:AVAssetExportPresetPassthrough];
hagulu
  • 201
  • 1
  • 8
7

MOV is very similar to MP4, you might be able to just change the extension and have it work, Windows Phone cant play .MOVS but can play mp4, all i did to get that to work is change the extension from .mov to .mp4 and it works fine, and this is from videos shot on the iphone...and if anything you can def try exporting with AVAssetExporter and try there is a file type in there for MP4 and M4A as you can see from the fileformat UTIs here

hope it helps

Daniel
  • 22,363
  • 9
  • 64
  • 71
  • Daniel,, below is what I have done but it crashes if i set different file type than its source files. – Elegant Microweb Dec 13 '11 at 13:10
  • 8
    It does not work everywhere that solution, for example some android devices dont reproduce these videos – Kasas Jan 13 '13 at 17:46
  • Changing the extension may be a hack for PS3, but not a real solution that would apply generically. – Eric Oct 09 '17 at 16:15
  • Even though you change the extension, the file itself is still a .mov.. The differences between mp4 and mov are subtle and will cause problems unexpectedly (such as audio not playing sometimes). MP4 is a container format. It is best to do a proper mp4 generation. – Sudhir Mar 10 '18 at 11:22
6

You can convert video in mp4 by AVAssets.

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;
  }
 }];

To easily convert video to mp4 use this link.

You can also find sample project to convert video to mp4.

Ramiz Wachtler
  • 5,623
  • 2
  • 28
  • 33
CodeCracker
  • 461
  • 5
  • 17
  • Could the output file be a temporary ```NSData``` object rather than the ```outputURL```? I don't understand where I am supposed to save the converted file.... and more to the point I don't want to save it, I just want to upload it to a server, so I don't need ```outputURL```, I just need to output it to an object. – Supertecnoboff Feb 27 '18 at 11:18
5

You need AVMutableComposition to do this. Because Asset can't be transcode to MP4 directly under iOS 5.0.

- (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;
}
Vaibhav Sharma
  • 1,123
  • 10
  • 22
achermao
  • 51
  • 1
  • 2
4

Use the below code

    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];

    }];
Hardik Mamtora
  • 1,642
  • 17
  • 23
4

Here is the code

    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__).")
    }
}
Jigar Thakkar
  • 6,834
  • 2
  • 17
  • 15
3

just wanted to say that the URL can not be like

[NSURL URLWithString: [@"~/Documents/movie.mov" stringByExpandingTildeInPath]]

It must be like

[NSURL fileURLWithPath: [@"~/Documents/movie.mov" stringByExpandingTildeInPath]]

Took me a while to figure that out :-)

rcpfuchs
  • 792
  • 1
  • 12
  • 26