From 6dba41cde6650ffa31b2efd9fb818c7233b6f8a1 Mon Sep 17 00:00:00 2001 From: Blake Nussey Date: Thu, 15 Dec 2016 23:17:08 -0800 Subject: [PATCH] 2.1 --- README.md | 6 ++--- package.json | 2 +- videoplayer-common.ts | 16 ++++++------- videoplayer.android.ts | 4 ++-- videoplayer.ios.ts | 53 +++++++++++++++++++++++++++--------------- 5 files changed, 47 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 53409e5..9ed855b 100644 --- a/README.md +++ b/README.md @@ -81,11 +81,11 @@ Mutes the native video player. Sets the native video player to loop once playback has finished. -- **aspect - (boolean)** - *optional* **ANDROID ONLY** +- **fill - (boolean)** - *optional* **ANDROID ONLY** -Defaults to true. If set to false, the aspect ratio of the video will not be honored and it will fill the entire container available.Ï +If set to true, the aspect ratio of the video will not be honored and it will fill the entire space available. -- **loadingComplete - (function)** - *optional* **ANDROID ONLY** +- **loadingComplete - (function)** - *optional* Attribute to specify an event callback to execute when the video has loaded. diff --git a/package.json b/package.json index b714b5b..821613b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nativescript-videoplayer", - "version": "2.0.0", + "version": "2.1.0", "main": "videoplayer.js", "typings": "videoplayer.d.ts", "description": "A NativeScript plugin that uses the native video players to play local and remote videos.", diff --git a/videoplayer-common.ts b/videoplayer-common.ts index 2e4f01f..bd42834 100644 --- a/videoplayer-common.ts +++ b/videoplayer-common.ts @@ -8,7 +8,6 @@ import platform = require("platform"); import utils = require("utils/utils"); import * as types from "utils/types"; - var SRC = "src"; var VIDEO_SOURCE = "videoSource"; var VIDEO = "Video"; @@ -17,7 +16,7 @@ var AUTOPLAY = "autoplay"; var CONTROLS = "controls"; var LOOP = "loop"; var MUTED = "muted"; -var ASPECT = "aspect"; +var FILL = "fill"; // on Android we explicitly set propertySettings to None because android will invalidate its layout (skip unnecessary native call). var AffectsLayout = platform.device.os === platform.platformNames.android ? dependencyObservable.PropertyMetadataSettings.None : dependencyObservable.PropertyMetadataSettings.AffectsLayout; @@ -97,8 +96,8 @@ export class Video extends view.View { VIDEO, new proxy.PropertyMetadata(false, dependencyObservable.PropertyMetadataSettings.None) ); - public static aspectProperty = new dependencyObservable.Property( - ASPECT, + public static fillProperty = new dependencyObservable.Property( + FILL, VIDEO, new proxy.PropertyMetadata(false, dependencyObservable.PropertyMetadataSettings.None) ); @@ -153,14 +152,13 @@ export class Video extends view.View { this._setValue(Video.mutedProperty, value); } - get aspect(): any { - return this._getValue(Video.aspectProperty); + get fill(): any { + return this._getValue(Video.fillProperty); } - set aspect(value: any) { - this._setValue(Video.aspectProperty, value); + set fill(value: any) { + this._setValue(Video.fillProperty, value); } - public _setNativeVideo(nativeVideo: any) { // } diff --git a/videoplayer.android.ts b/videoplayer.android.ts index d07e4be..c8134d9 100644 --- a/videoplayer.android.ts +++ b/videoplayer.android.ts @@ -157,7 +157,7 @@ export class Video extends videoCommon.Video { this.owner.mediaState = SURFACE_READY; - if (this.owner.aspect !== false) { + if (this.owner.fill !== true) { this.owner._setupAspectRatio(); } @@ -198,7 +198,7 @@ export class Video extends videoCommon.Video { this.owner.videoHeight = mediaPlayer.getVideoHeight(); if (this.owner.videoWidth !== 0 && this.owner.videoHeight !== 0) { this.owner._android.getSurfaceTexture().setDefaultBufferSize(this.owner.videoWidth, this.owner.videoHeight); - if (this.owner.aspect !== false) { + if (this.owner.fill !== true) { this.owner._setupAspectRatio(); } } diff --git a/videoplayer.ios.ts b/videoplayer.ios.ts index 0016f64..76e5faa 100644 --- a/videoplayer.ios.ts +++ b/videoplayer.ios.ts @@ -8,7 +8,7 @@ import definition = require("./videoplayer"); import * as typesModule from "utils/types"; import * as application from 'application'; -declare var NSURL, AVPlayer, AVPlayerViewController, AVPlayerItemDidPlayToEndTimeNotification, UIView, CMTimeMakeWithSeconds, NSNotification, NSNotificationCenter, CMTimeGetSeconds, CMTimeMake, kCMTimeZero; +declare var NSURL, AVPlayer, AVPlayerViewController, AVPlayerItemDidPlayToEndTimeNotification, UIView, CMTimeMakeWithSeconds, NSNotification, NSNotificationCenter, CMTimeGetSeconds, CMTimeMake, kCMTimeZero, AVPlayerItemStatusReadyToPlay; global.moduleMerge(common, exports); @@ -27,6 +27,8 @@ export class Video extends common.Video { private _playerController: any; /// AVPlayerViewController private _ios: any; /// UIView private _src: string; + private _AVPlayerItemDidPlayToEndTimeObserver: any; + private _observer: NSObject; constructor() { super(); @@ -38,6 +40,8 @@ export class Video extends common.Video { // showsPlaybackControls must be set to false on init to avoid any potential 'Unable to simultaneously satisfy constraints' errors this._playerController.showsPlaybackControls = false; this._ios = this._playerController.view; + this._observer = PlayerObserverClass.alloc(); + this._observer["_owner"] = this; } @@ -70,10 +74,6 @@ export class Video extends common.Video { this._playerController.player = this._player; - if (this.autoplay === true) { - this.play(); - } - if (isNaN(this.width) || isNaN(this.height)) { this.requestLayout(); } @@ -82,25 +82,22 @@ export class Video extends common.Video { this._player.muted = true; } + this._player.currentItem.addObserverForKeyPathOptionsContext(this._observer, "status", 0, null); + if (this.finishedCallback) { - application.ios.addNotificationObserver(AVPlayerItemDidPlayToEndTimeNotification, this.AVPlayerItemDidPlayToEndTimeNotification.bind(this)); + this._AVPlayerItemDidPlayToEndTimeObserver = application.ios.addNotificationObserver(AVPlayerItemDidPlayToEndTimeNotification, this.AVPlayerItemDidPlayToEndTimeNotification.bind(this)); } } private AVPlayerItemDidPlayToEndTimeNotification(notification: any) { - if (this._player.currentItem) { - // This will match exactly to the object from the notification so can ensure only looping the video that has finished. - let currentItem = this._player.currentItem.toString(); - let notificationString = notification.toString(); + if (this._player.currentItem && this._player.currentItem === notification.object) { + // This will match exactly to the object from the notification so can ensure only looping and finished event for the video that has finished. // Notification is structured like so: NSConcreteNotification 0x61000024f690 {name = AVPlayerItemDidPlayToEndTimeNotification; object = >} - // Check if object exists in notification. - if (notificationString.includes(currentItem)) { - this._emit(common.Video.finishedEvent); - if (this.loop === true && this._player !== null) { - // Go in 5ms for more seamless looping - this.seekToTime(CMTimeMake(5, 100)); - this.play(); - } + this._emit(common.Video.finishedEvent); + if (this.loop === true && this._player !== null) { + // Go in 5ms for more seamless looping + this.seekToTime(CMTimeMake(5, 100)); + this.play(); } } } @@ -141,11 +138,29 @@ export class Video extends common.Video { public destroy() { if (this.finishedCallback) { - application.ios.removeNotificationObserver(AVPlayerItemDidPlayToEndTimeNotification); + application.ios.removeNotificationObserver(this._AVPlayerItemDidPlayToEndTimeObserver, AVPlayerItemDidPlayToEndTimeNotification); } + this._player.currentItem.removeObserverForKeyPath(this._observer, "status"); this.pause(); this._player.replaceCurrentItemWithPlayerItem(null); //de-allocates the AVPlayer this._playerController = null; } + private _loadingComplete() { + this._emit(common.Video.loadingCompleteEvent); + } + } + +class PlayerObserverClass extends NSObject { + observeValueForKeyPathOfObjectChangeContext(path: string, obj: Object, change: NSDictionary, context: any) { + if (path === "status") { + if (this["_owner"]._player.currentItem.status === AVPlayerItemStatusReadyToPlay) { + this["_owner"]._loadingComplete(); + if (this["_owner"].autoplay === true) { + this["_owner"].play(); + } + } + } + } +} \ No newline at end of file