VapxProcessor.m 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // Tencent is pleased to support the open source community by making vap available.
  2. //
  3. // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  4. //
  5. // Licensed under the MIT License (the "License"); you may not use this file except in
  6. // compliance with the License. You may obtain a copy of the License at
  7. //
  8. // http://opensource.org/licenses/MIT
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed under the License is
  11. // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  12. // either express or implied. See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "VapxProcessor.h"
  15. #import "QGVAPConfigModel.h"
  16. #import "VapxMP4Decoder.h"
  17. #import "VapxAlphaExtractor.h"
  18. #import "QGVAPConfigModel.h"
  19. #import "VapxMp4Editor.h"
  20. #import "VapxMaskInfoGenerator.h"
  21. #import "VapxLayoutManager.h"
  22. #import "VapxFileHelper.h"
  23. #import "AppDelegate.h"
  24. @implementation VapxProcessor
  25. - (void)process:(processorProgressBlock)progress onCompletion:(processorCompletionBlock)block {
  26. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  27. NSError *error = nil;
  28. NSString *mp4Path = [self produceVapFile:&error progress:progress];
  29. dispatch_async(dispatch_get_main_queue(), ^{
  30. if (!block) {
  31. return ;
  32. }
  33. if (error || mp4Path.length == 0) {
  34. block(NO,nil,error);
  35. return ;
  36. }
  37. block(YES, mp4Path, nil);
  38. });
  39. });
  40. }
  41. - (NSString *)produceVapFile:(NSError **)error progress:(processorProgressBlock)progress {
  42. QGVAPConfigModel *configModel = [QGVAPConfigModel new];
  43. QGVAPCommonInfo *commonInfo = [QGVAPCommonInfo new];
  44. configModel.info = commonInfo;
  45. commonInfo.version = self.version;
  46. commonInfo.fps = self.fps;
  47. CGFloat currentProgress = 0.0;
  48. CGFloat stepSize = 1/8.0;
  49. //1.配置信息
  50. NSMutableArray<QGVAPSourceInfo *> *sources = [NSMutableArray new];
  51. NSMutableArray *maskDirs = [NSMutableArray new];
  52. [self.mergeInfoViews enumerateObjectsUsingBlock:^(VapMergeInfoView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  53. QGVAPSourceInfo *source = [QGVAPSourceInfo new];
  54. source.srcID = [NSString stringWithFormat:@"%@",@(idx+1)];
  55. if ([obj.resTypePopButton.title isEqualToString:@"网络图片"]) {
  56. source.type = kVapAttachmentSourceTypeImgUrl;
  57. source.loadType = kVapAttachmentLoadTypeNet;
  58. } else if([obj.resTypePopButton.title isEqualToString:@"文字"]) {
  59. source.type = kVapAttachmentSourceTypeTextStr;
  60. source.loadType = kVapAttachmentLoadTypeLocal;
  61. if ([obj.fontStyleButton.title isEqualToString:@"粗体"]) {
  62. source.style = kVapAttachmentSourceStyleBoldText;
  63. }
  64. }
  65. source.contentTag = obj.tagLabel.stringValue;
  66. source.color = obj.colorLabel.stringValue;
  67. source.size = NSMakeSize([obj.widthLabel.stringValue integerValue], [obj.heightLabel.stringValue integerValue]);
  68. if ([obj.fitTypePopButton.selectedItem.title isEqualToString:@"铺满"]) {
  69. source.fitType = kVapAttachmentFitTypeFitXY;
  70. } else if ([obj.fitTypePopButton.selectedItem.title isEqualToString:@"等比适配"]) {
  71. source.fitType = kVapAttachmentFitTypeCenterFull;
  72. }
  73. [sources addObject:source];
  74. [maskDirs addObject:obj.maskPath];
  75. }];
  76. configModel.resources = sources;
  77. currentProgress += stepSize;
  78. if (progress) {
  79. progress(currentProgress);
  80. }
  81. //2.拆分alpha rgb通道
  82. [VapxAlphaExtractor extractWithDir:[self.fileHelper videoFramesPath] info:&commonInfo completion:^(NSInteger framesCount, NSArray<NSString *> *alphaFiles, NSArray<NSString *> *rgbFiles) {
  83. NSLog(@"--count:%@", @(framesCount));
  84. }];
  85. currentProgress += stepSize;
  86. if (progress) {
  87. progress(currentProgress);
  88. }
  89. if (self.classicMode && (((int)commonInfo.size.width)%16 != 0 || ((int)commonInfo.size.height)%16 != 0)) {
  90. *error = [NSError errorWithDomain:@"经典模式下长宽必须是16整数倍" code:-1 userInfo:nil];
  91. return nil;
  92. }
  93. //3.生成每一帧的遮罩信息
  94. NSDictionary *mergeInfos = [VapxMaskInfoGenerator mergeInfoAt:maskDirs sources:sources frames:commonInfo.framesCount];
  95. configModel.mergedConfig = mergeInfos;
  96. if (mergeInfos.count > 0) {
  97. configModel.info.isMerged = YES;
  98. }
  99. currentProgress += stepSize;
  100. if (progress) {
  101. progress(currentProgress);
  102. }
  103. //4.布局计算
  104. CGFloat alphaScale = self.alphaScale;
  105. VapxLayoutManager *layoutManager = [VapxLayoutManager new];
  106. layoutManager.padding = self.layoutPadding;
  107. layoutManager.classicMode = self.classicMode;
  108. NSSize size = [layoutManager maximumSizeForInfo:configModel alphaMinScale:alphaScale];
  109. if (size.width > kVapLayoutMaxWidth || size.height > kVapLayoutMaxWidth) {
  110. NSLog(@"尺寸过大,请尝试减小scale");
  111. *error = [NSError errorWithDomain:@"尺寸过大,请尝试减小scale" code:-1 userInfo:nil];
  112. }
  113. currentProgress += stepSize;
  114. if (progress) {
  115. progress(currentProgress);
  116. }
  117. //5.布局
  118. CGFloat hexWidth = [self minimumHexNumberOf:(int)size.width];
  119. CGFloat hexHeight = [self minimumHexNumberOf:(int)size.height];
  120. commonInfo.videoSize = NSMakeSize(hexWidth, hexHeight);
  121. [layoutManager layoutWith:configModel desDir:[_fileHelper layoutDir] alphaScale:alphaScale];
  122. currentProgress += stepSize;
  123. if (progress) {
  124. progress(currentProgress);
  125. }
  126. //6.合成mp4文件
  127. NSString *outputPath = [VapxMP4Decoder encodeWithDir:[_fileHelper layoutDir] outputName:[_fileHelper layoutMP4Name] fps:commonInfo.fps bitRate:[NSString stringWithFormat:@"%@k",@(self.bitrates)] audioPath:self.audioPath];
  128. currentProgress += stepSize;
  129. if (progress) {
  130. progress(currentProgress);
  131. }
  132. //7.生成配置box
  133. NSString *jsonString = [configModel jsonString];
  134. NSData *utf8Data = [jsonString dataUsingEncoding:kCFStringEncodingUTF8];
  135. NSString *avcJsonPath = [[_fileHelper outputPath] stringByAppendingPathComponent:@"vapc.json"];
  136. [utf8Data writeToFile:avcJsonPath atomically:YES];
  137. NSInteger length = utf8Data.length+8;
  138. unsigned char bytes[8] = {(length&0xff000000)>>24,(length&0xff0000)>>16,(length&0xff00)>>8,length&0xff,'v','a','p','c'};
  139. NSMutableData *muData = [[[NSData alloc] initWithBytes:bytes length:8] mutableCopy];
  140. [muData appendData:utf8Data];
  141. NSString *vapcStringPath = [[_fileHelper outputPath] stringByAppendingPathComponent:@"vapc.bin"];
  142. BOOL succ = [muData writeToFile:vapcStringPath atomically:YES];
  143. if (!succ) {
  144. NSLog(@"vapc data write fail!%@", muData);
  145. *error = [NSError errorWithDomain:@"vapc data write fail!" code:-1 userInfo:nil];
  146. return nil;
  147. }
  148. currentProgress += stepSize;
  149. if (progress) {
  150. progress(currentProgress);
  151. }
  152. if ([[(AppDelegate *)[NSApplication sharedApplication].delegate encoder] isEqualToString:@"libvpx-vp9"]) {
  153. return outputPath;
  154. }
  155. //8.将配置信息写入mp4n并导出文件
  156. VapxMp4Editor *mp4Editor = [VapxMp4Editor new];
  157. mp4Editor.inputPath = [[_fileHelper layoutDir] stringByAppendingPathComponent:[_fileHelper layoutMP4Name]];
  158. mp4Editor.outputPath = [[_fileHelper outputPath] stringByAppendingPathComponent:[_fileHelper outputMP4Name]];
  159. NSString *newMp4 = [mp4Editor mp4ByInsertAtom:vapcStringPath atIndex:1];
  160. [[NSFileManager defaultManager] removeItemAtPath:vapcStringPath error:nil];
  161. return newMp4;
  162. }
  163. - (NSInteger)minimumHexNumberOf:(NSInteger)num {
  164. if (num%16 == 0) {
  165. return num;
  166. }
  167. return 16-((int)num%16)+num;
  168. }
  169. @end