提交 88ab8b48 编写于 作者: Z Zhang Rui

ios: improve KVO handle

上级 6dec14bb
......@@ -11,6 +11,7 @@
E62139BF180FAE5F00553533 /* IJKFFOptions.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = E62139BC180FA89A00553533 /* IJKFFOptions.h */; };
E63FC27117F01143003551EB /* ijksdl_audio.c in Sources */ = {isa = PBXBuildFile; fileRef = E63FC27017F01143003551EB /* ijksdl_audio.c */; };
E63FC27617F013DE003551EB /* ijksdl_vout_dummy.c in Sources */ = {isa = PBXBuildFile; fileRef = E63FC27417F013DE003551EB /* ijksdl_vout_dummy.c */; };
E65DC3B919D93D5F004F8A08 /* IJKKVOController.m in Sources */ = {isa = PBXBuildFile; fileRef = E65DC3B819D93D5F004F8A08 /* IJKKVOController.m */; };
E66F8DC117EEC65200354D80 /* IJKMPMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DC017EEC65200354D80 /* IJKMPMoviePlayerController.m */; };
E66F8DE717EFD9C300354D80 /* IJKFFMoviePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DE617EFD9C300354D80 /* IJKFFMoviePlayerController.m */; };
E66F8DF117EFEA9400354D80 /* ijkplayer.c in Sources */ = {isa = PBXBuildFile; fileRef = E66F8DEF17EFEA9400354D80 /* ijkplayer.c */; };
......@@ -83,6 +84,8 @@
E63FC27317F013DE003551EB /* ijksdl_dummy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_dummy.h; sourceTree = "<group>"; };
E63FC27417F013DE003551EB /* ijksdl_vout_dummy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ijksdl_vout_dummy.c; sourceTree = "<group>"; };
E63FC27517F013DE003551EB /* ijksdl_vout_dummy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ijksdl_vout_dummy.h; sourceTree = "<group>"; };
E65DC3B719D93D5F004F8A08 /* IJKKVOController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKKVOController.h; path = IJKMediaPlayer/IJKKVOController.h; sourceTree = "<group>"; };
E65DC3B819D93D5F004F8A08 /* IJKKVOController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKKVOController.m; path = IJKMediaPlayer/IJKKVOController.m; sourceTree = "<group>"; };
E66F8DBF17EEC65200354D80 /* IJKMPMoviePlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKMPMoviePlayerController.h; path = IJKMediaPlayer/IJKMPMoviePlayerController.h; sourceTree = "<group>"; };
E66F8DC017EEC65200354D80 /* IJKMPMoviePlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IJKMPMoviePlayerController.m; path = IJKMediaPlayer/IJKMPMoviePlayerController.m; sourceTree = "<group>"; };
E66F8DC217EECB1E00354D80 /* IJKMediaPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IJKMediaPlayer.h; path = IJKMediaPlayer/IJKMediaPlayer.h; sourceTree = "<group>"; };
......@@ -652,6 +655,8 @@
E66F8DC217EECB1E00354D80 /* IJKMediaPlayer.h */,
E6716E491807E5FC00B3FBC1 /* IJKMediaUtils.h */,
E6716E4A1807E5FC00B3FBC1 /* IJKMediaUtils.m */,
E65DC3B719D93D5F004F8A08 /* IJKKVOController.h */,
E65DC3B819D93D5F004F8A08 /* IJKKVOController.m */,
);
name = IJKMediaPlayer;
sourceTree = "<group>";
......@@ -731,6 +736,7 @@
E66F8DF117EFEA9400354D80 /* ijkplayer.c in Sources */,
E6EE92BB1878230C009EAB56 /* IJKSDLAudioUnitController.m in Sources */,
E66F8E0317EFEEA400354D80 /* ijkplayer_ios.m in Sources */,
E65DC3B919D93D5F004F8A08 /* IJKKVOController.m in Sources */,
E63FC27117F01143003551EB /* ijksdl_audio.c in Sources */,
E6EE92BD1878230C009EAB56 /* IJKSDLGLRenderRV24.m in Sources */,
E63FC27617F013DE003551EB /* ijksdl_vout_dummy.c in Sources */,
......
......@@ -72,6 +72,7 @@
#import "IJKAudioKit.h"
#import "IJKMediaModule.h"
#import "IJKMediaUtils.h"
#import "IJKKVOController.h"
#import <AVFoundation/AVFoundation.h>
static NSString *kErrorDomain = @"IJKAVMoviePlayer";
......@@ -106,7 +107,10 @@ static void *KVO_AVPlayerItem_playbackBufferEmpty = &KVO_AVPlayerItem_play
AVPlayerItem *_playerItem;
AVPlayer *_player;
IJKAVPlayerLayerView * _avView;
IJKKVOController *_playerKVO;
IJKKVOController *_playerItemKVO;
id _timeObserver;
BOOL _isSeeking;
......@@ -224,42 +228,6 @@ static void *KVO_AVPlayerItem_playbackBufferEmpty = &KVO_AVPlayerItem_play
return _player.rate >= 0.00001f;
}
- (void)removeObserversFromPlayerItem:(AVPlayerItem*)playerItem
{
if (playerItem == nil)
return;
[IJKMediaUtils kvoQuietlyRemoveObserver:self
forKeyPath:@"status"
fromObject:playerItem];
[IJKMediaUtils kvoQuietlyRemoveObserver:self
forKeyPath:@"loadedTimeRanges"
fromObject:playerItem];
[IJKMediaUtils kvoQuietlyRemoveObserver:self
forKeyPath:@"playbackLikelyToKeepUp"
fromObject:playerItem];
[IJKMediaUtils kvoQuietlyRemoveObserver:self
forKeyPath:@"playbackBufferFull"
fromObject:playerItem];
[IJKMediaUtils kvoQuietlyRemoveObserver:self
forKeyPath:@"playbackBufferEmpty"
fromObject:playerItem];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:nil
object:playerItem];
}
- (void)removeObserversFromPlayer:(AVPlayer*)player
{
if (player == nil)
return;
[player removeObserver:self forKeyPath:@"currentItem"];
[player removeObserver:self forKeyPath:@"rate"];
}
- (void)shutdown
{
[self stop];
......@@ -268,7 +236,13 @@ static void *KVO_AVPlayerItem_playbackBufferEmpty = &KVO_AVPlayerItem_play
[_playerItem cancelPendingSeeks];
}
[self removeObserversFromPlayerItem:_playerItem];
[_playerItemKVO safelyRemoveAllObservers];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:nil
object:_playerItem];
[_playerKVO safelyRemoveAllObservers];
[self unregisterApplicationObservers];
if (_avView != nil) {
......@@ -406,36 +380,40 @@ static void *KVO_AVPlayerItem_playbackBufferEmpty = &KVO_AVPlayerItem_play
/* At this point we're ready to set up for playback of the asset. */
/* Stop observing our prior AVPlayerItem, if we have one. */
[self removeObserversFromPlayerItem:_playerItem];
[_playerItemKVO safelyRemoveAllObservers];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:nil
object:_playerItem];
/* Create a new instance of AVPlayerItem from the now successfully loaded AVAsset. */
_playerItem = [AVPlayerItem playerItemWithAsset:asset];
_playerItemKVO = [[IJKKVOController alloc] initWithTarget:_playerItem];
/* Observe the player item "status" key to determine when it is ready to play. */
[_playerItem addObserver:self
forKeyPath:@"status"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayerItem_state];
[_playerItem addObserver:self
forKeyPath:@"loadedTimeRanges"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayerItem_loadedTimeRanges];
[_playerItem addObserver:self
forKeyPath:@"playbackLikelyToKeepUp"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayerItem_playbackLikelyToKeepUp];
[_playerItem addObserver:self
forKeyPath:@"playbackBufferEmpty"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayerItem_playbackBufferEmpty];
[_playerItem addObserver:self
forKeyPath:@"playbackBufferFull"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayerItem_playbackBufferFull];
[_playerItemKVO safelyAddObserver:self
forKeyPath:@"status"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayerItem_state];
[_playerItemKVO safelyAddObserver:self
forKeyPath:@"loadedTimeRanges"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayerItem_loadedTimeRanges];
[_playerItemKVO safelyAddObserver:self
forKeyPath:@"playbackLikelyToKeepUp"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayerItem_playbackLikelyToKeepUp];
[_playerItemKVO safelyAddObserver:self
forKeyPath:@"playbackBufferEmpty"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayerItem_playbackBufferEmpty];
[_playerItemKVO safelyAddObserver:self
forKeyPath:@"playbackBufferFull"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayerItem_playbackBufferFull];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playerItemDidReachEnd:)
......@@ -454,20 +432,21 @@ static void *KVO_AVPlayerItem_playbackBufferEmpty = &KVO_AVPlayerItem_play
{
/* Get a new AVPlayer initialized to play the specified player item. */
_player = [AVPlayer playerWithPlayerItem:_playerItem];
_playerKVO = [[IJKKVOController alloc] initWithTarget:_player];
/* Observe the AVPlayer "currentItem" property to find out when any
AVPlayer replaceCurrentItemWithPlayerItem: replacement will/did
occur.*/
[_player addObserver:self
forKeyPath:@"currentItem"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayer_currentItem];
[_playerKVO safelyAddObserver:self
forKeyPath:@"currentItem"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayer_currentItem];
/* Observe the AVPlayer "rate" property to update the scrubber control. */
[_player addObserver:self
forKeyPath:@"rate"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayer_rate];
[_playerKVO safelyAddObserver:self
forKeyPath:@"rate"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:KVO_AVPlayer_rate];
}
/* Make our new AVPlayerItem the AVPlayer's current item. */
......
//
// IJKKVOController.h
// IJKMediaPlayer
//
// Created by Zhang Rui on 14-9-29.
// Copyright (c) 2014年 bilibili. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface IJKKVOController : NSObject
- (id)initWithTarget:(NSObject *)target;
- (void)safelyAddObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
context:(void *)context;
- (void)safelyRemoveObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath;
- (void)safelyRemoveAllObservers;
@end
//
// IJKKVOController.m
// IJKMediaPlayer
//
// Created by Zhang Rui on 14-9-29.
// Copyright (c) 2014年 bilibili. All rights reserved.
//
#import "IJKKVOController.h"
@interface IJKKVOEntry : NSObject
@property(nonatomic, weak) NSObject *observer;
@property(nonatomic, strong) NSString *keyPath;
@end
@implementation IJKKVOEntry
@synthesize observer;
@synthesize keyPath;
@end
@implementation IJKKVOController {
__weak NSObject *_target;
NSMutableArray *_observerArray;
}
- (id)initWithTarget:(NSObject *)target
{
self = [super init];
if (self) {
_target = target;
_observerArray = [[NSMutableArray alloc] init];
}
return self;
}
- (void)safelyAddObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
context:(void *)context
{
NSObject *target = _target;
if (target == nil)
return;
BOOL removed = [self removeEntryOfObserver:observer forKeyPath:keyPath];
if (removed) {
// duplicated register
NSLog(@"duplicated observer");
}
@try {
[target addObserver:observer
forKeyPath:keyPath
options:options
context:context];
IJKKVOEntry *entry = [[IJKKVOEntry alloc] init];
entry.observer = observer;
entry.keyPath = keyPath;
[_observerArray addObject:entry];
} @catch (NSException *e) {
NSLog(@"IJKKVO: failed to add observer for %@\n", keyPath);
}
}
- (void)safelyRemoveObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
{
NSObject *target = _target;
if (target == nil)
return;
BOOL removed = [self removeEntryOfObserver:observer forKeyPath:keyPath];
if (removed) {
// duplicated register
NSLog(@"duplicated observer");
}
@try {
if (removed) {
[target removeObserver:observer
forKeyPath:keyPath];
}
} @catch (NSException *e) {
NSLog(@"IJKKVO: failed to remove observer for %@\n", keyPath);
}
}
- (void)safelyRemoveAllObservers
{
__block NSObject *target = _target;
if (target == nil)
return;
[_observerArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
IJKKVOEntry *entry = obj;
if (entry == nil)
return;
NSObject *observer = entry.observer;
if (observer == nil)
return;
@try {
[target removeObserver:observer
forKeyPath:entry.keyPath];
} @catch (NSException *e) {
NSLog(@"IJKKVO: failed to remove observer for %@\n", entry.keyPath);
}
}];
[_observerArray removeAllObjects];
}
- (BOOL)removeEntryOfObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
{
__block NSInteger foundIndex = -1;
[_observerArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
IJKKVOEntry *entry = (IJKKVOEntry *)obj;
if (entry.observer == observer &&
[entry.keyPath isEqualToString:keyPath]) {
foundIndex = idx;
*stop = YES;
}
}];
if (foundIndex >= 0) {
[_observerArray removeObjectAtIndex:foundIndex];
return YES;
}
return NO;
}
@end
......@@ -36,8 +36,4 @@
description: (NSString*)description
reason: (NSString*)reason;
+ (void)kvoQuietlyRemoveObserver:(NSObject *)anObserver
forKeyPath:(NSString *)keyPath
fromObject:(NSObject *)object;
@end
......@@ -73,16 +73,4 @@
return error;
}
+ (void)kvoQuietlyRemoveObserver:(NSObject *)anObserver
forKeyPath:(NSString *)keyPath
fromObject:(NSObject *)object
{
@try {
[object removeObserver:anObserver forKeyPath:@"status"];
}
@catch (NSException *exception) {
NSLog(@"dup remove observer\n");
}
}
@end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册