QGVAPConfigManager.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // QGVAPConfigManager.m
  2. // Tencent is pleased to support the open source community by making vap available.
  3. //
  4. // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  5. //
  6. // Licensed under the MIT License (the "License"); you may not use this file except in
  7. // compliance with the License. You may obtain a copy of the License at
  8. //
  9. // http://opensource.org/licenses/MIT
  10. //
  11. // Unless required by applicable law or agreed to in writing, software distributed under the License is
  12. // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  13. // either express or implied. See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. #import "QGVAPConfigManager.h"
  16. #import "QGMP4Parser.h"
  17. #import "QGVAPLogger.h"
  18. #import "NSDictionary+VAPUtil.h"
  19. #import "UIColor+VAPUtil.h"
  20. #import "NSArray+VAPUtil.h"
  21. #import "QGHWDMetalRenderer.h"
  22. #import "QGVAPTextureLoader.h"
  23. @interface QGVAPConfigManager () {
  24. QGMP4HWDFileInfo *_fileInfo;
  25. }
  26. @end
  27. @implementation QGVAPConfigManager
  28. - (instancetype)initWith:(QGMP4HWDFileInfo *)fileInfo {
  29. if (self = [super init]) {
  30. _fileInfo = fileInfo;
  31. [self setupConfig];
  32. }
  33. return self;
  34. }
  35. - (void)setupConfig {
  36. QGMP4Box *vapc = [_fileInfo.mp4Parser.rootBox subBoxOfType:QGMP4BoxType_vapc];
  37. if (!vapc) {
  38. self.hasValidConfig = NO;
  39. VAP_Error(kQGVAPModuleCommon, @"config can not find vapc box");
  40. return ;
  41. }
  42. self.hasValidConfig = YES;
  43. NSData *vapcData = [_fileInfo.mp4Parser readDataOfBox:vapc length:vapc.length-8 offset:8];
  44. NSError *error = nil;
  45. NSDictionary *configDictionary = [NSJSONSerialization JSONObjectWithData:vapcData options:kNilOptions error:&error];
  46. if (error) {
  47. VAP_Error(kQGVAPModuleCommon, @"fail to parse config as dictionary file %@", vapc);
  48. }
  49. [self parseConfigDictinary:configDictionary];
  50. }
  51. #pragma mark - resource loader
  52. - (void)loadConfigResources {
  53. if (self.model.resources.count == 0) {
  54. if ([self.delegate respondsToSelector:@selector(onVAPConfigResourcesLoaded:error:)]) {
  55. [self.delegate onVAPConfigResourcesLoaded:self.model error:nil];
  56. }
  57. return ;
  58. }
  59. //tags
  60. if ([self.delegate respondsToSelector:@selector(vap_contentForTag:resource:)]) {
  61. [self.model.resources enumerateObjectsUsingBlock:^(QGVAPSourceInfo * _Nonnull resource, NSUInteger idx, BOOL * _Nonnull stop) {
  62. resource.contentTagValue = [self.delegate vap_contentForTag:resource.contentTag resource:resource];
  63. }];
  64. }
  65. if (![self.delegate respondsToSelector:@selector(vap_loadImageWithURL:context:completion:)]) {
  66. return ;
  67. }
  68. __block NSError *loadError = nil;
  69. dispatch_group_t group = dispatch_group_create();
  70. [self.model.resources enumerateObjectsUsingBlock:^(QGVAPSourceInfo * _Nonnull resource, NSUInteger idx, BOOL * _Nonnull stop) {
  71. NSString *tagContent = resource.contentTagValue;
  72. if ([resource.type isEqualToString:kQGAGAttachmentSourceTypeText] && [resource.loadType isEqualToString:QGAGAttachmentSourceLoadTypeLocal]) {
  73. resource.sourceImage = [QGVAPTextureLoader drawingImageForText:tagContent color:resource.color size:resource.size bold:[resource.style isEqualToString:kQGAGAttachmentSourceStyleBoldText]];
  74. }
  75. if ([resource.type isEqualToString:kQGAGAttachmentSourceTypeImg] && [resource.loadType isEqualToString:QGAGAttachmentSourceLoadTypeNet]) {
  76. NSString *imageURL = tagContent;
  77. NSDictionary *context = @{@"resource":resource};
  78. dispatch_group_enter(group);
  79. [self.delegate vap_loadImageWithURL:imageURL context:context completion:^(UIImage *image, NSError *error, NSString *imageURL) {
  80. if (!image || error) {
  81. VAP_Error(kQGVAPModuleCommon, @"loadImageWithURL %@ error:%@", imageURL, error);
  82. loadError = (loadError ?: (error ?: ([NSError errorWithDomain:[NSString stringWithFormat:@"loadImageError:%@", imageURL] code:-1 userInfo:nil])));
  83. }
  84. resource.sourceImage = image;
  85. dispatch_group_leave(group);
  86. }];
  87. }
  88. }];
  89. dispatch_group_notify(group, dispatch_get_main_queue(), ^{
  90. if ([self.delegate respondsToSelector:@selector(onVAPConfigResourcesLoaded:error:)]) {
  91. [self.delegate onVAPConfigResourcesLoaded:self.model error:loadError];
  92. }
  93. });
  94. }
  95. - (void)loadMTLTextures:(id<MTLDevice>)device {
  96. [self.model.resources enumerateObjectsUsingBlock:^(QGVAPSourceInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  97. id<MTLTexture> texture = [QGVAPTextureLoader loadTextureWithImage:obj.sourceImage device:device];
  98. obj.sourceImage = nil;
  99. obj.texture = texture;
  100. }];
  101. }
  102. - (void)loadMTLBuffers:(id<MTLDevice>)device {
  103. [self.model.resources enumerateObjectsUsingBlock:^(QGVAPSourceInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  104. id<MTLBuffer> buffer = [QGVAPTextureLoader loadVapColorFillBufferWith:obj.color device:device];
  105. obj.colorParamsBuffer = buffer;
  106. }];
  107. }
  108. #pragma mark - parse json
  109. - (void)parseConfigDictinary:(NSDictionary *)configDic {
  110. NSDictionary *commonInfoDic = [configDic hwd_dicValue:@"info"];
  111. NSArray *sourcesArr = [configDic hwd_arrValue:@"src"];
  112. NSArray *framesArr = [configDic hwd_arrValue:@"frame"];
  113. if (!commonInfoDic) {
  114. VAP_Error(kQGVAPModuleCommon, @"has no commonInfoDic:%@", configDic);
  115. return ;
  116. }
  117. QGVAPConfigModel *configModel = [QGVAPConfigModel new];
  118. //parse
  119. NSInteger version = [commonInfoDic hwd_integerValue:@"v"];
  120. NSInteger frameCount = [commonInfoDic hwd_integerValue:@"f"];
  121. CGFloat w = [commonInfoDic hwd_floatValue:@"w"];
  122. CGFloat h = [commonInfoDic hwd_floatValue:@"h"];
  123. CGFloat video_w = [commonInfoDic hwd_floatValue:@"videoW"];
  124. CGFloat video_h = [commonInfoDic hwd_floatValue:@"videoH"];
  125. CGFloat orientaion = [commonInfoDic hwd_integerValue:@"orien"];
  126. NSInteger fps = [commonInfoDic hwd_integerValue:@"fps"];
  127. BOOL isMerged = ([commonInfoDic hwd_integerValue:@"isVapx"] == 1);
  128. NSArray *a_frame = [commonInfoDic hwd_arrValue:@"aFrame"];
  129. NSArray *rgb_frame = [commonInfoDic hwd_arrValue:@"rgbFrame"];
  130. self.model = configModel;
  131. //整体信息
  132. QGVAPCommonInfo *commonInfo = [QGVAPCommonInfo new];
  133. commonInfo.version = version;
  134. commonInfo.framesCount = frameCount;
  135. commonInfo.size = CGSizeMake(w, h);
  136. commonInfo.videoSize = CGSizeMake(video_w, video_h);
  137. commonInfo.targetOrientaion = orientaion;
  138. commonInfo.fps = fps;
  139. commonInfo.isMerged = isMerged;
  140. commonInfo.alphaAreaRect = a_frame ? [a_frame hwd_rectValue] : CGRectZero;
  141. commonInfo.rgbAreaRect = rgb_frame ? [rgb_frame hwd_rectValue] : CGRectZero;
  142. configModel.info = commonInfo;
  143. //更新parser的fps信息
  144. _fileInfo.mp4Parser.fps = fps;
  145. if (!sourcesArr) {
  146. VAP_Error(kQGVAPModuleCommon, @"has no sourcesArr:%@", configDic);
  147. return ;
  148. }
  149. //源信息
  150. NSMutableDictionary <NSString *, QGVAPSourceInfo *>*sources = [NSMutableDictionary new];
  151. [sourcesArr enumerateObjectsUsingBlock:^(NSDictionary *sourceDic, NSUInteger idx, BOOL * _Nonnull stop) {
  152. if (![sourceDic isKindOfClass:[NSDictionary class]]) {
  153. VAP_Error(kQGVAPModuleCommon, @"sourceDic is not dic:%@", sourceDic);
  154. return ;
  155. }
  156. NSString *sourceID = [sourceDic hwd_stringValue:@"srcId"];
  157. if (!sourceID) {
  158. VAP_Error(kQGVAPModuleCommon, @"has no sourceID:%@", sourceDic);
  159. return ;
  160. }
  161. //parse
  162. QGAGAttachmentSourceType sourceType = [sourceDic hwd_stringValue:@"srcType"];
  163. QGAGAttachmentSourceLoadType loadType = [sourceDic hwd_stringValue:@"loadType"];
  164. NSString *contentTag = [sourceDic hwd_stringValue:@"srcTag"];
  165. UIColor *color = [UIColor hwd_colorWithHexString:[sourceDic hwd_stringValue:@"color"]];
  166. QGAGAttachmentSourceStyle style = [sourceDic hwd_stringValue:@"style"];
  167. CGFloat width = [sourceDic hwd_floatValue:@"w"];
  168. CGFloat height = [sourceDic hwd_floatValue:@"h"];
  169. QGAGAttachmentFitType fitType = [sourceDic hwd_stringValue:@"fitType"];
  170. QGVAPSourceInfo *sourceInfo = [QGVAPSourceInfo new];
  171. sourceInfo.type = sourceType;
  172. sourceInfo.style = style;
  173. sourceInfo.contentTag = contentTag;
  174. sourceInfo.color = color;
  175. sourceInfo.size = CGSizeMake(width, height);
  176. sourceInfo.fitType = fitType;
  177. sourceInfo.loadType = loadType;
  178. sources[sourceID] = sourceInfo;
  179. }];
  180. configModel.resources = sources.allValues;
  181. //融合信息
  182. if (!framesArr) {
  183. VAP_Error(kQGVAPModuleCommon, @"has no framesArr:%@", configDic);
  184. return ;
  185. }
  186. NSMutableDictionary <NSNumber *, NSArray<QGVAPMergedInfo *>*> *mergedConfig = [NSMutableDictionary new];
  187. [framesArr enumerateObjectsUsingBlock:^(NSDictionary *frameMergedDic, NSUInteger idx, BOOL * _Nonnull stop) {
  188. if (![frameMergedDic isKindOfClass:[NSDictionary class]]) {
  189. VAP_Error(kQGVAPModuleCommon, @"frameMergedDic is not dic:%@", frameMergedDic);
  190. return ;
  191. }
  192. NSInteger frameIndex = [frameMergedDic hwd_integerValue:@"i"];
  193. NSMutableArray <QGVAPMergedInfo *> *mergedInfos = [NSMutableArray new];
  194. NSArray *mergedObjs = [frameMergedDic hwd_arrValue:@"obj"];
  195. [mergedObjs enumerateObjectsUsingBlock:^(NSDictionary *mergeInfoDic, NSUInteger idx, BOOL * _Nonnull stop) {
  196. if (![mergeInfoDic isKindOfClass:[NSDictionary class]]) {
  197. VAP_Error(kQGVAPModuleCommon, @"mergeInfoDic is not dic:%@", mergeInfoDic);
  198. return ;
  199. }
  200. NSString *sourceID = [mergeInfoDic hwd_stringValue:@"srcId"];
  201. QGVAPSourceInfo *sourceInfo = sources[sourceID];
  202. if (!sourceInfo) {
  203. VAP_Error(kQGVAPModuleCommon, @"sourceInfo is nil:%@", mergeInfoDic);
  204. return ;
  205. }
  206. //parse
  207. NSArray *frame = [mergeInfoDic hwd_arrValue:@"frame"];
  208. NSArray *m_frame = [mergeInfoDic hwd_arrValue:@"mFrame"];
  209. NSInteger renderIndex = [mergeInfoDic hwd_integerValue:@"z"];
  210. NSInteger rotationAngle = [mergeInfoDic hwd_integerValue:@"mt"];
  211. QGVAPMergedInfo *mergeInfo = [QGVAPMergedInfo new];
  212. mergeInfo.source = sourceInfo;
  213. mergeInfo.renderIndex = renderIndex;
  214. mergeInfo.needMask = (m_frame != nil);
  215. mergeInfo.renderRect = frame ? [frame hwd_rectValue] : CGRectZero;
  216. mergeInfo.maskRect = m_frame ? [m_frame hwd_rectValue] : CGRectZero;
  217. mergeInfo.maskRotation = rotationAngle;
  218. [mergedInfos addObject:mergeInfo];
  219. }];
  220. NSArray *sortedMergeInfos = [mergedInfos sortedArrayUsingComparator:^NSComparisonResult(QGVAPMergedInfo *info1, QGVAPMergedInfo *info2) {
  221. return [@(info1.renderIndex) compare:@(info2.renderIndex)];
  222. }];
  223. mergedConfig[@(frameIndex)] = sortedMergeInfos;
  224. }];
  225. configModel.mergedConfig = mergedConfig;
  226. }
  227. @end