Skip to content

Instantly share code, notes, and snippets.

@iby
Forked from k06a/MLWAsyncAVPlayer.h
Created March 11, 2018 15:48
Show Gist options
  • Select an option

  • Save iby/b8a3c923f702f7d34ca093abe52ea5cb to your computer and use it in GitHub Desktop.

Select an option

Save iby/b8a3c923f702f7d34ca093abe52ea5cb to your computer and use it in GitHub Desktop.

Revisions

  1. @k06a k06a revised this gist May 10, 2017. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions MLWAsyncAVPlayer.m
    Original file line number Diff line number Diff line change
    @@ -16,23 +16,23 @@ - (instancetype)init {

    - (void)prerollAtRate:(float)rate completionHandler:(void (^)(BOOL))completionHandler {
    [super prerollAtRate:rate completionHandler:^(BOOL finished) {
    dispatch_async(dispatch_get_main_queue(), ^{
    dispatch_sync(dispatch_get_main_queue(), ^{
    completionHandler(finished);
    });
    }];
    }

    - (id)addBoundaryTimeObserverForTimes:(NSArray<NSValue *> *)times queue:(dispatch_queue_t)queue usingBlock:(void (^)(void))block {
    return [super addBoundaryTimeObserverForTimes:times queue:queue usingBlock:^{
    dispatch_async(dispatch_get_main_queue(), ^{
    dispatch_sync(dispatch_get_main_queue(), ^{
    block();
    });
    }];
    }

    - (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime))block {
    return [super addPeriodicTimeObserverForInterval:interval queue:queue usingBlock:^(CMTime time) {
    dispatch_async(dispatch_get_main_queue(), ^{
    dispatch_sync(dispatch_get_main_queue(), ^{
    block(time);
    });
    }];
  2. @k06a k06a revised this gist May 10, 2017. No changes.
  3. @k06a k06a revised this gist May 10, 2017. 1 changed file with 35 additions and 23 deletions.
    58 changes: 35 additions & 23 deletions MLWAsyncAVPlayer.m
    Original file line number Diff line number Diff line change
    @@ -1,22 +1,17 @@
    #import <JRSwizzle/JRSwizzle.h>

    #import "MLWAsyncAVPlayer.h"

    @implementation MLWAsyncAVPlayer

    static void *MLWAsyncAVPlayer_currentItem_hasEnqueuedVideoFrame_context = &MLWAsyncAVPlayer_currentItem_hasEnqueuedVideoFrame_context;

    - (instancetype)init {
    self = [super init];
    if (self) {
    [self setValue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) forKeyPath:@"_player.stateDispatchQueue"];
    [self addObserver:self forKeyPath:@"currentItem.hasEnqueuedVideoFrame" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:MLWAsyncAVPlayer_currentItem_hasEnqueuedVideoFrame_context];
    }
    return self;
    }

    - (void)dealloc {
    [self removeObserver:self forKeyPath:@"currentItem.hasEnqueuedVideoFrame" context:MLWAsyncAVPlayer_currentItem_hasEnqueuedVideoFrame_context];
    }

    // Move completions from following methods to main thread

    - (void)prerollAtRate:(float)rate completionHandler:(void (^)(BOOL))completionHandler {
    @@ -43,22 +38,6 @@ - (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_
    }];
    }

    // Move KVO of currentItem.hasEnqueuedVideoFrame to main thread

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context {
    if (context == MLWAsyncAVPlayer_currentItem_hasEnqueuedVideoFrame_context) {
    if (![NSThread isMainThread]) {
    dispatch_sync(dispatch_get_main_queue(), ^{
    [self.currentItem willChangeValueForKey:@"hasEnqueuedVideoFrame"];
    [self.currentItem didChangeValueForKey:@"hasEnqueuedVideoFrame"];
    });
    }
    return;
    }

    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }

    // Move KVO of player properties to main thread

    - (void)willChangeValueForKey:(NSString *)key {
    @@ -83,4 +62,37 @@ - (void)didChangeValueForKey:(NSString *)key {
    });
    }

    @end

    //

    @implementation AVPlayerItem (MLWAsync)

    + (void)load {
    [self jr_swizzleMethod:@selector(willChangeValueForKey:) withMethod:@selector(mlw_willChangeValueForKey:) error:nil];
    [self jr_swizzleMethod:@selector(didChangeValueForKey:) withMethod:@selector(mlw_didChangeValueForKey:) error:nil];
    }

    - (void)mlw_willChangeValueForKey:(NSString *)key {
    if ([NSThread isMainThread]) {
    [self mlw_willChangeValueForKey:key];
    return;
    }

    dispatch_sync(dispatch_get_main_queue(), ^{
    [self mlw_willChangeValueForKey:key];
    });
    }

    - (void)mlw_didChangeValueForKey:(NSString *)key {
    if ([NSThread isMainThread]) {
    [self mlw_didChangeValueForKey:key];
    return;
    }

    dispatch_sync(dispatch_get_main_queue(), ^{
    [self mlw_didChangeValueForKey:key];
    });
    }

    @end
  4. @k06a k06a revised this gist May 10, 2017. No changes.
  5. @k06a k06a revised this gist May 6, 2017. 1 changed file with 73 additions and 16 deletions.
    89 changes: 73 additions & 16 deletions MLWAsyncAVPlayer.m
    Original file line number Diff line number Diff line change
    @@ -1,29 +1,86 @@
    #import <KVO-MVVM/KVO-MVVM.h>
    #import "MLWAsyncAVPlayer.h"

    @implementation MLWAsyncAVPlayer

    static void *MLWAsyncAVPlayer_currentItem_hasEnqueuedVideoFrame_context = &MLWAsyncAVPlayer_currentItem_hasEnqueuedVideoFrame_context;

    - (instancetype)init {
    self = [super init];
    if (self) {
    id internal = object_getIvar(self, class_getInstanceVariable([self class], "_player"));
    [internal setValue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) forKey:@"stateDispatchQueue"];

    [self mvvm_observe:@"currentItem.hasEnqueuedVideoFrame" with:^(typeof(self) self, NSNumber * value) {
    if (value && ![NSThread isMainThread]) {
    @weakify(self);
    dispatch_sync(dispatch_get_main_queue(), ^{
    @strongify(self);
    [self.currentItem willChangeValueForKey:@"hasEnqueuedVideoFrame"];
    [self.currentItem didChangeValueForKey:@"hasEnqueuedVideoFrame"];
    });
    }
    }];
    [self setValue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) forKeyPath:@"_player.stateDispatchQueue"];
    [self addObserver:self forKeyPath:@"currentItem.hasEnqueuedVideoFrame" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:MLWAsyncAVPlayer_currentItem_hasEnqueuedVideoFrame_context];
    }
    return self;
    }

    - (void)dealloc {
    [self mvvm_unobserve:@"currentItem.hasEnqueuedVideoFrame"];
    [self removeObserver:self forKeyPath:@"currentItem.hasEnqueuedVideoFrame" context:MLWAsyncAVPlayer_currentItem_hasEnqueuedVideoFrame_context];
    }

    // Move completions from following methods to main thread

    - (void)prerollAtRate:(float)rate completionHandler:(void (^)(BOOL))completionHandler {
    [super prerollAtRate:rate completionHandler:^(BOOL finished) {
    dispatch_async(dispatch_get_main_queue(), ^{
    completionHandler(finished);
    });
    }];
    }

    - (id)addBoundaryTimeObserverForTimes:(NSArray<NSValue *> *)times queue:(dispatch_queue_t)queue usingBlock:(void (^)(void))block {
    return [super addBoundaryTimeObserverForTimes:times queue:queue usingBlock:^{
    dispatch_async(dispatch_get_main_queue(), ^{
    block();
    });
    }];
    }

    - (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime))block {
    return [super addPeriodicTimeObserverForInterval:interval queue:queue usingBlock:^(CMTime time) {
    dispatch_async(dispatch_get_main_queue(), ^{
    block(time);
    });
    }];
    }

    // Move KVO of currentItem.hasEnqueuedVideoFrame to main thread

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context {
    if (context == MLWAsyncAVPlayer_currentItem_hasEnqueuedVideoFrame_context) {
    if (![NSThread isMainThread]) {
    dispatch_sync(dispatch_get_main_queue(), ^{
    [self.currentItem willChangeValueForKey:@"hasEnqueuedVideoFrame"];
    [self.currentItem didChangeValueForKey:@"hasEnqueuedVideoFrame"];
    });
    }
    return;
    }

    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }

    // Move KVO of player properties to main thread

    - (void)willChangeValueForKey:(NSString *)key {
    if ([NSThread isMainThread]) {
    [super willChangeValueForKey:key];
    return;
    }

    dispatch_sync(dispatch_get_main_queue(), ^{
    [super willChangeValueForKey:key];
    });
    }

    - (void)didChangeValueForKey:(NSString *)key {
    if ([NSThread isMainThread]) {
    [super didChangeValueForKey:key];
    return;
    }

    dispatch_sync(dispatch_get_main_queue(), ^{
    [super didChangeValueForKey:key];
    });
    }

    @end
    @end
  6. @k06a k06a revised this gist May 5, 2017. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions MLWAsyncAVPlayer.m
    Original file line number Diff line number Diff line change
    @@ -22,4 +22,8 @@ - (instancetype)init {
    return self;
    }

    - (void)dealloc {
    [self mvvm_unobserve:@"currentItem.hasEnqueuedVideoFrame"];
    }

    @end
  7. @k06a k06a created this gist May 5, 2017.
    5 changes: 5 additions & 0 deletions MLWAsyncAVPlayer.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    #import <AVFoundation/AVFoundation.h>

    @interface MLWAsyncAVPlayer : AVPlayer

    @end
    25 changes: 25 additions & 0 deletions MLWAsyncAVPlayer.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,25 @@
    #import <KVO-MVVM/KVO-MVVM.h>

    @implementation MLWAsyncAVPlayer

    - (instancetype)init {
    self = [super init];
    if (self) {
    id internal = object_getIvar(self, class_getInstanceVariable([self class], "_player"));
    [internal setValue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) forKey:@"stateDispatchQueue"];

    [self mvvm_observe:@"currentItem.hasEnqueuedVideoFrame" with:^(typeof(self) self, NSNumber * value) {
    if (value && ![NSThread isMainThread]) {
    @weakify(self);
    dispatch_sync(dispatch_get_main_queue(), ^{
    @strongify(self);
    [self.currentItem willChangeValueForKey:@"hasEnqueuedVideoFrame"];
    [self.currentItem didChangeValueForKey:@"hasEnqueuedVideoFrame"];
    });
    }
    }];
    }
    return self;
    }

    @end