1

I've looked and looked for an answer, but can't seem to find one. Lots have asked, but none have gotten answers. I have an app that have two video paths. Now I just want to merge them into one file that can be saved in a ".mov" format. Does anyone have any clue as to how this can be done?

Note : I want to to this without installing and obviously using ffmpeg.

Please if you have time, some code would be very helpful.

Alberto
  • 4,212
  • 5
  • 22
  • 36

1 Answers1

4

First, obviously you need to make sure that the movie type is readable/playable by the quicktime libraries.

But, assuming that's the case, the procedure is basically like this: Get a pointer to some memory to store the data:

QTMovie *myCombinedMovie = [[QTMovie alloc] initToWritableData:[NSMutableData data] error:nil];

Next, grab the first movie that you want to use and insert it into myCombinedMovie You can have the parts you want combined in an array and enumerate over them to combine as many parts as you like. Also, if you wanted, you could alter destination range to add an offset:

QTMovie *firstMovie = [QTMovie movieWithURL:firstURL error:nil];
// NOTE THAT THE 3 LINES BELOW WERE CHANGED FROM MY ORIGINAL POST!
QTTimeRange timeRange = QTMakeTimeRange(QTZeroTime, [firstMovie duration]);
QTTime insertionTime = [myCombinedMovie duration];
[myCombinedMovie insertSegmentOfMovie:firstMovie timeRange:timeRange atTime:insertionTime];

Rinse and repeat for the second movie part.

Then, output the flattened movie (flattening makes it self-contained):

NSDictionary *writeAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], QTMovieFlatten, nil]; //note that you can add a QTMovieExport key with an appropriate value here to export as a specific type
[myCombinedMovie writeToFile:destinationPath withAttributes:writeAttributes];

EDITED: I edited the above as insertion times were calculating wrong. This way seems easier. Below is the code all together as one, including enumerating through an array of movies and lots of error logging.

NSError *err = nil;
QTMovie *myCombinedMovie = [[QTMovie alloc] initToWritableData:[NSMutableData data] error:&err];
if (err)
{
    NSLog(@"Error creating myCombinedMovie: %@", [err localizedDescription]);
    return;
}

NSArray *myMovieURLs = [NSArray arrayWithObjects:[NSURL fileURLWithPath:@"/path/to/the/firstmovie.mov"], [NSURL fileURLWithPath:@"/path/to/the/secondmovie.mov"], nil];

for (NSURL *url in myMovieURLs)
{
    QTMovie *theMovie = [QTMovie movieWithURL:url error:&err];
    if (err){
        NSLog(@"Error loading one of the movies: %@", [err localizedDescription]);
        return;
    }
    QTTimeRange timeRange = QTMakeTimeRange(QTZeroTime, [theMovie duration]);
    QTTime insertionTime = [myCombinedMovie duration]; 
    [myCombinedMovie insertSegmentOfMovie:theMovie timeRange:timeRange atTime:insertionTime];
}

NSDictionary *writeAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], QTMovieFlatten, nil]; 
bool success = [myCombinedMovie writeToFile:@"/path/to/outputmovie.mov" withAttributes:writeAttributes error:&err];
if (!success)
{
    NSLog(@"Error writing movie: %@", [err localizedDescription]);
    return;
}
VsSoft
  • 288
  • 1
  • 11
  • Everything seems to work fine, but.. I have just discovered that the app is not saving the new movie anywhere.. Why ? No errors are reported. And Where do i set the name of the new movie ? – Alberto Feb 05 '12 at 17:38
  • Your screenshot is giving me a 404 error. At any rate, change the last to this: NSError *err = nil; BOOL success = [myCombinedMovie writeToFile:destinationPath withAttributes:writeAttributes error:&err]; if (!success){ NSLog(@"Error writing file - %@", [err localizedDescription]); } – VsSoft Feb 05 '12 at 19:34
  • I tried to get the comment above to come out on new lines but it seems comments have to be a single line. At any rate, in your code that would normally be 3 separate lines, obviously, though it doesn't really matter. When you get the error post back what you find. If you're not getting an error still put a log note just before the if to see if your method/loop handling the save is being called at all. – VsSoft Feb 05 '12 at 19:40
  • Ok i'm starting right now please wait a little time and i will post you back the error. In the meanwhile here is another [SCREENSHOT](http://img190.imageshack.us/img190/433/senzatitoloq.jpg) / [SCREENSHOT - ALTERNATIVE LINK](http://imageshack.us/photo/my-images/190/senzatitoloq.jpg/) – Alberto Feb 06 '12 at 12:59
  • Ok so here we are this is the error.. : Error writing file - You do not have sufficient permissions for this operation. o.o – Alberto Feb 06 '12 at 13:01
  • Your first problem is that you're using URLWithString. You need to use fileURLWithPath instead. – VsSoft Feb 06 '12 at 13:45
  • Hi again. I just edited my original post to use a different method (insertSegmentOfMovie:TimeRange:AtTime:) to add the movie as I screwed something up calculating the insertion time on the earlier version. This one works fine though, I just tried it. If you still get permissions errors then make sure that the output location URL is typed correctly (ie. make sure your user directory is actually at /Users/albo and not /Users/Albo or somesuch). – VsSoft Feb 06 '12 at 14:26
  • Ok the code obviously is perfect.. However i'm still having a permission error even if I'm sure 100% The path is correct : "/Users/albo/Desktop"... Why ? Let me know if you have any idea, in any case thank you for all ! – Alberto Feb 06 '12 at 15:34
  • It sounds like your issue is with that machine - likely a permissions issue. Try running Disk Utility and repairing permissions. If that doesn't work you might have to reboot into boot repair (Lion) or the install disk to repair permissions successfully (see http://osxdaily.com/2011/11/15/repair-user-permissions-in-mac-os-x-lion/ ). If you check out Apple's support forums they have a number of people with the same error message you got when doing save operations in QuickTime Pro, which obviously uses the same framework. To be continued... – VsSoft Feb 06 '12 at 17:34
  • As well, change your assignment for your path to desktop so that instead of manually writing /Users/albo/Desktop you use:::: NSString *outputPath= [[NSSearchPathForDirectoriesInDomains( NSDesktopDirectory, NSUserDomainMask, NO )] objectAtIndex:0]; ::::: This eliminates any spelling issues. – VsSoft Feb 06 '12 at 17:34
  • Ok thank you for all your help. Last question only, where do I set the name of the new movie that will be created ? Shouldn't be a save panel ? – Alberto Feb 06 '12 at 18:03
  • Wooow problem solved like this ! :::::::::::::::::::NSSavePanel *savePanel = [NSSavePanel savePanel]; if ([savePanel runModal]) { NSURL *saveURL = savePanel.URL; NSString *savePath = [saveURL path]; NSLog(savePath); bool success = [myCombinedMovie writeToFile:savePath withAttributes:writeAttributes error:&err]; if (!success) { NSLog(@"Error writing movie: %@", [err localizedDescription]); return; } } ::::::::::: XD THANK YOU – Alberto Feb 06 '12 at 18:36
  • Hey VsSoft could you help me with [**this**](http://stackoverflow.com/questions/9213088/qtkit-merge-two-videos-with-different-width-and-height) (http://stackoverflow.com/questions/9213088/qtkit-merge-two-videos-with-different-width-and-height)? – Alberto Feb 09 '12 at 15:22