QGAnimatedImageDecodeManager.m 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // QGAnimatedImageDecodeManager.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 "QGAnimatedImageDecodeManager.h"
  16. #import "QGAnimatedImageBufferManager.h"
  17. #import "QGBaseDecoder.h"
  18. #import "QGVAPSafeMutableArray.h"
  19. #import "QGMP4FrameHWDecoder.h"
  20. #import "QGVAPLogger.h"
  21. #import <sys/stat.h>
  22. #import <AVFoundation/AVFoundation.h>
  23. @interface QGAnimatedImageDecodeManager() {
  24. QGAnimatedImageDecodeConfig *_config; //解码配置
  25. QGBaseDFileInfo *_fileInfo; //sharpP文件信息
  26. NSMutableArray *_decoders; //解码器
  27. QGAnimatedImageBufferManager *_bufferManager; //缓冲管理
  28. AVAudioPlayer *_audioPlayer;
  29. }
  30. @end
  31. @implementation QGAnimatedImageDecodeManager
  32. - (instancetype)initWith:(QGBaseDFileInfo *)fileInfo
  33. config:(QGAnimatedImageDecodeConfig *)config
  34. delegate:(id<QGAnimatedImageDecoderDelegate>)delegate {
  35. if (self = [super init]) {
  36. _config = config;
  37. _fileInfo = fileInfo;
  38. _decoderDelegate = delegate;
  39. [self createDecodersByConfig:config];
  40. _bufferManager = [[QGAnimatedImageBufferManager alloc] initWithConfig:config];
  41. [self initializeBuffersFromIndex:0];
  42. [self setupAudioPlayerIfNeed];
  43. }
  44. return self;
  45. }
  46. /**
  47. 取出已解码的一帧并准备下一帧
  48. @param frameIndex 帧索引
  49. @return 帧内容
  50. */
  51. - (QGBaseAnimatedImageFrame *)consumeDecodedFrame:(NSInteger)frameIndex {
  52. @synchronized (self) {
  53. // 控制何时命中第一帧,缓存满了才命中
  54. if (frameIndex == 0 && _bufferManager.buffers.count < _config.bufferCount) {
  55. return nil;
  56. }
  57. BOOL decodeFinish = [self checkIfDecodeFinish:frameIndex];
  58. QGBaseAnimatedImageFrame *frame = [_bufferManager popVideoFrame];
  59. if (frame) {
  60. // pts顺序
  61. frame.frameIndex = frameIndex;
  62. [self decodeFrame:frameIndex+_config.bufferCount];
  63. }
  64. else if (!decodeFinish){
  65. // buffer已经空了,但还没有结束(退后台时可能出现这种情况)
  66. NSInteger decoderIndex = _decoders.count==1?0:frameIndex%_decoders.count;
  67. QGBaseDecoder *decoder = _decoders[decoderIndex];
  68. if ([decoder shouldStopDecode:frameIndex]) {
  69. // 其实已经该结束了
  70. if ([self.decoderDelegate respondsToSelector:@selector(decoderDidFinishDecode:)]) {
  71. [self.decoderDelegate decoderDidFinishDecode:decoder];
  72. }
  73. return nil;
  74. }
  75. [self initializeBuffersFromIndex:frameIndex];
  76. }
  77. return frame;
  78. }
  79. }
  80. - (void)tryToStartAudioPlay {
  81. if (!_audioPlayer) {
  82. return ;
  83. }
  84. [_audioPlayer play];
  85. }
  86. #pragma mark - private methods
  87. - (BOOL)checkIfDecodeFinish:(NSInteger)frameIndex {
  88. NSInteger decoderIndex = _decoders.count==1?0:frameIndex%_decoders.count;
  89. QGBaseDecoder *decoder = _decoders[decoderIndex];
  90. if ([decoder isFrameIndexBeyondEnd:frameIndex]) {
  91. if ([self.decoderDelegate respondsToSelector:@selector(decoderDidFinishDecode:)]) {
  92. [self.decoderDelegate decoderDidFinishDecode:decoder];
  93. }
  94. return YES;
  95. }
  96. return NO;
  97. }
  98. - (void)decodeFrame:(NSInteger)frameIndex {
  99. if (!_decoders || _decoders.count == 0) {
  100. //NSLog(@"error! can't find decoder");
  101. return ;
  102. }
  103. NSInteger decoderIndex = _decoders.count==1?0:frameIndex%_decoders.count;
  104. QGBaseDecoder *decoder = _decoders[decoderIndex];
  105. if ([decoder shouldStopDecode:frameIndex]) {
  106. return ;
  107. }
  108. [decoder decodeFrame:frameIndex buffers:_bufferManager.buffers];
  109. }
  110. - (void)createDecodersByConfig:(QGAnimatedImageDecodeConfig *)config {
  111. if (!self.decoderDelegate || ![self.decoderDelegate respondsToSelector:@selector(decoderClassForManager:)]) {
  112. VAP_Event(kQGVAPModuleCommon, @"you MUST implement the delegate in invoker!");
  113. NSAssert(0, @"you MUST implement the delegate in invoker!");
  114. return ;
  115. }
  116. _decoders = [QGVAPSafeMutableArray new];
  117. for (int i = 0; i < config.threadCount; i ++) {
  118. Class class = [self.decoderDelegate decoderClassForManager:self];
  119. NSError *error = nil;
  120. QGBaseDecoder *decoder = [class alloc];
  121. decoder = [decoder initWith:_fileInfo error:&error];
  122. if (!decoder) {
  123. if ([self.decoderDelegate respondsToSelector:@selector(decoderDidFailDecode:error:)]) {
  124. [self.decoderDelegate decoderDidFailDecode:nil error:error];
  125. }
  126. break ;
  127. }
  128. [_decoders addObject:decoder];
  129. }
  130. }
  131. - (void)initializeBuffersFromIndex:(NSInteger)start {
  132. for (int i = 0; i < _config.bufferCount; i++) {
  133. [self decodeFrame:start+i];
  134. }
  135. }
  136. - (void)setupAudioPlayerIfNeed {
  137. if ([_fileInfo isKindOfClass:[QGMP4HWDFileInfo class]]) {
  138. QGMP4ParserProxy *mp4Parser = [(QGMP4HWDFileInfo *)_fileInfo mp4Parser];
  139. if (!mp4Parser.audioTrackBox) {
  140. _audioPlayer = nil;
  141. return ;
  142. }
  143. NSError *error;
  144. _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:_fileInfo.filePath] error:&error];
  145. }
  146. }
  147. - (void)dealloc {
  148. }
  149. - (BOOL)containsThisDeocder:(id)decoder {
  150. for (id d in _decoders) {
  151. if (d == decoder) {
  152. return YES;
  153. }
  154. }
  155. return NO;
  156. }
  157. @end