Skip to content

Instantly share code, notes, and snippets.

@christianselig
Created March 22, 2020 04:03
Show Gist options
  • Save christianselig/6f2a341038122032ef60859413cbc993 to your computer and use it in GitHub Desktop.
Save christianselig/6f2a341038122032ef60859413cbc993 to your computer and use it in GitHub Desktop.
#import "ObjCRootViewController.h"
@import AVFoundation;
@import MobileCoreServices;
@import Photos;
@interface ObjCRootViewController ()
@end
@implementation ObjCRootViewController
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self startVideoToGIFProgess];
}
- (void)startVideoToGIFProgess {
NSLog(@"Downloading!");
NSString *urlString = @"https://v.redd.it/naxqsasl2nn41/DASH_720?source=fallback";
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
NSString *fileName = [NSString stringWithFormat:@"%@_%@", [[NSProcessInfo processInfo] globallyUniqueString], @"html5gif.mp4"];
NSURL *fileURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:fileName];
[data writeToURL:fileURL atomically:YES];
NSLog(@"Downloaded!");
[self createGIFFromVideoAtURL:fileURL];
}
- (void)createGIFFromVideoAtURL:(NSURL *)URL {
CFTimeInterval startTime = CACurrentMediaTime();
AVURLAsset *asset = [AVURLAsset assetWithURL:URL];
AVAssetReader *reader = [AVAssetReader assetReaderWithAsset:asset error:nil];
AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey,
[NSNumber numberWithInt:328], kCVPixelBufferWidthKey,
[NSNumber numberWithInt:480], kCVPixelBufferHeightKey,
nil];
AVAssetReaderTrackOutput* readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoTrack outputSettings:outputSettings];
[reader addOutput:readerOutput];
[reader startReading];
CMSampleBufferRef sample = [readerOutput copyNextSampleBuffer];
CGFloat delayBetweenFrames = 0.033333;
NSDictionary *fileProperties = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:0] forKey:(NSString *)kCGImagePropertyGIFLoopCount] forKey:(NSString *)kCGImagePropertyGIFDictionary];
NSDictionary *frameProperties = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:delayBetweenFrames] forKey:(NSString *)kCGImagePropertyGIFDelayTime] forKey:(NSString *)kCGImagePropertyGIFDictionary];
NSString *resultingFilename = [NSString stringWithFormat:@"%@_%@", [[NSProcessInfo processInfo] globallyUniqueString], @"html5gif.gif"];
NSURL *resultingFileURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:resultingFilename];
NSInteger totalFrames = 1086;
CGImageDestinationRef destination = CGImageDestinationCreateWithURL((CFURLRef)resultingFileURL, (CFStringRef)kUTTypeGIF, totalFrames, nil);
CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)fileProperties);
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
operationQueue.maxConcurrentOperationCount = 1;
while (sample) {
if (sample) {
CGImageRef cgImage = [self cgImageFromSampleBuffer:sample];
[operationQueue addOperationWithBlock:^{
CGImageDestinationAddImage(destination, cgImage, (__bridge CFDictionaryRef)frameProperties);
CGImageRelease(cgImage); // Memory never gets out of control
}];
}
CFRelease(sample);
sample = [readerOutput copyNextSampleBuffer];
}
[operationQueue waitUntilAllOperationsAreFinished];
CFTimeInterval endTime = CACurrentMediaTime();
NSLog(@"Total Runtime: %g s", endTime - startTime);
BOOL result = CGImageDestinationFinalize(destination);
NSLog(@"%d did complete", result);
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetCreationRequest creationRequestForAssetFromImageAtFileURL:resultingFileURL];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
NSLog(@"Saved successfully? %d", success);
}];
}
- (CGImageRef)cgImageFromSampleBuffer:(CMSampleBufferRef)buffer {
CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(buffer);
CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
void* baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
size_t width = CVPixelBufferGetWidth(pixelBuffer);
size_t height = CVPixelBufferGetHeight(pixelBuffer);
CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedFirst);
CGImageRef image = CGBitmapContextCreateImage(context);
CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
CGContextRelease(context);
return image;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment