mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Experimental hls implementation
This commit is contained in:
parent
d70a0cf0e0
commit
69bb337f6f
@ -20,7 +20,7 @@ public protocol UniversalVideoContentNode: AnyObject {
|
||||
var status: Signal<MediaPlayerStatus, NoError> { get }
|
||||
var bufferingStatus: Signal<(RangeSet<Int64>, Int64)?, NoError> { get }
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition)
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition)
|
||||
|
||||
func play()
|
||||
func pause()
|
||||
@ -68,7 +68,7 @@ public protocol UniversalVideoDecoration: AnyObject {
|
||||
|
||||
func updateContentNode(_ contentNode: (UniversalVideoContentNode & ASDisplayNode)?)
|
||||
func updateContentNodeSnapshot(_ snapshot: UIView?)
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition)
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition)
|
||||
func tap()
|
||||
}
|
||||
|
||||
@ -247,8 +247,8 @@ public final class UniversalVideoNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.decoration.updateLayout(size: size, transition: transition)
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize? = nil, transition: ContainedViewLayoutTransition) {
|
||||
self.decoration.updateLayout(size: size, actualSize: actualSize ?? size, transition: transition)
|
||||
}
|
||||
|
||||
public func play() {
|
||||
|
@ -325,7 +325,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -345,9 +345,9 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -405,8 +405,8 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -421,7 +421,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1141,7 +1141,7 @@ private final class StickerVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -1161,9 +1161,9 @@ private final class StickerVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1221,8 +1221,8 @@ private final class StickerVideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -1237,7 +1237,7 @@ private final class StickerVideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ public final class GalleryVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -34,9 +34,9 @@ public final class GalleryVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,8 +94,8 @@ public final class GalleryVideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -110,7 +110,7 @@ public final class GalleryVideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1186,7 +1186,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
videoScale = 2.0
|
||||
}
|
||||
let videoSize = CGSize(width: item.content.dimensions.width * videoScale, height: item.content.dimensions.height * videoScale)
|
||||
videoNode.updateLayout(size: videoSize, transition: .immediate)
|
||||
let actualVideoSize = CGSize(width: item.content.dimensions.width, height: item.content.dimensions.height)
|
||||
videoNode.updateLayout(size: videoSize, actualSize: actualVideoSize, transition: .immediate)
|
||||
videoNode.ownsContentNodeUpdated = { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateDisplayPlaceholder(!value)
|
||||
|
@ -626,7 +626,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -646,9 +646,9 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -706,8 +706,8 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -722,7 +722,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,7 +511,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -531,9 +531,9 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -591,8 +591,8 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -607,7 +607,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ public final class StoryVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -34,9 +34,9 @@ public final class StoryVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,8 +94,8 @@ public final class StoryVideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -110,7 +110,7 @@ public final class StoryVideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
171
submodules/TelegramUI/Resources/WebEmbed/HLSVideoPlayer.html
Executable file
171
submodules/TelegramUI/Resources/WebEmbed/HLSVideoPlayer.html
Executable file
@ -0,0 +1,171 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
#videoPlayer {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: fill;
|
||||
}
|
||||
</style>
|
||||
<script src="hls.js"></script>
|
||||
<script type="text/javascript">
|
||||
function postPlayerEvent(eventName, eventData) {
|
||||
window.webkit.messageHandlers.performAction.postMessage({'event': eventName, 'data': eventData});
|
||||
};
|
||||
|
||||
var video;
|
||||
var hls;
|
||||
|
||||
var isManifestParsed = false;
|
||||
var isFirstFrameReady = false;
|
||||
|
||||
var currentTimeUpdateTimeout = null;
|
||||
|
||||
function playerInitialize(params) {
|
||||
video = document.getElementById('videoPlayer');
|
||||
|
||||
video.addEventListener('loadeddata', (event) => {
|
||||
if (!isFirstFrameReady) {
|
||||
isFirstFrameReady = true;
|
||||
refreshPlayerStatus();
|
||||
}
|
||||
});
|
||||
video.addEventListener("playing", function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
video.addEventListener("pause", function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
video.addEventListener("seeking", function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
video.addEventListener("waiting", function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
|
||||
hls = new Hls({
|
||||
startLevel: 0,
|
||||
testBandwidth: false,
|
||||
debug: params['debug'],
|
||||
autoStartLoad: false
|
||||
});
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function() {
|
||||
isManifestParsed = true;
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
|
||||
hls.on(Hls.Events.LEVEL_SWITCHED, function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
hls.on(Hls.Events.LEVELS_UPDATED, function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
|
||||
hls.loadSource('master.m3u8');
|
||||
hls.attachMedia(video);
|
||||
}
|
||||
|
||||
function playerLoad(initialLevelIndex) {
|
||||
hls.startLevel = initialLevelIndex;
|
||||
hls.startLoad(startPosition=-1);
|
||||
}
|
||||
|
||||
function playerPlay() {
|
||||
video.play();
|
||||
}
|
||||
|
||||
function playerPause() {
|
||||
video.pause();
|
||||
}
|
||||
|
||||
function playerSetBaseRate(value) {
|
||||
video.playbackRate = value;
|
||||
}
|
||||
|
||||
function playerSetLevel(level) {
|
||||
if (level >= 0) {
|
||||
hls.autoLevelEnabled = false;
|
||||
hls.currentLevel = level;
|
||||
} else {
|
||||
hls.autoLevelEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
function playerSeek(value) {
|
||||
video.currentTime = value;
|
||||
}
|
||||
|
||||
function playerSetIsMuted(value) {
|
||||
video.muted = value;
|
||||
}
|
||||
|
||||
function getLevels() {
|
||||
var levels = [];
|
||||
for (var i = 0; i < hls.levels.length; i++) {
|
||||
level = hls.levels[i];
|
||||
levels.push({
|
||||
'index': i,
|
||||
'bitrate': level.bitrate || 0,
|
||||
'width': level.width || 0,
|
||||
'height': level.height || 0
|
||||
});
|
||||
}
|
||||
return levels;
|
||||
}
|
||||
|
||||
function refreshPlayerStatus() {
|
||||
var isPlaying = false;
|
||||
if (!video.paused && !video.ended && video.readyState > 2) {
|
||||
isPlaying = true;
|
||||
}
|
||||
|
||||
postPlayerEvent('playerStatus', {
|
||||
'isReady': isManifestParsed,
|
||||
'isFirstFrameReady': isFirstFrameReady,
|
||||
'isPlaying': !video.paused,
|
||||
'rate': isPlaying ? video.playbackRate : 0.0,
|
||||
'defaultRate': video.playbackRate,
|
||||
'levels': getLevels(),
|
||||
'currentLevel': hls.currentLevel
|
||||
});
|
||||
|
||||
refreshPlayerCurrentTime();
|
||||
|
||||
if (isPlaying) {
|
||||
if (currentTimeUpdateTimeout == null) {
|
||||
currentTimeUpdateTimeout = setTimeout(() => {
|
||||
refreshPlayerCurrentTime();
|
||||
}, 200);
|
||||
}
|
||||
} else {
|
||||
if(currentTimeUpdateTimeout != null){
|
||||
clearTimeout(currentTimeUpdateTimeout);
|
||||
currentTimeUpdateTimeout = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function refreshPlayerCurrentTime() {
|
||||
postPlayerEvent('playerCurrentTime', {
|
||||
'value': video.currentTime
|
||||
});
|
||||
currentTimeUpdateTimeout = setTimeout(() => {
|
||||
refreshPlayerCurrentTime()
|
||||
}, 200);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<video id="videoPlayer" playsinline></video>
|
||||
</body>
|
||||
</html>
|
29290
submodules/TelegramUI/Resources/WebEmbed/hls.js
Normal file
29290
submodules/TelegramUI/Resources/WebEmbed/hls.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@ final class OverlayInstantVideoDecoration: UniversalVideoDecoration {
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
private var contentNodeSnapshot: UIView?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
init(tapped: @escaping () -> Void) {
|
||||
self.tapped = tapped
|
||||
@ -58,9 +58,9 @@ final class OverlayInstantVideoDecoration: UniversalVideoDecoration {
|
||||
self.progressNode.status = contentNode.status
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -74,15 +74,15 @@ final class OverlayInstantVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
if let snapshot = snapshot {
|
||||
self.contentContainerNode.view.addSubview(snapshot)
|
||||
if let _ = self.validLayoutSize {
|
||||
if let _ = self.validLayout {
|
||||
snapshot.frame = CGRect(origin: CGPoint(), size: snapshot.frame.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
self.contentContainerNode.cornerRadius = size.width / 2.0
|
||||
|
||||
@ -96,7 +96,7 @@ final class OverlayInstantVideoDecoration: UniversalVideoDecoration {
|
||||
transition.updateFrame(node: self.contentContainerNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size).insetBy(dx: -0.5, dy: -0.5))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
|
||||
if let contentNodeSnapshot = self.contentNodeSnapshot {
|
||||
|
@ -16,7 +16,7 @@ public final class ChatBubbleInstantVideoDecoration: UniversalVideoDecoration {
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
private let inset: CGFloat
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init(inset: CGFloat, backgroundImage: UIImage?, tapped: @escaping () -> Void) {
|
||||
self.inset = inset
|
||||
@ -51,9 +51,9 @@ public final class ChatBubbleInstantVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -63,8 +63,8 @@ public final class ChatBubbleInstantVideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let diameter = size.width + inset
|
||||
self.contentContainerNode.cornerRadius = (diameter - 3.0) / 2.0
|
||||
@ -80,7 +80,7 @@ public final class ChatBubbleInstantVideoDecoration: UniversalVideoDecoration {
|
||||
self.contentContainerNode.subnodeTransform = CATransform3DMakeScale((contentFrame.width + 2.0) / contentFrame.width, (contentFrame.width + 2.0) / contentFrame.width, 1.0)
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ public final class ChatBubbleVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init(corners: ImageCorners, nativeSize: CGSize, contentMode: ChatBubbleVideoDecorationContentMode, backgroundColor: UIColor) {
|
||||
self.corners = corners
|
||||
@ -82,23 +82,23 @@ public final class ChatBubbleVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let size = self.validLayoutSize {
|
||||
if let validLayout = self.validLayout {
|
||||
var scaledSize: CGSize
|
||||
switch self.contentMode {
|
||||
case .aspectFit:
|
||||
scaledSize = self.nativeSize.aspectFitted(size)
|
||||
scaledSize = self.nativeSize.aspectFitted(validLayout.size)
|
||||
case .aspectFill:
|
||||
scaledSize = self.nativeSize.aspectFilled(size)
|
||||
scaledSize = self.nativeSize.aspectFilled(validLayout.size)
|
||||
}
|
||||
if abs(scaledSize.width - size.width) < 2.0 {
|
||||
scaledSize.width = size.width
|
||||
if abs(scaledSize.width - validLayout.size.width) < 2.0 {
|
||||
scaledSize.width = validLayout.size.width
|
||||
}
|
||||
if abs(scaledSize.height - size.height) < 2.0 {
|
||||
scaledSize.height = size.height
|
||||
if abs(scaledSize.height - validLayout.size.height) < 2.0 {
|
||||
scaledSize.height = validLayout.size.height
|
||||
}
|
||||
|
||||
contentNode.frame = CGRect(origin: CGPoint(x: floor((size.width - scaledSize.width) / 2.0), y: floor((size.height - scaledSize.height) / 2.0)), size: scaledSize)
|
||||
contentNode.updateLayout(size: scaledSize, transition: .immediate)
|
||||
contentNode.frame = CGRect(origin: CGPoint(x: floor((validLayout.size.width - scaledSize.width) / 2.0), y: floor((validLayout.size.height - scaledSize.height) / 2.0)), size: scaledSize)
|
||||
contentNode.updateLayout(size: scaledSize, actualSize: scaledSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,8 +108,8 @@ public final class ChatBubbleVideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -137,7 +137,7 @@ public final class ChatBubbleVideoDecoration: UniversalVideoDecoration {
|
||||
scaledSize.height = size.height
|
||||
}
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(x: floor((size.width - scaledSize.width) / 2.0), y: floor((size.height - scaledSize.height) / 2.0)), size: scaledSize))
|
||||
contentNode.updateLayout(size: scaledSize, transition: transition)
|
||||
contentNode.updateLayout(size: scaledSize, actualSize: scaledSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -217,7 +217,7 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
private var dimensions: CGSize?
|
||||
private let dimensionsPromise = ValuePromise<CGSize>(CGSize())
|
||||
|
||||
private var validLayout: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
private var shouldPlay: Bool = false
|
||||
|
||||
@ -306,8 +306,8 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
if let dimensions = getSize() {
|
||||
strongSelf.dimensions = dimensions
|
||||
strongSelf.dimensionsPromise.set(dimensions)
|
||||
if let size = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(size: size, transition: .immediate)
|
||||
if let validLayout = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -432,8 +432,8 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = size
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
if let dimensions = self.dimensions {
|
||||
let imageSize = CGSize(width: floor(dimensions.width / 2.0), height: floor(dimensions.height / 2.0))
|
||||
|
@ -47,7 +47,7 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private let statusDisposable = MetaDisposable()
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
init(contentDimensions: CGSize, unminimize: @escaping () -> Void, togglePlayPause: @escaping () -> Void, expand: @escaping () -> Void, close: @escaping () -> Void, controlsAreShowingUpdated: @escaping (Bool) -> Void) {
|
||||
self.contentDimensions = contentDimensions
|
||||
@ -106,9 +106,9 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = self.frameForContent(size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = self.frameForContent(size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,8 +118,8 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let contentFrame = self.frameForContent(size: size)
|
||||
|
||||
@ -146,7 +146,7 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: contentFrame)
|
||||
contentNode.updateLayout(size: contentFrame.size, transition: transition)
|
||||
contentNode.updateLayout(size: contentFrame.size, actualSize: contentFrame.size, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,8 +209,8 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
if self.minimizedBlurView == nil {
|
||||
let minimizedBlurView = UIVisualEffectView(effect: nil)
|
||||
self.minimizedBlurView = minimizedBlurView
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
minimizedBlurView.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
if let validLayout = self.validLayout {
|
||||
minimizedBlurView.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
}
|
||||
minimizedBlurView.isHidden = true
|
||||
self.foregroundContainerNode.view.addSubview(minimizedBlurView)
|
||||
@ -222,8 +222,8 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
self.minimizedBlurView?.contentView.addSubview(minimizedArrowView)
|
||||
}
|
||||
if let minimizedArrowView = self.minimizedArrowView {
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
setupArrowFrame(size: validLayoutSize, edge: edge, view: minimizedArrowView)
|
||||
if let validLayout = self.validLayout {
|
||||
setupArrowFrame(size: validLayout.size, edge: edge, view: minimizedArrowView)
|
||||
}
|
||||
minimizedArrowView.setAngled(!adjusting, animated: true)
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte
|
||||
private var dimensions: CGSize?
|
||||
private let dimensionsPromise = ValuePromise<CGSize>(CGSize())
|
||||
|
||||
private var validLayout: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
init(postbox: Postbox, audioSessionManager: ManagedAudioSession, userLocation: MediaResourceUserLocation, content: PlatformVideoContent.Content, streamVideo: Bool, loopVideo: Bool, enableSound: Bool, baseRate: Double, fetchAutomatically: Bool) {
|
||||
self.postbox = postbox
|
||||
@ -203,8 +203,8 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte
|
||||
if let dimensions = getSize() {
|
||||
strongSelf.dimensions = dimensions
|
||||
strongSelf.dimensionsPromise.set(dimensions)
|
||||
if let size = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(size: size, transition: .immediate)
|
||||
if let validLayout = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -371,7 +371,7 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
transition.updatePosition(node: self.playerNode, position: CGPoint(x: size.width / 2.0, y: size.height / 2.0))
|
||||
transition.updateTransformScale(node: self.playerNode, scale: size.width / self.intrinsicDimensions.width)
|
||||
|
||||
|
@ -207,7 +207,7 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
transition.updatePosition(node: self.playerNode, position: CGPoint(x: size.width / 2.0, y: size.height / 2.0))
|
||||
transition.updateTransformScale(node: self.playerNode, scale: size.width / self.intrinsicDimensions.width)
|
||||
|
||||
|
@ -116,7 +116,7 @@ final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode {
|
||||
self.readyDisposable.dispose()
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
transition.updatePosition(node: self.playerNode, position: CGPoint(x: size.width / 2.0, y: size.height / 2.0))
|
||||
transition.updateTransformScale(node: self.playerNode, scale: size.width / self.intrinsicDimensions.width)
|
||||
|
||||
|
@ -336,6 +336,10 @@ public final class ExternalMediaStreamingContext: SharedHLSServerSource {
|
||||
impl.fileData(id: id, range: range).start(next: subscriber.putNext)
|
||||
}
|
||||
}
|
||||
|
||||
public func arbitraryFileData(path: String) -> Signal<(data: Data, contentType: String)?, NoError> {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|
||||
public protocol SharedHLSServerSource: AnyObject {
|
||||
@ -345,6 +349,7 @@ public protocol SharedHLSServerSource: AnyObject {
|
||||
func playlistData(quality: Int) -> Signal<String, NoError>
|
||||
func partData(index: Int, quality: Int) -> Signal<Data?, NoError>
|
||||
func fileData(id: Int64, range: Range<Int>) -> Signal<(TempBoxFile, Range<Int>, Int)?, NoError>
|
||||
func arbitraryFileData(path: String) -> Signal<(data: Data, contentType: String)?, NoError>
|
||||
}
|
||||
|
||||
@available(iOS 12.0, macOS 14.0, *)
|
||||
@ -651,7 +656,19 @@ public final class SharedHLSServer {
|
||||
}
|
||||
})
|
||||
} else {
|
||||
self.sendErrorAndClose(connection: connection, error: .notFound)
|
||||
let _ = (source.arbitraryFileData(path: filePath)
|
||||
|> deliverOn(self.queue)
|
||||
|> take(1)).start(next: { [weak self] result in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
if let result {
|
||||
self.sendResponseAndClose(connection: connection, data: result.data, contentType: result.contentType)
|
||||
} else {
|
||||
self.sendErrorAndClose(connection: connection, error: .notFound)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -665,13 +682,14 @@ public final class SharedHLSServer {
|
||||
})
|
||||
}
|
||||
|
||||
private func sendResponseAndClose(connection: NWConnection, data: Data, range: Range<Int>? = nil, totalSize: Int? = nil) {
|
||||
private func sendResponseAndClose(connection: NWConnection, data: Data, contentType: String = "application/octet-stream", range: Range<Int>? = nil, totalSize: Int? = nil) {
|
||||
var responseHeaders = "HTTP/1.1 200 OK\r\n"
|
||||
responseHeaders.append("Content-Length: \(data.count)\r\n")
|
||||
if let range, let totalSize {
|
||||
responseHeaders.append("Content-Range: bytes \(range.lowerBound)-\(range.upperBound)/\(totalSize)\r\n")
|
||||
}
|
||||
responseHeaders.append("Content-Type: application/octet-stream\r\n")
|
||||
|
||||
responseHeaders.append("Content-Type: \(contentType)\r\n")
|
||||
responseHeaders.append("Connection: close\r\n")
|
||||
responseHeaders.append("Access-Control-Allow-Origin: *\r\n")
|
||||
responseHeaders.append("\r\n")
|
||||
|
Loading…
x
Reference in New Issue
Block a user