圖片合成視頻
首先需要導(dǎo)入的三個(gè)依賴庫(kù)
AVKit.framework??? MediaPlayer.framework??? AVFoundation.framework
下面代碼中的注釋很清楚, 就不做多解釋, 直接上代碼了
[objc]view plaincopy
#import?"ViewController.h"
#import?
#import?
#import?
@interfaceViewController?()
{
NSMutableArray*imageArr;//未壓縮的圖片
NSMutableArray*imageArray;//經(jīng)過壓縮的圖片
}
@property(nonatomic,strong)NSString*theVideoPath;
@end
@implementationViewController
-?(void)viewDidLoad?{
[superviewDidLoad];
imageArray?=?[[NSMutableArrayalloc]init];
imageArr?=[[NSMutableArrayalloc]initWithObjects:
[UIImageimageNamed:@"IMG_3811.jpg"],[UIImageimageNamed:@"IMG_3812.jpg"],[UIImageimageNamed:@"IMG_3813.jpg"],[UIImageimageNamed:@"IMG_3814.jpg"],[UIImageimageNamed:@"IMG_3815.jpg"],[UIImageimageNamed:@"IMG_3816.jpg"],[UIImageimageNamed:@"IMG_3817.jpg"],[UIImageimageNamed:@"IMG_3818.jpg"],[UIImageimageNamed:@"IMG_3820.jpg"],[UIImageimageNamed:@"IMG_3821.jpg"],[UIImageimageNamed:@"IMG_3822.jpg"],[UIImageimageNamed:@"IMG_3823.jpg"],[UIImageimageNamed:@"IMG_3824.jpg"],[UIImageimageNamed:@"IMG_3825.jpg"],[UIImageimageNamed:@"IMG_3826.jpg"],[UIImageimageNamed:@"IMG_3827.jpg"],[UIImageimageNamed:@"IMG_3828.jpg"],[UIImageimageNamed:@"IMG_3829.jpg"],[UIImageimageNamed:@"IMG_3830.jpg"],[UIImageimageNamed:@"IMG_3831.jpg"],[UIImageimageNamed:@"IMG_3832.jpg"],[UIImageimageNamed:@"IMG_3833.jpg"],[UIImageimageNamed:@"IMG_3834.jpg"],[UIImageimageNamed:@"IMG_3835.jpg"],[UIImageimageNamed:@"IMG_3836.jpg"],[UIImageimageNamed:@"IMG_3837.jpg"],[UIImageimageNamed:@"IMG_3838.jpg"],[UIImageimageNamed:@"IMG_3839.jpg"],[UIImageimageNamed:@"IMG_3840.jpg"],[UIImageimageNamed:@"IMG_3841.jpg"],[UIImageimageNamed:@"IMG_3842.jpg"],[UIImageimageNamed:@"IMG_3843.jpg"],[UIImageimageNamed:@"IMG_3844.jpg"],[UIImageimageNamed:@"IMG_3845.jpg"],[UIImageimageNamed:@"IMG_3846.jpg"],nil];
for(inti?=0;?i
UIImage*imageNew?=?imageArr[i];
//設(shè)置image的尺寸
CGSize?imagesize?=?imageNew.size;
imagesize.height=408;
imagesize.width=306;
//對(duì)圖片大小進(jìn)行壓縮--
imageNew?=?[selfimageWithImage:imageNewscaledToSize:imagesize];
[imageArrayaddObject:imageNew];
}
UIButton*?button?=[UIButtonbuttonWithType:UIButtonTypeRoundedRect];
[buttonsetFrame:CGRectMake(100,100,100,50)];
[buttonsetTitle:@"視頻合成"forState:UIControlStateNormal];
[buttonaddTarget:selfaction:@selector(testCompressionSession)forControlEvents:UIControlEventTouchUpInside];
button.backgroundColor=?[UIColorredColor];
[self.viewaddSubview:button];
UIButton*?button1=[UIButtonbuttonWithType:UIButtonTypeRoundedRect];
[button1setFrame:CGRectMake(100,200,100,50)];
[button1setTitle:@"視頻播放"forState:UIControlStateNormal];
[button1addTarget:selfaction:@selector(playAction)forControlEvents:UIControlEventTouchUpInside];
button1.backgroundColor=?[UIColorredColor];
[self.viewaddSubview:button1];
}
//對(duì)圖片尺寸進(jìn)行壓縮--
-(UIImage*)imageWithImage:(UIImage*)imagescaledToSize:(CGSize)newSize
{
//????新創(chuàng)建的位圖上下文?newSize為其大小
UIGraphicsBeginImageContext(newSize);
//????對(duì)圖片進(jìn)行尺寸的改變
[imagedrawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
//????從當(dāng)前上下文中獲取一個(gè)UIImage對(duì)象??即獲取新的圖片對(duì)象
UIImage*?newImage?=?UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//?Return?the?new?image.
returnnewImage;
}
-(void)testCompressionSession
{
//設(shè)置mov路徑
NSArray*paths?=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString*moviePath?=[[pathsobjectAtIndex:0]stringByAppendingPathComponent:[NSStringstringWithFormat:@"%@.mov",@"test"]];
self.theVideoPath=moviePath;
//定義視頻的大小320?480?倍數(shù)
CGSize?size?=CGSizeMake(320,480);
//????????[selfwriteImages:imageArr?ToMovieAtPath:moviePath?withSize:sizeinDuration:4?byFPS:30];//第2中方法
NSError*error?=nil;
//????轉(zhuǎn)成UTF-8編碼
unlink([moviePathUTF8String]);
NSLog(@"path->%@",moviePath);
//?????iphone提供了AVFoundation庫(kù)來方便的操作多媒體設(shè)備驾孔,AVAssetWriter這個(gè)類可以方便的將圖像和音頻寫成一個(gè)完整的視頻文件
AVAssetWriter*videoWriter?=?[[AVAssetWriteralloc]initWithURL:[NSURLfileURLWithPath:moviePath]fileType:AVFileTypeQuickTimeMovieerror:&error];
NSParameterAssert(videoWriter);
if(error)
NSLog(@"error?=%@",?[errorlocalizedDescription]);
//mov的格式設(shè)置?編碼格式?寬度?高度
NSDictionary*videoSettings?=[NSDictionarydictionaryWithObjectsAndKeys:AVVideoCodecH264,AVVideoCodecKey,
[NSNumbernumberWithInt:size.width],AVVideoWidthKey,
[NSNumbernumberWithInt:size.height],AVVideoHeightKey,nil];
AVAssetWriterInput*writerInput?=[AVAssetWriterInputassetWriterInputWithMediaType:AVMediaTypeVideooutputSettings:videoSettings];
NSDictionary*sourcePixelBufferAttributesDictionary?=[NSDictionarydictionaryWithObjectsAndKeys:[NSNumbernumberWithInt:kCVPixelFormatType_32ARGB],kCVPixelBufferPixelFormatTypeKey,nil];
//????AVAssetWriterInputPixelBufferAdaptor提供CVPixelBufferPool實(shí)例,
//????可以使用分配像素緩沖區(qū)寫入輸出文件。使用提供的像素為緩沖池分配通常
//????是更有效的比添加像素緩沖區(qū)分配使用一個(gè)單獨(dú)的池
AVAssetWriterInputPixelBufferAdaptor*adaptor?=[AVAssetWriterInputPixelBufferAdaptorassetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInputsourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary];
NSParameterAssert(writerInput);
NSParameterAssert([videoWritercanAddInput:writerInput]);
if([videoWritercanAddInput:writerInput])
{
NSLog(@"11111");
}
else
{
NSLog(@"22222");
}
[videoWriteraddInput:writerInput];
[videoWriterstartWriting];
[videoWriterstartSessionAtSourceTime:kCMTimeZero];
//合成多張圖片為一個(gè)視頻文件
dispatch_queue_t?dispatchQueue?=dispatch_queue_create("mediaInputQueue",NULL);
int__block?frame?=0;
[writerInputrequestMediaDataWhenReadyOnQueue:dispatchQueueusingBlock:^{
while([writerInputisReadyForMoreMediaData])
{
if(++frame?>=[imageArraycount]*10)
{
[writerInputmarkAsFinished];
[videoWriterfinishWriting];
//??????????????[videoWriterfinishWritingWithCompletionHandler:nil];
break;
}
CVPixelBufferRef?buffer?=NULL;
intidx?=frame/10;
NSLog(@"idx==%d",idx);
buffer?=?(CVPixelBufferRef)[selfpixelBufferFromCGImage:[[imageArrayobjectAtIndex:idx]CGImage]size:size];
if(buffer)
{
if(![adaptorappendPixelBuffer:bufferwithPresentationTime:CMTimeMake(frame,30)])//設(shè)置每秒鐘播放圖片的個(gè)數(shù)
{
NSLog(@"FAIL");
}
else
{
NSLog(@"OK");
}
CFRelease(buffer);
}
}
}];
}
-?(CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)imagesize:(CGSize)size
{
NSDictionary*options?=[NSDictionarydictionaryWithObjectsAndKeys:
[NSNumbernumberWithBool:YES],kCVPixelBufferCGImageCompatibilityKey,
[NSNumbernumberWithBool: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);
voidvoid*pxdata?=CVPixelBufferGetBaseAddress(pxbuffer);
NSParameterAssert(pxdata?!=NULL);
CGColorSpaceRef?rgbColorSpace=CGColorSpaceCreateDeviceRGB();
//????當(dāng)你調(diào)用這個(gè)函數(shù)的時(shí)候惯疙,Quartz創(chuàng)建一個(gè)位圖繪制環(huán)境翠勉,也就是位圖上下文。當(dāng)你向上下文中繪制信息時(shí)霉颠,Quartz把你要繪制的信息作為位圖數(shù)據(jù)繪制到指定的內(nèi)存塊对碌。一個(gè)新的位圖上下文的像素格式由三個(gè)參數(shù)決定:每個(gè)組件的位數(shù),顏色空間蒿偎,alpha選項(xiàng)
CGContextRef?context?=CGBitmapContextCreate(pxdata,size.width,size.height,8,4*size.width,rgbColorSpace,kCGImageAlphaPremultipliedFirst);
NSParameterAssert(context);
//使用CGContextDrawImage繪制圖片??這里設(shè)置不正確的話?會(huì)導(dǎo)致視頻顛倒
//????當(dāng)通過CGContextDrawImage繪制圖片到一個(gè)context中時(shí)朽们,如果傳入的是UIImage的CGImageRef,因?yàn)閁IKit和CG坐標(biāo)系y軸相反诉位,所以圖片繪制將會(huì)上下顛倒
CGContextDrawImage(context,CGRectMake(0,0,CGImageGetWidth(image),CGImageGetHeight(image)),?image);
//?釋放色彩空間
CGColorSpaceRelease(rgbColorSpace);
//?釋放context
CGContextRelease(context);
//?解鎖pixel?buffer
CVPixelBufferUnlockBaseAddress(pxbuffer,0);
returnpxbuffer;
}
//播放
-(void)playAction
{
NSLog(@"************%@",self.theVideoPath);
NSURL*sourceMovieURL?=?[NSURLfileURLWithPath:self.theVideoPath];
AVAsset*movieAsset?=?[AVURLAssetURLAssetWithURL:sourceMovieURLoptions:nil];
AVPlayerItem*playerItem?=?[AVPlayerItemplayerItemWithAsset:movieAsset];
AVPlayer*player?=?[AVPlayerplayerWithPlayerItem:playerItem];
AVPlayerLayer*playerLayer?=?[AVPlayerLayerplayerLayerWithPlayer:player];
playerLayer.frame=self.view.layer.bounds;
playerLayer.videoGravity=?AVLayerVideoGravityResizeAspect;
[self.view.layeraddSublayer:playerLayer];
[playerplay];
}