SVGAVideoEntity.m 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. //
  2. // SVGAVideoEntity.m
  3. // SVGAPlayer
  4. //
  5. // Created by 崔明辉 on 16/6/17.
  6. // Copyright © 2016年 UED Center. All rights reserved.
  7. //
  8. #import <AVFoundation/AVFoundation.h>
  9. #import "SVGAVideoEntity.h"
  10. #import "SVGABezierPath.h"
  11. #import "SVGAVideoSpriteEntity.h"
  12. #import "SVGAAudioEntity.h"
  13. #import "Svga.pbobjc.h"
  14. #define MP3_MAGIC_NUMBER "ID3"
  15. @interface SVGAVideoEntity ()
  16. @property (nonatomic, assign) CGSize videoSize;
  17. @property (nonatomic, assign) int FPS;
  18. @property (nonatomic, assign) int frames;
  19. @property (nonatomic, copy) NSDictionary<NSString *, UIImage *> *images;
  20. @property (nonatomic, copy) NSDictionary<NSString *, NSData *> *audiosData;
  21. @property (nonatomic, copy) NSArray<SVGAVideoSpriteEntity *> *sprites;
  22. @property (nonatomic, copy) NSArray<SVGAAudioEntity *> *audios;
  23. @property (nonatomic, copy) NSString *cacheDir;
  24. @end
  25. @implementation SVGAVideoEntity
  26. static NSCache *videoCache;
  27. static NSMapTable * weakCache;
  28. static dispatch_semaphore_t videoSemaphore;
  29. + (void)load {
  30. static dispatch_once_t onceToken;
  31. dispatch_once(&onceToken, ^{
  32. videoCache = [[NSCache alloc] init];
  33. weakCache = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
  34. valueOptions:NSPointerFunctionsWeakMemory
  35. capacity:64];
  36. videoSemaphore = dispatch_semaphore_create(1);
  37. });
  38. }
  39. - (instancetype)initWithJSONObject:(NSDictionary *)JSONObject cacheDir:(NSString *)cacheDir {
  40. self = [super init];
  41. if (self) {
  42. _videoSize = CGSizeMake(100, 100);
  43. _FPS = 20;
  44. _images = @{};
  45. _cacheDir = cacheDir;
  46. [self resetMovieWithJSONObject:JSONObject];
  47. }
  48. return self;
  49. }
  50. - (void)resetMovieWithJSONObject:(NSDictionary *)JSONObject {
  51. if ([JSONObject isKindOfClass:[NSDictionary class]]) {
  52. NSDictionary *movieObject = JSONObject[@"movie"];
  53. if ([movieObject isKindOfClass:[NSDictionary class]]) {
  54. NSDictionary *viewBox = movieObject[@"viewBox"];
  55. if ([viewBox isKindOfClass:[NSDictionary class]]) {
  56. NSNumber *width = viewBox[@"width"];
  57. NSNumber *height = viewBox[@"height"];
  58. if ([width isKindOfClass:[NSNumber class]] && [height isKindOfClass:[NSNumber class]]) {
  59. _videoSize = CGSizeMake(width.floatValue, height.floatValue);
  60. }
  61. }
  62. NSNumber *FPS = movieObject[@"fps"];
  63. if ([FPS isKindOfClass:[NSNumber class]]) {
  64. _FPS = [FPS intValue];
  65. }
  66. NSNumber *frames = movieObject[@"frames"];
  67. if ([frames isKindOfClass:[NSNumber class]]) {
  68. _frames = [frames intValue];
  69. }
  70. }
  71. }
  72. }
  73. - (void)resetImagesWithJSONObject:(NSDictionary *)JSONObject {
  74. if ([JSONObject isKindOfClass:[NSDictionary class]]) {
  75. NSMutableDictionary<NSString *, UIImage *> *images = [[NSMutableDictionary alloc] init];
  76. NSDictionary<NSString *, NSString *> *JSONImages = JSONObject[@"images"];
  77. if ([JSONImages isKindOfClass:[NSDictionary class]]) {
  78. [JSONImages enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
  79. if ([obj isKindOfClass:[NSString class]]) {
  80. NSString *filePath = [self.cacheDir stringByAppendingFormat:@"/%@.png", obj];
  81. // NSData *imageData = [NSData dataWithContentsOfFile:filePath];
  82. NSData *imageData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:NULL];
  83. if (imageData != nil) {
  84. UIImage *image = [[UIImage alloc] initWithData:imageData scale:2.0];
  85. if (image != nil) {
  86. [images setObject:image forKey:[key stringByDeletingPathExtension]];
  87. }
  88. }
  89. }
  90. }];
  91. }
  92. self.images = images;
  93. }
  94. }
  95. - (void)resetSpritesWithJSONObject:(NSDictionary *)JSONObject {
  96. if ([JSONObject isKindOfClass:[NSDictionary class]]) {
  97. NSMutableArray<SVGAVideoSpriteEntity *> *sprites = [[NSMutableArray alloc] init];
  98. NSArray<NSDictionary *> *JSONSprites = JSONObject[@"sprites"];
  99. if ([JSONSprites isKindOfClass:[NSArray class]]) {
  100. [JSONSprites enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  101. if ([obj isKindOfClass:[NSDictionary class]]) {
  102. SVGAVideoSpriteEntity *spriteItem = [[SVGAVideoSpriteEntity alloc] initWithJSONObject:obj];
  103. [sprites addObject:spriteItem];
  104. }
  105. }];
  106. }
  107. self.sprites = sprites;
  108. }
  109. }
  110. - (instancetype)initWithProtoObject:(SVGAProtoMovieEntity *)protoObject cacheDir:(NSString *)cacheDir {
  111. self = [super init];
  112. if (self) {
  113. _videoSize = CGSizeMake(100, 100);
  114. _FPS = 20;
  115. _images = @{};
  116. _cacheDir = cacheDir;
  117. [self resetMovieWithProtoObject:protoObject];
  118. }
  119. return self;
  120. }
  121. - (void)resetMovieWithProtoObject:(SVGAProtoMovieEntity *)protoObject {
  122. if (protoObject.hasParams) {
  123. self.videoSize = CGSizeMake((CGFloat)protoObject.params.viewBoxWidth, (CGFloat)protoObject.params.viewBoxHeight);
  124. self.FPS = (int)protoObject.params.fps;
  125. self.frames = (int)protoObject.params.frames;
  126. }
  127. }
  128. + (BOOL)isMP3Data:(NSData *)data {
  129. BOOL result = NO;
  130. if (!strncmp([data bytes], MP3_MAGIC_NUMBER, strlen(MP3_MAGIC_NUMBER))) {
  131. result = YES;
  132. }
  133. return result;
  134. }
  135. - (void)resetImagesWithProtoObject:(SVGAProtoMovieEntity *)protoObject {
  136. NSMutableDictionary<NSString *, UIImage *> *images = [[NSMutableDictionary alloc] init];
  137. NSMutableDictionary<NSString *, NSData *> *audiosData = [[NSMutableDictionary alloc] init];
  138. NSDictionary *protoImages = [protoObject.images copy];
  139. for (NSString *key in protoImages) {
  140. NSString *fileName = [[NSString alloc] initWithData:protoImages[key] encoding:NSUTF8StringEncoding];
  141. if (fileName != nil) {
  142. NSString *filePath = [self.cacheDir stringByAppendingFormat:@"/%@.png", fileName];
  143. if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
  144. filePath = [self.cacheDir stringByAppendingFormat:@"/%@", fileName];
  145. }
  146. if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
  147. // NSData *imageData = [NSData dataWithContentsOfFile:filePath];
  148. NSData *imageData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:NULL];
  149. if (imageData != nil) {
  150. UIImage *image = [[UIImage alloc] initWithData:imageData scale:2.0];
  151. if (image != nil) {
  152. [images setObject:image forKey:key];
  153. }
  154. }
  155. }
  156. }
  157. else if ([protoImages[key] isKindOfClass:[NSData class]]) {
  158. if ([SVGAVideoEntity isMP3Data:protoImages[key]]) {
  159. // mp3
  160. [audiosData setObject:protoImages[key] forKey:key];
  161. } else {
  162. UIImage *image = [[UIImage alloc] initWithData:protoImages[key] scale:2.0];
  163. if (image != nil) {
  164. [images setObject:image forKey:key];
  165. }
  166. }
  167. }
  168. }
  169. self.images = images;
  170. self.audiosData = audiosData;
  171. }
  172. - (void)resetSpritesWithProtoObject:(SVGAProtoMovieEntity *)protoObject {
  173. NSMutableArray<SVGAVideoSpriteEntity *> *sprites = [[NSMutableArray alloc] init];
  174. NSArray *protoSprites = [protoObject.spritesArray copy];
  175. [protoSprites enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  176. if ([obj isKindOfClass:[SVGAProtoSpriteEntity class]]) {
  177. SVGAVideoSpriteEntity *spriteItem = [[SVGAVideoSpriteEntity alloc] initWithProtoObject:obj];
  178. [sprites addObject:spriteItem];
  179. }
  180. }];
  181. self.sprites = sprites;
  182. }
  183. - (void)resetAudiosWithProtoObject:(SVGAProtoMovieEntity *)protoObject {
  184. NSMutableArray<SVGAAudioEntity *> *audios = [[NSMutableArray alloc] init];
  185. NSArray *protoAudios = [protoObject.audiosArray copy];
  186. [protoAudios enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  187. if ([obj isKindOfClass:[SVGAProtoAudioEntity class]]) {
  188. SVGAAudioEntity *audioItem = [[SVGAAudioEntity alloc] initWithProtoObject:obj];
  189. [audios addObject:audioItem];
  190. }
  191. }];
  192. self.audios = audios;
  193. }
  194. + (SVGAVideoEntity *)readCache:(NSString *)cacheKey {
  195. dispatch_semaphore_wait(videoSemaphore, DISPATCH_TIME_FOREVER);
  196. SVGAVideoEntity * object = [videoCache objectForKey:cacheKey];
  197. if (!object) {
  198. object = [weakCache objectForKey:cacheKey];
  199. }
  200. dispatch_semaphore_signal(videoSemaphore);
  201. return object;
  202. }
  203. - (void)saveCache:(NSString *)cacheKey {
  204. dispatch_semaphore_wait(videoSemaphore, DISPATCH_TIME_FOREVER);
  205. [videoCache setObject:self forKey:cacheKey];
  206. dispatch_semaphore_signal(videoSemaphore);
  207. }
  208. - (void)saveWeakCache:(NSString *)cacheKey {
  209. dispatch_semaphore_wait(videoSemaphore, DISPATCH_TIME_FOREVER);
  210. [weakCache setObject:self forKey:cacheKey];
  211. dispatch_semaphore_signal(videoSemaphore);
  212. }
  213. - (void)clearCache:(NSString *)cacheKey {
  214. dispatch_semaphore_wait(videoSemaphore, DISPATCH_TIME_FOREVER);
  215. [videoCache removeObjectForKey:cacheKey];
  216. [weakCache removeObjectForKey:cacheKey];
  217. dispatch_semaphore_signal(videoSemaphore);
  218. }
  219. + (void)clearCache:(NSString *)cacheKey {
  220. dispatch_semaphore_wait(videoSemaphore, DISPATCH_TIME_FOREVER);
  221. [videoCache removeObjectForKey:cacheKey];
  222. [weakCache removeObjectForKey:cacheKey];
  223. dispatch_semaphore_signal(videoSemaphore);
  224. }
  225. //- (void)dealloc {
  226. // NSLog(@"===== SVGAVideoEntity =====");
  227. //}
  228. @end
  229. @interface SVGAVideoSpriteEntity()
  230. @property (nonatomic, copy) NSString *imageKey;
  231. @property (nonatomic, copy) NSArray<SVGAVideoSpriteFrameEntity *> *frames;
  232. @property (nonatomic, copy) NSString *matteKey;
  233. @end