From 15b0e886b6c2878789234e86e5c8b0ab5e403a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Fri, 26 Oct 2018 15:03:10 +0200 Subject: [PATCH 1/5] Bump version number --- SRGMediaPlayer.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SRGMediaPlayer.xcodeproj/project.pbxproj b/SRGMediaPlayer.xcodeproj/project.pbxproj index ccb4c705..f42cb3e1 100644 --- a/SRGMediaPlayer.xcodeproj/project.pbxproj +++ b/SRGMediaPlayer.xcodeproj/project.pbxproj @@ -1289,7 +1289,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 2.5.3; + MARKETING_VERSION = 2.5.4; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1426,7 +1426,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 2.5.3; + MARKETING_VERSION = 2.5.4; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; @@ -1652,7 +1652,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 2.5.3; + MARKETING_VERSION = 2.5.4; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1703,7 +1703,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MARKETING_VERSION = 2.5.3; + MARKETING_VERSION = 2.5.4; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; From dcb397c3c47a58e1ea1a33eaa513b168f87b54bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 1 Nov 2018 11:16:32 +0100 Subject: [PATCH 2/5] Use properties --- Framework/Sources/Controllers/SRGMediaPlayerController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Sources/Controllers/SRGMediaPlayerController.m b/Framework/Sources/Controllers/SRGMediaPlayerController.m index cfe00689..81780d22 100644 --- a/Framework/Sources/Controllers/SRGMediaPlayerController.m +++ b/Framework/Sources/Controllers/SRGMediaPlayerController.m @@ -1161,7 +1161,7 @@ - (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_ return nil; } - NSString *identifier = [[NSUUID UUID] UUIDString]; + NSString *identifier = NSUUID.UUID.UUIDString; SRGPeriodicTimeObserver *periodicTimeObserver = [self periodicTimeObserverForInterval:interval queue:queue]; [periodicTimeObserver setBlock:block forIdentifier:identifier]; From f6391edbac8d56fa47f27a63a1e2f227cd287fd8 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Bertholon Date: Thu, 22 Nov 2018 22:44:44 +0100 Subject: [PATCH 3/5] Add Copy Frameworks step in Demo app export --- SRGMediaPlayer.xcodeproj/project.pbxproj | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/SRGMediaPlayer.xcodeproj/project.pbxproj b/SRGMediaPlayer.xcodeproj/project.pbxproj index f42cb3e1..9ec40772 100644 --- a/SRGMediaPlayer.xcodeproj/project.pbxproj +++ b/SRGMediaPlayer.xcodeproj/project.pbxproj @@ -929,6 +929,7 @@ E69A1E641D61BEFC0064E6C1 /* Frameworks */, E69A1E651D61BEFC0064E6C1 /* Resources */, E69A1FC31D61C0180064E6C1 /* Embed Frameworks */, + 0805608821A75209000FA74E /* Copy Frameworks (Carthage) */, ); buildRules = ( ); @@ -1077,6 +1078,27 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 0805608821A75209000FA74E /* Copy Frameworks (Carthage) */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/iOS/libextobjc.framework", + "$(SRCROOT)/Carthage/Build/iOS/MAKVONotificationCenter.framework", + "$(SRCROOT)/Carthage/Build/iOS/SRGLogger.framework", + ); + name = "Copy Frameworks (Carthage)"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks\n"; + }; 6F44486B210F24CD009FDB70 /* Copy Framework Dependencies for Xcode View Rendering */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; From 8e3258b1de0f333a9a205710d7362f53f32e7e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 29 Nov 2018 13:53:39 +0100 Subject: [PATCH 4/5] Fix DVR streams incorrectly sometimes starting in the past --- .../Controllers/SRGMediaPlayerController.m | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/Framework/Sources/Controllers/SRGMediaPlayerController.m b/Framework/Sources/Controllers/SRGMediaPlayerController.m index 81780d22..20d110d1 100644 --- a/Framework/Sources/Controllers/SRGMediaPlayerController.m +++ b/Framework/Sources/Controllers/SRGMediaPlayerController.m @@ -172,30 +172,34 @@ - (void)setPlayer:(AVPlayer *)player } }; - // If a segment is targeted, add a small offset so that playback is guaranteed to start within the segment SRGPosition *startPosition = self.startPosition; - if (self.targetSegment) { - startPosition = SRGMediaPlayerControllerOffset(startPosition, CMTimeMakeWithSeconds(SRGSegmentSeekOffsetInSeconds, NSEC_PER_SEC)); - } - - // Take into account tolerance at the end of the content being played. If near the end enough, start - // at the default position instead. - CMTimeRange timeRange = self.targetSegment ? self.targetSegment.srg_timeRange : self.timeRange; - CMTime tolerance = SRGMediaPlayerEffectiveEndTolerance(self.endTolerance, self.endToleranceRatio, CMTimeGetSeconds(timeRange.duration)); - CMTime toleratedStartTime = CMTIME_COMPARE_INLINE(startPosition.time, >=, CMTimeSubtract(timeRange.duration, tolerance)) ? kCMTimeZero : startPosition.time; - // Positions in segments are relative. If not within a segment, they are absolute (relative positions - // are misleading for a DVR stream with a sliding window, and match the absolute position in other cases) - if (self.targetSegment) { - toleratedStartTime = CMTimeAdd(toleratedStartTime, timeRange.start); - } - SRGPosition *toleratedPosition = [SRGPosition positionWithTime:toleratedStartTime toleranceBefore:startPosition.toleranceBefore toleranceAfter:startPosition.toleranceAfter]; - - SRGPosition *seekPosition = SRGMediaPlayerControllerPositionInTimeRange(toleratedPosition, timeRange); - if (CMTIME_COMPARE_INLINE(seekPosition.time, ==, kCMTimeZero)) { + // Default position. Nothing to do. + if (CMTIME_COMPARE_INLINE(self.startPosition.time, ==, kCMTimeZero) && ! self.targetSegment) { completionBlock(YES); } + // Non-default start position. Calculate a valid position to seek to. else { + // If a segment is targeted, add a small offset so that playback is guaranteed to start within the segment + if (self.targetSegment) { + startPosition = SRGMediaPlayerControllerOffset(startPosition, CMTimeMakeWithSeconds(SRGSegmentSeekOffsetInSeconds, NSEC_PER_SEC)); + } + + // Take into account tolerance at the end of the content being played. If near the end enough, start + // at the default position instead. + CMTimeRange timeRange = self.targetSegment ? self.targetSegment.srg_timeRange : self.timeRange; + CMTime tolerance = SRGMediaPlayerEffectiveEndTolerance(self.endTolerance, self.endToleranceRatio, CMTimeGetSeconds(timeRange.duration)); + CMTime toleratedStartTime = CMTIME_COMPARE_INLINE(startPosition.time, >=, CMTimeSubtract(timeRange.duration, tolerance)) ? kCMTimeZero : startPosition.time; + + // Positions in segments are relative. If not within a segment, they are absolute (relative positions + // are misleading for a DVR stream with a sliding window, and match the absolute position in other cases) + if (self.targetSegment) { + toleratedStartTime = CMTimeAdd(toleratedStartTime, timeRange.start); + } + SRGPosition *toleratedPosition = [SRGPosition positionWithTime:toleratedStartTime toleranceBefore:startPosition.toleranceBefore toleranceAfter:startPosition.toleranceAfter]; + + SRGPosition *seekPosition = SRGMediaPlayerControllerPositionInTimeRange(toleratedPosition, timeRange); + // Call system method to avoid unwanted seek state in this special case [player seekToTime:seekPosition.time toleranceBefore:seekPosition.toleranceBefore toleranceAfter:seekPosition.toleranceAfter completionHandler:^(BOOL finished) { completionBlock(finished); From d749b2de26a4d18ac2e9c4cb2a395c0413b3ef5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20De=CC=81fago?= Date: Thu, 29 Nov 2018 13:59:05 +0100 Subject: [PATCH 5/5] Improve skip button behavior --- .../SRGMediaPlayerViewController.m | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Framework/Sources/Controllers/SRGMediaPlayerViewController.m b/Framework/Sources/Controllers/SRGMediaPlayerViewController.m index 6ac38566..de54c5d0 100644 --- a/Framework/Sources/Controllers/SRGMediaPlayerViewController.m +++ b/Framework/Sources/Controllers/SRGMediaPlayerViewController.m @@ -361,7 +361,14 @@ - (BOOL)canSkipBackwardFromTime:(CMTime)time return NO; } - SRGMediaPlayerStreamType streamType = self.controller.streamType; + SRGMediaPlayerController *controller = self.controller; + SRGMediaPlayerPlaybackState playbackState = controller.playbackState; + + if (playbackState == SRGMediaPlayerPlaybackStateIdle || playbackState == SRGMediaPlayerPlaybackStatePreparing) { + return NO; + } + + SRGMediaPlayerStreamType streamType = controller.streamType; return (streamType == SRGMediaPlayerStreamTypeOnDemand || streamType == SRGMediaPlayerStreamTypeDVR); } @@ -372,8 +379,15 @@ - (BOOL)canSkipForwardFromTime:(CMTime)time } SRGMediaPlayerController *controller = self.controller; - return (controller.streamType == SRGMediaPlayerStreamTypeOnDemand && CMTimeGetSeconds(time) + SRGMediaPlayerViewControllerForwardSkipInterval < CMTimeGetSeconds(controller.player.currentItem.duration)) - || (controller.streamType == SRGMediaPlayerStreamTypeDVR && ! controller.live); + SRGMediaPlayerPlaybackState playbackState = controller.playbackState; + + if (playbackState == SRGMediaPlayerPlaybackStateIdle || playbackState == SRGMediaPlayerPlaybackStatePreparing) { + return NO; + } + + SRGMediaPlayerStreamType streamType = controller.streamType; + return (streamType == SRGMediaPlayerStreamTypeOnDemand && CMTimeGetSeconds(time) + SRGMediaPlayerViewControllerForwardSkipInterval < CMTimeGetSeconds(controller.player.currentItem.duration)) + || (streamType == SRGMediaPlayerStreamTypeDVR && ! controller.live); } - (void)skipBackwardFromTime:(CMTime)time withCompletionHandler:(void (^)(BOOL finished))completionHandler