效果gif
均为网络图片,如有侵权问题联系我删除。感谢图片模特们对技术的支持与奉献❤️❤️❤️❤️❤️
图片转视频.gif苹果.jpg这里传入的是 PHAsset *expAsset
然后我处理,获取到image 数组
通过图片数组 来搞
用到XPFFile了
使用
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:[ViewTool topViewController].view animated:YES];
// Set the label text.
//self.hud.label.text = @"转码中...";//NSLocalizedString(@"Loading...", @"HUD loading title");
WeakSelf;
TXWXEditImageArys *imageAry = [[TXWXEditImageArys alloc] init];
[imageAry onHandlePHAssetArys:assets url:^(NSURL * _Nonnull outurl) {
dispatch_async(dispatch_get_main_queue(), ^{
[hud hideAnimated:YES];
AVAsset *movieAsset = [AVURLAsset URLAssetWithURL:outurl options:nil];
XPFLog(@" =movieAsset=> %@", movieAsset);
TXWXEditRecordVC *vc = [[TXWXEditRecordVC alloc] init];
//vc.renderRotation = _renderRotation;
vc.videoAsset = movieAsset;
//vc.videoPath = self.recordVideoPath;
vc.editType = RecordEditType_Video;
[weakSelf pushViewController:vc];
[vc setOnback:^(BOOL value) {
[weakSelf.navigationController dismissViewControllerAnimated:YES completion:nil];
}];
});
} vc:[ViewTool topViewController]];
bug.gif
模型1
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef void(^editimageArys) (NSURL *outurl);
@interface TXWXEditImageArys : NSObject
- (void)onHandlePHAssetArys:(NSArray *)assets url:(editimageArys)url vc:(UIViewController *)vc;
@end
NS_ASSUME_NONNULL_END
//
#import "TXWXEditImageArys.h"
#import "XPicToVideo.h"
@interface TXWXEditImageArys ()
@property (nonatomic, strong) NSMutableArray *imagesToEdit;
@property (nonatomic, assign) NSInteger indexs;
@property (nonatomic, copy) editimageArys blockbackurl;
@end
@implementation TXWXEditImageArys
// MARK: ----- 对外
- (void)onHandlePHAssetArys:(NSArray *)assets url:(editimageArys)url vc:(UIViewController *)vc
{
self.blockbackurl = url;
self.imagesToEdit = [[NSMutableArray array] init];
self.indexs = 0;
[self addEditImageArysindex:self.indexs PHAssetArys:assets vc:vc];
}
- (void)addEditImageArysindex:(NSInteger)index PHAssetArys:(NSArray *)assets vc:(UIViewController *)vcontroller;
{
if (assets.count == self.indexs)
{
[XPicToVideo compressImages:self.imagesToEdit completion:^(NSURL * _Nonnull outurl) {
if (self.blockbackurl) {
self.blockbackurl(outurl);
}
}];
return;
}
PHAsset *expAsset = assets[self.indexs];
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.version = PHImageRequestOptionsVersionCurrent;
options.networkAccessAllowed = YES;
options.synchronous = YES;
//sync requests are automatically processed this way regardless of the specified mode
//originRequestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
options.progressHandler = ^(double progress, NSError *__nullable error, BOOL *stop, NSDictionary *__nullable info){
};
[[PHImageManager defaultManager] requestImageForAsset:expAsset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
if (result) {
//这里做一次压缩,否则读入内存的图片数据会过大
UIImage *image = [self scaleImage:result scaleToSize:[self getVideoSize:result.size]];
if (image != nil)
{
[self.imagesToEdit addObject:image];
self.indexs ++;
[self addEditImageArysindex:self.indexs PHAssetArys:assets vc:vcontroller];
}
}
});
}];
}
// MARK: ----- 扩展方法
- (UIImage *)scaleImage:(UIImage *)image scaleToSize:(CGSize)size
{
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
- (CGSize)getVideoSize:(CGSize)sourceSize
{
CGSize videoSize = CGSizeMake(sourceSize.width, sourceSize.height);
if (videoSize.height >= videoSize.width)
{
if([self supportCompressSize:CGSizeMake(720, 1280) videoSize:videoSize])
{
videoSize = [self compress:CGSizeMake(720, 1280) videoSize:videoSize];
}
}
else
{
if ([self supportCompressSize:CGSizeMake(1280, 720) videoSize:videoSize])
{
videoSize = [self compress:CGSizeMake(1280, 720) videoSize:videoSize];
}
}
return videoSize;
}
///< 判断是否需要压缩图片
- (BOOL)supportCompressSize:(CGSize)compressSize videoSize:(CGSize)videoSize
{
if (videoSize.width >= compressSize.width && videoSize.height >= compressSize.height)
{
return YES;
}
if (videoSize.width >= compressSize.height && videoSize.height >= compressSize.width)
{
return YES;
}
return NO;
}
///< 获得压缩后图片大小
- (CGSize)compress:(CGSize)compressSize videoSize:(CGSize)videoSize
{
CGSize size = CGSizeZero;
if (compressSize.height / compressSize.width >= videoSize.height / videoSize.width)
{
size.width = compressSize.width;
size.height = compressSize.width * videoSize.height / videoSize.width;
}
else
{
size.height = compressSize.height;
size.width = compressSize.height * videoSize.width / videoSize.height;
}
return size;
}
@end
幼虎等嬉戏.jpg
模型2
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface XPicToVideo : NSObject
/**
* 多张图片合成视频
*
*/
+ (void)compressImages:(NSArray <UIImage *> *)images completion:(void(^)(NSURL *outurl))block;
@end
NS_ASSUME_NONNULL_END
//
#import "XPicToVideo.h"
#import "XPFFile.h"
@implementation XPicToVideo
/**
* 裁剪图片
*
* @param image 图片
* @param bounds 大小
*
*/
+ (UIImage *)croppedImage:(UIImage *)image bounds:(CGRect)bounds
{
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], bounds);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return croppedImage;
}
+ (UIImage *)clipImage:(UIImage *)image ScaleWithsize:(CGSize)asize
{
UIImage *newimage;
if (nil == image)
{
newimage = nil;
}
else
{
CGSize oldsize = image.size;
CGRect rect;
if (asize.width/asize.height > oldsize.width/oldsize.height)
{
rect.size.width = asize.width;
rect.size.height = asize.width*oldsize.height/oldsize.width;
rect.origin.x = 0;
rect.origin.y = (asize.height - rect.size.height)/2;
}
else
{
rect.size.width = asize.height*oldsize.width/oldsize.height;
rect.size.height = asize.height;
rect.origin.x = (asize.width - rect.size.width)/2;
rect.origin.y = 0;
}
UIGraphicsBeginImageContext(asize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClipToRect(context, CGRectMake(0, 0, asize.width, asize.height));
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
UIRectFill(CGRectMake(0, 0, asize.width, asize.height));//clear background
[image drawInRect:rect];
newimage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
return newimage;
}
+ (CVPixelBufferRef )pixelBufferFromCGImage:(CGImageRef)image size:(CGSize)size
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
[NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil];
CVPixelBufferRef pxbuffer = NULL;
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, &pxbuffer);
NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
CVPixelBufferLockBaseAddress(pxbuffer, 0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
NSParameterAssert(pxdata != NULL);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, 4*size.width, rgbColorSpace, kCGImageAlphaPremultipliedFirst);
NSParameterAssert(context);
//CGSize drawSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
//BOOL baseW = drawSize.width < drawSize.height;
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
return pxbuffer;
}
/**
* 多张图片合成视频
*
*/
+ (void)compressImages:(NSArray <UIImage *> *)images completion:(void(^)(NSURL *outurl))block;
{
//先裁剪图片
NSMutableArray *imageArray = [NSMutableArray array];
for (UIImage *image in images)
{
CGRect rect = CGRectMake(0, 0,image.size.width, image.size.height);
if (rect.size.width < rect.size.height)
{
rect.origin.y = (rect.size.height - rect.size.width)/2;
rect.size.height = rect.size.width;
}
else
{
rect.origin.x = (rect.size.width - rect.size.height)/2;
rect.size.width = rect.size.height;
}
//裁剪
UIImage *newImage = [XPicToVideo croppedImage:image bounds:rect];
/**
* 缩放
*/
UIImage *finalImage = [XPicToVideo clipImage:newImage ScaleWithsize:CGSizeMake(640, 640)];
[imageArray addObject:finalImage];
}
// NSDate *date = [NSDate date];
// NSString *string = [NSString stringWithFormat:@"%ld.mov", (unsigned long)(date.timeIntervalSince1970 * 1000)];
// NSString *cachePath = [NSTemporaryDirectory() stringByAppendingPathComponent:string];
[XPFFile file_tmpRemoveFileName:@"imagevideo"];
NSString *cachePath = [XPFFile file_tmpAddFileName:@"imagevideo" txt:[NSString stringWithFormat:@"%ld.mov", (unsigned long)([NSDate date].timeIntervalSince1970 * 1000)] content:@""];
if ([[NSFileManager defaultManager] fileExistsAtPath:cachePath])
{
[[NSFileManager defaultManager] removeItemAtPath:cachePath error:nil];
}
NSURL *exportUrl = [NSURL fileURLWithPath:cachePath];
CGSize size = CGSizeMake(640, 640);//定义视频的大小
__block AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:exportUrl fileType:AVFileTypeQuickTimeMovie error:nil];
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:size.width], AVVideoWidthKey,
[NSNumber numberWithInt:size.height], AVVideoHeightKey, nil];
AVAssetWriterInput *writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
NSDictionary *sourcePixelBufferAttributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil];
AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary];
NSParameterAssert(writerInput);
NSParameterAssert([videoWriter canAddInput:writerInput]);
if ([videoWriter canAddInput:writerInput])
NSLog(@"");
else
NSLog(@"");
[videoWriter addInput:writerInput];
[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:kCMTimeZero];
//合成多张图片为一个视频文件
dispatch_queue_t dispatchQueue = dispatch_queue_create("mediaInputQueue", NULL);
int __block frame = 0;
__weak typeof(self) ws = self;
[writerInput requestMediaDataWhenReadyOnQueue:dispatchQueue usingBlock:^{
while ([writerInput isReadyForMoreMediaData])
{
if(++frame > 8 * 30)
{
[writerInput markAsFinished];
//[videoWriter_ finishWriting];
if (videoWriter.status == AVAssetWriterStatusWriting)
{
NSCondition *cond = [[NSCondition alloc] init];
[cond lock];
[videoWriter finishWritingWithCompletionHandler:^{
[cond lock];
[cond signal];
[cond unlock];
}];
[cond wait];
[cond unlock];
!block?:block(exportUrl);
}
break;
}
CVPixelBufferRef buffer = NULL;
int idx = frame/30 * images.count/8;
if (idx >= images.count)
{
idx = images.count - 1;
}
buffer = (CVPixelBufferRef)[XPicToVideo pixelBufferFromCGImage:[[imageArray objectAtIndex:idx] CGImage] size:size];
if (buffer)
{
if(![adaptor appendPixelBuffer:buffer withPresentationTime:CMTimeMake(frame, 30)])
{
NSLog(@"fail");
}
else
{
NSLog(@"success:%d", frame);
}
CFRelease(buffer);
}
}
}];
}
@end
柴犬安详.jpg
网友评论