Re: Merge 2 QTTracks in a QTMovie
Re: Merge 2 QTTracks in a QTMovie
- Subject: Re: Merge 2 QTTracks in a QTMovie
- From: Alex Bumbu <email@hidden>
- Date: Fri, 22 May 2009 15:08:03 +0300
Below is the code I'm using in this test application. I'm loading 2
mp4 movies (h.264 AAC) in the first action, getting an array of merged
frames from the 2 movies and add them to the mixed video (method 3), get
the sound qttracks from the 2 movies, change the layer number of the
second and add them to the mix movie. Please if you have any idea on
how I can make this work tell me. Thank you!
//loading the 2 movies
- (IBAction)btnPressed:(id)sender
{
NSError *aError = nil;
OSStatus theError = noErr;
Boolean active = TRUE;
Movie channelMovie1, channelMovie2;
NSString *video1Path = [NSString stringWithFormat: @"%@%@",
NSHomeDirectory(), @"/Desktop/mv/video1.mp4"];
NSString *video2Path = [NSString stringWithFormat: @"%@%@",
NSHomeDirectory(), @"/Desktop/mv/video2.mp4"];
QTNewMoviePropertyElement newMovieProperties[] = {
{kQTPropertyClass_DataLocation,
kQTDataLocationPropertyID_CFStringNativePath, sizeof(video1Path),
&video1Path, 0},
{kQTPropertyClass_NewMovieProperty,
kQTNewMoviePropertyID_Active, sizeof(active), &active, 0} };
theError = NewMovieFromProperties(sizeof(newMovieProperties) /
sizeof(newMovieProperties[0]), newMovieProperties, 0, nil, &channelMovie1);
if(theError) {
NSLog(@"NewMovie1FromProperties failed with %d", theError);
[self dealloc];
return nil;
}
else {
movie1 = [QTMovie movieWithQuickTimeMovie: channelMovie1
disposeWhenDone: NO error: aError];
[movie1 setAttribute: [NSNumber numberWithBool:YES]
forKey:QTMovieEditableAttribute];
if (aError == nil)
[movieView1 setMovie: movie1];
else
NSLog(@"Error 1: %@", [aError localizedDescription]);
}
QTNewMoviePropertyElement newMovieProperties2[] = {
{kQTPropertyClass_DataLocation,
kQTDataLocationPropertyID_CFStringNativePath, sizeof(video2Path),
&video2Path, 0},
{kQTPropertyClass_NewMovieProperty,
kQTNewMoviePropertyID_Active, sizeof(active), &active, 0} };
theError = NewMovieFromProperties(sizeof(newMovieProperties2) /
sizeof(newMovieProperties2[0]), newMovieProperties2, 0, nil,
&channelMovie2);
if(theError) {
NSLog(@"NewMovie2FromProperties failed with %d", theError);
[self dealloc];
return nil;
}
else {
movie2 = [QTMovie movieWithQuickTimeMovie: channelMovie2
disposeWhenDone: NO error: aError];
if (aError == nil)
[movieView2 setMovie: movie2];
else
NSLog(@"Error 2: %@", [aError localizedDescription]);
}
}
//creating the mixed video
- (IBAction)mixBtnPressed:(id)sender
{
frames = [[NSMutableArray alloc] init];
frame = 0;
for (float i = 0; i < 70; i+=0.5) {
NSImage *mixedFrame = [movie1 frameImageAtTime:
QTMakeTimeWithTimeInterval(i)];
NSImage *image2 = [movie2 frameImageAtTime:
QTMakeTimeWithTimeInterval(i)];
[image2 setSize: NSMakeSize(200, 100)];
[mixedFrame lockFocus];
[image2 compositeToPoint: NSMakePoint(100, 150)
operation: NSCompositeSourceOver];
[mixedFrame unlockFocus];
[frames addObject: mixedFrame];
}
QTMovie *mMovie;
DataHandler mDataHandlerRef;
// Check first if the new QuickTime 7.2.1 initToWritableFile: method
is available
if ([[[[QTMovie alloc] init] autorelease] respondsToSelector:
@selector(initToWritableFile:error:)] == YES)
{
// generate a name for our movie file
NSString *tempName = [NSString stringWithCString: tmpnam(nil)
encoding: [NSString
defaultCStringEncoding]];
if (nil == tempName) goto bail;
// Create a QTMovie with a writable data reference
mMovie = [[QTMovie alloc] initToWritableFile:tempName error:NULL];
}
else
{
// The QuickTime 7.2.1 initToWritableFile: method is not
available, so use the native
// QuickTime API CreateMovieStorage() to create a QuickTime
movie with a writable
// data reference
OSErr err;
// create a native QuickTime movie
Movie qtMovie = [self quicktimeMovieFromTempFile:
&mDataHandlerRef error: &err];
if (nil == qtMovie) goto bail;
// instantiate a QTMovie from our native QuickTime movie
mMovie = [QTMovie movieWithQuickTimeMovie: qtMovie
disposeWhenDone: YES error: nil];
if (!mMovie || err) goto bail;
}
// mark the movie as editable
[mMovie setAttribute: [NSNumber numberWithBool:YES]
forKey:QTMovieEditableAttribute];
// keep it around until we are done with it...
[mMovie retain];
// add all the images to our movie as MPEG-4 frames
[mMovie addImagesAsMPEG4: frames];
//add sounds
NSArray *audioTracks1 = [movie1 tracksOfMediaType: QTMediaTypeSound];
NSArray *audioTracks2 = [movie2 tracksOfMediaType: QTMediaTypeSound];
QTTrack *audioTrack1 = nil;
QTTrack *audioTrack2 = nil;
if( [audioTracks1 count] > 0 )
{
audioTrack1 = [audioTracks1 objectAtIndex:0];
}
if( [audioTracks2 count] > 0 )
{
audioTrack2 = [audioTracks2 objectAtIndex:0];
}
if( audioTrack1 && audioTrack2 )
{
QTTimeRange totalRange;
totalRange.time = QTZeroTime;
totalRange.duration = [[movie1 attributeForKey:
QTMovieDurationAttribute] QTTimeValue];
[audioTrack2 setAttribute: [NSNumber numberWithShort: 1000]
forKey: QTTrackLayerAttribute];
//[mMovie insertSegmentOfTrack: audioTrack1 timeRange:
totalRange atTime: QTZeroTime];
//[mMovie insertSegmentOfTrack: audioTrack2 timeRange:
totalRange atTime: QTZeroTime];
[mMovie insertSegmentOfTrack: audioTrack1
fromRange: QTMakeTimeRange(QTZeroTime,
[movie1 duration])
scaledToRange: QTMakeTimeRange(QTZeroTime,
[movie1 duration])];
[mMovie insertSegmentOfTrack: audioTrack2
fromRange: QTMakeTimeRange(QTZeroTime,
[movie1 duration])
scaledToRange: QTMakeTimeRange(QTZeroTime,
[movie1 duration])];
}
//[mMovie setAttribute: [NSNumber numberWithBool: YES] forKey:
@"QTMovieHasAudioAttribute"];
//[mMovie setAttribute: [NSNumber numberWithBool: YES] forKey:
@"QTMoviePlaysAllFramesAttribute"];
//[mMovie setAttribute: [NSNumber numberWithBool: YES] forKey:
@"QTMovieIsInteractiveAttribute"];
[movieView3 setMovie: mMovie];
bail:
return;
}
//add images from array to our movie
- (void)addImagesAsMPEG4:(NSArray *)imageFilesArray
{
if (!imageFilesArray)
goto bail;
// when adding images we must provide a dictionary
// specifying the codec attributes
NSDictionary *myDict = nil;
myDict = [NSDictionary dictionaryWithObjectsAndKeys:@"mp4v",
QTAddImageCodecType,
[NSNumber
numberWithLong:codecHighQuality],
QTAddImageCodecQuality,
nil];
if (!myDict)
goto bail;
// create a QTTime value to be used as a duration when adding
// the image to the movie
long long timeValue = 30;
long timeScale = 600;
QTTime duration = QTMakeTime(timeValue, timeScale);
// iterate over all the images in the array and add
// them to our movie one-by-one
int i;
for (i = 0; i < [imageFilesArray count]; ++i)
{
//NSURL *fileUrl = [NSURL fileURLWithPath:[imageFilesArray
objectAtIndex:i]];
//NSImage *anImage = [[NSImage alloc]
initWithContentsOfURL:fileUrl];
NSImage *anImage = [imageFilesArray objectAtIndex: i];
if (anImage)
{
// Adds an image for the specified duration to the QTMovie
[self addImage:anImage
forDuration:duration
withAttributes:myDict];
// free up our image object
[anImage release];
}
}
bail:
return;
}
douglas welton wrote:
Yes. It'd possible. How are you creating your tracks? Can you show
us a little code to see what you've tried already?
On May 21, 2009, at 8:44 AM, Alex Bumbu wrote:
Hi all,
I'm trying to add 2 sounds tracks in a QTMovie so they play at the
same time. I've tried adding both sound tracks with the layer
property changed to the qtmovie but the tracks are played one after
another. Is this possible? And if is possible any help is really
appreciated.
Thanks in advance,
Alex
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden