123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- // QGAnimatedImageDecodeManager.m
- // Tencent is pleased to support the open source community by making vap available.
- //
- // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
- //
- // Licensed under the MIT License (the "License"); you may not use this file except in
- // compliance with the License. You may obtain a copy of the License at
- //
- // http://opensource.org/licenses/MIT
- //
- // Unless required by applicable law or agreed to in writing, software distributed under the License is
- // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
- // either express or implied. See the License for the specific language governing permissions and
- // limitations under the License.
- #import "QGAnimatedImageDecodeManager.h"
- #import "QGAnimatedImageBufferManager.h"
- #import "QGBaseDecoder.h"
- #import "QGVAPSafeMutableArray.h"
- #import "QGMP4FrameHWDecoder.h"
- #import "QGVAPLogger.h"
- #import <sys/stat.h>
- #import <AVFoundation/AVFoundation.h>
- @interface QGAnimatedImageDecodeManager() {
- QGAnimatedImageDecodeConfig *_config; //解码配置
- QGBaseDFileInfo *_fileInfo; //sharpP文件信息
- NSMutableArray *_decoders; //解码器
- QGAnimatedImageBufferManager *_bufferManager; //缓冲管理
- AVAudioPlayer *_audioPlayer;
- }
- @end
- @implementation QGAnimatedImageDecodeManager
- - (instancetype)initWith:(QGBaseDFileInfo *)fileInfo
- config:(QGAnimatedImageDecodeConfig *)config
- delegate:(id<QGAnimatedImageDecoderDelegate>)delegate {
- if (self = [super init]) {
-
- _config = config;
- _fileInfo = fileInfo;
- _decoderDelegate = delegate;
- [self createDecodersByConfig:config];
- _bufferManager = [[QGAnimatedImageBufferManager alloc] initWithConfig:config];
- [self initializeBuffersFromIndex:0];
- [self setupAudioPlayerIfNeed];
- }
- return self;
- }
- /**
- 取出已解码的一帧并准备下一帧
-
- @param frameIndex 帧索引
- @return 帧内容
- */
- - (QGBaseAnimatedImageFrame *)consumeDecodedFrame:(NSInteger)frameIndex {
- @synchronized (self) {
- // 控制何时命中第一帧,缓存满了才命中
- if (frameIndex == 0 && _bufferManager.buffers.count < _config.bufferCount) {
- return nil;
- }
- BOOL decodeFinish = [self checkIfDecodeFinish:frameIndex];
- QGBaseAnimatedImageFrame *frame = [_bufferManager popVideoFrame];
- if (frame) {
- // pts顺序
- frame.frameIndex = frameIndex;
- [self decodeFrame:frameIndex+_config.bufferCount];
- }
- else if (!decodeFinish){
- // buffer已经空了,但还没有结束(退后台时可能出现这种情况)
- NSInteger decoderIndex = _decoders.count==1?0:frameIndex%_decoders.count;
- QGBaseDecoder *decoder = _decoders[decoderIndex];
- if ([decoder shouldStopDecode:frameIndex]) {
- // 其实已经该结束了
- if ([self.decoderDelegate respondsToSelector:@selector(decoderDidFinishDecode:)]) {
- [self.decoderDelegate decoderDidFinishDecode:decoder];
- }
- return nil;
- }
-
- [self initializeBuffersFromIndex:frameIndex];
- }
- return frame;
- }
- }
- - (void)tryToStartAudioPlay {
- if (!_audioPlayer) {
- return ;
- }
- [_audioPlayer play];
- }
- #pragma mark - private methods
- - (BOOL)checkIfDecodeFinish:(NSInteger)frameIndex {
-
- NSInteger decoderIndex = _decoders.count==1?0:frameIndex%_decoders.count;
- QGBaseDecoder *decoder = _decoders[decoderIndex];
- if ([decoder isFrameIndexBeyondEnd:frameIndex]) {
- if ([self.decoderDelegate respondsToSelector:@selector(decoderDidFinishDecode:)]) {
- [self.decoderDelegate decoderDidFinishDecode:decoder];
- }
- return YES;
- }
- return NO;
- }
- - (void)decodeFrame:(NSInteger)frameIndex {
- if (!_decoders || _decoders.count == 0) {
- //NSLog(@"error! can't find decoder");
- return ;
- }
- NSInteger decoderIndex = _decoders.count==1?0:frameIndex%_decoders.count;
- QGBaseDecoder *decoder = _decoders[decoderIndex];
- if ([decoder shouldStopDecode:frameIndex]) {
- return ;
- }
- [decoder decodeFrame:frameIndex buffers:_bufferManager.buffers];
- }
- - (void)createDecodersByConfig:(QGAnimatedImageDecodeConfig *)config {
- if (!self.decoderDelegate || ![self.decoderDelegate respondsToSelector:@selector(decoderClassForManager:)]) {
- VAP_Event(kQGVAPModuleCommon, @"you MUST implement the delegate in invoker!");
- NSAssert(0, @"you MUST implement the delegate in invoker!");
- return ;
- }
-
- _decoders = [QGVAPSafeMutableArray new];
- for (int i = 0; i < config.threadCount; i ++) {
- Class class = [self.decoderDelegate decoderClassForManager:self];
- NSError *error = nil;
- QGBaseDecoder *decoder = [class alloc];
- decoder = [decoder initWith:_fileInfo error:&error];
- if (!decoder) {
- if ([self.decoderDelegate respondsToSelector:@selector(decoderDidFailDecode:error:)]) {
- [self.decoderDelegate decoderDidFailDecode:nil error:error];
- }
- break ;
- }
- [_decoders addObject:decoder];
- }
- }
- - (void)initializeBuffersFromIndex:(NSInteger)start {
-
- for (int i = 0; i < _config.bufferCount; i++) {
- [self decodeFrame:start+i];
- }
- }
- - (void)setupAudioPlayerIfNeed {
-
- if ([_fileInfo isKindOfClass:[QGMP4HWDFileInfo class]]) {
- QGMP4ParserProxy *mp4Parser = [(QGMP4HWDFileInfo *)_fileInfo mp4Parser];
- if (!mp4Parser.audioTrackBox) {
- _audioPlayer = nil;
- return ;
- }
- NSError *error;
- _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:_fileInfo.filePath] error:&error];
- }
- }
- - (void)dealloc {
- }
- - (BOOL)containsThisDeocder:(id)decoder {
- for (id d in _decoders) {
- if (d == decoder) {
- return YES;
- }
- }
- return NO;
- }
- @end
|