From 1e952247bb28bacbff83f16f1916529e2b235662 Mon Sep 17 00:00:00 2001 From: marcoschmickler Date: Sun, 23 Jan 2022 09:40:22 +0100 Subject: [PATCH] BMPlayer removed --- kplayer.xcodeproj/project.pbxproj | 52 +- kplayer/core/DatabaseManager.swift | 68 +- kplayer/core/MediaItem.swift | 2 + kplayer/core/MediaModel.swift | 1 + kplayer/detail/DetailViewController.swift | 4 +- kplayer/master/MasterViewController.swift | 15 +- kplayer/timeline/CenterLine.swift | 126 --- kplayer/timeline/FrameImagesView.swift | 451 ---------- kplayer/timeline/TimelineMeasure.swift | 206 ----- kplayer/timeline/TimelineScroller.swift | 178 ---- kplayer/timeline/TimelineView.swift | 460 ----------- kplayer/timeline/TrimView.swift | 773 ------------------ kplayer/timeline/VideoTimelineView.swift | 301 ------- kplayer/{svideo => video}/SVideoModel.swift | 0 kplayer/{svideo => video}/SVideoPlayer.swift | 0 .../{svideo => video}/VideoPlayerView.swift | 0 16 files changed, 84 insertions(+), 2553 deletions(-) delete mode 100644 kplayer/timeline/CenterLine.swift delete mode 100644 kplayer/timeline/FrameImagesView.swift delete mode 100644 kplayer/timeline/TimelineMeasure.swift delete mode 100644 kplayer/timeline/TimelineScroller.swift delete mode 100644 kplayer/timeline/TimelineView.swift delete mode 100644 kplayer/timeline/TrimView.swift delete mode 100644 kplayer/timeline/VideoTimelineView.swift rename kplayer/{svideo => video}/SVideoModel.swift (100%) rename kplayer/{svideo => video}/SVideoPlayer.swift (100%) rename kplayer/{svideo => video}/VideoPlayerView.swift (100%) diff --git a/kplayer.xcodeproj/project.pbxproj b/kplayer.xcodeproj/project.pbxproj index 1547eeb..f30919a 100644 --- a/kplayer.xcodeproj/project.pbxproj +++ b/kplayer.xcodeproj/project.pbxproj @@ -12,11 +12,7 @@ 1C7360C0F2A4F0214FE353BD /* FileHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7367ECBD369A2A0C94C499 /* FileHelper.swift */; }; 1C73613562EB375F53A0BD03 /* ServerDownloadDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736595533B56039C417E0D /* ServerDownloadDelegate.swift */; }; 1C7361B3AF46CEB30D3F4FA0 /* KSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736AE5021E3D985FE3402D /* KSettings.swift */; }; - 1C7361D3BA77C40275F89D4A /* TimelineMeasure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7368C7B946BC9E067D37E7 /* TimelineMeasure.swift */; }; - 1C7361F376DA11F17CD3250B /* TrimView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736ABA0E14A51ACAC84AB5 /* TrimView.swift */; }; - 1C7362AF931E0F228E5D2AED /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360B53C4C1496320953C2 /* VideoPlayerView.swift */; }; 1C73631EACF56BABD3B2BCFB /* LayoutTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736BC4450890C45F8FBC63 /* LayoutTools.swift */; }; - 1C73633AAF0D77F8AC3557B9 /* SVideoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7362603E8588B4D1A8C617 /* SVideoModel.swift */; }; 1C73633C00C18FDA2E9F0A2F /* KNetworkProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DCD945ABAE984FF43EF /* KNetworkProtocol.swift */; }; 1C73635138BBD2BB480A308F /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C736777456388CA571DA17B /* MediaPlayer.framework */; }; 1C7363D4C34EBBD5C7AAD0A8 /* scratch.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1C7363E0DDA5854D55F8836E /* scratch.txt */; }; @@ -25,11 +21,11 @@ 1C736503B656C999E5E12081 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */; }; 1C73654C9EA6D255CFC039C5 /* NetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */; }; 1C7365885FAF292F2221ED44 /* PhotoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73673DC671535E3A049F54 /* PhotoController.swift */; }; - 1C7365BEFFB35E8DE8F04CCF /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73661561AD069C92FE3B15 /* TimelineView.swift */; }; + 1C7365C59F72C29EA41C8717 /* SVideoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736EEC570C71AAC50F2E95 /* SVideoModel.swift */; }; + 1C7365CE76693E7772585CA8 /* SVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73621E431C9BEC1440B936 /* SVideoPlayer.swift */; }; 1C73666A07CF2416B1B8D3F0 /* KSettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C94157754DE1C808173 /* KSettingsModel.swift */; }; 1C7366A0CFD2B55BF8C3BAF0 /* NetworkDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7364F10BED5DA0F1C0423C /* NetworkDelegate.swift */; }; 1C73671FC2CCCACAA2FFC153 /* ThumbnailCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736EA15A11AF7D57F85824 /* ThumbnailCache.swift */; }; - 1C73672CEAE1B9DA7805D4F2 /* CenterLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7361C26ED27AB54594317D /* CenterLine.swift */; }; 1C73675C34BE0990D44570BE /* ItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736253AB7A95EA41B605B7 /* ItemModel.swift */; }; 1C736771C503FB0D52AEB8F7 /* kplayer.js in Sources */ = {isa = PBXBuildFile; fileRef = 1C73625012D50E457D18A785 /* kplayer.js */; }; 1C7367AF39961D2BA72480ED /* DataLoadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736F9338CE36708244D42A /* DataLoadOperation.swift */; }; @@ -51,17 +47,14 @@ 1C736D24891597F2728230EE /* ImageLoadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360A94DBECA685ED8602F /* ImageLoadOperation.swift */; }; 1C736D24B49451141CD4B64D /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7369F53095B7A4D65679C2 /* DetailViewController.swift */; }; 1C736D89CF86841F4C98A1F7 /* KPersistentContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7362DE1D6BE634D7C2ACBF /* KPersistentContainer.swift */; }; + 1C736DFA8544C773E3C22F10 /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73675F8DDFA82DEADB542E /* VideoPlayerView.swift */; }; 1C736DFD076D9CC30F0B9D58 /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736677D4EF2437358B2387 /* Utility.swift */; }; 1C736E21B246C0BE7E123FD3 /* MediaModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736B41C6AC33F3FA592C63 /* MediaModel.swift */; }; 1C736EC45EE7DA5F7FCE63DA /* LocalManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73659CC9B523B957E58DC6 /* LocalManager.swift */; }; - 1C736ECAE78F5C722423D7ED /* TimelineScroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736362946D7A8585B0D875 /* TimelineScroller.swift */; }; - 1C736F1C31D1EC23F59125F0 /* VideoTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736FC4180B42C3A357E9BF /* VideoTimelineView.swift */; }; - 1C736F3D082067948BA4DE84 /* FrameImagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736A5140D9B25BEC266B72 /* FrameImagesView.swift */; }; 1C736F6A223D4ADB2E1BA733 /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736069C214E9522BB1BD97 /* ItemCell.swift */; }; 1C736F7D29B76C7037CEF778 /* DatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73647019E6C2E822127BA3 /* DatabaseManager.swift */; }; 1C736FAE5D3E5D3BA3C1FAE5 /* links.html in Resources */ = {isa = PBXBuildFile; fileRef = 1C73645DBD6499A726D34973 /* links.html */; }; 1C736FB92B19FE17E4357C85 /* MediaItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73688DAB88F9360FB62A49 /* MediaItem.swift */; }; - 1C736FF8FF423F01F880F94D /* SVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73624617102E0DEB001C25 /* SVideoPlayer.swift */; }; AA74B07A01F0E99E6DEC7D1B /* Pods_kplayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B75159FFCD5A882E6F167FE /* Pods_kplayer.framework */; }; C91E05892795AC5C0003AB79 /* KTag+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C91E05832795AC5C0003AB79 /* KTag+CoreDataClass.swift */; }; C91E058A2795AC5C0003AB79 /* KTag+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C91E05842795AC5C0003AB79 /* KTag+CoreDataProperties.swift */; }; @@ -93,21 +86,17 @@ 1C736069C214E9522BB1BD97 /* ItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = ""; }; 1C7360744ABACC3557D05760 /* HanekeFetchOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HanekeFetchOperation.swift; sourceTree = ""; }; 1C7360A94DBECA685ED8602F /* ImageLoadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageLoadOperation.swift; sourceTree = ""; }; - 1C7360B53C4C1496320953C2 /* VideoPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VideoPlayerView.swift; path = svideo/VideoPlayerView.swift; sourceTree = ""; }; 1C7360B6D0757D4FB6433E7B /* AsyncImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncImage.swift; sourceTree = ""; }; 1C73611D226B48C24DB37535 /* MasterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; }; 1C73615FFA2AA98BD1C56CD4 /* links.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = links.html; sourceTree = ""; }; - 1C7361C26ED27AB54594317D /* CenterLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CenterLine.swift; path = timeline/CenterLine.swift; sourceTree = ""; }; 1C7361F01841F546FA7AFD58 /* nspersistentcontainer-defaults-swift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "nspersistentcontainer-defaults-swift.swift"; sourceTree = ""; }; 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkHelper.swift; sourceTree = ""; }; - 1C73624617102E0DEB001C25 /* SVideoPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SVideoPlayer.swift; path = svideo/SVideoPlayer.swift; sourceTree = ""; }; + 1C73621E431C9BEC1440B936 /* SVideoPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVideoPlayer.swift; sourceTree = ""; }; 1C73625012D50E457D18A785 /* kplayer.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = kplayer.js; sourceTree = ""; }; 1C736253AB7A95EA41B605B7 /* ItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemModel.swift; sourceTree = ""; }; - 1C7362603E8588B4D1A8C617 /* SVideoModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SVideoModel.swift; path = svideo/SVideoModel.swift; sourceTree = ""; }; 1C736260E748CF136FF37EA7 /* UploadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadOperation.swift; sourceTree = ""; }; 1C7362DE1D6BE634D7C2ACBF /* KPersistentContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KPersistentContainer.swift; sourceTree = ""; }; 1C73631C96E6C860833052CA /* ItemType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemType.swift; sourceTree = ""; }; - 1C736362946D7A8585B0D875 /* TimelineScroller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TimelineScroller.swift; path = timeline/TimelineScroller.swift; sourceTree = ""; }; 1C7363E0DDA5854D55F8836E /* scratch.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = scratch.txt; sourceTree = ""; }; 1C73645DBD6499A726D34973 /* links.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = links.html; sourceTree = ""; }; 1C73647019E6C2E822127BA3 /* DatabaseManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseManager.swift; sourceTree = ""; }; @@ -117,20 +106,17 @@ 1C736595533B56039C417E0D /* ServerDownloadDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServerDownloadDelegate.swift; sourceTree = ""; }; 1C73659CC9B523B957E58DC6 /* LocalManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalManager.swift; sourceTree = ""; }; 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = ""; }; - 1C73661561AD069C92FE3B15 /* TimelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TimelineView.swift; path = timeline/TimelineView.swift; sourceTree = ""; }; 1C736677D4EF2437358B2387 /* Utility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utility.swift; sourceTree = ""; }; 1C7366C09381DC0052B52B69 /* EditItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditItemView.swift; sourceTree = ""; }; 1C73673DC671535E3A049F54 /* PhotoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoController.swift; sourceTree = ""; }; + 1C73675F8DDFA82DEADB542E /* VideoPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoPlayerView.swift; sourceTree = ""; }; 1C736777456388CA571DA17B /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; 1C7367ECBD369A2A0C94C499 /* FileHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileHelper.swift; sourceTree = ""; }; 1C73685B4BBFDAFBF08C032C /* readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = readme.md; sourceTree = ""; }; 1C73688DAB88F9360FB62A49 /* MediaItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaItem.swift; sourceTree = ""; }; - 1C7368C7B946BC9E067D37E7 /* TimelineMeasure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TimelineMeasure.swift; path = timeline/TimelineMeasure.swift; sourceTree = ""; }; 1C7369EC16B19B32B515169E /* NetData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetData.swift; sourceTree = ""; }; 1C7369F53095B7A4D65679C2 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; - 1C736A5140D9B25BEC266B72 /* FrameImagesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FrameImagesView.swift; path = timeline/FrameImagesView.swift; sourceTree = ""; }; 1C736A6E8396EE306B1AD3A8 /* KSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSettingsView.swift; sourceTree = ""; }; - 1C736ABA0E14A51ACAC84AB5 /* TrimView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TrimView.swift; path = timeline/TrimView.swift; sourceTree = ""; }; 1C736AE5021E3D985FE3402D /* KSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KSettings.swift; sourceTree = ""; }; 1C736B41C6AC33F3FA592C63 /* MediaModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaModel.swift; sourceTree = ""; }; 1C736B794396F2E50387B8F2 /* stringutil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = stringutil.swift; sourceTree = ""; }; @@ -142,8 +128,8 @@ 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = ""; }; 1C736DCD945ABAE984FF43EF /* KNetworkProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KNetworkProtocol.swift; sourceTree = ""; }; 1C736EA15A11AF7D57F85824 /* ThumbnailCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailCache.swift; sourceTree = ""; }; + 1C736EEC570C71AAC50F2E95 /* SVideoModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVideoModel.swift; sourceTree = ""; }; 1C736F9338CE36708244D42A /* DataLoadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataLoadOperation.swift; sourceTree = ""; }; - 1C736FC4180B42C3A357E9BF /* VideoTimelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VideoTimelineView.swift; path = timeline/VideoTimelineView.swift; sourceTree = ""; }; 6D522F61736592330F481B4F /* Pods-kplayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-kplayer.debug.xcconfig"; path = "Pods/Target Support Files/Pods-kplayer/Pods-kplayer.debug.xcconfig"; sourceTree = ""; }; 8B75159FFCD5A882E6F167FE /* Pods_kplayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_kplayer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C91E05832795AC5C0003AB79 /* KTag+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KTag+CoreDataClass.swift"; sourceTree = ""; }; @@ -278,6 +264,9 @@ 1C736F3946A38499113D351A /* video */ = { isa = PBXGroup; children = ( + 1C736EEC570C71AAC50F2E95 /* SVideoModel.swift */, + 1C73621E431C9BEC1440B936 /* SVideoPlayer.swift */, + 1C73675F8DDFA82DEADB542E /* VideoPlayerView.swift */, ); path = video; sourceTree = ""; @@ -339,16 +328,6 @@ 1C7363B608460DED4F522D1C /* photo */, 1C736F3946A38499113D351A /* video */, 1C73633B55AC5378053BDCE2 /* server */, - 1C736FC4180B42C3A357E9BF /* VideoTimelineView.swift */, - 1C7361C26ED27AB54594317D /* CenterLine.swift */, - 1C736A5140D9B25BEC266B72 /* FrameImagesView.swift */, - 1C7368C7B946BC9E067D37E7 /* TimelineMeasure.swift */, - 1C736362946D7A8585B0D875 /* TimelineScroller.swift */, - 1C73661561AD069C92FE3B15 /* TimelineView.swift */, - 1C736ABA0E14A51ACAC84AB5 /* TrimView.swift */, - 1C73624617102E0DEB001C25 /* SVideoPlayer.swift */, - 1C7362603E8588B4D1A8C617 /* SVideoModel.swift */, - 1C7360B53C4C1496320953C2 /* VideoPlayerView.swift */, ); path = kplayer; sourceTree = ""; @@ -580,28 +559,21 @@ 1C7361B3AF46CEB30D3F4FA0 /* KSettings.swift in Sources */, 1C73600CB93F16F4F28C116F /* KSettingsView.swift in Sources */, 1C73666A07CF2416B1B8D3F0 /* KSettingsModel.swift in Sources */, - 1C736F1C31D1EC23F59125F0 /* VideoTimelineView.swift in Sources */, - 1C73672CEAE1B9DA7805D4F2 /* CenterLine.swift in Sources */, C91E058E2795AC5C0003AB79 /* KSnapshot+CoreDataProperties.swift in Sources */, - 1C736F3D082067948BA4DE84 /* FrameImagesView.swift in Sources */, C91E058A2795AC5C0003AB79 /* KTag+CoreDataProperties.swift in Sources */, - 1C7361D3BA77C40275F89D4A /* TimelineMeasure.swift in Sources */, C91E058B2795AC5C0003AB79 /* KItem+CoreDataClass.swift in Sources */, - 1C736ECAE78F5C722423D7ED /* TimelineScroller.swift in Sources */, - 1C7365BEFFB35E8DE8F04CCF /* TimelineView.swift in Sources */, - 1C7361F376DA11F17CD3250B /* TrimView.swift in Sources */, 1C736A622876405F3EE2D043 /* EditItemView.swift in Sources */, 1C73613562EB375F53A0BD03 /* ServerDownloadDelegate.swift in Sources */, 1C736EC45EE7DA5F7FCE63DA /* LocalManager.swift in Sources */, - 1C736FF8FF423F01F880F94D /* SVideoPlayer.swift in Sources */, - 1C73633AAF0D77F8AC3557B9 /* SVideoModel.swift in Sources */, - 1C7362AF931E0F228E5D2AED /* VideoPlayerView.swift in Sources */, 1C736DFD076D9CC30F0B9D58 /* Utility.swift in Sources */, 1C736998044A9A7D89411892 /* AsyncImage.swift in Sources */, 1C73633C00C18FDA2E9F0A2F /* KNetworkProtocol.swift in Sources */, 1C736B4B0889BD35DC566124 /* nspersistentcontainer-defaults-swift.swift in Sources */, 1C736D89CF86841F4C98A1F7 /* KPersistentContainer.swift in Sources */, 1C736F7D29B76C7037CEF778 /* DatabaseManager.swift in Sources */, + 1C7365C59F72C29EA41C8717 /* SVideoModel.swift in Sources */, + 1C7365CE76693E7772585CA8 /* SVideoPlayer.swift in Sources */, + 1C736DFA8544C773E3C22F10 /* VideoPlayerView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/kplayer/core/DatabaseManager.swift b/kplayer/core/DatabaseManager.swift index f04cb10..021d021 100644 --- a/kplayer/core/DatabaseManager.swift +++ b/kplayer/core/DatabaseManager.swift @@ -73,14 +73,17 @@ class DatabaseManager { new.local = item.local new.favorite = item.favorite new.type = item.type.rawValue + save() + return new; + } + + private func save() { do { try managedObjectContext.save() } catch { print("Error") } - - return new; } func saveItemMetaData(_ item: MediaItem) { @@ -136,11 +139,7 @@ class DatabaseManager { } } - do { - try managedObjectContext.save() - } catch { - print("Error") - } + save() } } @@ -148,11 +147,7 @@ class DatabaseManager { let tag = KTag(context: managedObjectContext) tag.name = answer - do { - try managedObjectContext.save() - } catch { - print("Error") - } + save() } func loadTags(completionHandler: @escaping Weiter) -> Void { @@ -163,12 +158,26 @@ class DatabaseManager { let results = try! managedObjectContext.fetch(fetchRequest) for t in results { - let tag = MediaItem(name: t.name!, path: t.name!, root: "tags", type: ItemType.DETAILS) + let tag = MediaItem(name: t.name!, path: t.name!, root: "tags", type: ItemType.VIDEO) + tag.loaded = true let snapshots = t.tagged as! Set for s in snapshots { let i = s.item! let sitem = MediaItem(name: i.name!, path: i.path!, root: i.root!, type: ItemType.VIDEO) + let c = MediaItem(name: i.name!, path: i.path!, root: i.root!, type: ItemType.SNAPSHOT) + c.time = s.time + c.length = s.length + c.loop = s.loop + c.size.width = CGFloat(s.sizex) + c.size.height = CGFloat(s.sizey) + c.offset.x = CGFloat(s.offx) + c.offset.y = CGFloat(s.offy) + c.scale = s.scale + c.rating = Int(s.rating) + c.thumbUrl = s.thumb + + sitem.children.append(c) tag.children.append(sitem) } @@ -182,4 +191,37 @@ class DatabaseManager { completionHandler(res) } + + func addTag(_ name: String, _ item: MediaItem) { + let kFetch = KTag.fetchRequest() + kFetch.predicate = NSPredicate(format: "name == %@", name) + let tags = try! managedObjectContext.fetch(kFetch) + + if tags.isEmpty { + return + } + + let tag = tags[0] + + let fetchRequest = KItem.fetchRequest() + fetchRequest.predicate = NSPredicate(format: "name == %@", item.name) + + let results = try! managedObjectContext.fetch(fetchRequest) + + for r in results { + if "\(item.root)\(item.path)" == "\(r.root!)\(r.path!)" { + + let ksitems = r.snapshots as! Set + + for snap in ksitems { + if snap.index == item.indexId { + snap.addToTags(tag) + print(item.name) + } + } + } + } + + save() + } } diff --git a/kplayer/core/MediaItem.swift b/kplayer/core/MediaItem.swift index 85ef658..21c0b4d 100644 --- a/kplayer/core/MediaItem.swift +++ b/kplayer/core/MediaItem.swift @@ -98,6 +98,7 @@ class MediaItem: CustomDebugStringConvertible, ObservableObject, Identifiable { self.favorite = model.favorite self.loaded = true self.local = true + self.indexId = model.indexId for m in model.children { let item = MediaItem(model: m) @@ -128,6 +129,7 @@ class MediaItem: CustomDebugStringConvertible, ObservableObject, Identifiable { model.offset = offset model.scale = scale model.favorite = favorite + model.indexId = indexId return model } diff --git a/kplayer/core/MediaModel.swift b/kplayer/core/MediaModel.swift index 63c37bc..ab8f21c 100644 --- a/kplayer/core/MediaModel.swift +++ b/kplayer/core/MediaModel.swift @@ -21,6 +21,7 @@ public struct MediaModel : Codable { var scale = 0.0 var offset = CGPoint() var size = CGSize() + var indexId = 0 var children: [MediaModel] let type: ItemType diff --git a/kplayer/detail/DetailViewController.swift b/kplayer/detail/DetailViewController.swift index 1c559b4..9bcf04e 100644 --- a/kplayer/detail/DetailViewController.swift +++ b/kplayer/detail/DetailViewController.swift @@ -508,11 +508,11 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout var selectedItem = detail.children[indexPath.section] if selectedItem.children.count > indexPath.item { - selectedItem = selectedItem.children[indexPath.count] + selectedItem = selectedItem.children[indexPath.item] } if !selectedItem.local { - return [] + // return [] } let itemProvider = NSItemProvider(object: selectedItem.toJSON() as NSString) diff --git a/kplayer/master/MasterViewController.swift b/kplayer/master/MasterViewController.swift index 1ba2cb7..58c3ff6 100644 --- a/kplayer/master/MasterViewController.swift +++ b/kplayer/master/MasterViewController.swift @@ -308,11 +308,14 @@ class MasterViewController: UITableViewController, UISearchResultsUpdating, UITa if model.items.count <= d.row { return UITableViewDropProposal(operation: .forbidden) } - if (model.items[d.row].path == "new") { + let element = model.items[d.row] + if (element.path == "new") { return UITableViewDropProposal(operation: .forbidden) } - if (!model.items[d.row].local) { - return UITableViewDropProposal(operation: .forbidden) + if (!element.local) { + if element.root != "/tags" { + return UITableViewDropProposal(operation: .forbidden) + } } } else { @@ -352,6 +355,12 @@ class MasterViewController: UITableViewController, UISearchResultsUpdating, UITa let m = MediaItem(model: items) m.local = true let at = m.playerURL! + + if destinationItem.root == "/tags" { + DatabaseManager.sharedInstance.addTag(destinationItem.name, m) + return + } + m.path = destinationItem.path var to = m.playerURL! print(destinationItem.name) diff --git a/kplayer/timeline/CenterLine.swift b/kplayer/timeline/CenterLine.swift deleted file mode 100644 index c33fd5a..0000000 --- a/kplayer/timeline/CenterLine.swift +++ /dev/null @@ -1,126 +0,0 @@ -// -// CenterLine.swift -// Examplay -// -// Created by Tomohiro Yamashita on 2020/03/09. -// Copyright © 2020 Tom. All rights reserved. -// - -import UIKit -import AVFoundation - -class CenterLine: UIView { - - var mainView:VideoTimelineView! - - let timeLabel = UILabel() - var parentView:TimelineView? = nil - var duration:Float64 = 0 - var currentTime:Float64 = 0 - let margin:CGFloat = 6 - - override init (frame: CGRect) { - super.init(frame: frame) - - self.backgroundColor = .clear - self.isUserInteractionEnabled = false - } - - required init(coder aDecoder: NSCoder) { - fatalError("CenterLine init(coder:) has not been implemented") - } - - func configure(parent:TimelineView) { - parentView = parent - self.setNeedsDisplay() - - self.timeLabel.adjustsFontSizeToFitWidth = true - self.timeLabel.textAlignment = .center - - self.timeLabel.text = String("00:00.00") - - - self.addSubview(timeLabel) - } - - func update() { - self.setNeedsDisplay() - let textMargin = margin + 3 - self.timeLabel.frame.size.width = self.bounds.size.width - textMargin * 2 - self.timeLabel.frame.origin = CGPoint(x:textMargin,y:0) - self.timeLabel.textColor = UIColor(hue: 0.94, saturation:0.68, brightness:0.95, alpha: 0.94) - setTimeText() - timeLabel.font = UIFont(name:"HelveticaNeue-CondensedBold" ,size:timeLabel.frame.size.height * 0.9) - - } - - - override func draw(_ rect: CGRect) { - - - gradient() - - let context = UIGraphicsGetCurrentContext()! - context.saveGState() - context.setShadow(offset: CGSize(width: 0,height: 0), blur: 6, color: UIColor(hue: 0, saturation:0, brightness:0.0, alpha: 0.30).cgColor) - - UIColor(hue: 0, saturation:0, brightness:1, alpha: 0.92).setFill() - - let labelRect = CGRect(x: margin,y: 0.3,width: self.frame.size.width - margin * 2,height: timeLabel.frame.size.height + 1) - let rectPath = UIBezierPath(roundedRect:labelRect, cornerRadius:timeLabel.frame.size.height) - rectPath.fill() - context.restoreGState() - - - - let path = UIBezierPath() - path.move(to: CGPoint(x: self.frame.size.width / 2 , y:timeLabel.frame.size.height)) - path.addLine(to: CGPoint(x:self.frame.size.width / 2 , y:self.frame.size.height)) - path.lineWidth = 1.4 - UIColor(hue: 0, saturation:0, brightness:1.0, alpha: 0.7).setStroke() - path.stroke() - - } - - - func gradient() { - let width = self.frame.size.width - - - let context = UIGraphicsGetCurrentContext()! - - let startColor = UIColor(hue: 0, saturation:0, brightness:0.0, alpha: 0.06).cgColor - let endColor = UIColor.clear.cgColor - let colors = [startColor, endColor] as CFArray - - let locations = [0, 1] as [CGFloat] - - let space = CGColorSpaceCreateDeviceRGB() - - let gradient = CGGradient(colorsSpace: space, colors: colors, locations: locations)! - context.drawLinearGradient(gradient, start: CGPoint(x:(width / 2) - 0.7, y:0), end: CGPoint(x: (width / 2) - 4, y: 0), options: []) - context.drawLinearGradient(gradient, start: CGPoint(x:(width / 2) + 0.7, y:0), end: CGPoint(x: (width / 2) + 4, y: 0), options: []) - } - - var ignoreSendScrollToParent = false - func setScrollPoint(_ scrollPoint:CGFloat) { - currentTime = Float64(scrollPoint) * duration - setTimeText() - if !ignoreSendScrollToParent { - if let parent = parentView { - parent.moved(currentTime) - } - } - - mainView!.currentTime = currentTime - ignoreSendScrollToParent = false - } - - func setTimeText() { - let minute = Int(currentTime / 60) - let second = (currentTime - Float64(minute) * 60) - let milliSec = Int((second - Float64(Int(second))) * 100) - let text = String(format: "%02d:%02d.%02d", minute, (Int(second)), milliSec) - timeLabel.text = text - } -} diff --git a/kplayer/timeline/FrameImagesView.swift b/kplayer/timeline/FrameImagesView.swift deleted file mode 100644 index 366c348..0000000 --- a/kplayer/timeline/FrameImagesView.swift +++ /dev/null @@ -1,451 +0,0 @@ -// -// FrameImagesView.swift -// Examplay -// -// Created by Tomohiro Yamashita on 2020/03/01. -// Copyright © 2020 Tom. All rights reserved. -// - -import Foundation -import UIKit -import AVFoundation - - - -class FrameImage: UIImageView { - var tolerance:Float64? = nil -} - - -// MARK: - FrameImagesView -class FrameImagesView: UIScrollView { - - - var mainView:VideoTimelineView! - - var frameImagesArray:[FrameImage] = [] - - - var thumbnailFrameSize:CGSize = CGSize(width: 640,height: 480) - let preferredTimescale:Int32 = 100 - var timeTolerance = CMTimeMakeWithSeconds(10 , preferredTimescale:100) - - var maxWidth:CGFloat = 0 - var minWidth:CGFloat = 0 - - var parentScroller:TimelineScroller? = nil - - override init (frame: CGRect) { - super.init(frame: frame) - self.isScrollEnabled = false - self.isUserInteractionEnabled = false - self.backgroundColor = UIColor(hue: 0, saturation:0, brightness:0.0, alpha: 0.02) - } - - required init(coder aDecoder: NSCoder) { - fatalError("FrameImagesView init(coder:) has not been implemented") - } - - - - - func reset() { - discardAllFrameImages() - cancelImageGenerator() - - prepareFrameViews() - layout() - requestVisible(depth:0, wide:2, direction:0) - } - - //MARK: - timer for animation - var animationTimer = Timer() - var animating = false - func startAnimation() { - animating = true - displayFrames() - animationTimer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.animate(_:)), userInfo: nil, repeats: true) - RunLoop.main.add(animationTimer, forMode:RunLoop.Mode.common) - - } - - func stopAnimation() { - animationTimer.invalidate() - animating = false - - - if let parent = parentScroller { - frame.origin = CGPoint(x: parent.frame.size.width / 2, y: parent.measureHeight) - parent.addSubview(self) - } - displayFrames() - } - - @objc func animate(_ timer:Timer) { - if animating == false { - return - } - displayFrames() - } - - //MARK: - layout - - - var uponFrames = Set() - var belowFrames = Set() - var deepFrames = Set() - var hiddenFrames = Set() - - - func layout() { - setThumnailFrameSize() - let coordinated = coordinateFrames() - uponFrames = coordinated.upon - belowFrames = coordinated.below - hiddenFrames = coordinated.hidden - deepFrames = coordinated.deep - displayFrames() - } - - func displayFrames() { - - var baseView:UIView = self - var offset:CGPoint = CGPoint.zero - - if let parent = parentScroller { - let visibleHalf = parent.frame.size.width / 2 - - if animating { - if let layer = parent.layer.presentation() { - offset.x = visibleHalf - layer.bounds.origin.x - offset.y = parent.frame.origin.y + parent.measureHeight - frame.origin = offset - mainView!.timelineView.viewForAnimate.addSubview(self) - } - } - } - - let visibleSide = indexOfVisibleSide() - func locate(_ index:Int, visible:Bool) { - if frameImagesArray.count > index && index >= 0 { - let frameImg = frameImagesArray[index] - if index >= visibleSide.left && index <= visibleSide.right { - let position = positionWithIndex(index) - frameImg.frame = CGRect(x: position, y:0, width: thumbnailFrameSize.width, height: thumbnailFrameSize.height) - if visible { - self.addSubview(frameImg) - } else { - frameImg.removeFromSuperview() - } - } else { - frameImg.removeFromSuperview() - } - - } - } - for element in belowFrames {//do addSubview under the upon - locate(element, visible:true) - } - for element in uponFrames { - locate(element, visible:true) - } - for element in hiddenFrames {// includes deep - locate(element, visible:false) - } - - } - - func positionWithIndex(_ index:Int) -> CGFloat { - let position = frame.size.width * (CGFloat(index) / CGFloat(thumbnailCountFloat())) - return position - } - - func coordinateFrames() -> (upon:Set, below:Set, hidden:Set, deep:Set) { - - let keyDivision = Int(pow(2,Double(Int(log2(maxWidth * 2 / (self.frame.size.width + 1)))))) - if keyDivision <= 0 { - return (Set(), Set(), Set(), Set()) - } - let keyCount = ((frameImagesArray.count - 1) / keyDivision) + 1 - - - var visibleIndexes = Set() - var uponElements = Set() - for index in 0 ... (keyCount - 1) { - let uponIndex = index * keyDivision - uponElements.insert(uponIndex) - visibleIndexes.insert(uponIndex) - } - var belowElements = Set() - let belowDivision = keyDivision / 2 - if belowDivision >= 1 { - for index in 0 ..< (keyCount - 1) { - let belowIndex = (index * keyDivision) + (keyDivision / 2) - belowElements.insert(belowIndex) - visibleIndexes.insert(belowIndex) - } - } - var deepElements = Set() - let deepDivision = belowDivision / 2 - if deepDivision >= 1 { - if let max = visibleIndexes.max() { - for index in visibleIndexes { - if max > index { - deepElements.insert(index + deepDivision) - } - } - } - } - var hiddenElements = Set() - for index in 0 ..< frameImagesArray.count { - if !visibleIndexes.contains(index) { - let hiddenIndex = index - hiddenElements.insert(hiddenIndex) - } - } - return (uponElements,belowElements,hiddenElements, deepElements) - } - - - func setThumnailFrameSize() { - if let asset = mainView!.asset { - var frameSize = CGSize(width: 640,height: 480) - let tracks:Array = asset.tracks(withMediaType:AVMediaType.video) - if tracks.count > 0 { - let track = tracks[0] - frameSize = track.naturalSize.applying(track.preferredTransform) - frameSize.width = abs(frameSize.width) - frameSize.height = abs(frameSize.height) - } - thumbnailFrameSize = mainView!.resizeHeightKeepRatio(frameSize, height:self.frame.size.height) - } - } - - func assetDuration() -> Float64? { - if let asset = mainView!.asset { - return CMTimeGetSeconds(asset.duration) - } - return nil - } - - func prepareFrameViews() { - frameImagesArray = [] - for _ in 0 ... Int(thumbnailCountFloat()) { - let view = FrameImage() - view.alpha = 0 - frameImagesArray += [view] - } - } - - - - func thumbnailCountFloat() -> CGFloat { - return maxWidth / thumbnailFrameSize.width - } - - - func indexWithTime(_ time:Float64) -> Int? { - if let assetDuration = assetDuration() { - let value = time / (assetDuration / Float64(thumbnailCountFloat())) - var intValue = Int(value) - if value - Float64(intValue) >= 0.5 { - intValue += 1 - } - return intValue - } - return nil - } - - func timeWithIndex(_ index:Int) -> Float64 { - if let assetDuration = assetDuration() { - return assetDuration * ((Float64(index)) / Float64(thumbnailCountFloat())) - } - return 0 - } - - - - - //MARK: - frame images - func cancelImageGenerator() { - if let asset = mainView!.asset { - let assetImgGenerate : AVAssetImageGenerator = AVAssetImageGenerator(asset: asset) - assetImgGenerate.cancelAllCGImageGeneration() - } - } - - func discardAllFrameImages() { - - for index in 0 ..< frameImagesArray.count { - let view = frameImagesArray[index] - UIView.animate(withDuration: 0.5,delay:Double(0.0),options:UIView.AnimationOptions.curveEaseOut, animations: { () -> Void in - - view.alpha = 0 - - },completion: { finished in - - view.image = nil - view.removeFromSuperview() - view.tolerance = nil - }) - } - frameImagesArray = [] - } - - - - func requestAll(){ - - var timesArray = [NSValue]() - for index in 0 ..< frameImagesArray.count { - timesArray += [NSValue(time:CMTimeMakeWithSeconds(timeWithIndex(index) , preferredTimescale:preferredTimescale))] - } - requestImageGeneration(timesArray:timesArray) - } - - - var requesting = Set() - func requestVisible(depth:Int, wide:Float, direction:Float) { - var timesArray = [NSValue]() - func request(_ index:Int) { - - if self.requesting.count > 0 && self.requesting.contains(index) { - return - } - - if frameImagesArray.count > index { - let imageView = frameImagesArray[index] - var needsUpdate = false - if let tolerance = imageView.tolerance { - if tolerance > CMTimeGetSeconds(timeTolerance) * 1.2 { - needsUpdate = true - } - } - if imageView.image == nil || needsUpdate { - timesArray += [NSValue(time:CMTimeMakeWithSeconds(timeWithIndex(index) , preferredTimescale:preferredTimescale))] - self.requesting.insert(index) - } - } - } - let visibleSide = indexOfVisibleSide() - let width = visibleSide.right - visibleSide.left - var additionLeft = Int(Float(width) * wide) - var additionRight = additionLeft - if direction > 0 { - additionLeft = Int(Float(-width) * direction) - } else if direction < 0 { - additionRight = Int(Float(width) * direction) - } - - - for index in uponFrames { - if index >= visibleSide.left - additionLeft && index <= visibleSide.right + additionRight { - request(index) - } - } - let belowAddLeft = Int(Float(additionLeft) * 0.5) - Int(Float(width) * 0.7) - let belowAddRight = Int(Float(additionRight) * 0.5) - Int(Float(width) * 0.7) - if depth > 0 { - for index in belowFrames { - if index >= visibleSide.left - belowAddLeft && index <= visibleSide.right + belowAddRight { - request(index) - } - } - } - let deepAddLeft = Int(Float(additionLeft) * 0.2) - Int(Float(width) * 0.4) - let deepAddRight = Int(Float(additionRight) * 0.2) - Int(Float(width) * 0.4) - if depth > 1 { - for index in deepFrames { - if index >= visibleSide.left - deepAddLeft && index <= visibleSide.right + deepAddRight { - request(index) - } - } - } - if timesArray.count > 0 { - requestImageGeneration(timesArray:timesArray) - } - } - - func indexOfVisibleSide() -> (left:Int, right:Int) { - func indexWithPosition(_ position:CGFloat) -> Int{ - let index = position * CGFloat(thumbnailCountFloat()) / frame.size.width - var indexInt = Int(index) - if index - CGFloat(indexInt) > 0.5 { - indexInt += 1 - } - return indexInt - } - var visibleLeft = indexWithPosition(-(parentScroller!.frame.width / 2) + parentScroller!.contentOffset.x - thumbnailFrameSize.width) - 1 - var visibleRight = indexWithPosition(parentScroller!.contentOffset.x + (parentScroller!.frame.size.width * 0.5) + thumbnailFrameSize.width) - if visibleLeft < 0 { - visibleLeft = 0 - } - let max = frameImagesArray.count - 1 - if visibleRight > max { - visibleRight = max - } - return (visibleLeft, visibleRight) - } - - func updateTolerance() { - if mainView!.asset == nil { - return - } - let thumbDuration = Float64(thumbnailFrameSize.width / self.frame.size.width) * mainView!.duration * 2 - timeTolerance = CMTimeMakeWithSeconds(thumbDuration , preferredTimescale:100) - - - } - - func requestImageGeneration(timesArray:[NSValue]) { - - if let asset = mainView!.asset { - let assetImgGenerate : AVAssetImageGenerator = AVAssetImageGenerator(asset: asset) - assetImgGenerate.appliesPreferredTrackTransform = true - let maxsize = CGSize(width: thumbnailFrameSize.width * 1.5,height: thumbnailFrameSize.height * 1.5) - assetImgGenerate.maximumSize = maxsize - assetImgGenerate.requestedTimeToleranceAfter = timeTolerance - assetImgGenerate.requestedTimeToleranceBefore = timeTolerance - - assetImgGenerate.generateCGImagesAsynchronously(forTimes: timesArray, - completionHandler: - { time,resultImage,actualTime,result,error in - - let timeValue = CMTimeGetSeconds(time) - if let image = resultImage { - DispatchQueue.main.async { - self.setFrameImage(image:UIImage(cgImage:image), time:timeValue) - } - } - if let index = self.indexWithTime(timeValue) { - self.requesting.remove(index) - } - }) - } - } - - - func setFrameImage(image:UIImage, time:Float64) { - - if let index = indexWithTime(time) { - if frameImagesArray.count > index && index >= 0 { - let imageView = frameImagesArray[index] - - imageView.image = image - imageView.tolerance = CMTimeGetSeconds(timeTolerance) - UIView.animate(withDuration: 0.2,delay:Double(0),options:UIView.AnimationOptions.curveEaseOut, animations: { () -> Void in - - imageView.alpha = 1 - - },completion: { finished in - - - }) - imageView.alpha = 1 - imageView.backgroundColor = .red - } - } - } -} - - diff --git a/kplayer/timeline/TimelineMeasure.swift b/kplayer/timeline/TimelineMeasure.swift deleted file mode 100644 index f546ce3..0000000 --- a/kplayer/timeline/TimelineMeasure.swift +++ /dev/null @@ -1,206 +0,0 @@ -// -// TimelineMeasure.swift -// Examplay -// -// Created by Tomohiro Yamashita on 2020/03/08. -// Copyright © 2020 Tom. All rights reserved. -// - -import UIKit - -class TimelineMeasure: UIView { - - var unitSize:CGFloat = 100 - var frameImagesView:FrameImagesView? = nil - var parentScroller:TimelineScroller? = nil - var parentView:TimelineView? = nil - var stringColor:UIColor = UIColor(hue: 0.0, saturation:0.0, brightness:0.35, alpha: 1) - var animating = false - - override init (frame: CGRect) { - super.init(frame: frame) - - self.isMultipleTouchEnabled = true - self.isUserInteractionEnabled = true - } - - required init(coder aDecoder: NSCoder) { - fatalError("TimelineMeasure init(coder:) has not been implemented") - } - - - - override func draw(_ rect: CGRect) { - - if frameImagesView == nil { - return - } - - let max = frameImagesView!.maxWidth - var width = frameImagesView!.frame.size.width - if animating { - if let layer = frameImagesView!.layer.presentation() { - width = layer.frame.size.width - } - } - if width == 0 { - return - } - var unit = (width / max) * unitSize - - let unitWidth = CGFloat(80) - var division = 0 - while (unit <= unitWidth) { - unit *= 2 - division += 1 - if division > 1000 { - break - } - } - let unitLength = pow(2,Double(division + 1)) / 2 - func index(_ position:CGFloat) -> Int { - return Int(position / unit) - } - - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.alignment = .center - - let attributes = [NSAttributedString.Key.font: UIFont(name: "HelveticaNeue", size: self.frame.size.height * 0.7)!, NSAttributedString.Key.paragraphStyle: paragraphStyle, NSAttributedString.Key.foregroundColor: stringColor] - - var string = "" - - var visibleRect = rect - if let parent = parentScroller { - - if animating { - if let layer = parent.layer.presentation() { - let offset = layer.bounds.origin - visibleRect.origin = offset - visibleRect.size = parent.frame.size - } else { - visibleRect = parent.visibleRect() - } - } else { - visibleRect = parent.visibleRect() - } - } - let startIndex = index(visibleRect.origin.x) - 10 * (division + 1) - let endIndex = index(visibleRect.origin.x + visibleRect.size.width) - - for index in startIndex ... endIndex { - if index < 0 { - continue - } - let position = CGFloat(index) * unit - visibleRect.origin.x + (visibleRect.size.width / 2) - if division == 0 { - let path = UIBezierPath() - path.move(to: CGPoint(x: position + (unit / 2 ) - (unitWidth / 4) , y:(self.frame.size.height / 2))) - path.addLine(to: CGPoint(x: position + (unit / 2) + (unitWidth / 4), y:(self.frame.size.height / 2))) - path.lineWidth = 1 - stringColor.setStroke() - path.stroke() - } else { - for i in 1 ... 3 { - let point = position + ((unit / 4 ) * CGFloat(i)) - let r:CGFloat = 0.8 - let pointRect = CGRect(x: point - r, y: (self.frame.size.height / 2) - r, width: r * 2,height: r * 2) - let path = UIBezierPath(ovalIn:pointRect) - stringColor.setFill() - path.fill() - } - } - - let length = unitLength * Double(index) - let minute = Int(length / 60) - let second = Int(length - Double(minute * 60)) - - string = String(format: "%02d:%02d", minute, (Int(second))) - - string.draw(with: CGRect(x: position - (unitWidth / 2), y:0, width: unitWidth, height: self.frame.size.height), options: .usesLineFragmentOrigin, attributes: attributes, context: nil) - - - } - } - - //MARK: - timer for animation - var animationTimer = Timer() - func startAnimation() { - animationTimer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.animate(_:)), userInfo: nil, repeats: true) - RunLoop.main.add(animationTimer, forMode:RunLoop.Mode.common) - animating = true - } - - func stopAnimation() { - animating = false - self.setNeedsDisplay() - animationTimer.invalidate() - } - - @objc func animate(_ timer:Timer) { - if animating == false { - return - } - self.setNeedsDisplay() - } - - - - //MARK: - Touch Events - var allTouches = [UITouch]() - - override open func touchesBegan(_ touches: Set, with event: UIEvent?) - { - for touch in touches { - if !allTouches.contains(touch) { - allTouches += [touch] - } - if !parentView!.allTouches.contains(touch) { - parentView!.allTouches += [touch] - } - } - } - - - override open func touchesMoved(_ touches: Set, with event: UIEvent?) - { - if parentView!.allTouches.count == 2 { - if parentView!.pinching { - parentView!.updatePinch() - } else { - parentView!.startPinch() - } - } - } - - override open func touchesEnded(_ touches: Set, with event: UIEvent?) - { - for touch in touches { - if let index = allTouches.firstIndex(of:touch) { - allTouches.remove(at: index) - } - if let index = parentView!.allTouches.firstIndex(of:touch) { - parentView!.allTouches.remove(at: index) - } - } - if parentView!.pinching && parentView!.allTouches.count < 2 { - parentView!.endPinch() - } - } - - override open func touchesCancelled(_ touches: Set, with event: UIEvent?) - { - for touch in touches { - if let index = allTouches.firstIndex(of:touch) { - allTouches.remove(at: index) - } - if let index = parentView!.allTouches.firstIndex(of:touch) { - parentView!.allTouches.remove(at: index) - } - } - - if parentView!.pinching { - parentView!.endPinch() - } - } -} - diff --git a/kplayer/timeline/TimelineScroller.swift b/kplayer/timeline/TimelineScroller.swift deleted file mode 100644 index 698cb1b..0000000 --- a/kplayer/timeline/TimelineScroller.swift +++ /dev/null @@ -1,178 +0,0 @@ -// -// TimelineScroller.swift -// Examplay -// -// Created by Tomohiro Yamashita on 2020/03/01. -// Copyright © 2020 Tom. All rights reserved. -// - -import UIKit - -class TimelineScroller: UIScrollView { - - var parentView:TimelineView? = nil - let frameImagesView = FrameImagesView() - let measure = TimelineMeasure() - let trimView = TrimView() - - - override init (frame: CGRect) { - super.init(frame: frame) - - self.isScrollEnabled = true - self.isDirectionalLockEnabled = true - self.showsHorizontalScrollIndicator = false - self.showsVerticalScrollIndicator = false - self.bounces = false - self.decelerationRate = .fast - self.isMultipleTouchEnabled = true - self.delaysContentTouches = false - self.frameImagesView.parentScroller = self - self.addSubview(frameImagesView) - self.measure.parentScroller = self - self.measure.frameImagesView = self.frameImagesView - self.measure.backgroundColor = .clear - } - - required init(coder aDecoder: NSCoder) { - fatalError("TimelineScroller init(coder:) has not been implemented") - } - - func configure(parent:TimelineView) { - parentView = parent - trimView.configure(parent, scroller:self) - } - - func reset() { - frameImagesView.reset() - } - - var ignoreScrollViewDidScroll:Bool = false - func setContentWidth(_ width:CGFloat) { - setContentWidth(width, setOrigin:true) - } - - func setContentWidth(_ width: CGFloat, setOrigin:Bool) { - ignoreScrollViewDidScroll = true - self.contentSize = CGSize(width:width + self.frame.size.width, height:self.frame.size.height) - frameImagesView.frame.size.width = width - //measure.frame.size.width = width - - if setOrigin { - let halfVisibleWidth = self.frame.size.width / 2 - //frameImagesView.frame.size.height = self.frame.size.height - frameImagesView.frame.origin.x = halfVisibleWidth - } - //measure.frame.origin.x = halfVisibleWidth - measure.setNeedsDisplay() - frameImagesView.displayFrames() - } - - var measureHeight:CGFloat = 5 - func coordinate() { - - let measureMin:CGFloat = 10 - - let wholeHeight = self.frame.size.height - measureHeight = wholeHeight * 0.2 - if measureHeight < measureMin { - measureHeight = measureMin - } - frameImagesView.frame.size.height = wholeHeight - measureHeight - if frameImagesView.animating == false { - frameImagesView.frame.origin = CGPoint(x: self.frame.size.width / 2,y: measureHeight) - } - measure.frame.size.height = measureHeight - //frameImagesView.layout() - - trimView.frame = self.frame - - } - - func visibleRect() -> CGRect { - var visibleRect = frame - visibleRect.origin = contentOffset - if contentSize.width < frame.size.width { - visibleRect.size.width = contentSize.width - } - if contentSize.height < frame.size.height { - visibleRect.size.height = contentSize.height - } - if zoomScale != 1 { - let theScale = 1.0 / zoomScale; - visibleRect.origin.x *= theScale; - visibleRect.origin.y *= theScale; - visibleRect.size.width *= theScale; - visibleRect.size.height *= theScale; - } - return visibleRect - } - - - //MARK: - scroll - func setScrollPoint(_ scrollPoint:CGFloat) { - let offset = (scrollPoint * frameImagesView.frame.size.width) + (self.frame.size.width / 2) - - self.contentOffset.x = offset - (self.frame.size.width / 2) - } - - - //MARK: - Touch Events - var allTouches = [UITouch]() - - override open func touchesBegan(_ touches: Set, with event: UIEvent?) - { - for touch in touches { - if !allTouches.contains(touch) { - allTouches += [touch] - } - if !parentView!.allTouches.contains(touch) { - parentView!.allTouches += [touch] - } - } - - } - - override open func touchesMoved(_ touches: Set, with event: UIEvent?) - { - if parentView!.allTouches.count == 2 { - if parentView!.pinching { - parentView!.updatePinch() - } else { - parentView!.startPinch() - } - } - } - - override open func touchesEnded(_ touches: Set, with event: UIEvent?) - { - for touch in touches { - if let index = allTouches.firstIndex(of:touch) { - allTouches.remove(at: index) - } - if let index = parentView!.allTouches.firstIndex(of:touch) { - parentView!.allTouches.remove(at: index) - } - } - if parentView!.pinching && parentView!.allTouches.count < 2 { - parentView!.endPinch() - } - } - - override open func touchesCancelled(_ touches: Set, with event: UIEvent?) - { - for touch in touches { - if let index = allTouches.firstIndex(of:touch) { - allTouches.remove(at: index) - } - if let index = parentView!.allTouches.firstIndex(of:touch) { - parentView!.allTouches.remove(at: index) - } - } - - if parentView!.pinching { - parentView!.endPinch() - } - } -} - diff --git a/kplayer/timeline/TimelineView.swift b/kplayer/timeline/TimelineView.swift deleted file mode 100644 index da7d225..0000000 --- a/kplayer/timeline/TimelineView.swift +++ /dev/null @@ -1,460 +0,0 @@ -// -// TimelineView.swift -// Examplay -// -// Created by Tomohiro Yamashita on 2020/02/18. -// Copyright © 2020 Tom. All rights reserved. -// - -import Foundation -import UIKit -import AVFoundation - -class TimelineView: UIView, UIScrollViewDelegate { - var mainView:VideoTimelineView? = nil - let scroller = TimelineScroller() - let centerLine = CenterLine() - let viewForAnimate = UIScrollView() - - let durationPerHeight:Float64 = 0.35 - var animating = false - - override init (frame: CGRect) { - - super.init(frame: frame) - - self.backgroundColor = UIColor(hue: 0, saturation:0, brightness:0.0, alpha: 0.05) - - viewForAnimate.frame.origin = CGPoint.zero - viewForAnimate.isScrollEnabled = false - viewForAnimate.isUserInteractionEnabled = false - self.addSubview(viewForAnimate) - - self.addSubview(scroller) - scroller.delegate = self - - self.addSubview(scroller.measure) - scroller.configure(parent: self) - centerLine.configure(parent:self) - coordinate() - - self.addSubview(scroller.trimView) - self.addSubview(centerLine) - - scroller.measure.parentView = self - } - - required init(coder aDecoder: NSCoder) { - fatalError("TimelineView init(coder:) has not been implemented") - } - - - //MARK: - coordinate - func coordinate() { - if mainView == nil { - return - } - frame = mainView!.bounds - viewForAnimate.frame.size = self.frame.size - - scroller.frame = self.bounds - scroller.frameImagesView.frame.size.height = scroller.frame.size.height - scroller.measure.frame = scroller.frame - scroller.measure.frame.size.height = 20 - scroller.coordinate() - - centerLine.timeLabel.frame.size.height = scroller.measure.frame.size.height - 2 - let centerLineWidth:CGFloat = scroller.measure.frame.size.height * 5 - centerLine.frame = CGRect(x: (self.frame.size.width - centerLineWidth) / 2,y: 0,width: centerLineWidth,height: self.frame.size.height) - - centerLine.update() - - guard let view = (mainView) else { return } - guard let _ = (view.asset) else { return } - if scroller.frameImagesView.frame.size.width <= 0 { - return - } - let previousThumbSize = scroller.frameImagesView.thumbnailFrameSize - scroller.frameImagesView.setThumnailFrameSize() - let thumbSize = scroller.frameImagesView.thumbnailFrameSize - let unit = (thumbSize.height / CGFloat(durationPerHeight)) - scroller.measure.unitSize = unit - let contentMaxWidth = (unit * CGFloat(centerLine.duration)) - scroller.frameImagesView.maxWidth = contentMaxWidth - let defineMin = scroller.frame.size.width * 0.8 - var contentMinWidth:CGFloat - - if scroller.frameImagesView.maxWidth <= defineMin { - contentMinWidth = scroller.frameImagesView.maxWidth - } else { - contentMinWidth = snapWidth(defineMin, max:scroller.frameImagesView.maxWidth) - } - - scroller.frameImagesView.minWidth = contentMinWidth - - var currentWidth = snapWidth((scroller.frameImagesView.thumbnailFrameSize.width / previousThumbSize.width) * scroller.frameImagesView.frame.size.width, max:scroller.frameImagesView.maxWidth) - if currentWidth < scroller.frameImagesView.minWidth { - currentWidth = scroller.frameImagesView.minWidth - } else if currentWidth > scroller.frameImagesView.maxWidth { - currentWidth = scroller.frameImagesView.maxWidth - } - - scroller.setContentWidth(currentWidth) - - scroller.reset() - - scroller.trimView.layout() - if view.currentTime <= view.duration { - setCurrentTime(view.currentTime, force:false) - } - } - - func snapWidth(_ width:CGFloat, max:CGFloat) -> CGFloat { - let n = log2((2 * max) / width) - var intN = CGFloat(Int(n)) - if n - intN >= 0.5 { - intN += 1 - } - let result = (2 * max) / (pow(2,intN)) - return result - } - - func scrollPoint() -> CGFloat { - return scroller.contentOffset.x / scroller.frameImagesView.frame.size.width - } - - - - //MARK: new movie set - func newMovieSet() { - - coordinate() - if let asset = mainView!.asset{ - scroller.frameImagesView.setThumnailFrameSize() - - let duration = asset.duration - let durationFloat = CMTimeGetSeconds(duration) - centerLine.duration = durationFloat - - let detailThumbSize = scroller.frameImagesView.thumbnailFrameSize - - let unit = (detailThumbSize.height / CGFloat(durationPerHeight)) - scroller.measure.unitSize = unit - - - let contentMaxWidth = (unit * CGFloat(centerLine.duration)) - scroller.frameImagesView.maxWidth = contentMaxWidth - - - let defineMin = scroller.frame.size.width * 0.8 - var contentMinWidth:CGFloat - - if scroller.frameImagesView.maxWidth <= defineMin { - contentMinWidth = scroller.frameImagesView.maxWidth - } else { - contentMinWidth = snapWidth(defineMin, max:scroller.frameImagesView.maxWidth) - } - scroller.frameImagesView.minWidth = contentMinWidth - scroller.setContentWidth(scroller.frameImagesView.minWidth) - - scroller.reset() - scroller.trimView.reset(duration:durationFloat) - } - } - - //MARK: - currentTime - func setCurrentTime(_ currentTime:Float64, force:Bool) { - if inAction() && force == false { - return - } - if mainView!.asset == nil { - return - } - var scrollPoint:CGFloat = 0 - scrollPoint = CGFloat(currentTime / mainView!.duration) - - centerLine.ignoreSendScrollToParent = true - centerLine.setScrollPoint(scrollPoint) - scroller.ignoreScrollViewDidScroll = true - scroller.setScrollPoint(scrollPoint) - - scroller.frameImagesView.requestVisible(depth:0, wide:0, direction:0) - - scroller.frameImagesView.displayFrames() - scroller.measure.setNeedsDisplay() - } - - func moved(_ currentTime:Float64) { - mainView!.timelineIsMoved(currentTime, scrub:true) - } - - - //MARK: - TrimViews - func setTrimmerStatus(enabled:Bool) { - if enabled { - scroller.trimView.alpha = 1 - scroller.trimView.startKnob.isUserInteractionEnabled = true - scroller.trimView.alpha = 1 - scroller.trimView.endKnob.isUserInteractionEnabled = true - - } else { - scroller.trimView.alpha = 0.5 - scroller.trimView.startKnob.isUserInteractionEnabled = false - scroller.trimView.alpha = 0.5 - scroller.trimView.endKnob.isUserInteractionEnabled = false - } - } - - func setTrimmerVisible(_ visible:Bool) { - scroller.trimView.isHidden = !visible - } - - - func setTrim(start:Float64?, end:Float64?) { - var changed = false - if start != nil { - scroller.trimView.startKnob.knobTimePoint = start! - changed = true - } - if end != nil { - scroller.trimView.endKnob.knobTimePoint = end! - changed = true - } - if changed { - scroller.trimView.layout() - } - } - - func setTrimWithAnimation(trim:VideoTimelineTrim, time:Float64) { - scroller.trimView.moveToTimeAndTrimWithAnimation(time, trim:trim) - } - - - var manualScrolledAfterEnd = false - func setTrimViewInteraction(_ active:Bool) { - if mainView!.trimEnabled == false && active { - return - } - - scroller.trimView.startKnob.isUserInteractionEnabled = active - scroller.trimView.endKnob.isUserInteractionEnabled = active - - if active { - setManualScrolledAfterEnd() - } - } - - func setManualScrolledAfterEnd() { - let trim = currentTrim() - if mainView!.asset != nil { - let currentTime = mainView!.currentTime - if currentTime >= trim.end { - manualScrolledAfterEnd = true - } else { - manualScrolledAfterEnd = false - } - } - } - - func currentTrim() -> (start:Float64, end:Float64) { - var start = scroller.trimView.startKnob.knobTimePoint - var end = scroller.trimView.endKnob.knobTimePoint - if mainView!.asset != nil { - if end > mainView!.duration { - end = mainView!.duration - } - if start < 0 { - start = 0 - } - } - return (start, end) - } - - - func swapTrimKnobs() { - let knob = scroller.trimView.endKnob - scroller.trimView.endKnob = scroller.trimView.startKnob - scroller.trimView.startKnob = knob - } - - //MARK: - animation - func startAnimation() { - scroller.frameImagesView.startAnimation() - scroller.measure.startAnimation() - scroller.trimView.startAnimation() - } - - func stopAnimation() { - scroller.frameImagesView.stopAnimation() - scroller.measure.stopAnimation() - scroller.trimView.stopAnimation() - } - - - - - - //MARK: - Gestures - func inAction() -> Bool { - if allTouches.count > 0 || scroller.isTracking || scroller.isDecelerating { - return true - } else { - return false - } - } - - //MARK: - Scrolling - - var allTouches = [UITouch]() - var pinching:Bool = false - - func scrollViewDidScroll(_ scrollView:UIScrollView) { - scroller.trimView.layout() - if scroller.ignoreScrollViewDidScroll { - scroller.ignoreScrollViewDidScroll = false - return - } - scroller.measure.setNeedsDisplay() - scroller.frameImagesView.displayFrames() - setTrimViewInteraction(false) - let scrollPoint = scroller.contentOffset.x / scroller.frameImagesView.frame.size.width - self.centerLine.setScrollPoint(scrollPoint) - - guard let mView = (mainView) else { return } - if let receiver = mView.playStatusReceiver { - receiver.videoTimelineMoved() - } - } - - func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { - scroller.frameImagesView.requestVisible(depth:0, wide:0, direction:0) - setTrimViewInteraction(true) - let scrollPoint = scroller.contentOffset.x / scroller.frameImagesView.frame.size.width - self.centerLine.setScrollPoint(scrollPoint) - } - - func scrollViewDidEndDragging(_ scrollView: UIScrollView, - willDecelerate decelerate: Bool) { - scroller.frameImagesView.requestVisible(depth:0, wide:0, direction:0) - if decelerate == false { - setTrimViewInteraction(true) - } - let scrollPoint = scroller.contentOffset.x / scroller.frameImagesView.frame.size.width - self.centerLine.setScrollPoint(scrollPoint) - } - - - - //MARK: - Zooming - - var pinchCenterInContent:CGFloat = 0 - var pinchStartDistance:CGFloat = 0 - var pinchStartContent:(x:CGFloat,width:CGFloat) = (0,0) - func pinchCenter(_ pointA:CGPoint, pointB:CGPoint) -> CGPoint { - return CGPoint(x: (pointA.x + pointB.x) / 2, y: (pointA.y + pointB.y) / 2) - } - func pinchDistance(_ pointA:CGPoint, pointB:CGPoint) -> CGFloat { - return sqrt(pow((pointA.x - pointB.x),2) + pow((pointA.y - pointB.y),2)); - } - func startPinch() { - pinching = true - scroller.isScrollEnabled = false - - let touch1 = allTouches[0] - let touch2 = allTouches[1] - let center = pinchCenter(touch1.location(in: self),pointB: touch2.location(in: self)) - - pinchStartDistance = pinchDistance(touch1.location(in: self),pointB: touch2.location(in: self)) - let framewidth = scroller.frame.size.width - pinchStartContent = ((framewidth / 2) - scroller.contentOffset.x,scroller.contentSize.width - framewidth) - pinchCenterInContent = (center.x - pinchStartContent.x) / pinchStartContent.width - } - - func updatePinch() { - let touch1 = allTouches[0] - let touch2 = allTouches[1] - let center = pinchCenter(touch1.location(in: self), pointB:touch2.location(in: self)) - var sizeChange = (1 * pinchDistance(touch1.location(in: self), pointB: touch2.location(in: self))) / pinchStartDistance - - var contentWidth = pinchStartContent.width * sizeChange - - let sizeMin = scroller.frameImagesView.minWidth - let sizeMax = scroller.frameImagesView.maxWidth - - if contentWidth < sizeMin { - let sizeUnit = sizeMin / pinchStartContent.width - sizeChange = ((pow(sizeChange/sizeUnit,2)/4) + 0.75) * sizeUnit - contentWidth = pinchStartContent.width * sizeChange - contentWidth = sizeMin - } else if contentWidth > sizeMax { - sizeChange = sizeMax - contentWidth = sizeMax - } else { - let startRatio = pinchStartContent.width / sizeMax - let currentRatio = startRatio * sizeChange - let effect = ((sin(CGFloat.pi * 2 * log2(2/currentRatio)) * 0.108) - (sin(CGFloat.pi * 6 * log2(2/currentRatio)) * 0.009)) * currentRatio - let resultWidth = sizeMax * (currentRatio + effect) - contentWidth = resultWidth - } - let contentOrigin = center.x - (contentWidth * pinchCenterInContent) - scroller.contentOffset.x = (scroller.frame.size.width / 2) - contentOrigin - scroller.setContentWidth(contentWidth) - scroller.frameImagesView.layout() - - scroller.frameImagesView.requestVisible(depth:2, wide:0, direction:0) - self.centerLine.setScrollPoint(scroller.contentOffset.x / scroller.frameImagesView.frame.size.width) - scroller.trimView.layout() - } - - func endPinch() { - scroller.frameImagesView.requestVisible(depth:0, wide:1, direction:0) - - let width = snapWidth(scroller.frameImagesView.frame.size.width, max:scroller.frameImagesView.maxWidth) - - let offset = self.resizedPositionWithKeepOrigin(width:scroller.frameImagesView.frame.size.width, origin:scroller.contentOffset.x, destinationWidth:width) - //startAnimation() - - UIView.animate(withDuration: 0.1,delay:Double(0.0),options:UIView.AnimationOptions.curveEaseOut, animations: { () -> Void in - - self.scroller.setContentWidth(width, setOrigin:false) - self.scroller.contentOffset.x = offset - self.scroller.frameImagesView.layout() - self.scroller.trimView.layout() - },completion: { finished in - self.pinching = false - self.scroller.isScrollEnabled = true - }) - - self.scroller.frameImagesView.updateTolerance() - - self.centerLine.setScrollPoint(scroller.contentOffset.x / scroller.frameImagesView.frame.size.width) - - setTrimViewInteraction(true) - - guard let mView = (mainView) else { return } - if let receiver = mView.playStatusReceiver { - receiver.videoTimelineMoved() - } - } - - func resizedPositionWithKeepOrigin(width:CGFloat, origin:CGFloat, destinationWidth:CGFloat) -> CGFloat { - let originPoint = origin / width - let result = originPoint * destinationWidth - return result - } - - -} - - - - - - - - - - - - - diff --git a/kplayer/timeline/TrimView.swift b/kplayer/timeline/TrimView.swift deleted file mode 100644 index d1f7da3..0000000 --- a/kplayer/timeline/TrimView.swift +++ /dev/null @@ -1,773 +0,0 @@ -// -// TrimView.swift -// Examplay -// -// Created by Tomohiro Yamashita on 2020/03/12. -// Copyright © 2020 Tom. All rights reserved. -// - -import UIKit - -class TrimView: UIView { - var mainView:VideoTimelineView! - - var timelineView:TimelineView! - var parentScroller:TimelineScroller! - var startKnob = TrimKnob() - var endKnob = TrimKnob() - var movieDuration:Float64 = 0 - - let canPassThroughEachKnobs = true - - override init (frame: CGRect) { - super.init(frame: frame) - self.isUserInteractionEnabled = false - self.backgroundColor = .clear - - } - - required init(coder aDecoder: NSCoder) { - fatalError("TrimView init(coder:) has not been implemented") - } - - func configure(_ timeline:TimelineView, scroller:TimelineScroller) { - timelineView = timeline - parentScroller = scroller - self.frame = timeline.frame - startKnob.configure(timeline, trimmer:self) - endKnob.configure(timeline, trimmer:self) - - timelineView.addSubview(startKnob) - timelineView.addSubview(endKnob) - } - - - func reset(duration:Float64) { - movieDuration = duration - startKnob.knobTimePoint = 0 - endKnob.knobTimePoint = 3 - if duration < endKnob.knobTimePoint { - endKnob.knobTimePoint = duration - } - layout() - } - - - - let knobWidth:CGFloat = 20 - let knobWidthExtend:CGFloat = 5 - func layout() { - if self.isHidden { - return - } - - swapKnobs() - - let knobPositions = knobPositionsAsVisible() - let startPosition = knobPositions.start - let endPosition = knobPositions.end - - startKnob.knobPositionOnScreen = startPosition - endKnob.knobPositionOnScreen = endPosition - startKnob.isOutOfScreen = knobPositions.startFixed - endKnob.isOutOfScreen = knobPositions.endFixed - - startKnob.frame = CGRect(x:startPosition - knobWidth - knobWidthExtend, y:self.frame.origin.y, width:knobWidth + knobWidthExtend * 2, height:self.frame.size.height) - endKnob.frame = CGRect(x:endPosition - knobWidthExtend, y:self.frame.origin.y, width:knobWidth + knobWidthExtend * 2, height:self.frame.size.height) - - self.setNeedsDisplay() - } - - //MARK: - draw - - override func draw(_ rect: CGRect) { - - - var startRect = startKnob.frame - var endRect = endKnob.frame - if startRect.size.height <= 0 { - return - } - if animating { - if let layer = startKnob.layer.presentation() { - startRect = layer.frame - } - if let layer = endKnob.layer.presentation() { - endRect = layer.frame - } - } - startRect.origin.x += knobWidthExtend - startRect.size.width -= knobWidthExtend * 2 - endRect.origin.x += knobWidthExtend - endRect.size.width -= knobWidthExtend * 2 - if startRect.origin.x > endRect.origin.x + endRect.size.width { - let swapRect = startRect - startRect = endRect - endRect = swapRect - } - - - let beamWidth:CGFloat = 3 - var outerRect = CGRect(x: startRect.origin.x,y: 0,width: endRect.origin.x + endRect.size.width - startRect.origin.x,height:startRect.size.height) - var innerRect = CGRect(x:startRect.origin.x + startRect.size.width,y:beamWidth,width: endRect.origin.x - startRect.origin.x - startRect.size.width,height:startRect.size.height - (beamWidth * 2)) - - let screenLeft = cgToTime(screenToTimelinePosition(0)) - let screenRight = cgToTime(screenToTimelinePosition(timelineView.frame.size.width)) - var color = UIColor(hue: 0.1, saturation:0.8, brightness:1, alpha: 1) - let outColor = UIColor(hue: 0.1, saturation:0.8, brightness:1, alpha: 0.3) - if (endKnob.knobTimePoint < screenLeft || startKnob.knobTimePoint > screenRight) { - color = outColor - } else { - let addition = knobWidth + 10 - let knobWidthTime = cgToTime(knobWidth) - if endKnob.knobTimePoint + knobWidthTime * 0.9 > screenRight { - outerRect.size.width += addition - innerRect.size.width += addition - let outRect = CGRect(x: timelineView.frame.size.width - knobWidth, y: beamWidth,width: knobWidth, height: endRect.size.height - beamWidth * 2) - let path = UIBezierPath(rect:outRect) - outColor.setFill() - path.fill() - } - if startKnob.knobTimePoint - knobWidthTime * 0.9 < screenLeft { - outerRect.origin.x -= addition - innerRect.origin.x -= addition - outerRect.size.width += addition - innerRect.size.width += addition - let outRect = CGRect(x: 0, y: beamWidth,width: knobWidth, height: endRect.size.height - beamWidth * 2) - let path = UIBezierPath(rect:outRect) - outColor.setFill() - path.fill() - } - } - - let path = UIBezierPath(roundedRect:outerRect, cornerRadius:5) - path.usesEvenOddFillRule = true - let innerPath = UIBezierPath(roundedRect:innerRect, cornerRadius:2) - path.append(innerPath) - color.setFill() - path.fill() - } - - - - //MARK: - timer for animation - var animationTimer = Timer() - var animating = false - func startAnimation() { - animationTimer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.animate(_:)), userInfo: nil, repeats: true) - RunLoop.main.add(animationTimer, forMode:RunLoop.Mode.common) - animating = true - } - - func stopAnimation() { - animating = false - self.setNeedsDisplay() - animationTimer.invalidate() - } - - @objc func animate(_ timer:Timer) { - if animating == false { - return - } - self.setNeedsDisplay() - } - - - //MARK: - positioning - func swapKnobs() { - if startKnob.knobTimePoint > endKnob.knobTimePoint { - if canPassThroughEachKnobs { - //timelineView.swapTrimKnobs() - } else { - let start = endKnob.knobTimePoint - endKnob.knobTimePoint = startKnob.knobTimePoint - startKnob.knobTimePoint = start - } - } - } - - func anotherKnob(_ knob:TrimKnob) -> TrimKnob { - if knob == startKnob { - return endKnob - } - return startKnob - } - - func knobOnScreen(_ knob:TrimKnob) -> CGFloat { - let maxWidth = scrollMaxWidth() - let offset = scrollOffset() - let position = CGFloat(knob.knobTimePoint / movieDuration) * maxWidth - return position - offset + (timelineView.frame.size.width / 2) - } - - func knobsMinDistanceTime() -> Float64 { - return Float64(0.1) - } - - func knobsMinDistanceFloat() -> CGFloat { - return timeToCG(knobsMinDistanceTime()) - } - - func timeToCG(_ time:Float64) -> CGFloat { - return CGFloat(time / movieDuration) * scrollMaxWidth() - } - - func cgToTime(_ cgFloat:CGFloat) -> Float64 { - return Float64(cgFloat / scrollMaxWidth()) * movieDuration - } - - func screenToTimelinePosition(_ onScreen:CGFloat) -> CGFloat { - return onScreen + scrollOffset() - (timelineView.frame.size.width / 2) - } - - func timelineToScreenPosition(_ position:CGFloat) -> CGFloat { - return position - scrollOffset() + (timelineView.frame.size.width / 2) - } - - func knobPositionsAsVisible() -> (start:CGFloat, end:CGFloat, startFixed:Bool, endFixed:Bool) { - - let positionStart = knobOnScreen(startKnob) - let positionEnd = knobOnScreen(endKnob) - var resultStart = positionStart - var resultEnd = positionEnd - var startFixed:Bool = false - var endFixed:Bool = false - let screenRight = timelineView.frame.size.width// + offset - let minDistance = knobsMinDistanceFloat() - - if positionStart < knobWidth { - if (positionEnd - minDistance - knobWidth) < 0 { - resultStart = positionEnd - minDistance - } else { - resultStart = knobWidth - } - startFixed = true - } else if positionStart > screenRight { - resultStart = screenRight - startFixed = true - } - if positionEnd < 0 { - resultEnd = 0 - endFixed = true - } else if positionEnd + knobWidth > screenRight { - if positionStart + minDistance + knobWidth > screenRight { - resultEnd = positionStart + minDistance - } else { - resultEnd = screenRight - knobWidth - } - } - if true { - let distance = abs(resultStart - resultEnd) - if distance < minDistance { - let value = (minDistance - distance) / 2 - resultStart -= value - resultEnd += value - startFixed = true - endFixed = true - } - } - return (resultStart, resultEnd, startFixed, endFixed) - } - - func scrollOffset() -> CGFloat { - return parentScroller.contentOffset.x - } - - func scrollMaxWidth() -> CGFloat { - return parentScroller.frameImagesView.frame.size.width - } - - func knobTimeOnScreen(_ knob:TrimKnob) -> Float64 { - let offset = scrollOffset() - let position = offset + knob.knobPositionOnScreen - (timelineView.frame.size.width / 2) - let maxWidth = scrollMaxWidth() - let time = Float64(position / maxWidth) * movieDuration - return time - } - - - func knobMoveRange(_ knob:TrimKnob) -> (min:Float64, max:Float64) { - var min:Float64 = 0 - var max:Float64 = movieDuration - let minDistance = knobsMinDistanceTime() - if canPassThroughEachKnobs { - if knob == startKnob { - max -= minDistance - } else if knob == endKnob { - min += minDistance - } - } else { - if knob == startKnob { - max = endKnob.knobTimePoint - minDistance - } else if knob == endKnob { - min = startKnob.knobTimePoint + minDistance - } - } - return (min, max) - } - - func visibleKnobMoveLimit(_ knob:TrimKnob, margin:CGFloat) -> (min:Bool, max:Bool) { - let range = knobMoveRange(knob) - let minOnScreen = timelineToScreenPosition(timeToCG(range.min)) - let maxOnScreen = timelineToScreenPosition(timeToCG(range.max)) - var resultMin = false - var resultMax = false - if minOnScreen >= margin && minOnScreen <= timelineView.frame.width - margin { - resultMin = true - } - if maxOnScreen >= margin && maxOnScreen <= timelineView.frame.width - margin { - resultMax = true - } - return (resultMin , resultMax ) - } - - func directionReachesEnd(_ knob:TrimKnob, direction:CGFloat) -> Bool { - let visibleLimit = visibleKnobMoveLimit(knob, margin:knobWidth) - if direction > 0 { - if visibleLimit.max { - return true - } - } else if direction < 0 { - if visibleLimit.min { - return true - } - } - return false - } - - func fixKnobPoint(_ knob:TrimKnob, move:CGFloat, startKnobPoint:Float64) -> (knobPoint:Float64, fixed:Bool) { - - var timePoint = startKnobPoint + cgToTime(move) - - let moveRange = knobMoveRange(knob) - var fixed = false - if timePoint < moveRange.min { - timePoint = moveRange.min - fixed = true - } - if timePoint > moveRange.max { - timePoint = moveRange.max - fixed = true - } - return (timePoint, fixed) - } - - func updateKnob(_ knob:TrimKnob, timePoint:Float64) { - knob.knobTimePoint = timePoint - layout() - - timelineView.moved(knob.knobTimePoint) - } - - func resetSeek(_ time:Float64) { - if edgeScrolled { - moveToTimeWithAnimation(time) - } else { - mainView!.accurateSeek(time, scrub:true) - } - edgeScrolled = false - } - - func moveToTimeWithAnimation(_ time:Float64) { - moveToTimeAndTrimWithAnimation(time, trim:nil) - } - - func moveToTimeAndTrimWithAnimation(_ time:Float64, trim:VideoTimelineTrim?) { - let player = mainView!.player - if player == nil { - return - } - if player!.timeControlStatus == .playing { - player!.pause() - } - timelineView.animating = true - mainView!.isUserInteractionEnabled = false - timelineView.startAnimation() - - UIView.animate(withDuration: 0.2,delay:Double(0.0),options:UIView.AnimationOptions.curveEaseOut, animations: { () -> Void in - if let pinnedTrim = trim { - self.timelineView.setTrim(start:pinnedTrim.start,end:pinnedTrim.end) - } - self.timelineView.setCurrentTime(time,force:false) - },completion: { finished in - - self.mainView!.isUserInteractionEnabled = true - if self.mainView!.playing { - self.mainView!.accurateSeek(time, scrub:false) - player!.play() - } else { - self.mainView!.accurateSeek(time, scrub:true) - } - self.timelineView.animating = false - self.timelineView.setManualScrolledAfterEnd() - self.timelineView.stopAnimation() - if let receiver = self.mainView!.playStatusReceiver { - receiver.videoTimelineMoved() - } - }) - } - - //MARK: - edgeScroll - var edgeScrollTimer = Timer() - var edgeScrolled = false - var edgeScrollingKnob:TrimKnob? = nil - var edgeScrollStrength:CGFloat = 0 - var edgeScrollingKnobPosition:CGFloat = 0 - var edgeScrollLastChangedTime:Date = Date() - var edgeScrollLastChangedPosition:CGFloat = 0 - - - func updateEdgeScroll(_ knob:TrimKnob, strength:CGFloat, position:CGFloat) { - var changed = false - if edgeScrollStrength != strength { - edgeScrollStrength = strength - changed = true - } - if edgeScrolling() == false { - startEdgeScroll(knob) - edgeScrolled = true - } else if changed { - edgeScrollLastChangedPosition = scrollOffset() - edgeScrollLastChangedTime = Date() - } - edgeScrollingKnobPosition = position - edgeScrollingKnob = knob - } - - func startEdgeScroll(_ knob:TrimKnob) { - edgeScrollTimer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.edgeScrollTimer(_:)), userInfo: nil, repeats: true) - RunLoop.main.add(edgeScrollTimer, forMode:RunLoop.Mode.common) - edgeScrollLastChangedTime = Date() - edgeScrollLastChangedPosition = scrollOffset() - } - - @objc func edgeScrollTimer(_ timer:Timer) { - if let knob = edgeScrollingKnob { - let movedPosition = currentEdgeScrollMovedPosition() - let destination = currentEdgeScrollPosition(movedPosition) - let moveRange = knobMoveRange(knob) - var knobPoint = cgToTime(edgeScrollingKnobPosition - (timelineView.frame.size.width / 2) + destination) - - var overLimit:Float64 = 0 - if knobPoint > moveRange.max { - overLimit = knobPoint - moveRange.max - knobPoint = moveRange.max - - } else if knobPoint < moveRange.min { - overLimit = knobPoint - moveRange.min - knobPoint = moveRange.min - - } - updateKnob(knob, timePoint:knobPoint) - if (knob == startKnob && knobPoint > endKnob.knobTimePoint) || (knob == endKnob && knobPoint < startKnob.knobTimePoint) { - timelineView.swapTrimKnobs() - } - timelineView.setCurrentTime(cgToTime(destination) - overLimit,force:true) - } - } - - func stopEdgeScrollTimer() { - edgeScrollTimer.invalidate() - edgeScrollStrength = 0 - edgeScrollingKnob = nil - } - - func edgeScrolling() -> Bool { - return edgeScrollTimer.isValid - } - - func currentEdgeScrollPosition(_ moved:CGFloat) -> CGFloat { - var result:CGFloat = 0 - - let maxWidth = scrollMaxWidth() - result = edgeScrollLastChangedPosition + moved - if result < 0 { - result = 0 - } else if result > maxWidth { - result = maxWidth - } - return result - } - - func currentEdgeScrollMovedPosition() -> CGFloat { - let pastTime = -edgeScrollLastChangedTime.timeIntervalSinceNow - return CGFloat(pastTime) * edgeScrollStrength * 5 - } -} - - -//MARK: - TrimKnob -class TrimKnob:UIView { - var timelineView:TimelineView! - var knobPositionOnScreen:CGFloat = 0 - var trimView:TrimView! - var knobTimePoint:Float64 = 0 - var isOutOfScreen:Bool = false - - - override init (frame: CGRect) { - super.init(frame: frame) - - self.isMultipleTouchEnabled = true - self.isUserInteractionEnabled = true - - } - - required init(coder aDecoder: NSCoder) { - fatalError("TrimKnob init(coder:) has not been implemented") - } - - func configure(_ timeline:TimelineView, trimmer:TrimView) { - timelineView = timeline - trimView = trimmer - } - - //MARK: - Touch Events - var allTouches = [UITouch]() - - override open func touchesBegan(_ touches: Set, with event: UIEvent?) - { - for touch in touches { - if !allTouches.contains(touch) { - allTouches += [touch] - } - if !timelineView!.allTouches.contains(touch) { - timelineView!.allTouches += [touch] - } - } - if timelineView!.allTouches.count == 1 && allTouches.count == 1 { - if dragging == false { - startDrag() - } - evaluateTap = true - } else { - evaluateTap = false - } - } - - - override open func touchesMoved(_ touches: Set, with event: UIEvent?) - { - if timelineView!.allTouches.count > 1 { - if dragging { - cancelDrag() - } - } - if timelineView!.allTouches.count == 2 { - if timelineView!.pinching { - timelineView!.updatePinch() - } else { - timelineView!.startPinch() - } - } - if dragging && timelineView!.allTouches.count == 1 && allTouches.count == 1 { - updateDrag() - } - evaluateTap = false - } - - override open func touchesEnded(_ touches: Set, with event: UIEvent?) - { - for touch in touches { - if let index = allTouches.firstIndex(of:touch) { - allTouches.remove(at: index) - } - if let index = timelineView!.allTouches.firstIndex(of:touch) { - timelineView!.allTouches.remove(at: index) - } - } - if timelineView!.pinching && timelineView!.allTouches.count < 2 { - timelineView!.endPinch() - } - if dragging { - endDrag() - } - - if evaluateTap && timelineView!.allTouches.count == 0 { - tapped() - } - evaluateTap = false - } - - override open func touchesCancelled(_ touches: Set, with event: UIEvent?) - { - for touch in touches { - if let index = allTouches.firstIndex(of:touch) { - allTouches.remove(at: index) - } - if let index = timelineView!.allTouches.firstIndex(of:touch) { - timelineView!.allTouches.remove(at: index) - } - } - - if timelineView!.pinching { - timelineView!.endPinch() - } - if dragging { - endDrag() - } - evaluateTap = false - } - - - //MARK: - actions - - var dragging:Bool = false - var dragStartPoint = CGPoint.zero - var startKnobTimePoint:Float64 = 0 - var dragStartOffset:CGFloat = 0 - var startTimeOutOfScreen:Float64 = 0 - var scrolling = false - var startCurrentTime:Float64 = 0 - var evaluateTap:Bool = false - var ignoreEdgeScroll = false - - func startDrag() { - - dragging = true - let touch = allTouches[0] - dragStartPoint = touch.location(in: timelineView) - startKnobTimePoint = knobTimePoint - dragStartOffset = trimView.scrollOffset() - startTimeOutOfScreen = trimView.knobTimeOnScreen(self) - startKnobTimePoint - - - startCurrentTime = timelineView.mainView!.currentTime - - if edgeScrollStrength(dragStartPoint.x) != 0 { - ignoreEdgeScroll = true - } else { - ignoreEdgeScroll = false - } - } - - func updateDrag() { - let touch = allTouches[0] - let currentPoint = touch.location(in: timelineView) - let scrolled = trimView.scrollOffset() - dragStartOffset - let move = currentPoint.x - dragStartPoint.x + scrolled - let startKnobPoint = startKnobTimePoint + startTimeOutOfScreen - - let timePoint = startKnobPoint + trimView.cgToTime(move) - let dragPoint = trimView.cgToTime(trimView.screenToTimelinePosition(currentPoint.x)) - let onKnob = trimView.timeToCG(timePoint - dragPoint) - let anotherKnob = trimView.anotherKnob(self) - let anotherTimePoint = anotherKnob.knobTimePoint - let knobWidth = trimView.knobWidth - var swapping:CGFloat = 0 - - - if anotherTimePoint < timePoint && startKnobPoint < anotherTimePoint - { - swapping = trimView.timeToCG(anotherTimePoint - timePoint) - if -swapping > knobWidth { - swapping = -knobWidth - } - } else if anotherTimePoint > timePoint && startKnobPoint > anotherTimePoint - { - swapping = trimView.timeToCG(anotherTimePoint - timePoint) - if swapping > knobWidth { - swapping = knobWidth - } - } - var rangeOut = false - let range = trimView.knobMoveRange(self) - if timePoint > range.max || timePoint < range.min { - rangeOut = true - } - - if rangeOut == false && ((self == trimView.startKnob && dragPoint > anotherTimePoint) || (self == trimView.endKnob && dragPoint < anotherTimePoint)) { - timelineView.swapTrimKnobs() - } - - - let strength = edgeScrollStrength(currentPoint.x) - let reachedEnd = trimView.directionReachesEnd(self, direction:strength) - if strength != 0 && ignoreEdgeScroll == false && reachedEnd == false { - trimView.updateEdgeScroll(self, strength:strength, position:currentPoint.x + onKnob + swapping) - } else { - let fixedKnobPoint = trimView.fixKnobPoint(self, move:move + swapping, startKnobPoint:startKnobPoint) - - trimView.updateKnob(self, timePoint:fixedKnobPoint.knobPoint) - if strength == 0 { - ignoreEdgeScroll = false - - } - if strength == 0 || reachedEnd { - if trimView.edgeScrolling() { - trimView.stopEdgeScrollTimer() - } - } - } - - guard let mainView = (timelineView.mainView) else { return } - if let receiver = mainView.playStatusReceiver { - receiver.videoTimelineTrimChanged() - } - } - - func endDrag() { - let anotherKnob = trimView.anotherKnob(self) - let distance = abs(anotherKnob.knobTimePoint - knobTimePoint) - let minDistance = trimView.knobsMinDistanceTime() - if distance < minDistance { - if self == trimView.startKnob { - knobTimePoint -= (minDistance - distance) - } else if self == trimView.endKnob { - knobTimePoint += (minDistance - distance) - } - - trimView.timelineView.animating = true - trimView.startAnimation() - UIView.animate(withDuration: 0.2,delay:Double(0.0),options:UIView.AnimationOptions.curveEaseOut, animations: { () -> Void in - - self.trimView.layout() - - },completion: { finished in - self.trimView.stopAnimation() - self.timelineView.animating = false - }) - } - timelineView.setManualScrolledAfterEnd() - trimView.resetSeek(startCurrentTime) - dragging = false - trimView.stopEdgeScrollTimer() - - if evaluateTap == false { - guard let mainView = (timelineView.mainView) else { return } - if let receiver = mainView.playStatusReceiver { - receiver.videoTimelineTrimChanged() - } - } - } - - func cancelDrag() { - knobTimePoint = startKnobTimePoint - - timelineView.setManualScrolledAfterEnd() - dragging = false - trimView.layout() - trimView.resetSeek(startCurrentTime) - trimView.stopEdgeScrollTimer() - } - - func tapped() { - trimView.moveToTimeWithAnimation(knobTimePoint) - timelineView.setManualScrolledAfterEnd() - } - - - func edgeScrollStrength(_ position:CGFloat) -> CGFloat { - var strength:CGFloat = 0 - let edgeWidth:CGFloat = 40 - if position >= timelineView.frame.size.width - edgeWidth { - strength = position + edgeWidth - timelineView.frame.size.width - } else if position <= edgeWidth { - strength = position - edgeWidth - } - return strength - } - - - -} diff --git a/kplayer/timeline/VideoTimelineView.swift b/kplayer/timeline/VideoTimelineView.swift deleted file mode 100644 index a7d6f33..0000000 --- a/kplayer/timeline/VideoTimelineView.swift +++ /dev/null @@ -1,301 +0,0 @@ -// -// VideoTimelineView.swift -// VideoTimelineView -// -// Created by Tomohiro Yamashita on 2020/03/28. -// Copyright © 2020 Tom. All rights reserved. -// - -import UIKit -import AVFoundation - -protocol TimelinePlayStatusReceiver: class { - func videoTimelineStopped() - func videoTimelineMoved() - func videoTimelineTrimChanged() -} - - -struct VideoTimelineTrim { - var start:Float64 - var end:Float64 -} - -class VideoTimelineView: UIView { - - public private(set) var asset:AVAsset? = nil - var player:AVPlayer? = nil - - weak var playStatusReceiver:TimelinePlayStatusReceiver? = nil - - var repeatOn:Bool = false - - public private(set) var trimEnabled:Bool = false - - - - var currentTime:Float64 = 0 - public private(set) var duration:Float64 = 0 - - public private(set) var audioPlayer:AVPlayer! - public private(set) var audioPlayer2:AVPlayer! - - let timelineView = TimelineView() - - override init (frame: CGRect) { - super.init(frame: frame) - timelineView.mainView = self - timelineView.centerLine.mainView = self - timelineView.scroller.frameImagesView.mainView = self - timelineView.scroller.trimView.mainView = self - - self.addSubview(timelineView) - } - - required init(coder aDecoder: NSCoder) { - fatalError("MainView init(coder:) has not been implemented") - } - - - func viewDidLayoutSubviews() { - coordinate() - } - - func coordinate() { - timelineView.coordinate() - } - - func new(asset newAsset:AVAsset?) { - if let new = newAsset { - asset = new - duration = CMTimeGetSeconds(new.duration) - player = AVPlayer(playerItem: AVPlayerItem(asset: asset!)) - audioPlayer = AVPlayer(playerItem: AVPlayerItem(asset: asset!)) - audioPlayer.volume = 1.0 - audioPlayer2 = AVPlayer(playerItem: AVPlayerItem(asset: asset!)) - audioPlayer2.volume = 1.0 - timelineView.newMovieSet() - } - } - - - func setTrim(start:Float64, end:Float64, seek:Float64?, animate:Bool) { - - var seekTime = currentTime - if let time = seek { - seekTime = time - } - if animate { - timelineView.setTrimWithAnimation(trim:VideoTimelineTrim(start:start, end:end), time:seekTime) - } else { - timelineView.setTrim(start:start, end:end) - if seek != nil { - moveTo(seek!, animate:animate) - } - } - } - - func setTrimIsEnabled(_ enabled:Bool) { - trimEnabled = enabled - timelineView.setTrimmerStatus(enabled:enabled) - } - - func setTrimmerIsHidden(_ hide:Bool) { - timelineView.setTrimmerVisible(!hide) - } - - func currentTrim() -> (start:Float64, end:Float64) { - let trim = timelineView.currentTrim() - return (trim.start,trim.end) - } - - func moveTo(_ time:Float64, animate:Bool) { - if animate { - - } else { - accurateSeek(time, scrub:false) - timelineView.setCurrentTime(time, force:true) - } - } - - //MARK: - seeking - var previousSeektime:Float64 = 0 - func timelineIsMoved(_ currentTime:Float64, scrub:Bool) { - let move = abs(currentTime - previousSeektime) - let seekTolerance = CMTimeMakeWithSeconds(move, preferredTimescale:100) - - if player != nil { - player!.seek(to:CMTimeMakeWithSeconds(currentTime , preferredTimescale:100), toleranceBefore:seekTolerance,toleranceAfter:seekTolerance) - } - previousSeektime = currentTime - if scrub { - audioScrub() - } - } - - func accurateSeek(_ currentTime:Float64, scrub:Bool) { - previousSeektime = currentTime - timelineIsMoved(currentTime, scrub:scrub) - } - - var scrubed1 = Date() - var scrubed2 = Date() - var canScrub1 = true - var canScrub2 = true - func audioScrub() { - if player == nil { - return - } - if scrubed2.timeIntervalSinceNow < -0.16 && canScrub1 { - canScrub1 = false - self.scrubed1 = Date() - DispatchQueue.main.async { - if self.audioPlayer.timeControlStatus == .playing { - self.audioPlayer.pause() - self.canScrub1 = true - } else { - self.audioPlayer.seek(to: self.player!.currentTime()) - self.audioPlayer.play() - DispatchQueue.main.asyncAfter(deadline: .now() + 0.22) { - self.audioPlayer.pause() - self.audioPlayer.seek(to: self.player!.currentTime()) - self.canScrub1 = true - } - } - - } - } - if scrubed1.timeIntervalSinceNow < -0.16 && canScrub2 { - canScrub2 = false - self.scrubed2 = Date() - DispatchQueue.main.async { - if self.audioPlayer2.timeControlStatus == .playing { - self.audioPlayer2.pause() - self.canScrub2 = true - } else { - self.audioPlayer2.seek(to: self.player!.currentTime()) - self.audioPlayer2.play() - - DispatchQueue.main.asyncAfter(deadline: .now() + 0.22) { - self.audioPlayer2.pause() - self.audioPlayer2.seek(to: self.player!.currentTime()) - self.canScrub2 = true - } - } - } - } - } - - - //MARK: - play - var playerTimer = Timer() - @objc dynamic var playing = false - func play() { - if asset == nil { - return - } - let currentTime = timelineView.centerLine.currentTime - let reached = timeReachesEnd(currentTime) - - if reached.trimEnd { - accurateSeek(timelineView.currentTrim().start, scrub:false) - timelineView.manualScrolledAfterEnd = false - } else if reached.movieEnd { - accurateSeek(0, scrub:false) - timelineView.manualScrolledAfterEnd = false - } - if player != nil { - player!.play() - } - playerTimer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.playerTimerAction(_:)), userInfo: nil, repeats: true) - RunLoop.main.add(playerTimer, forMode:RunLoop.Mode.common) - playing = true - } - - func stop() { - playing = false - if asset == nil || player == nil { - return - } - player!.pause() - playerTimer.invalidate() - - if let receiver = playStatusReceiver { - receiver.videoTimelineStopped() - } - } - - var reachFlg = false - @objc func playerTimerAction(_ timer:Timer) { - if player == nil { - return - } - var currentPlayerTime = CMTimeGetSeconds(player!.currentTime()) - - let trim = timelineView.currentTrim() - let reached = timeReachesEnd(currentPlayerTime) - if timelineView.inAction() { - if player!.timeControlStatus == .playing { - player!.pause() - } - } else if reached.reached { - if repeatOn && reached.trimEnd { - - if player!.timeControlStatus == .playing { - player!.pause() - } - currentPlayerTime = trim.start - accurateSeek(currentPlayerTime, scrub:false) - reachFlg = true - - } else { - stop() - } - timelineView.setCurrentTime(currentPlayerTime,force:false) - timelineView.manualScrolledAfterEnd = false - } else if timelineView.animating == false { - timelineView.setCurrentTime(currentPlayerTime,force:false) - if player!.timeControlStatus == .paused { - player!.play() - } - if reachFlg { - if let receiver = playStatusReceiver { - receiver.videoTimelineMoved() - } - reachFlg = false - } - } - } - - func timeReachesEnd(_ time:Float64) -> (reached:Bool, trimEnd:Bool, movieEnd:Bool) { - var reached = false - var trimEnd = false - var movieEnd = false - if asset != nil { - let duration = CMTimeGetSeconds(asset!.duration) - let trimTimeEnd = timelineView.currentTrim().end - if (time >= trimTimeEnd && timelineView.manualScrolledAfterEnd == false && trimEnabled) { - trimEnd = true - reached = true - } - if time >= duration { - if trimTimeEnd < duration { - trimEnd = false - } - movieEnd = true - reached = true - } - } - return (reached, trimEnd, movieEnd) - } - - - //MARK: - - func resizeHeightKeepRatio(_ size:CGSize, height:CGFloat) -> CGSize { - var result = size - let ratio = size.width / size.height - result.height = height - result.width = height * ratio - return result - } -} diff --git a/kplayer/svideo/SVideoModel.swift b/kplayer/video/SVideoModel.swift similarity index 100% rename from kplayer/svideo/SVideoModel.swift rename to kplayer/video/SVideoModel.swift diff --git a/kplayer/svideo/SVideoPlayer.swift b/kplayer/video/SVideoPlayer.swift similarity index 100% rename from kplayer/svideo/SVideoPlayer.swift rename to kplayer/video/SVideoPlayer.swift diff --git a/kplayer/svideo/VideoPlayerView.swift b/kplayer/video/VideoPlayerView.swift similarity index 100% rename from kplayer/svideo/VideoPlayerView.swift rename to kplayer/video/VideoPlayerView.swift