heTranscodeOperation ()
@property (assign, nonatomic) BOOL executing;//判断NSOperation是否执行
@property (assign, nonatomic) BOOL finished;//判断NSOperation是否结束
@property (nonatomic,copy)NSString *diskCachePath;//
@property (nonatomic,copy)NSString *fileName;//沙盒文件名称
@property (nonatomic, copy) DownloaderCancelBlock completedBlock; //下载完成回调block
@end
@implementation HGVideoCacheTranscodeOperation
@synthesize executing = _executing;
@synthesize finished = _finished;
-
(instancetype)initWithPath:(NSString *)diskCachePath fileName:(NSString *)fileName completedBlock:(DownloaderCancelBlock)completedBlock{
self = [super init];
if (self) {
_diskCachePath = [diskCachePath copy];
_fileName = [fileName copy];
_completedBlock = [completedBlock copy];
}
return self;
} -
(void)start {
[self willChangeValueForKey:@"isExecuting"];
_executing = YES;
[self didChangeValueForKey:@"isExecuting"];//判断任务执行前是否取消了任务
if (self.isCancelled) {
[self done];
return;
}
[self videoTranscodingWithPath:self.diskCachePath fileName:self.fileName completedBlock:self.completedBlock];
}
-(BOOL)isExecuting {
return _executing;
}
-
(BOOL)isFinished {
return _finished;
} -
(BOOL)isAsynchronous {
return YES;
}
//取消任务
-(void)cancel {
@synchronized (self) {
[self done];
}
}
//更新任务状态
- (void)done {
[super cancel];
if(_executing) {
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
_finished = YES;
_executing = NO;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];
[self reset];
}
}
//重置请求数据
- (void)reset {
if (self.completedBlock) {
self.completedBlock = nil;
}
}
pragma mark - 视频转gif -
-(void)videoTranscodingWithPath:(NSString *)diskCachePath fileName:(NSString *)fileName completedBlock:(DownloaderCancelBlock)completedBlock{
NSString *videoPath = [[diskCachePath stringByAppendingPathComponent:fileName] stringByAppendingString:KVideoSuffix];
NSURL *videoURL = [NSURL fileURLWithPath:videoPath];
NSLog(@"存在文件:\n%@",videoURL);
AVURLAsset *asset = [AVURLAsset assetWithURL:videoURL];
AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
generator.appliesPreferredTrackTransform = YES;
generator.requestedTimeToleranceBefore = kCMTimeZero;
generator.requestedTimeToleranceAfter = kCMTimeZero;
//视频宽高
AVAssetTrack *videoTrack = [asset tracksWithMediaType:AVMediaTypeVideo].firstObject;
CGSize videoSize = CGSizeApplyAffineTransform(videoTrack.naturalSize, videoTrack.preferredTransform);
videoSize = CGSizeMake(fabs(videoSize.width), fabs(videoSize.height));
generator.maximumSize = videoSize;
NSArray *indexes = [self generateOffsets:asset];
NSLog(@"%li",(unsigned long)[indexes count]);
NSMutableDictionary *images = [NSMutableDictionary dictionaryWithCapacity:[indexes count]];
CMTime actualTime;
for (NSNumber *number in indexes) {
if (self.isCancelled) {
[self done];
return;
}
double offset = [number doubleValue];
NSLog(@"%f",offset);
if (offset < 0 || offset > CMTimeGetSeconds(asset.duration)) {
continue;
}
CMTime t = CMTimeMakeWithSeconds(offset, (int)[indexes count]);
NSError *error = nil;
CGImageRef source = [generator copyCGImageAtTime:t actualTime:nil error:&error];
if (!source) {
NSLog(@"Error copying image at index %f: %@", CMTimeGetSeconds(actualTime), [error localizedDescription]);
return;
}
[images setObject:CFBridgingRelease(source) forKey:number];
}
if (self.isCancelled) {
[self done];
return;
}
NSMutableArray *strip =[NSMutableArray array];
if (images) {
NSArray *times = [self generateOffsets:asset];
for (int idx = 0; idx < [times count]; idx++) {
NSNumber *time = [times objectAtIndex:idx];
CGImageRef image = (__bridge CGImageRef)([images objectForKey:time]);
[strip addObject:[UIImage imageWithCGImage:image]];
NSLog(@"%d",idx);
}
//转码
@weakify(self)
[self writeImageAsGIF:strip toPath:videoPath callbackBlock:^{
@strongify(self)
self.completedBlock();
[self done];
}];
}
}
//时间个数
- (NSArray *) generateOffsets:(AVAsset *)asset{
double duration = CMTimeGetSeconds(asset.duration);
NSMutableArray *indexes = [NSMutableArray array];
double time = 0.0f;
while (time < duration) {
[indexes addObject:[NSNumber numberWithDouble:time]];
time +=0.1;
}
return indexes;
}
///绘制gif
-(void)writeImageAsGIF:(NSArray )images
toPath:(NSString)path
callbackBlock:(dispatch_block_t)callbackBlock {
if ([ [NSFileManager defaultManager] fileExistsAtPath:path]){
[[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
}
path = [path stringByReplacingOccurrencesOfString:KVideoSuffix withString:KGifSuffix];
CGFloat secondsPerFrameFloat = 1 / 30;
NSNumber * secondsPerFrame = [NSNumber numberWithFloat:secondsPerFrameFloat];//30帧
NSDictionary * gifDict = [NSDictionary dictionaryWithObject:secondsPerFrame
forKey:( NSString *)kCGImagePropertyGIFDelayTime] ;
NSDictionary *prep = [NSDictionary dictionaryWithObject:gifDict
forKey:(NSString *)kCGImagePropertyGIFDictionary];
NSDictionary *fileProperties = @{
(__bridge id)kCGImagePropertyGIFDictionary: @{
(__bridge id)kCGImagePropertyGIFLoopCount: @0, // 0 means loop forever
}
};
CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:path];
CGImageDestinationRef dst = CGImageDestinationCreateWithURL(url, kUTTypeGIF, [images count], nil);
CGImageDestinationSetProperties(dst, (__bridge CFDictionaryRef)fileProperties);
for (int i=0;i<[images count];i++){
UIImage * anImage = [images objectAtIndex:i];
CGImageDestinationAddImage(dst, anImage.CGImage,(__bridge CFDictionaryRef)(prep));
}
bool fileSave = CGImageDestinationFinalize(dst);
CFRelease(dst);
if(fileSave) {
NSLog(@"animated GIF file created at %@", path);
if ([ [NSFileManager defaultManager] fileExistsAtPath:path]){
CGFloat gif = [[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil] fileSize];
NSLog(@" hehe%lf",gif);
}
}else{
NSLog(@"error: no animated GIF file created at %@", path);
}
!callbackBlock?:callbackBlock();
}
@end
网友评论