想要實現這個功能,能夠先了解一下有關錄製視頻的相關知識:素材庫、素材的軌道、合成視頻的工程文件等等,具體能夠參考視頻編輯素材
html
相關術語:ios
AVAsset:素材庫裏的素材;
AVAssetTrack:素材的軌道;
AVMutableComposition:一個用來合成視頻的工程文件;
AVMutableCompositionTrack:工程文件中的軌道,有音頻軌、視頻軌等,裏面能夠插入各類對應的素材;
AVMutableVideoCompositionLayerInstruction:視頻軌道中的一個視頻,能夠縮放、旋轉等;
AVMutableVideoCompositionInstruction:一個視頻軌道,包含了這個軌道上的全部視頻素材;
AVMutableVideoComposition:管理全部視頻軌道,能夠決定最終視頻的尺寸,裁剪須要在這裏進行;
AVAssetExportSession:配置渲染參數並渲染。複製代碼
問題記錄:git
下面帶橫線的是錯誤思路,一開始走進了誤區,這種方式並不能解決點擊view觸發toucherBegan的問題github
長按拍攝,利用的是touchesbegan開始錄製,touchesEnded結束錄製;存在一個小問題就是點擊這個view的時候,會觸發touchesBegan,然而不會觸發touchesEnded。這裏使用了一個延時機制去觸發touchesBegan事件的觸發,代碼以下
bash
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"開始觸摸");
if ([[touches anyObject] view] == self.progressView) {
if (!self.capture) { // 表示是否正在錄製
double delayInSeconds = 0.5; // 長按0.5s觸發錄製事件
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self startCapture]; // 開始錄製
});
}else {
[self startCapture];
}
}
}複製代碼
解決方案就是用長按手勢來觸發ide
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(LongPressProgressView:)];
longPress.minimumPressDuration = 0.5;
[progressView addGestureRecognizer:longPress];複製代碼
- (void)LongPressProgressView:(UILongPressGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
[self startCapture];
}else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
if ([self.mediaCaptureDelegate respondsToSelector:@selector(stopCapture)]) {
self.capture = NO;
self.bgView.hidden = YES;
[self.mediaCaptureDelegate stopCapture];
[self.progressView clearProgress];
}
}
}複製代碼
其次有個能夠拖動、縮放、旋轉的文本框,點擊能夠從新編輯,我是封裝了一個類FWTextView,具體代碼能夠從下面的demo裏找到,如圖fetch
最關鍵的一點就是水印的添加,主要功能就是這個麼。先說下思路:ui
首先咱們要知道咱們能看到的視頻其實是由一個叫作videoLayer負責顯示的,和他同級的有個layer叫作animationLayer,咱們可以控制的其實就是這個東西,他能夠由咱們本身建立,他們有一個共同的父類叫作parentLayer。spa
添加圖片水印的代碼:.net
CALayer *imgLayer = [CALayer layer];
imgLayer.contents = (id)img.CGImage;
imgLayer.frame = CGRectMake(0, 0, size.width, size.height);複製代碼
建立好了圖片layer後,就須要建立videoLayer
//把文字和圖標都添加到layer
CALayer *overlayLayer = [CALayer layer];
[overlayLayer addSublayer:imgLayer];
overlayLayer.frame = CGRectMake(0, 0, size.width, size.height);
[overlayLayer setMasksToBounds:YES];
[overlayLayer addSublayer:imgLayer];
CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, size.width, size.height);
parentLayer.backgroundColor = [UIColor redColor].CGColor;
videoLayer.frame = CGRectMake(0, 0, size.width, size.height);
[parentLayer addSublayer:videoLayer];
[parentLayer addSublayer:overlayLayer];
composition.animationTool = [AVVideoCompositionCoreAnimationTool
videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];複製代碼
這裏主要是告訴系統咱們的layer層時parentLayer,在parentLayer裏負責video顯示的是咱們的videoLayer。想詳細瞭解的可參考視頻特效製做
最後就是錄製完的視頻保存本地,這裏使用的不是系統的,ios10開始ALAssetsLibrary被標誌爲棄用(DEPRECATED),並建議使用Photos framework的PHPhotoLibrary,使用需先引用#import <Photos/Photos.h>
方法1:同步存到系統相冊(iOS10系統執行該方法,沒法保存成功)
__block NSString *createdAssetID =nil;//惟一標識,能夠用於圖片資源獲取
NSError *error =nil;
[[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
createdAssetID = [PHAssetChangeRequest creationRequestForAssetFromImage:image].placeholderForCreatedAsset.localIdentifier;
} error:&error];複製代碼
補充:
上面的方法1在系統是10的真機上出現保存視頻失敗,更新一下新的方法:
NSString *path = [SNSImageEngine getRealHouseVideoPathWithVideoPath:videoPath];
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path)) {
UISaveVideoAtPathToSavedPhotosAlbum(path , self, @selector(video:didFinishSavingWithError:contextInfo:), nil);
}else {
[MBProgressHUD showMessage:@"保存失敗"];
}
// 視頻保存回調
- (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if (error == nil) {
[MBProgressHUD showMessage:@"已保存至手機"];
}else {
[MBProgressHUD showMessage:@"保存失敗"];
}
}
複製代碼
上面代碼裏的path是視頻在本地的路徑,還有一個回調方法提供。
方法2:存到某個自定義相冊
[[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{
PHAssetChangeRequest *changeAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
PHAssetCollection *targetCollection = [[PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil]lastObject];
PHAssetCollectionChangeRequest *changeCollectionRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:targetCollection];
PHObjectPlaceholder *assetPlaceholder = [changeAssetRequest placeholderForCreatedAsset];
[changeCollectionRequest addAssets:@[assetPlaceholder]];
} completionHandler:^(BOOL success,NSError * _Nullable error) {
NSLog(@"finished adding");
}];複製代碼
詳細瞭解參考保存照片到相冊
demo連接:github.com/SXDgit/ZB_A…
到此基本結束了,後期有更新的話,會繼續更新。
需求更改,要求錄製時間加長,大於10s,會出現新的bug。視頻超過10s後,聲音會丟失。
-(AVCaptureMovieFileOutput *)movieFileOutput{
if (!_movieFileOutput) {
_movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
/* 默認的錄製視頻時間是10秒,若是視頻大於10秒必須禁用他,不然錄製的視頻將會沒有聲音*/
_movieFileOutput.movieFragmentInterval = kCMTimeInvalid;
}
return _movieFileOutput;
}
複製代碼