Skip to content

Instantly share code, notes, and snippets.

@rfistman
Created January 30, 2016 21:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rfistman/93d114959ae83ebabcda to your computer and use it in GitHub Desktop.
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
@blixt
Copy link

blixt commented Nov 21, 2016

@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 like timetstamp > previousTimestamp etc it still fails the moment I use movieFragmentInterval

@blixt
Copy link

blixt commented Nov 21, 2016

(I'm getting error -16341 which I assume is different from -16364 which I would get if my timestamps were not incrementing properly.)

@rfistman
Copy link
Author

It seems to be working fine for me. Do you have a snippet that reproduces the error?

@blixt
Copy link

blixt commented Nov 22, 2016

@blixt
Copy link

blixt commented Nov 23, 2016

@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).

@rfistman
Copy link
Author

Raising the fragment interval seems to help - I'm not getting errors with 3 seconds.

@blixt
Copy link

blixt commented Nov 27, 2016

That does appear to fix the problem! Thank you!

@rfistman
Copy link
Author

rfistman commented Dec 2, 2016

Glad to be of help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment