I'm finishing an iPhone app that saves a movie to the photos album. The movie source is an array of images. I have it making movies and it's putting them in the photos album quite nicely, but it always has an extra green frame at the start.
Any ideas?
I've re-read the docs at Apple, jiggled the wires and did some tests with numbered images to confirm it's not dropping a frame or something like that. still not getting it the right way round.
//build save path with time
NSMutableString *buildPath = [[NSMutableString alloc] init];
[buildPath setString:@"Documents/"];
[buildPath appendString:@"temporary.mp4"];
NSString *fullPath = [NSHomeDirectory() stringByAppendingPathComponent:buildPath];
[buildPath release];
//if the file already exists, deleate it
NSFileManager *fileMgr = [NSFileManager defaultManager];
if([fileMgr fileExistsAtPath:fullPath]){
if([fileMgr removeItemAtPath:fullPath error:&error] != YES){
//error
}
}
//prepare to write the movie
AVAssetWriter *videoWriter =
[[AVAssetWriter alloc] initWithURL
:[NSURL fileURLWithPath:fullPath]
fileType:AVFileTypeMPEG4
error:&error];
NSParameterAssert(videoWriter);
NSDictionary *videoSettings =
[NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264,AVVideoCodecKey,
[NSNumber numberWithInt:width],AVVideoWidthKey,
[NSNumber numberWithInt:height],AVVideoHeightKey,
nil];
AVAssetWriterInput* writerInput =
[[AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:videoSettings]
retain];
AVAssetWriterInputPixelBufferAdaptor *adaptor =
[AVAssetWriterInputPixelBufferAdaptor
assetWriterInputPixelBufferAdaptorWithAssetWriterInput
:writerInput sourcePixelBufferAttributes
:nil];
NSParameterAssert(writerInput);
NSParameterAssert([videoWriter canAddInput:writerInput]);
[videoWriter addInput:writerInput];
//start writing
[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:kCMTimeZero];
CVPixelBufferRef buffer = NULL;
buffer = [self pixelBufferFromCGImage
:[[imageArray objectAtIndex:0] CGImage]
:CGSizeMake(width,height)];
CVPixelBufferPoolCreatePixelBuffer(NULL,adaptor.pixelBufferPool,&buffer);
[adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];
//loop through image array
int y = [imageArray count];
int x = 0;
while(x < y)
{
if(writerInput.readyForMoreMediaData == YES){
CMTime frameTime = CMTimeMake(1,24);
CMTime lastTime = CMTimeMake(x,24);
CMTime presentTime = CMTimeAdd(lastTime,frameTime);
buffer = [self pixelBufferFromCGImage
:[[imageArray objectAtIndex:x] CGImage]
:CGSizeMake(width,height)];
[adaptor appendPixelBuffer:buffer
withPresentationTime:presentTime];
x++;
}
}
//finish writing
[writerInput markAsFinished];
[videoWriter finishWriting];
//clean up
CVPixelBufferPoolRelease(adaptor.pixelBufferPool);
[videoWriter release];
[writerInput release];
//handle after save, save is asynchronous
void(^completionBlock)(NSURL *, NSError *) =
^(NSURL *assetURL, NSError *error)
{
if(error != nil){
//error
}
//remove temp movie file
if([fileMgr removeItemAtPath:fullPath error:&error] != YES){
//error
}
};
//write the movie to photo album
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
NSURL *filePathURL = [NSURL fileURLWithPath:fullPath isDirectory:NO];
if([library videoAtPathIsCompatibleWithSavedPhotosAlbum:filePathURL]){
[library
writeVideoAtPathToSavedPhotosAlbum:filePathURL
completionBlock:completionBlock];
}
//clean up
[library release];
Your first PTS should be 0/24s and not 1/24s
Oops, sorry my mistake, your first PTS is zero - I didn't notice that CVPixelBufferPoolCreatePixelBuffer
and appendPixelBuffer:withPresentationTime:
, so I've changed my answer.
That very first pixel buffer that you append has nothing to do with your array of images. Is it undefined? I guess it's green. I'm not sure what you're doing with the pixel buffer pool - deleting those two lines and rebasing your loop at zero should get rid of the green frame.