Video avatar fixes

This commit is contained in:
Ilya Laktyushin 2020-07-17 12:34:40 +03:00
parent bc78f7f7fe
commit a911b403ca
4 changed files with 97 additions and 13 deletions

View File

@ -1356,7 +1356,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
return 2000;
case TGMediaVideoConversionPresetProfileVeryHigh:
return 2500;
return 2300;
default:
return 900;

View File

@ -147,7 +147,7 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
}
}
let imageSize = layoutConstants.instantVideo.dimensions
let imageSize = CGSize(width: 212.0, height: 212.0)
let (labelLayout, apply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: attributedString, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: constrainedSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
@ -222,7 +222,7 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
if let image = image, let video = image.videoRepresentations.last, let id = image.id?.id {
let videoFileReference = FileMediaReference.standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.resource, previewRepresentations: image.representations, videoThumbnails: [], immediateThumbnailData: image.immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.dimensions, flags: [])]))
let videoContent = NativeVideoContent(id: .profileVideo(id, "action"), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, autoFetchFullSizeThumbnail: true, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
let videoContent = NativeVideoContent(id: .profileVideo(id, "action"), fileReference: videoFileReference, streamVideo: isMediaStreamable(resource: video.resource) ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, useLargeThumbnail: true, autoFetchFullSizeThumbnail: true, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .clear)
if videoContent.id != strongSelf.videoContent?.id {
let mediaManager = item.context.sharedContext.mediaManager
let videoNode = UniversalVideoNode(postbox: item.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: videoContent, priority: .secondaryOverlay)

View File

@ -519,7 +519,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
}
var isBuffering: Bool?
if let message = self.item?.message, let media = self.media, let size = media.size, (isMediaStreamable(message: message, media: media) || size <= 256 * 1024) && (self.automaticDownload ?? false) {
if let message = self.item?.message, let media = self.media, isMediaStreamable(message: message, media: media) && (self.automaticDownload ?? false) {
if let playerStatus = self.playerStatus, case .buffering = playerStatus.status {
isBuffering = true
} else {

View File

@ -198,8 +198,13 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
private var videoNode: UniversalVideoNode?
private var videoContent: NativeVideoContent?
private var videoStartTimestamp: Double?
private let playbackStatusDisposable = MetaDisposable()
private let playbackStartDisposable = MetaDisposable()
private let statusDisposable = MetaDisposable()
private let preloadDisposable = MetaDisposable()
private var statusNode: RadialStatusNode?
private var fetchStatus: MediaResourceStatus?
private var playerStatus: MediaPlayerStatus?
let isReady = Promise<Bool>()
private var didSetReady: Bool = false
@ -229,7 +234,7 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
self.preloadDisposable.set(nil)
} else {
if let videoNode = self.videoNode {
self.playbackStatusDisposable.set(nil)
self.playbackStartDisposable.set(nil)
self.statusPromise.set(.single(nil))
self.videoNode = nil
if self.delayCentralityLose {
@ -262,10 +267,76 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
}
deinit {
self.playbackStatusDisposable.dispose()
self.statusDisposable.dispose()
self.playbackStartDisposable.dispose()
self.preloadDisposable.dispose()
}
private func updateStatus() {
guard let videoContent = self.videoContent, let fetchStatus = self.fetchStatus else {
return
}
var isBuffering: Bool?
var isPlaying = false
if isMediaStreamable(resource: videoContent.fileReference.media.resource) {
if let playerStatus = self.playerStatus {
if case .buffering = playerStatus.status {
isBuffering = true
} else if case .playing = playerStatus.status {
isPlaying = true
}
} else {
isBuffering = false
}
}
var progressRequired = false
if case .Local = fetchStatus {
} else if isBuffering ?? false {
progressRequired = true
} else if case .Fetching = fetchStatus, !isPlaying {
progressRequired = true
} else if case .Remote = fetchStatus, !isPlaying {
progressRequired = true
}
if progressRequired {
if self.statusNode == nil {
let statusNode = RadialStatusNode(backgroundNodeColor: UIColor(rgb: 0x000000, alpha: 0.3))
statusNode.isUserInteractionEnabled = false
statusNode.frame = CGRect(origin: CGPoint(x: floor((self.frame.size.width - 50.0) / 2.0), y: floor((self.frame.size.height - 50.0) / 2.0)), size: CGSize(width: 50.0, height: 50.0))
self.statusNode = statusNode
self.addSubnode(statusNode)
}
} else {
if let statusNode = self.statusNode {
statusNode.transitionToState(.none, completion: { [weak statusNode] in
statusNode?.removeFromSupernode()
})
self.statusNode = nil
}
}
var state: RadialStatusNodeState
if progressRequired {
state = .progress(color: .white, lineWidth: nil, value: nil, cancelEnabled: false)
} else {
state = .none
}
if let statusNode = self.statusNode {
if state == .none {
self.statusNode = nil
}
statusNode.transitionToState(state, completion: { [weak statusNode] in
if state == .none {
statusNode?.removeFromSupernode()
}
})
}
}
func updateTransitionFraction(_ fraction: CGFloat, transition: ContainedViewLayoutTransition) {
if let videoNode = self.videoNode {
if case .immediate = transition, fraction == 1.0 {
@ -287,7 +358,7 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
videoNode.isHidden = true
if let _ = self.videoStartTimestamp {
self.playbackStatusDisposable.set((videoNode.status
self.playbackStartDisposable.set((videoNode.status
|> map { status -> Bool in
if let status = status, case .playing = status.status {
return true
@ -307,7 +378,7 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
}
}))
} else {
self.playbackStatusDisposable.set(nil)
self.playbackStartDisposable.set(nil)
videoNode.isHidden = false
}
videoNode.play()
@ -316,6 +387,17 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
let videoStartTimestamp = self.videoStartTimestamp
self.statusPromise.set(videoNode.status |> map { ($0, videoStartTimestamp) })
self.statusDisposable.set((combineLatest(self.mediaStatus, self.context.account.postbox.mediaBox.resourceStatus(videoContent.fileReference.media.resource))
|> deliverOnMainQueue).start(next: { [weak self] mediaStatus, fetchStatus in
if let strongSelf = self {
if let mediaStatusAndStartTimestamp = mediaStatus {
strongSelf.playerStatus = mediaStatusAndStartTimestamp.0
}
strongSelf.fetchStatus = fetchStatus
strongSelf.updateStatus()
}
}))
self.addSubnode(videoNode)
self.isReady.set(videoNode.ready |> map { return true })
@ -369,6 +451,8 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode {
self.statusPromise.set(.single(nil))
self.statusDisposable.set(nil)
self.imageNode.imageUpdated = { [weak self] _ in
guard let strongSelf = self else {
return
@ -1186,7 +1270,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
private var isFirstAvatarLoading = true
var item: PeerInfoAvatarListItem?
private let playbackStatusDisposable = MetaDisposable()
private let playbackStartDisposable = MetaDisposable()
init(context: AccountContext) {
self.context = context
@ -1202,7 +1286,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
}
deinit {
self.playbackStatusDisposable.dispose()
self.playbackStartDisposable.dispose()
}
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
@ -1289,7 +1373,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
if let startTimestamp = video.representation.startTimestamp {
self.videoStartTimestamp = startTimestamp
self.playbackStatusDisposable.set((videoNode.status
self.playbackStartDisposable.set((videoNode.status
|> map { status -> Bool in
if let status = status, case .playing = status.status {
return true
@ -1310,7 +1394,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
}))
} else {
self.videoStartTimestamp = nil
self.playbackStatusDisposable.set(nil)
self.playbackStartDisposable.set(nil)
videoNode.isHidden = false
}