MGTCVideoRecordManager.m 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. //
  2. // MGTCVideoRecordManager.m
  3. // BuguLive
  4. //
  5. // Created by 宋晨光 on 2019/7/4.
  6. // Copyright © 2019年 xfg. All rights reserved.
  7. //
  8. #import "MGTCVideoRecordManager.h"
  9. @implementation MGTCVideoRecordManager
  10. /** 截取视频的背景音乐 */
  11. + (void)dM_VideoManager_getBackgroundMiusicWithVideoUrl:(NSURL*)videoUrl newFile:(NSString*)newFile completion:(void(^)(NSString*data))completionHandle{
  12. // newFile = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true) lastObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"%ld_compressedVideo.m4a",time(NULL)]];
  13. // 1562308959
  14. // 1562309212
  15. // 创建输出路径
  16. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  17. NSString *documentsDirectory = [paths objectAtIndex:0];
  18. newFile = [documentsDirectory stringByAppendingPathComponent:
  19. [NSString stringWithFormat:@"mergeAudio%ld.m4a",time(NULL)]];
  20. // arc4random() % 1000]];
  21. NSData *data = [NSData dataWithContentsOfURL:videoUrl];
  22. if (data) {
  23. NSLog(ASLocalizedString(@"视频data存在"));
  24. }
  25. // /var/mobile/Containers/Data/Application/10443AD4-5FB7-43B8-A506-A870B9B01B13/Documents/mergeAudio-295.m4a
  26. AVURLAsset* videoAsset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil];
  27. NSArray *keys = @[@"duration",@"tracks"];
  28. [videoAsset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
  29. NSError*error =nil;
  30. AVKeyValueStatus status = [videoAsset statusOfValueForKey:@"tracks"error:&error];
  31. if(status ==AVKeyValueStatusLoaded) {//数据加载完成
  32. // 1 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances.
  33. //创建一个AVMutableComposition实例
  34. AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
  35. // 2 - Video track
  36. //创建一个轨道,类型是AVMediaTypeAudio
  37. AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
  38. preferredTrackID:kCMPersistentTrackID_Invalid];
  39. //获取videoAsset中的音频,插入轨道
  40. // NSLog(@"%f",videoAsset);
  41. // 视频时间范围
  42. [firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
  43. ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
  44. //创建输出对象
  45. AVAssetExportSession *exporter = [[AVAssetExportSession alloc]initWithAsset:mixComposition presetName:AVAssetExportPresetPassthrough];
  46. //输出为M4A音频
  47. NSURL *a = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error];
  48. NSURL *url = [a URLByAppendingPathComponent:@"filename.m4a"];
  49. NSString *filePath = [url absoluteString];
  50. // file:///var/mobile/Containers/Data/Application/C92D2683-EEC2-4287-B475-A2D11E27E6A2/Documents/filename.m4a
  51. // file:///var/mobile/Containers/Data/Application/C92D2683-EEC2-4287-B475-A2D11E27E6A2/Documents/filename.m4a
  52. NSLog(@"filePath%@",filePath);
  53. if ([[NSFileManager defaultManager]
  54. fileExistsAtPath:filePath]){
  55. [[NSFileManager defaultManager]removeItemAtPath:filePath error:nil];
  56. NSLog(@"filePath123456%@",filePath);
  57. }
  58. exporter.outputURL = [NSURL URLWithString:newFile];
  59. // url;
  60. // [NSURL URLWithString:newFile];
  61. exporter.outputFileType = @"com.apple.m4a-audio";
  62. // AVFileTypeAppleM4A;
  63. exporter.shouldOptimizeForNetworkUse = YES;
  64. [exporter exportAsynchronouslyWithCompletionHandler:^(void){    dispatch_async(dispatch_get_main_queue(), ^{
  65. switch (exporter.status) {
  66. case AVAssetExportSessionStatusCompleted:{
  67. completionHandle(newFile);
  68. }
  69. break;
  70. case AVAssetExportSessionStatusFailed:
  71. NSLog(ASLocalizedString(@"导出失败:Failed:%@"),exporter.error);
  72. completionHandle(@"");
  73. break;
  74. case AVAssetExportSessionStatusCancelled:
  75. NSLog(ASLocalizedString(@"导出取消:Canceled:%@"),exporter.error);
  76. completionHandle(@"");
  77. break;
  78. default:
  79. break;
  80. }
  81. });
  82. }];
  83. }else{
  84. NSLog(ASLocalizedString(@"音轨提取失败"));
  85. completionHandle(@"");
  86. }
  87. }];
  88. }
  89. /** 截取视频的无声音视频 */
  90. + (void)dM_VideoManager_RemoveVideoWithVideoUrl:(NSURL*)videoUrl newFile:(NSString*)newFile completion:(void(^)(NSString*data))completionHandle{
  91. AVMutableComposition *mutableComposition = [AVMutableComposition composition];
  92. AVMutableCompositionTrack *compositionVideoTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
  93. AVAssetTrack *videoTrack = nil;
  94. AVAssetTrack *assetAudioTrack = nil;
  95. AVURLAsset* asset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil];
  96. CGFloat _sound = 0;
  97. if([asset tracksWithMediaType:AVMediaTypeVideo].count!=0){
  98. videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo]objectAtIndex:0];
  99. }
  100. CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, videoTrack.timeRange.duration);
  101. if(videoTrack!=nil){
  102. [compositionVideoTrack insertTimeRange:timeRange ofTrack:videoTrack atTime:kCMTimeZero error:nil];
  103. }
  104. //测试改变原声
  105. if ([[asset tracksWithMediaType:AVMediaTypeAudio] count] != 0) {
  106. assetAudioTrack = [asset tracksWithMediaType:AVMediaTypeAudio][0];
  107. }
  108. if (assetAudioTrack != nil) {
  109. AVMutableCompositionTrack *compositionAudioTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
  110. [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, assetAudioTrack.timeRange.duration) ofTrack:assetAudioTrack atTime:kCMTimeZero error:nil];
  111. AVMutableAudioMixInputParameters *mixParameters = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:compositionAudioTrack];
  112. [mixParameters setVolumeRampFromStartVolume:_sound toEndVolume:_sound timeRange:CMTimeRangeMake(kCMTimeZero,assetAudioTrack.timeRange.duration)];
  113. AVMutableAudioMix *mutableAudioMix = [AVMutableAudioMix audioMix];
  114. mutableAudioMix.inputParameters = @[mixParameters];
  115. }
  116. //创建输出路径
  117. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  118. NSString *documentsDirectory = [paths objectAtIndex:0];
  119. newFile = [documentsDirectory stringByAppendingPathComponent:
  120. [NSString stringWithFormat:@"mergeVideos-%ld.mov",time(NULL)]];
  121. AVURLAsset* videoAsset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil];
  122. NSArray *keys = @[@"duration",@"tracks"];
  123. //导出
  124. AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:[mutableComposition
  125. copy] presetName:AVAssetExportPreset1280x720];
  126. // }
  127. // exporter.videoComposition = mutableVideoComposition;
  128. exporter.audioMix = [AVMutableAudioMix audioMix];
  129. exporter.outputURL = [NSURL fileURLWithPath:newFile];
  130. exporter.outputFileType = AVFileTypeQuickTimeMovie;
  131. exporter.shouldOptimizeForNetworkUse = YES;
  132. [exporter exportAsynchronouslyWithCompletionHandler:^(void){
  133. switch (exporter.status) {
  134. case AVAssetExportSessionStatusCompleted:{
  135. NSLog(@"AVAssetExportSessionStatusCompleted%@",newFile);
  136. completionHandle(newFile);
  137. }
  138. break;
  139. case AVAssetExportSessionStatusFailed:
  140. NSLog(ASLocalizedString(@"导出失败:Failed:%@"),exporter.error);
  141. break;
  142. case AVAssetExportSessionStatusCancelled:
  143. NSLog(ASLocalizedString(@"导出取消:Canceled:%@"),exporter.error);
  144. break;
  145. default:
  146. break;
  147. }
  148. }];
  149. [videoAsset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
  150. NSError*error =nil;
  151. AVKeyValueStatus status = [videoAsset statusOfValueForKey:@"tracks"error:&error];
  152. if(status ==AVKeyValueStatusLoaded) {//数据加载完成
  153. // 1 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances.
  154. //创建一个AVMutableComposition实例
  155. AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
  156. // 2 - Video track
  157. //创建一个轨道,类型是AVMediaTypeVideo
  158. AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
  159. preferredTrackID:kCMPersistentTrackID_Invalid];
  160. //获取videoAsset中的音频,插入轨道
  161. // NSLog(@"%f",videoAsset);
  162. [firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
  163. ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
  164. //创建输出对象
  165. AVAssetExportSession *exporter = [[AVAssetExportSession alloc]initWithAsset:mixComposition presetName:AVAssetExportPresetAppleM4A];//输出为M4A音频
  166. exporter.outputURL = [NSURL fileURLWithPath:newFile];
  167. // [NSURL URLWithString:newFile];
  168. exporter.outputFileType = @"com.apple.m4a-audio";
  169. // AVFileTypeAppleM4A;
  170. exporter.shouldOptimizeForNetworkUse = YES;
  171. [exporter exportAsynchronouslyWithCompletionHandler:^{     dispatch_async(dispatch_get_main_queue(), ^{
  172. switch (exporter.status) {
  173. case AVAssetExportSessionStatusCompleted:{
  174. completionHandle(newFile);
  175. }
  176. break;
  177. case AVAssetExportSessionStatusFailed:
  178. NSLog(ASLocalizedString(@"导出失败:Failed:%@"),exporter.error);
  179. break;
  180. case AVAssetExportSessionStatusCancelled:
  181. NSLog(ASLocalizedString(@"导出取消:Canceled:%@"),exporter.error);
  182. break;
  183. default:
  184. break;
  185. }
  186. });
  187. }];
  188. }
  189. }];
  190. }
  191. ///使用AVfoundation添加水印
  192. + (void)AVsaveVideoPath:(NSURL*)videoPath WithWaterImg:(UIImage*)img WithCoverImage:(UIImage*)coverImg WithQustion:(NSString*)question WithFileName:(NSString*)fileName completion:(void(^)(NSString*data))completionHandle;
  193. {
  194. if (!videoPath) {
  195. return;
  196. }
  197. //1 创建AVAsset实例 AVAsset包含了video的所有信息 self.videoUrl输入视频的路径
  198. //封面图片
  199. NSDictionary *opts = [NSDictionary dictionaryWithObject:@(YES) forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
  200. AVURLAsset *videoAsset = [AVURLAsset URLAssetWithURL:videoPath options:opts]; //初始化视频媒体文件
  201. NSData *data = [NSData dataWithContentsOfURL:videoPath];
  202. CMTime startTime = CMTimeMakeWithSeconds(0.2, 600);
  203. CMTime endTime = CMTimeMakeWithSeconds(videoAsset.duration.value/videoAsset.duration.timescale-0.2, videoAsset.duration.timescale);
  204. //声音采集
  205. AVURLAsset * audioAsset = [[AVURLAsset alloc] initWithURL:videoPath options:opts];
  206. //2 创建AVMutableComposition实例. apple developer 里边的解释 【AVMutableComposition is a mutable subclass of AVComposition you use when you want to create a new composition from existing assets. You can add and remove tracks, and you can add, remove, and scale time ranges.】
  207. AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
  208. //3 视频通道 工程文件中的轨道,有音频轨、视频轨等,里面可以插入各种对应的素材
  209. AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
  210. preferredTrackID:kCMPersistentTrackID_Invalid];
  211. //把视频轨道数据加入到可变轨道中 这部分可以做视频裁剪TimeRange
  212. [videoTrack insertTimeRange:CMTimeRangeMake(startTime, endTime)
  213. ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
  214. atTime:kCMTimeZero error:nil];
  215. //音频通道
  216. AVMutableCompositionTrack * audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
  217. //音频采集通道
  218. AVAssetTrack * audioAssetTrack = [[audioAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];
  219. [audioTrack insertTimeRange:CMTimeRangeMake(startTime, endTime) ofTrack:audioAssetTrack atTime:kCMTimeZero error:nil];
  220. //3.1 AVMutableVideoCompositionInstruction 视频轨道中的一个视频,可以缩放、旋转等
  221. AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
  222. mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, videoTrack.timeRange.duration);
  223. // 3.2 AVMutableVideoCompositionLayerInstruction 一个视频轨道,包含了这个轨道上的所有视频素材
  224. AVMutableVideoCompositionLayerInstruction *videolayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
  225. AVAssetTrack *videoAssetTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
  226. // UIImageOrientation videoAssetOrientation_ = UIImageOrientationUp;
  227. BOOL isVideoAssetPortrait_ = NO;
  228. CGAffineTransform videoTransform = videoAssetTrack.preferredTransform;
  229. if (videoTransform.a == 0 && videoTransform.b == 1.0 && videoTransform.c == -1.0 && videoTransform.d == 0) {
  230. // videoAssetOrientation_ = UIImageOrientationRight;
  231. isVideoAssetPortrait_ = YES;
  232. }
  233. if (videoTransform.a == 0 && videoTransform.b == -1.0 && videoTransform.c == 1.0 && videoTransform.d == 0) {
  234. // videoAssetOrientation_ = UIImageOrientationLeft;
  235. isVideoAssetPortrait_ = YES;
  236. }
  237. // if (videoTransform.a == 1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == 1.0) {
  238. // videoAssetOrientation_ = UIImageOrientationUp;
  239. // }
  240. // if (videoTransform.a == -1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == -1.0) {
  241. // videoAssetOrientation_ = UIImageOrientationDown;
  242. // }
  243. [videolayerInstruction setTransform:videoAssetTrack.preferredTransform atTime:kCMTimeZero];
  244. [videolayerInstruction setOpacity:0.0 atTime:endTime];
  245. // 3.3 - Add instructions
  246. mainInstruction.layerInstructions = [NSArray arrayWithObjects:videolayerInstruction,nil];
  247. //AVMutableVideoComposition:管理所有视频轨道,可以决定最终视频的尺寸,裁剪需要在这里进行
  248. AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition];
  249. CGSize naturalSize;
  250. if(isVideoAssetPortrait_){
  251. naturalSize = CGSizeMake(videoAssetTrack.naturalSize.height, videoAssetTrack.naturalSize.width);
  252. } else {
  253. naturalSize = videoAssetTrack.naturalSize;
  254. }
  255. float renderWidth, renderHeight;
  256. renderWidth = naturalSize.width;
  257. renderHeight = naturalSize.height;
  258. mainCompositionInst.renderSize = CGSizeMake(renderWidth, renderHeight);
  259. mainCompositionInst.renderSize = CGSizeMake(renderWidth, renderHeight);
  260. mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction];
  261. mainCompositionInst.frameDuration = CMTimeMake(1, 25);
  262. [self applyVideoEffectsToComposition:mainCompositionInst WithWaterImg:img WithCoverImage:coverImg WithQustion:question size:CGSizeMake(renderWidth, renderHeight)];
  263. // 4 - 输出路径
  264. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  265. NSString *documentsDirectory = [paths objectAtIndex:0];
  266. NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mp4",fileName]];
  267. unlink([myPathDocs UTF8String]);
  268. NSURL* videoUrl = [NSURL fileURLWithPath:myPathDocs];
  269. // CADisplayLink *dlink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateProgress)];
  270. // [dlink setFrameInterval:15];
  271. // [dlink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  272. // [dlink setPaused:NO];
  273. // 5 - 视频文件输出
  274. AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition
  275. presetName:AVAssetExportPresetHighestQuality];
  276. exporter.outputURL=videoUrl;
  277. exporter.outputFileType = AVFileTypeQuickTimeMovie;
  278. exporter.shouldOptimizeForNetworkUse = YES;
  279. exporter.videoComposition = mainCompositionInst;
  280. [exporter exportAsynchronouslyWithCompletionHandler:^{
  281. dispatch_async(dispatch_get_main_queue(), ^{
  282. //这里是输出视频之后的操作,做你想做的
  283. // [MGTCVideoRecordManager exportDidFinish:exporter];
  284. completionHandle(myPathDocs);
  285. });
  286. }];
  287. }
  288. + (void)applyVideoEffectsToComposition:(AVMutableVideoComposition *)composition WithWaterImg:(UIImage*)img WithCoverImage:(UIImage*)coverImg WithQustion:(NSString*)question size:(CGSize)size {
  289. NSArray *strArr = [question componentsSeparatedByString:@","];
  290. NSString *titleLeft = strArr.firstObject;
  291. NSString *weiboID = [NSString stringWithFormat:ASLocalizedString(@"唯播ID:%@"),strArr.lastObject];
  292. UIFont *font = [UIFont systemFontOfSize:30.0];
  293. CATextLayer *subtitle1Text = [[CATextLayer alloc] init];
  294. [subtitle1Text setFontSize:30];
  295. [subtitle1Text setString:titleLeft];
  296. [subtitle1Text setAlignmentMode:kCAAlignmentLeft];
  297. [subtitle1Text setForegroundColor:[[UIColor whiteColor] CGColor]];
  298. subtitle1Text.masksToBounds = YES;
  299. subtitle1Text.cornerRadius = 23.0f;
  300. // [subtitle1Text setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.5].CGColor];
  301. CGSize textSize = [titleLeft sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:font,NSFontAttributeName, nil]];
  302. [subtitle1Text setFrame:CGRectMake(50, size.height - textSize.height - 100, textSize.width+20, textSize.height+15)];
  303. CATextLayer *subtitle1Text2 = [[CATextLayer alloc] init];
  304. [subtitle1Text2 setFontSize:30];
  305. [subtitle1Text2 setString:weiboID];
  306. [subtitle1Text2 setAlignmentMode:kCAAlignmentRight];
  307. [subtitle1Text2 setForegroundColor:[[UIColor whiteColor] CGColor]];
  308. subtitle1Text2.masksToBounds = YES;
  309. subtitle1Text2.cornerRadius = 23.0f;
  310. // [subtitle1Text2 setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.5].CGColor];
  311. CGSize textSize2 = [weiboID sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:font,NSFontAttributeName, nil]];
  312. [subtitle1Text2 setFrame:CGRectMake(size.width - textSize2.width - 20 , textSize2.height + 10, textSize2.width , textSize2.height + 10)];
  313. //水印
  314. CALayer *imgLayer = [CALayer layer];
  315. imgLayer.contents = (id)img.CGImage;
  316. // imgLayer.bounds = CGRectMake(0, 0, size.width, size.height);
  317. // imgLayer.bounds = CGRectMake(0, 0, 210, 50);
  318. // imgLayer.position = CGPointMake(size.width/2.0, size.height/2.0);
  319. //第二个水印
  320. CALayer *coverImgLayer = [CALayer layer];
  321. coverImgLayer.contents = (id)coverImg.CGImage;
  322. // [coverImgLayer setContentsGravity:@"resizeAspect"];
  323. // coverImgLayer.bounds = CGRectMake(50, 200,210, 50);
  324. // coverImgLayer.position = CGPointMake(size.width/4.0, size.height/4.0);
  325. // 2 - The usual overlay
  326. CALayer *overlayLayer = [CALayer layer];
  327. [overlayLayer addSublayer:subtitle1Text];
  328. [overlayLayer addSublayer:imgLayer];
  329. overlayLayer.frame = CGRectMake(0, 0, size.width, size.height);
  330. // [overlayLayer setMasksToBounds:YES];
  331. // 3 -
  332. CALayer *overlayLayer2 = [CALayer layer];
  333. [overlayLayer2 addSublayer:subtitle1Text2];
  334. // [overlayLayer2 addSublayer:imgLayer];
  335. overlayLayer2.frame = CGRectMake(0, 0, size.width, size.height);
  336. [overlayLayer2 setMasksToBounds:YES];
  337. CALayer *parentLayer = [CALayer layer];
  338. CALayer *videoLayer = [CALayer layer];
  339. parentLayer.frame = CGRectMake(0, 0, size.width, size.height);
  340. videoLayer.frame = CGRectMake(0, 0, size.width, size.height);
  341. [parentLayer addSublayer:videoLayer];
  342. [parentLayer addSublayer:overlayLayer];
  343. [parentLayer addSublayer:coverImgLayer];
  344. [parentLayer addSublayer:overlayLayer2];
  345. //设置封面
  346. CABasicAnimation *anima = [CABasicAnimation animationWithKeyPath:@"opacity"];
  347. anima.fromValue = [NSNumber numberWithFloat:1.0f];
  348. anima.toValue = [NSNumber numberWithFloat:0.0f];
  349. anima.repeatCount = 0;
  350. anima.duration = 5.0f; //5s之后消失
  351. [anima setRemovedOnCompletion:NO];
  352. [anima setFillMode:kCAFillModeForwards];
  353. anima.beginTime = AVCoreAnimationBeginTimeAtZero;
  354. [coverImgLayer addAnimation:anima forKey:@"opacityAniamtion"];
  355. composition.animationTool = [AVVideoCompositionCoreAnimationTool
  356. videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
  357. }
  358. //
  359. //更新生成进度
  360. + (void)updateProgress {
  361. // [SVProgressHUD showProgress:exporter.progress status:NSLocalizedString(ASLocalizedString(@"生成中..."), nil)];
  362. // if (exporter.progress>=1.0) {
  363. // [dlink setPaused:true];
  364. // [dlink invalidate];
  365. // // [SVProgressHUD dismiss];
  366. // }
  367. }
  368. @end