Browse Source

Merge pull request #88 from Tencent/feature/ios_background

fix: 修复退后台继续播放导致花屏的问题
StyxS 5 years ago
parent
commit
5846db29ec

+ 3 - 0
iOS/QGVAPlayer/QGVAPlayer/Classes/Controllers/Decoders/QGBaseDecoder.h

@@ -17,6 +17,9 @@
 #import "QGAnimatedImageDecodeThread.h"
 #import "QGBaseDFileInfo.h"
 
+extern NSString* kQGVAPDecoderSeekStart;
+extern NSString* kQGVAPDecoderSeekFinish;
+
 @interface QGBaseDecoder : NSObject
 
 @property (atomic, assign) NSInteger currentDecodeFrame;    //正在解码的帧索引

+ 3 - 0
iOS/QGVAPlayer/QGVAPlayer/Classes/Controllers/Decoders/QGBaseDecoder.m

@@ -16,6 +16,9 @@
 #import "QGBaseDecoder.h"
 #import "QGAnimatedImageDecodeThreadPool.h"
 
+NSString* kQGVAPDecoderSeekStart = @"kQGVAPDecoderSeekStart";
+NSString* kQGVAPDecoderSeekFinish = @"kQGVAPDecoderSeekFinish";
+
 @interface QGBaseDecoder() {
 
     QGBaseDFileInfo *_fileInfo;

+ 14 - 0
iOS/QGVAPlayer/QGVAPlayer/Classes/Controllers/Decoders/QGMP4FrameHWDecoder.m

@@ -96,6 +96,8 @@
 /** Video Parameter Set */
 @property (nonatomic, strong) NSData *vpsData;
 
+@property (atomic, assign) NSInteger lastDecodeFrame;
+
 @end
 
 NSString *const QGMP4HWDErrorDomain = @"QGMP4HWDErrorDomain";
@@ -136,6 +138,7 @@ NSString *const QGMP4HWDErrorDomain = @"QGMP4HWDErrorDomain";
     
     if (self = [super initWith:fileInfo error:error]) {
         _decodeQueue = dispatch_queue_create("com.qgame.vap.decode", DISPATCH_QUEUE_SERIAL);
+        _lastDecodeFrame = -1;
         _mp4Parser = fileInfo.mp4Parser;
         BOOL isOpenSuccess = [self onInputStart];
         if (!isOpenSuccess) {
@@ -166,6 +169,10 @@ NSString *const QGMP4HWDErrorDomain = @"QGMP4HWDErrorDomain";
     self.currentDecodeFrame = frameIndex;
     _buffers = buffers;
     dispatch_async(self.decodeQueue, ^{
+        if (frameIndex != self.lastDecodeFrame + 1) {
+            // 必须是依次增大,否则解出来的画面会异常
+            return;
+        }
         [self _decodeFrame:frameIndex drop:NO];
     });
 }
@@ -294,6 +301,8 @@ NSString *const QGMP4HWDErrorDomain = @"QGMP4HWDErrorDomain";
                          status:(OSStatus)status
                        needDrop:(BOOL)dropFlag {
     
+    self.lastDecodeFrame = frameIndex;
+    
     CFRelease(sampleBuffer);
     
     if(status == kVTInvalidSessionErr) {
@@ -489,6 +498,9 @@ NSString *const QGMP4HWDErrorDomain = @"QGMP4HWDErrorDomain";
 }
 
 - (void)findKeyFrameAndDecodeToCurrent:(NSInteger)frameIndex {
+    
+    [[NSNotificationCenter defaultCenter] postNotificationName:kQGVAPDecoderSeekStart object:self];
+    
     NSArray<NSNumber *> *keyframeIndexes = [_mp4Parser videoSyncSampleIndexes];
     NSInteger index = [[keyframeIndexes firstObject] integerValue];
     for(NSNumber *number in keyframeIndexes) {
@@ -506,6 +518,8 @@ NSString *const QGMP4HWDErrorDomain = @"QGMP4HWDErrorDomain";
         index++;
     }
     [self _decodeFrame:frameIndex drop:NO];
+    
+    [[NSNotificationCenter defaultCenter] postNotificationName:kQGVAPDecoderSeekFinish object:self];
 }
 
 - (void)_onInputEnd  {

+ 1 - 0
iOS/QGVAPlayer/QGVAPlayer/Classes/Controllers/QGAnimatedImageDecodeManager.h

@@ -53,5 +53,6 @@
 - (QGBaseAnimatedImageFrame *)consumeDecodedFrame:(NSInteger)frameIndex;
 
 - (void)tryToStartAudioPlay;
+- (BOOL)containsThisDeocder:(id)decoder;
 
 @end

+ 9 - 0
iOS/QGVAPlayer/QGVAPlayer/Classes/Controllers/QGAnimatedImageDecodeManager.m

@@ -174,4 +174,13 @@
 
 }
 
+- (BOOL)containsThisDeocder:(id)decoder {
+    for (id d in _decoders) {
+        if (d == decoder) {
+            return YES;
+        }
+    }
+    return NO;
+}
+
 @end

+ 25 - 7
iOS/QGVAPlayer/QGVAPlayer/Classes/UIView+VAP.m

@@ -48,6 +48,7 @@ NSInteger const VapMaxCompatibleVersion = 2;
 @property (nonatomic, strong) QGAnimatedImageDecodeConfig   *hwd_decodeConfig;          //线程数与buffer数
 @property (nonatomic, strong) NSOperationQueue              *hwd_callbackQueue;         //回调执行队列
 @property (nonatomic, assign) BOOL                          hwd_onPause;                //标记是否暂停中
+@property (nonatomic, assign) BOOL                          hwd_onSeek;                 //正在seek当中,此时继续播放会导致时序混乱
 @property (nonatomic, strong) QGHWDMP4OpenGLView            *hwd_openGLView;            //opengl绘制图层
 @property (nonatomic, strong) QGHWDMetalView                *hwd_metalView;             //metal绘制图层
 @property (nonatomic, strong) QGVAPMetalView                *vap_metalView;             //vap格式mp4渲染图层
@@ -66,12 +67,27 @@ NSInteger const VapMaxCompatibleVersion = 2;
     
     [[NSNotificationCenter defaultCenter] hwd_addSafeObserver:self selector:@selector(hwd_didReceiveEnterBackgroundNotification:) name:UIApplicationDidEnterBackgroundNotification object:nil];
     [[NSNotificationCenter defaultCenter] hwd_addSafeObserver:self selector:@selector(hwd_didReceiveWillEnterForegroundNotification:) name:UIApplicationWillEnterForegroundNotification object:nil];
+    
+    [[NSNotificationCenter defaultCenter] hwd_addSafeObserver:self selector:@selector(hwd_didReceiveSeekStartNotification:) name:kQGVAPDecoderSeekStart object:nil];
+    [[NSNotificationCenter defaultCenter] hwd_addSafeObserver:self selector:@selector(hwd_didReceiveSeekFinishNotification:) name:kQGVAPDecoderSeekFinish object:nil];
 }
 
 - (void)hwd_didReceiveEnterBackgroundNotification:(NSNotification *)notification {
     [self pauseHWDMP4];
 }
 
+- (void)hwd_didReceiveSeekStartNotification:(NSNotification *)notification {
+    if ([self.hwd_decodeManager containsThisDeocder:notification.object]) {
+        self.hwd_onSeek = YES;
+    }
+}
+
+- (void)hwd_didReceiveSeekFinishNotification:(NSNotification *)notification {
+    if ([self.hwd_decodeManager containsThisDeocder:notification.object]) {
+        self.hwd_onSeek = NO;
+    }
+}
+
 //结束播放
 - (void)hwd_stopHWDMP4 {
     
@@ -350,7 +366,7 @@ NSInteger const VapMaxCompatibleVersion = 2;
                 if (self.hwd_isFinish) {
                     break ;
                 }
-                if (self.hwd_onPause) {
+                if (self.hwd_onPause || self.hwd_onSeek) {
                     lastRenderingInterval = NSDate.timeIntervalSinceReferenceDate;
                     continue;
                 }
@@ -427,12 +443,13 @@ NSInteger const VapMaxCompatibleVersion = 2;
     
     VAP_Info(kQGVAPModuleCommon, @"pauseHWDMP4");
     self.hwd_onPause = YES;
-    [self.hwd_callbackQueue addOperationWithBlock:^{
-        //此处必须延迟释放,避免野指针
-        if ([self.hwd_Delegate respondsToSelector:@selector(viewDidStopPlayMP4:view:)]) {
-            [self.hwd_Delegate viewDidStopPlayMP4:self.hwd_currentFrame.frameIndex view:self];
-        }
-    }];
+// pause回调stop会导致一般使用场景将view移除,无法resume,因此暂时去掉该回调触发
+//    [self.hwd_callbackQueue addOperationWithBlock:^{
+//        //此处必须延迟释放,避免野指针
+//        if ([self.hwd_Delegate respondsToSelector:@selector(viewDidStopPlayMP4:view:)]) {
+//            [self.hwd_Delegate viewDidStopPlayMP4:self.hwd_currentFrame.frameIndex view:self];
+//        }
+//    }];
 }
 
 - (void)resumeHWDMP4 {
@@ -542,6 +559,7 @@ NSInteger const VapMaxCompatibleVersion = 2;
 
 //category methods
 HWDSYNTH_DYNAMIC_PROPERTY_CTYPE(hwd_onPause, setHwd_onPause, BOOL)
+HWDSYNTH_DYNAMIC_PROPERTY_CTYPE(hwd_onSeek, setHwd_onSeek, BOOL)
 HWDSYNTH_DYNAMIC_PROPERTY_CTYPE(hwd_renderByOpenGL, setHwd_renderByOpenGL, BOOL)
 HWDSYNTH_DYNAMIC_PROPERTY_CTYPE(hwd_isFinish, setHwd_isFinish, BOOL)
 HWDSYNTH_DYNAMIC_PROPERTY_CTYPE(hwd_fps, setHwd_fps, NSInteger)

+ 3 - 1
iOS/QGVAPlayerDemo/QGVAPlayerDemo/ViewController.m

@@ -114,7 +114,9 @@ void qg_VAP_Logger_handler(VAPLogLevel level, const char* file, int line, const
     NSString *resPath = [NSString stringWithFormat:@"%@/Resource/demo.mp4", [[NSBundle mainBundle] resourcePath]];
     [wrapView vapWrapView_playHWDMP4:resPath repeatCount:-1 delegate:self];
     UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onImageviewTap:)];
-    [wrapView addGestureRecognizer:tap];
+    [wrapView vapWrapView_addVapGesture:tap callback:^(UIGestureRecognizer *gestureRecognizer, BOOL insideSource, QGVAPSourceDisplayItem *source) {
+        
+    }];
 }
 
 #pragma mark -  mp4 hwd delegate