-
-
Save rfistman/93d114959ae83ebabcda to your computer and use it in GitHub Desktop.
#import "AppDelegate.h" | |
#import <AVFoundation/AVFoundation.h> | |
@interface AppDelegate () | |
@property (nonatomic) AVAssetWriter *writer; | |
@property (nonatomic) AVAssetWriterInputPixelBufferAdaptor *adaptor; | |
@property (nonatomic) dispatch_queue_t q; | |
@end | |
@implementation AppDelegate | |
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { | |
NSString *path = @"/Users/gchilds/Desktop/foo.mov"; | |
NSURL *fileUrl = [NSURL fileURLWithPath:path]; | |
[[NSFileManager defaultManager] removeItemAtURL:fileUrl error:nil]; | |
NSError *error; | |
AVAssetWriter *writer = [[AVAssetWriter alloc] initWithURL:fileUrl fileType:AVFileTypeQuickTimeMovie error:&error]; | |
NSDictionary* vidOpts = [NSDictionary dictionaryWithObjectsAndKeys: | |
AVVideoCodecH264, AVVideoCodecKey, // the only supported codec. perfectly natural. | |
[NSNumber numberWithInt:640], AVVideoWidthKey, | |
[NSNumber numberWithInt:480], AVVideoHeightKey, | |
nil]; | |
AVAssetWriterInput *writerInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:vidOpts]; | |
NSDictionary *sourcePixelBufferAttributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys: | |
[NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil]; | |
AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput | |
sourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary]; | |
//writer.movieFragmentInterval = CMTimeMake(5, 1); | |
writer.movieFragmentInterval = CMTimeMakeWithSeconds(10, 1000000000); | |
[writer addInput:writerInput]; | |
if (![writer startWriting]) { | |
NSLog(@"BOO"); | |
} | |
[writer startSessionAtSourceTime:kCMTimeZero]; | |
self.writer = writer; | |
self.adaptor = adaptor; | |
self.q = dispatch_queue_create("blerg", DISPATCH_QUEUE_SERIAL); | |
UIImage *image = [UIImage imageNamed:@"Cosmos09.jpg"]; | |
__block int i = 0; | |
CVPixelBufferRef img = [AppDelegate pixelBufferFromCGImage:image.CGImage]; | |
[writerInput requestMediaDataWhenReadyOnQueue:self.q usingBlock:^{ | |
if (![adaptor appendPixelBuffer:img withPresentationTime:CMTimeMake(i++, 30)]) { | |
NSLog(@"zzz %@", writer.error); | |
} | |
}]; | |
// [adaptor appendPixelBuffer:[AppDelegate pixelBufferFromCGImage:image.CGImage] withPresentationTime:kCMTimeZero]; | |
if (false) { | |
[writer finishWritingWithCompletionHandler:^{ | |
NSLog(@"fini"); | |
}]; | |
} | |
return YES; | |
} | |
+ (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image | |
{ | |
CGSize frameSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image)); | |
NSDictionary *options = @{ | |
(__bridge NSString *)kCVPixelBufferCGImageCompatibilityKey: @(NO), | |
(__bridge NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey: @(NO) | |
}; | |
CVPixelBufferRef pixelBuffer; | |
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameSize.width, | |
frameSize.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, | |
&pixelBuffer); | |
if (status != kCVReturnSuccess) { | |
return NULL; | |
} | |
CVPixelBufferLockBaseAddress(pixelBuffer, 0); | |
void *data = CVPixelBufferGetBaseAddress(pixelBuffer); | |
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); | |
CGContextRef context = CGBitmapContextCreate(data, frameSize.width, frameSize.height, | |
8, CVPixelBufferGetBytesPerRow(pixelBuffer), rgbColorSpace, | |
(CGBitmapInfo) kCGImageAlphaNoneSkipFirst); | |
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), | |
CGImageGetHeight(image)), image); | |
CGColorSpaceRelease(rgbColorSpace); | |
CGContextRelease(context); | |
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); | |
return pixelBuffer; | |
} | |
@end |
(I'm getting error -16341
which I assume is different from -16364
which I would get if my timestamps were not incrementing properly.)
It seems to be working fine for me. Do you have a snippet that reproduces the error?
@rfistman By the way, I came across this from Facebook's codebase that mentions you: https://github.com/facebook/FBSimulatorControl/blob/86087cff4d6dbff4da55d4c489cb281c3e58bd6d/FBSimulatorControl/Framebuffer/FBFramebufferVideo.m#L208-L216
They say that movieFragmentInterval
exacerbates problems in the input, but I'm unable to figure out what the problem is in my case (since I'm already handling the timestamps).
Raising the fragment interval seems to help - I'm not getting errors with 3 seconds.
That does appear to fix the problem! Thank you!
Glad to be of help!
@rfistman I see that you're using
movieFragmentInterval
with pixel buffer adaptor… Did you run into write failures with this configuration? I'm trying to debug this cryptic behavior and even if I have sanity checks liketimetstamp > previousTimestamp
etc it still fails the moment I usemovieFragmentInterval
…