QGAnimatedImageDecodeManager.m 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. - (void)tryToStopAudioPlay {
  87. if (!_audioPlayer) {
  88. return;
  89. }
  90. // CoreAudio(AVAudioPlaeyrCpp)回调audioPlayerDidFinishPlaying:successfully:时在子线程,恰巧此时释放将可能导致野指针问题
  91. // 如果只是stop不能解决,可以考虑产生循环持有并延迟释放_audioPlayer
  92. [_audioPlayer stop];
  93. }
  94. - (void)tryToPauseAudioPlay {
  95. if (!_audioPlayer) {
  96. return;
  97. }
  98. [_audioPlayer pause];
  99. }
  100. - (void)tryToResumeAudioPlay {
  101. if (!_audioPlayer) {
  102. return;
  103. }
  104. [_audioPlayer play];
  105. }
  106. #pragma mark - private methods
  107. - (BOOL)checkIfDecodeFinish:(NSInteger)frameIndex {
  108. NSInteger decoderIndex = _decoders.count==1?0:frameIndex%_decoders.count;
  109. QGBaseDecoder *decoder = _decoders[decoderIndex];
  110. if ([decoder isFrameIndexBeyondEnd:frameIndex]) {
  111. if ([self.decoderDelegate respondsToSelector:@selector(decoderDidFinishDecode:)]) {
  112. [self.decoderDelegate decoderDidFinishDecode:decoder];
  113. }
  114. return YES;
  115. }
  116. return NO;
  117. }
  118. - (void)decodeFrame:(NSInteger)frameIndex {
  119. if (!_decoders || _decoders.count == 0) {
  120. //MOLogV(@"error! can't find decoder");
  121. return ;
  122. }
  123. NSInteger decoderIndex = _decoders.count==1?0:frameIndex%_decoders.count;
  124. QGBaseDecoder *decoder = _decoders[decoderIndex];
  125. if ([decoder shouldStopDecode:frameIndex]) {
  126. return ;
  127. }
  128. [decoder decodeFrame:frameIndex buffers:_bufferManager.buffers];
  129. }
  130. - (void)createDecodersByConfig:(QGAnimatedImageDecodeConfig *)config {
  131. if (!self.decoderDelegate || ![self.decoderDelegate respondsToSelector:@selector(decoderClassForManager:)]) {
  132. VAP_Event(kQGVAPModuleCommon, @"you MUST implement the delegate in invoker!");
  133. NSAssert(0, @"you MUST implement the delegate in invoker!");
  134. return ;
  135. }
  136. _decoders = [QGVAPSafeMutableArray new];
  137. for (int i = 0; i < config.threadCount; i ++) {
  138. Class class = [self.decoderDelegate decoderClassForManager:self];
  139. NSError *error = nil;
  140. QGBaseDecoder *decoder = [class alloc];
  141. decoder = [decoder initWith:_fileInfo error:&error];
  142. if (!decoder) {
  143. if ([self.decoderDelegate respondsToSelector:@selector(decoderDidFailDecode:error:)]) {
  144. [self.decoderDelegate decoderDidFailDecode:nil error:error];
  145. }
  146. break ;
  147. }
  148. [_decoders addObject:decoder];
  149. }
  150. }
  151. - (void)initializeBuffersFromIndex:(NSInteger)start {
  152. for (int i = 0; i < _config.bufferCount; i++) {
  153. [self decodeFrame:start+i];
  154. }
  155. }
  156. - (void)setupAudioPlayerIfNeed {
  157. if ([_decoderDelegate respondsToSelector:@selector(shouldSetupAudioPlayer)]) {
  158. BOOL should = [_decoderDelegate shouldSetupAudioPlayer];
  159. if (!should) {
  160. return;
  161. }
  162. }
  163. if ([_fileInfo isKindOfClass:[QGMP4HWDFileInfo class]]) {
  164. QGMP4ParserProxy *mp4Parser = [(QGMP4HWDFileInfo *)_fileInfo mp4Parser];
  165. if (!mp4Parser.audioTrackBox) {
  166. _audioPlayer = nil;
  167. return ;
  168. }
  169. NSError *error;
  170. _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:_fileInfo.filePath] error:&error];
  171. }
  172. }
  173. - (void)dealloc {
  174. }
  175. - (BOOL)containsThisDeocder:(id)decoder {
  176. for (id d in _decoders) {
  177. if (d == decoder) {
  178. return YES;
  179. }
  180. }
  181. return NO;
  182. }
  183. @end