Various improvements

This commit is contained in:
Isaac 2025-03-07 17:52:50 +01:00
parent a63a3074bd
commit 383ab9e479
33 changed files with 373 additions and 203 deletions

View File

@ -112,7 +112,7 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
}
if source.isVideo {
if let videoSource = makeVideoStickerDirectFrameSource(queue: DirectAnimatedStickerNode.sharedQueue, path: path, width: width, height: height, cachePathPrefix: nil, unpremultiplyAlpha: false) {
if let videoSource = makeVideoStickerDirectFrameSource(queue: DirectAnimatedStickerNode.sharedQueue, path: path, hintVP9: true, width: width, height: height, cachePathPrefix: nil, unpremultiplyAlpha: false) {
strongSelf.setupPlayback(videoSource: videoSource)
}
} else {

View File

@ -273,8 +273,8 @@ private final class VideoStickerFrameSourceCache {
private let useCache = true
public func makeVideoStickerDirectFrameSource(queue: Queue, path: String, width: Int, height: Int, cachePathPrefix: String?, unpremultiplyAlpha: Bool) -> AnimatedStickerFrameSource? {
return VideoStickerDirectFrameSource(queue: queue, path: path, width: width, height: height, cachePathPrefix: cachePathPrefix, unpremultiplyAlpha: unpremultiplyAlpha)
public func makeVideoStickerDirectFrameSource(queue: Queue, path: String, hintVP9: Bool, width: Int, height: Int, cachePathPrefix: String?, unpremultiplyAlpha: Bool) -> AnimatedStickerFrameSource? {
return VideoStickerDirectFrameSource(queue: queue, path: path, isVP9: hintVP9, width: width, height: height, cachePathPrefix: cachePathPrefix, unpremultiplyAlpha: unpremultiplyAlpha)
}
public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
@ -290,7 +290,7 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
public var duration: Double
fileprivate var currentFrame: Int
private let source: SoftwareVideoSource?
private var source: FFMpegFileReader?
public var frameIndex: Int {
if self.frameCount == 0 {
@ -300,7 +300,7 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
}
}
public init?(queue: Queue, path: String, width: Int, height: Int, cachePathPrefix: String?, unpremultiplyAlpha: Bool = true) {
public init?(queue: Queue, path: String, isVP9: Bool = true, width: Int, height: Int, cachePathPrefix: String?, unpremultiplyAlpha: Bool = true) {
self.queue = queue
self.path = path
self.width = width
@ -329,12 +329,25 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
self.frameCount = 1
self.duration = 0.0
} else {
let source = SoftwareVideoSource(path: path, hintVP9: true, unpremultiplyAlpha: unpremultiplyAlpha)
self.source = source
let source = FFMpegFileReader(
source: .file(path),
passthroughDecoder: false,
useHardwareAcceleration: false,
selectedStream: .mediaType(.video),
seek: nil,
maxReadablePts: nil
)
if let source {
self.source = source
self.frameRate = min(30, source.frameRate())
self.duration = source.duration().seconds
} else {
self.source = nil
self.frameRate = 30
self.duration = 0.0
}
self.image = nil
self.frameRate = min(30, source.getFramerate())
self.frameCount = 0
self.duration = source.reportedDuration.seconds
}
}
@ -365,56 +378,66 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
} else if useCache, let cache = self.cache, let yuvData = cache.readUncompressedYuvaFrame(index: frameIndex) {
return AnimatedStickerFrame(data: yuvData, type: .yuva, width: self.width, height: self.height, bytesPerRow: self.width * 2, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount)
} else if let source = self.source {
let frameAndLoop = source.readFrame(maxPts: nil)
if frameAndLoop.0 == nil {
if frameAndLoop.3 {
if self.frameCount == 0 {
if let cache = self.cache {
if cache.storedFrames == frameIndex {
self.frameCount = frameIndex
cache.storeFrameRateAndCount(frameRate: self.frameRate, frameCount: self.frameCount)
} else {
Logger.shared.log("VideoSticker", "Missed a frame? \(frameIndex) \(cache.storedFrames)")
}
} else {
self.frameCount = frameIndex
}
let frameAndLoop = source.readFrame(argb: true)
switch frameAndLoop {
case let .frame(frame):
var frameData = Data(count: self.bytesPerRow * self.height)
frameData.withUnsafeMutableBytes { buffer -> Void in
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
return
}
self.currentFrame = 0
} else {
Logger.shared.log("VideoSticker", "Skipped a frame?")
let imageBuffer = CMSampleBufferGetImageBuffer(frame.sampleBuffer)
CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!)
let width = CVPixelBufferGetWidth(imageBuffer!)
let height = CVPixelBufferGetHeight(imageBuffer!)
let srcData = CVPixelBufferGetBaseAddress(imageBuffer!)
var sourceBuffer = vImage_Buffer(data: srcData, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow)
var destBuffer = vImage_Buffer(data: bytes, height: vImagePixelCount(self.height), width: vImagePixelCount(self.width), rowBytes: self.bytesPerRow)
let _ = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, nil, vImage_Flags(kvImageDoNotTile))
CVPixelBufferUnlockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))
}
return nil
}
guard let frame = frameAndLoop.0 else {
return nil
}
var frameData = Data(count: self.bytesPerRow * self.height)
frameData.withUnsafeMutableBytes { buffer -> Void in
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
return
}
let imageBuffer = CMSampleBufferGetImageBuffer(frame.sampleBuffer)
CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!)
let width = CVPixelBufferGetWidth(imageBuffer!)
let height = CVPixelBufferGetHeight(imageBuffer!)
let srcData = CVPixelBufferGetBaseAddress(imageBuffer!)
var sourceBuffer = vImage_Buffer(data: srcData, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow)
var destBuffer = vImage_Buffer(data: bytes, height: vImagePixelCount(self.height), width: vImagePixelCount(self.width), rowBytes: self.bytesPerRow)
let _ = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, nil, vImage_Flags(kvImageDoNotTile))
CVPixelBufferUnlockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))
}
self.cache?.storeUncompressedRgbFrame(index: frameIndex, rgbData: frameData)
return AnimatedStickerFrame(data: frameData, type: .argb, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount, multiplyAlpha: true)
self.cache?.storeUncompressedRgbFrame(index: frameIndex, rgbData: frameData)
return AnimatedStickerFrame(data: frameData, type: .argb, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount, multiplyAlpha: true)
case .endOfStream:
if self.frameCount == 0 {
if let cache = self.cache {
if cache.storedFrames == frameIndex {
self.frameCount = frameIndex
cache.storeFrameRateAndCount(frameRate: self.frameRate, frameCount: self.frameCount)
} else {
Logger.shared.log("VideoSticker", "Missed a frame? \(frameIndex) \(cache.storedFrames)")
}
} else {
self.frameCount = frameIndex
}
}
self.currentFrame = 0
self.source = FFMpegFileReader(
source: .file(self.path),
passthroughDecoder: false,
useHardwareAcceleration: false,
selectedStream: .mediaType(.video),
seek: nil,
maxReadablePts: nil
)
if let cache = self.cache {
if let yuvData = cache.readUncompressedYuvaFrame(index: self.currentFrame) {
return AnimatedStickerFrame(data: yuvData, type: .yuva, width: self.width, height: self.height, bytesPerRow: self.width * 2, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount)
}
}
return nil
case .waitingForMoreData, .error:
return nil
}
} else {
return nil
}

View File

@ -25,6 +25,7 @@ public final class AvatarVideoNode: ASDisplayNode {
private var emojiMarkup: TelegramMediaImage.EmojiMarkup?
private var videoFileDisposable: Disposable?
private var fileDisposable = MetaDisposable()
private var animationFile: TelegramMediaFile?
private var itemLayer: EmojiKeyboardItemLayer?
@ -32,6 +33,7 @@ public final class AvatarVideoNode: ASDisplayNode {
private var animationNode: AnimatedStickerNode?
private let stickerFetchedDisposable = MetaDisposable()
private var videoItemLayer: EmojiKeyboardItemLayer?
private var videoNode: UniversalVideoNode?
private var videoContent: NativeVideoContent?
private let playbackStartDisposable = MetaDisposable()
@ -55,6 +57,7 @@ public final class AvatarVideoNode: ASDisplayNode {
}
deinit {
self.videoFileDisposable?.dispose()
self.fileDisposable.dispose()
self.stickerFetchedDisposable.dispose()
self.playbackStartDisposable.dispose()
@ -137,6 +140,7 @@ public final class AvatarVideoNode: ASDisplayNode {
self.videoLoopCount += 1
if self.videoLoopCount >= maxVideoLoopCount {
self.itemLayer?.isVisibleForAnimations = false
self.videoItemLayer?.isVisibleForAnimations = false
}
}
}
@ -211,6 +215,9 @@ public final class AvatarVideoNode: ASDisplayNode {
if videoContent.id != self.videoContent?.id {
self.videoNode?.removeFromSupernode()
self.videoContent = videoContent
self.videoFileDisposable?.dispose()
self.videoFileDisposable = fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .avatar, reference: videoFileReference.resourceReference(videoFileReference.media.resource)).startStrict()
}
}
}
@ -231,56 +238,111 @@ public final class AvatarVideoNode: ASDisplayNode {
}
self.animationNode?.visibility = isVisible
if isVisible, let videoContent = self.videoContent, self.videoLoopCount < maxVideoLoopCount {
if self.videoNode == nil {
let context = self.context
let mediaManager = context.sharedContext.mediaManager
let videoNode = UniversalVideoNode(context: context, postbox: context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: VideoDecoration(), content: videoContent, priority: .embedded)
videoNode.clipsToBounds = true
videoNode.isUserInteractionEnabled = false
videoNode.isHidden = true
videoNode.playbackCompleted = { [weak self] in
if let strongSelf = self {
strongSelf.videoLoopCount += 1
if strongSelf.videoLoopCount >= maxVideoLoopCount {
if let videoNode = strongSelf.videoNode {
strongSelf.videoNode = nil
videoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak videoNode] _ in
videoNode?.removeFromSupernode()
})
var useDirectCache = false
if self.internalSize.width <= 200.0 {
useDirectCache = true
}
if useDirectCache {
if self.videoItemLayer == nil {
let animationData = EntityKeyboardAnimationData(file: TelegramMediaFile.Accessor(videoContent.fileReference.media))
let videoItemLayer = EmojiKeyboardItemLayer(
item: EmojiPagerContentComponent.Item(
animationData: animationData,
content: .animation(animationData),
itemFile: TelegramMediaFile.Accessor(videoContent.fileReference.media),
subgroupId: nil,
icon: .none,
tintMode: .none
),
context: self.context,
attemptSynchronousLoad: false,
content: .animation(animationData),
cache: self.context.animationCache,
renderer: self.context.animationRenderer,
placeholderColor: .clear,
blurredBadgeColor: .clear,
accentIconColor: .white,
pointSize: self.internalSize,
onUpdateDisplayPlaceholder: { _, _ in
}
)
videoItemLayer.onLoop = { [weak self] in
if let self {
self.videoLoopCount += 1
if self.videoLoopCount >= maxVideoLoopCount {
self.itemLayer?.isVisibleForAnimations = false
}
}
}
self.videoItemLayer = videoItemLayer
self.layer.addSublayer(videoItemLayer)
}
if let _ = videoContent.startTimestamp {
self.playbackStartDisposable.set((videoNode.status
|> map { status -> Bool in
if let status = status, case .playing = status.status {
return true
} else {
return false
}
}
|> filter { playing in
return playing
}
|> take(1)
|> deliverOnMainQueue).startStrict(completed: { [weak self] in
} else {
if let videoItemLayer = self.videoItemLayer {
self.videoItemLayer = nil
videoItemLayer.removeFromSuperlayer()
}
}
if useDirectCache {
if let videoNode = self.videoNode {
self.videoNode = nil
videoNode.removeFromSupernode()
}
} else {
if self.videoNode == nil {
let context = self.context
let mediaManager = context.sharedContext.mediaManager
let videoNode = UniversalVideoNode(context: context, postbox: context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: VideoDecoration(), content: videoContent, priority: .embedded)
videoNode.clipsToBounds = true
videoNode.isUserInteractionEnabled = false
videoNode.isHidden = true
videoNode.playbackCompleted = { [weak self] in
if let strongSelf = self {
Queue.mainQueue().after(0.15) {
strongSelf.videoNode?.isHidden = false
strongSelf.videoLoopCount += 1
if strongSelf.videoLoopCount >= maxVideoLoopCount {
if let videoNode = strongSelf.videoNode {
strongSelf.videoNode = nil
videoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak videoNode] _ in
videoNode?.removeFromSupernode()
})
}
}
}
}))
} else {
self.playbackStartDisposable.set(nil)
videoNode.isHidden = false
}
if let _ = videoContent.startTimestamp {
self.playbackStartDisposable.set((videoNode.status
|> map { status -> Bool in
if let status = status, case .playing = status.status {
return true
} else {
return false
}
}
|> filter { playing in
return playing
}
|> take(1)
|> deliverOnMainQueue).startStrict(completed: { [weak self] in
if let strongSelf = self {
Queue.mainQueue().after(0.15) {
strongSelf.videoNode?.isHidden = false
}
}
}))
} else {
self.playbackStartDisposable.set(nil)
videoNode.isHidden = false
}
videoNode.canAttachContent = true
videoNode.play()
self.addSubnode(videoNode)
self.videoNode = videoNode
}
videoNode.canAttachContent = true
videoNode.play()
self.addSubnode(videoNode)
self.videoNode = videoNode
}
} else if let videoNode = self.videoNode {
self.videoNode = nil
@ -289,6 +351,7 @@ public final class AvatarVideoNode: ASDisplayNode {
if self.videoLoopCount < maxVideoLoopCount {
self.itemLayer?.isVisibleForAnimations = isVisible
}
self.videoItemLayer?.isVisibleForAnimations = isVisible
}
public func updateLayout(size: CGSize, cornerRadius: CGFloat, transition: ContainedViewLayoutTransition) {
@ -301,6 +364,9 @@ public final class AvatarVideoNode: ASDisplayNode {
videoNode.frame = CGRect(origin: .zero, size: size)
videoNode.updateLayout(size: size, transition: transition)
}
if let videoItemLayer = self.videoItemLayer {
videoItemLayer.frame = CGRect(origin: .zero, size: size)
}
let itemSize = CGSize(width: size.width * 0.67, height: size.height * 0.67)
let itemFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - itemSize.width) / 2.0), y: floorToScreenPixels((size.height - itemSize.height) / 2.0)), size: itemSize)

View File

@ -1747,7 +1747,11 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
self.avatarNode.font = avatarPlaceholderFont(size: avatarFontSize)
}
}
self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, clipStyle: isForumAvatar ? .roundedRect : .round, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0))
if peer.smallProfileImage != nil && overrideImage == nil {
self.avatarNode.setPeerV2(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, clipStyle: isForumAvatar ? .roundedRect : .round, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0))
} else {
self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, clipStyle: isForumAvatar ? .roundedRect : .round, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0))
}
if peer.isPremium && peer.id != item.context.account.peerId {
let context = item.context

View File

@ -954,10 +954,10 @@ final class ChatSendMessageContextScreenComponent: Component {
}
var customEffectResource: (FileMediaReference, MediaResource)?
if let effectAnimation = messageEffect.effectAnimation {
if let effectAnimation = messageEffect.effectAnimation?._parse() {
customEffectResource = (FileMediaReference.standalone(media: effectAnimation), effectAnimation.resource)
} else {
let effectSticker = messageEffect.effectSticker
let effectSticker = messageEffect.effectSticker._parse()
if let effectFile = effectSticker.videoThumbnails.first {
customEffectResource = (FileMediaReference.standalone(media: effectSticker), effectFile.resource)
}

View File

@ -309,7 +309,7 @@ final class MessageItemView: UIView {
}
let effectIconContent: ChatSendMessageScreenEffectIcon.Content
if let staticIcon = effect.staticIcon {
effectIconContent = .file(staticIcon)
effectIconContent = .file(staticIcon._parse())
} else {
effectIconContent = .text(effect.emoticon)
}

View File

@ -52,6 +52,8 @@ final class NavigationTransitionCoordinator {
private var currentCompletion: (() -> Void)?
private var didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)?
private var frameRateLink: SharedDisplayLinkDriver.Link?
init(transition: NavigationTransition, isInteractive: Bool, isFlat: Bool, container: NavigationContainer, topNode: ASDisplayNode, topNavigationBar: NavigationBar?, bottomNode: ASDisplayNode, bottomNavigationBar: NavigationBar?, didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)? = nil) {
self.transition = transition
self.isInteractive = isInteractive
@ -114,6 +116,8 @@ final class NavigationTransitionCoordinator {
self.maybeCreateNavigationBarTransition()
self.updateProgress(0.0, transition: .immediate, completion: {})
self.frameRateLink = SharedDisplayLinkDriver.shared.add(framesPerSecond: .max, { _ in })
}
required init(coder aDecoder: NSCoder) {

View File

@ -403,6 +403,22 @@ public final class FFMpegFileReader {
deinit {
}
public func frameRate() -> Int {
if let stream = self.stream {
return Int(stream.info.fps.seconds)
} else {
return 0
}
}
public func duration() -> CMTime {
if let stream = self.stream {
return stream.info.duration
} else {
return .zero
}
}
private func readPacketInternal() -> FFMpegPacket? {
guard let avFormatContext = self.avFormatContext else {
return nil
@ -452,7 +468,7 @@ public final class FFMpegFileReader {
return nil
}
public func readFrame() -> ReadFrameResult {
public func readFrame(argb: Bool = false) -> ReadFrameResult {
guard let stream = self.stream else {
return .error
}
@ -461,7 +477,7 @@ public final class FFMpegFileReader {
var result: MediaTrackFrame?
switch stream.decoder {
case let .video(decoder):
result = decoder.decode(ptsOffset: nil, forceARGB: false, unpremultiplyAlpha: false, displayImmediately: false)
result = decoder.decode(ptsOffset: nil, forceARGB: argb, unpremultiplyAlpha: false, displayImmediately: false)
case let .videoPassthrough(decoder):
result = decoder.decode()
case let .audio(decoder):

View File

@ -448,7 +448,7 @@ private func chatMessageImageFileThumbnailDatas(account: Account, userLocation:
return signal
}
private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, fileReference: FileMediaReference, previewSourceFileReference: FileMediaReference?, thumbnailSize: Bool = false, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, forceThumbnail: Bool = false) -> Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError> {
private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, fileReference: FileMediaReference, previewSourceFileReference: FileMediaReference?, alternativeFileAndRange: Signal<(TelegramMediaFile, Range<Int64>), NoError>? = nil, thumbnailSize: Bool = false, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, forceThumbnail: Bool = false) -> Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError> {
let fullSizeResource = fileReference.media.resource
var reducedSizeResource: MediaResource?
if let videoThumbnail = fileReference.media.videoThumbnails.first {
@ -1627,7 +1627,7 @@ public func mediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceU
}
}
public func internalMediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, videoReference: FileMediaReference, previewSourceFileReference: FileMediaReference? = nil, imageReference: ImageMediaReference? = nil, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false, blurred: Bool = false) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> {
public func internalMediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, videoReference: FileMediaReference, previewSourceFileReference: FileMediaReference? = nil, imageReference: ImageMediaReference? = nil, alternativeFileAndRange: Signal<(TelegramMediaFile, Range<Int64>), NoError>? = nil, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false, blurred: Bool = false) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> {
let signal: Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError>
if let imageReference = imageReference {
signal = chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, photoReference: imageReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad, forceThumbnail: blurred)
@ -1638,7 +1638,7 @@ public func internalMediaGridMessageVideo(postbox: Postbox, userLocation: MediaR
return Tuple(thumbnailData, fullSizeData.flatMap({ Tuple($0, "") }), fullSizeComplete)
}
} else {
signal = chatMessageVideoDatas(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, fileReference: videoReference, previewSourceFileReference: previewSourceFileReference, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail, forceThumbnail: blurred)
signal = chatMessageVideoDatas(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, fileReference: videoReference, previewSourceFileReference: previewSourceFileReference, alternativeFileAndRange: alternativeFileAndRange, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail, forceThumbnail: blurred)
}
return signal

View File

@ -1893,7 +1893,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
for i in 0 ..< 2 {
let groupId = i == 0 ? "reactions" : "stickers"
for item in i == 0 ? reactionEffects : stickerEffects {
let itemFile: TelegramMediaFile = item.effectSticker
let itemFile = item.effectSticker
var tintMode: EmojiPagerContentComponent.Item.TintMode = .none
if itemFile.isCustomTemplateEmoji {
@ -1917,11 +1917,11 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
}
}
let animationData = EntityKeyboardAnimationData(file: TelegramMediaFile.Accessor(itemFile), partialReference: .none)
let animationData = EntityKeyboardAnimationData(file: itemFile, partialReference: .none)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
content: .animation(animationData),
itemFile: TelegramMediaFile.Accessor(itemFile),
itemFile: itemFile,
subgroupId: nil,
icon: icon,
tintMode: tintMode
@ -2257,7 +2257,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
for i in 0 ..< 2 {
let groupId = i == 0 ? "reactions" : "stickers"
for item in i == 0 ? reactionEffects : stickerEffects {
let itemFile: TelegramMediaFile = item.effectSticker
let itemFile = item.effectSticker
var tintMode: EmojiPagerContentComponent.Item.TintMode = .none
if itemFile.isCustomTemplateEmoji {
@ -2281,11 +2281,11 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
}
}
let animationData = EntityKeyboardAnimationData(file: TelegramMediaFile.Accessor(itemFile), partialReference: .none)
let animationData = EntityKeyboardAnimationData(file: itemFile, partialReference: .none)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
content: .animation(animationData),
itemFile: TelegramMediaFile.Accessor(itemFile),
itemFile: itemFile,
subgroupId: nil,
icon: icon,
tintMode: tintMode

View File

@ -976,7 +976,7 @@ func applyLoadMessageHistoryThreadsResults(accountPeerId: PeerId, transaction: T
transaction.replaceMessageTagSummary(peerId: result.peerId, threadId: item.threadId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, customTag: nil, count: item.unreadReactionsCount, maxId: item.topMessage)
if item.topMessage != 0 {
transaction.removeHole(peerId: result.peerId, threadId: item.threadId, namespace: Namespaces.Message.Cloud, space: .everywhere, range: item.topMessage ... (Int32.max - 1))
//transaction.removeHole(peerId: result.peerId, threadId: item.threadId, namespace: Namespaces.Message.Cloud, space: .everywhere, range: item.topMessage ... (Int32.max - 1))
}
for message in result.messages {

View File

@ -2,6 +2,8 @@ import Foundation
import TelegramApi
import Postbox
import SwiftSignalKit
import FlatBuffers
import FlatSerialization
public final class AvailableMessageEffects: Equatable, Codable {
public final class MessageEffect: Equatable, Codable {
@ -10,24 +12,27 @@ public final class AvailableMessageEffects: Equatable, Codable {
case isPremium
case emoticon
case staticIcon
case staticIconData = "sid"
case effectSticker
case effectStickerData = "esd"
case effectAnimation
case effectAnimationData = "ead"
}
public let id: Int64
public let isPremium: Bool
public let emoticon: String
public let staticIcon: TelegramMediaFile?
public let effectSticker: TelegramMediaFile
public let effectAnimation: TelegramMediaFile?
public let staticIcon: TelegramMediaFile.Accessor?
public let effectSticker: TelegramMediaFile.Accessor
public let effectAnimation: TelegramMediaFile.Accessor?
public init(
id: Int64,
isPremium: Bool,
emoticon: String,
staticIcon: TelegramMediaFile?,
effectSticker: TelegramMediaFile,
effectAnimation: TelegramMediaFile?
staticIcon: TelegramMediaFile.Accessor?,
effectSticker: TelegramMediaFile.Accessor,
effectAnimation: TelegramMediaFile.Accessor?
) {
self.id = id
self.isPremium = isPremium
@ -66,19 +71,28 @@ public final class AvailableMessageEffects: Equatable, Codable {
self.isPremium = try container.decodeIfPresent(Bool.self, forKey: .isPremium) ?? false
self.emoticon = try container.decode(String.self, forKey: .emoticon)
if let staticIconData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .staticIcon) {
self.staticIcon = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: staticIconData.data)))
if let staticIconData = try container.decodeIfPresent(Data.self, forKey: .staticIconData) {
var byteBuffer = ByteBuffer(data: staticIconData)
self.staticIcon = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, staticIconData)
} else if let staticIconData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .staticIcon) {
self.staticIcon = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: staticIconData.data))))
} else {
self.staticIcon = nil
}
do {
if let effectStickerData = try container.decodeIfPresent(Data.self, forKey: .effectStickerData) {
var byteBuffer = ByteBuffer(data: effectStickerData)
self.effectSticker = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, effectStickerData)
} else {
let effectStickerData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .effectSticker)
self.effectSticker = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectStickerData.data)))
self.effectSticker = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectStickerData.data))))
}
if let effectAnimationData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .effectAnimation) {
self.effectAnimation = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectAnimationData.data)))
if let effectAnimationData = try container.decodeIfPresent(Data.self, forKey: .effectAnimationData) {
var byteBuffer = ByteBuffer(data: effectAnimationData)
self.effectAnimation = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, effectAnimationData)
} else if let effectAnimationData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .effectAnimation) {
self.effectAnimation = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectAnimationData.data))))
} else {
self.effectAnimation = nil
}
@ -91,12 +105,26 @@ public final class AvailableMessageEffects: Equatable, Codable {
try container.encode(self.emoticon, forKey: .emoticon)
try container.encode(self.isPremium, forKey: .isPremium)
if let staticIcon = self.staticIcon {
try container.encode(PostboxEncoder().encodeObjectToRawData(staticIcon), forKey: .staticIcon)
let encodeFileItem: (TelegramMediaFile.Accessor, CodingKeys) throws -> Void = { file, key in
if let serializedFile = file._wrappedData {
try container.encode(serializedFile, forKey: key)
} else if let file = file._wrappedFile {
var builder = FlatBufferBuilder(initialSize: 1024)
let value = file.encodeToFlatBuffers(builder: &builder)
builder.finish(offset: value)
let serializedFile = builder.data
try container.encode(serializedFile, forKey: key)
} else {
preconditionFailure()
}
}
try container.encode(PostboxEncoder().encodeObjectToRawData(self.effectSticker), forKey: .effectSticker)
if let staticIcon = self.staticIcon {
try encodeFileItem(staticIcon, .staticIconData)
}
try encodeFileItem(self.effectSticker, .effectStickerData)
if let effectAnimation = self.effectAnimation {
try container.encode(PostboxEncoder().encodeObjectToRawData(effectAnimation), forKey: .effectAnimation)
try encodeFileItem(effectAnimation, .effectAnimationData)
}
}
}
@ -142,8 +170,6 @@ public final class AvailableMessageEffects: Equatable, Codable {
}
}
//availableEffect flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect;
private extension AvailableMessageEffects.MessageEffect {
convenience init?(apiMessageEffect: Api.AvailableEffect, files: [Int64: TelegramMediaFile]) {
switch apiMessageEffect {
@ -157,9 +183,9 @@ private extension AvailableMessageEffects.MessageEffect {
id: id,
isPremium: isPremium,
emoticon: emoticon,
staticIcon: staticIconId.flatMap({ files[$0] }),
effectSticker: effectSticker,
effectAnimation: effectAnimationId.flatMap({ files[$0] })
staticIcon: staticIconId.flatMap({ files[$0].flatMap(TelegramMediaFile.Accessor.init) }),
effectSticker: TelegramMediaFile.Accessor(effectSticker),
effectAnimation: effectAnimationId.flatMap({ files[$0].flatMap(TelegramMediaFile.Accessor.init) })
)
}
}
@ -289,22 +315,3 @@ func managedSynchronizeAvailableMessageEffects(postbox: Postbox, network: Networ
)
|> restart
}
public extension Message {
func messageEffect(availableMessageEffects: AvailableMessageEffects?) -> AvailableMessageEffects.MessageEffect? {
guard let availableMessageEffects else {
return nil
}
for attribute in self.attributes {
if let attribute = attribute as? EffectMessageAttribute {
for effect in availableMessageEffects.messageEffects {
if effect.id == attribute.id {
return effect
}
}
break
}
}
return nil
}
}

View File

@ -1411,7 +1411,7 @@ public final class InstantPage: PostboxCoding, Equatable {
self.url = decoder.decodeStringForKey("url", orElse: "")
self.views = decoder.decodeOptionalInt32ForKey("v")
#if DEBUG
#if DEBUG && false
var builder = FlatBufferBuilder(initialSize: 1024)
let offset = self.encodeToFlatBuffers(builder: &builder)
builder.finish(offset: offset)

View File

@ -104,7 +104,7 @@ public final class StickerPackCollectionInfo: ItemCollectionInfo, Equatable {
encoder.encodeInt32(self.flags.rawValue, forKey: "f")
encoder.encodeInt32(self.count, forKey: "n")
#if DEBUG
#if DEBUG && false
var builder = FlatBufferBuilder(initialSize: 1024)
let offset = self.encodeToFlatBuffers(builder: &builder)
builder.finish(offset: offset)

View File

@ -347,7 +347,7 @@ public final class TelegramChannel: Peer, Equatable {
self.verificationIconFileId = decoder.decodeOptionalInt64ForKey("vfid")
self.sendPaidMessageStars = decoder.decodeCodable(StarsAmount.self, forKey: "sendPaidMessageStars")
#if DEBUG
#if DEBUG && false
var builder = FlatBufferBuilder(initialSize: 1024)
let offset = self.encodeToFlatBuffers(builder: &builder)
builder.finish(offset: offset)

View File

@ -207,7 +207,7 @@ public final class TelegramGroup: Peer, Equatable {
self.creationDate = decoder.decodeInt32ForKey("d", orElse: 0)
self.version = Int(decoder.decodeInt32ForKey("v", orElse: 0))
#if DEBUG
#if DEBUG && false
var builder = FlatBufferBuilder(initialSize: 1024)
let offset = self.encodeToFlatBuffers(builder: &builder)
builder.finish(offset: offset)

View File

@ -698,8 +698,7 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
} else if let lhsWrappedData = lhs._wrappedData, let rhsWrappedData = rhs._wrappedData {
return lhsWrappedData == rhsWrappedData
} else {
assertionFailure()
return false
return lhs._parse() == rhs._parse()
}
}
}
@ -903,13 +902,6 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
try container.encode(postboxEncoder.makeData(), forKey: .data)
}
public func encodeToFlatBuffersData() -> Data {
var builder = FlatBufferBuilder(initialSize: 1024)
let value = self.encodeToFlatBuffers(builder: &builder)
builder.finish(offset: value)
return builder.data
}
public init(flatBuffersObject: TelegramCore_TelegramMediaFile) throws {
self.fileId = MediaId(namespace: flatBuffersObject.fileId.namespace, id: flatBuffersObject.fileId.id)
self.partialReference = try flatBuffersObject.partialReference.flatMap { try PartialMediaReference(flatBuffersObject: $0 ) }

View File

@ -21,10 +21,21 @@ private let cloudSoundMapping: [Int32: Int64] = [
108: 5078299559046677216,
109: 5078299559046677217,
110: 5078299559046677218,
111: 5078299559046677219
111: 5078299559046677219,
200: 5032932652722685163,
201: 5032932652722685160,
202: 5032932652722685159,
203: 5032932652722685158,
204: 5032932652722685168,
205: 5032932652722685167,
206: 5032932652722685166,
207: 5032932652722685165,
208: 5032932652722685164,
209: 5032932652722685162,
210: 5032932652722685161
]
public let defaultCloudPeerNotificationSound: PeerMessageSound = .cloud(fileId: cloudSoundMapping[100]!)
public let defaultCloudPeerNotificationSound: PeerMessageSound = .cloud(fileId: cloudSoundMapping[200]!)
public enum CloudSoundBuiltinCategory {
case modern

View File

@ -331,7 +331,7 @@ public final class TelegramUser: Peer, Equatable {
self.subscriberCount = decoder.decodeOptionalInt32ForKey("ssc")
self.verificationIconFileId = decoder.decodeOptionalInt64ForKey("vfid")
#if DEBUG
#if DEBUG && false
var builder = FlatBufferBuilder(initialSize: 1024)
let offset = self.encodeToFlatBuffers(builder: &builder)
builder.finish(offset: offset)

View File

@ -642,3 +642,22 @@ public func _internal_parseMediaAttachment(data: Data) -> Media? {
return nil
}
}
public extension Message {
func messageEffect(availableMessageEffects: AvailableMessageEffects?) -> AvailableMessageEffects.MessageEffect? {
guard let availableMessageEffects else {
return nil
}
for attribute in self.attributes {
if let attribute = attribute as? EffectMessageAttribute {
for effect in availableMessageEffects.messageEffects {
if effect.id == attribute.id {
return effect
}
}
break
}
}
return nil
}
}

View File

@ -14,7 +14,18 @@ private let modernSoundsNamePaths: [KeyPath<PresentationStrings, String>] = [
\.NotificationsSound_Keys,
\.NotificationsSound_Popcorn,
\.NotificationsSound_Pulse,
\.NotificationsSound_Synth
\.NotificationsSound_Synth,
\.NotificationsSound_Rebound,
\.NotificationsSound_Antic,
\.NotificationsSound_Cheers,
\.NotificationsSound_Droplet,
\.NotificationsSound_Handoff,
\.NotificationsSound_Milestone,
\.NotificationsSound_Passage,
\.NotificationsSound_Portal,
\.NotificationsSound_Rattle,
\.NotificationsSound_Slide,
\.NotificationsSound_Welcome
]
private let classicSoundNamePaths: [KeyPath<PresentationStrings, String>] = [

View File

@ -1116,7 +1116,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
var centerAnimation: TelegramMediaFile?
centerAnimation = messageEffect.staticIcon
centerAnimation = messageEffect.staticIcon?._parse()
node.update(
context: arguments.context,

View File

@ -2286,7 +2286,8 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
if automaticDownload != .none, let file = media as? TelegramMediaFile, NativeVideoContent.isHLSVideo(file: file) {
let postbox = context.account.postbox
let fetchSignal = HLSVideoContent.minimizedHLSQualityPreloadData(postbox: context.account.postbox, file: .message(message: MessageReference(message), media: file), userLocation: .peer(message.id.peerId), prefixSeconds: 10, autofetchPlaylist: true, codecConfiguration: HLSCodecConfiguration(context: context))
let fetchSignal: Signal<Never, NoError>
fetchSignal = HLSVideoContent.minimizedHLSQualityPreloadData(postbox: context.account.postbox, file: .message(message: MessageReference(message), media: file), userLocation: .peer(message.id.peerId), prefixSeconds: 10, autofetchPlaylist: true, codecConfiguration: HLSCodecConfiguration(context: context))
|> mapToSignal { fileAndRange -> Signal<Never, NoError> in
guard let fileAndRange else {
return .complete()

View File

@ -938,13 +938,13 @@ open class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol {
}
self.playedEffectAnimation = true
if let effectAnimation = effect.effectAnimation {
if let effectAnimation = effect.effectAnimation?._parse() {
self.playEffectAnimation(resource: effectAnimation.resource)
if self.fetchEffectDisposable == nil {
self.fetchEffectDisposable = freeMediaFileResourceInteractiveFetched(account: item.context.account, userLocation: .other, fileReference: .standalone(media: effectAnimation), resource: effectAnimation.resource).startStrict()
}
} else {
let effectSticker = effect.effectSticker
let effectSticker = effect.effectSticker._parse()
if let effectFile = effectSticker.videoThumbnails.first {
self.playEffectAnimation(resource: effectFile.resource)
if self.fetchEffectDisposable == nil {

View File

@ -501,7 +501,7 @@ public func effectMessageReactions(context: AccountContext) -> Signal<[ReactionI
}
existingIds.insert(messageEffect.id)
let mainFile = TelegramMediaFile.Accessor(messageEffect.effectSticker)
let mainFile = messageEffect.effectSticker
result.append(ReactionItem(
reaction: ReactionItem.Reaction(rawValue: .custom(messageEffect.id)),

View File

@ -82,18 +82,20 @@ public func generateTopicIcon(title: String, backgroundColors: [UIColor], stroke
})
}
public enum AnimationCacheAnimationType {
public enum AnimationCacheAnimationType: Equatable {
case still
case lottie
case video
case video(isVP9: Bool)
}
public extension AnimationCacheAnimationType {
init(file: TelegramMediaFile) {
if file.isVideoSticker || file.isVideoEmoji {
self = .video
self = .video(isVP9: true)
} else if file.isAnimatedSticker {
self = .lottie
} else if file.isVideo {
self = .video(isVP9: false)
} else {
self = .still
}
@ -122,8 +124,8 @@ public func animationCacheFetchFile(postbox: Postbox, userLocation: MediaResourc
}
switch type {
case .video:
cacheVideoAnimation(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
case let .video(isVP9):
cacheVideoAnimation(path: result, hintVP9: isVP9, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
case .lottie:
guard let data = try? Data(contentsOf: URL(fileURLWithPath: result)) else {
options.writer.finish()
@ -153,8 +155,8 @@ public func animationCacheLoadLocalFile(name: String, type: AnimationCacheAnimat
}
switch type {
case .video:
cacheVideoAnimation(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
case let .video(isVP9):
cacheVideoAnimation(path: result, hintVP9: isVP9, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
case .lottie:
guard let data = try? Data(contentsOf: URL(fileURLWithPath: result)) else {
options.writer.finish()

View File

@ -33,7 +33,7 @@ public final class EmojiKeyboardItemLayer: MultiAnimationRenderTarget {
case locked
case featured
case text(String)
case customFile(TelegramMediaFile)
case customFile(TelegramMediaFile.Accessor)
}
public let item: EmojiPagerContentComponent.Item

View File

@ -43,10 +43,10 @@ public final class EntityKeyboardAnimationData: Equatable {
case gift(String)
}
public enum ItemType {
public enum ItemType: Equatable {
case still
case lottie
case video
case video(isVP9: Bool)
var animationCacheAnimationType: AnimationCacheAnimationType {
switch self {
@ -54,8 +54,8 @@ public final class EntityKeyboardAnimationData: Equatable {
return .still
case .lottie:
return .lottie
case .video:
return .video
case let .video(isVP9):
return .video(isVP9: isVP9)
}
}
}
@ -105,9 +105,11 @@ public final class EntityKeyboardAnimationData: Equatable {
public convenience init(file: TelegramMediaFile.Accessor, isReaction: Bool = false, partialReference: PartialMediaReference? = nil) {
let type: ItemType
if file.isVideoSticker || file.isVideoEmoji {
type = .video
type = .video(isVP9: true)
} else if file.isAnimatedSticker {
type = .lottie
} else if file.isVideo {
type = .video(isVP9: false)
} else {
type = .still
}
@ -406,7 +408,7 @@ public final class EmojiPagerContentComponent: Component {
case locked
case premium
case text(String)
case customFile(TelegramMediaFile)
case customFile(TelegramMediaFile.Accessor)
}
public enum TintMode: Equatable {

View File

@ -287,7 +287,9 @@ public extension EmojiPagerContentComponent {
if item.file.isAnimatedSticker {
type = .lottie
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
type = .video
type = .video(isVP9: true)
} else if item.file.isVideo {
type = .video(isVP9: false)
} else {
type = .still
}
@ -1390,7 +1392,9 @@ public extension EmojiPagerContentComponent {
if item.file.isAnimatedSticker {
type = .lottie
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
type = .video
type = .video(isVP9: true)
} else if item.file.isVideo {
type = .video(isVP9: false)
} else {
type = .still
}
@ -1477,7 +1481,9 @@ public extension EmojiPagerContentComponent {
if item.file.isAnimatedSticker {
type = .lottie
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
type = .video
type = .video(isVP9: true)
} else if item.file.isVideo {
type = .video(isVP9: false)
} else {
type = .still
}
@ -1774,7 +1780,9 @@ public extension EmojiPagerContentComponent {
if item.file.isAnimatedSticker {
type = .lottie
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
type = .video
type = .video(isVP9: true)
} else if item.file.isVideo {
type = .video(isVP9: false)
} else {
type = .still
}
@ -2011,7 +2019,9 @@ public extension EmojiPagerContentComponent {
if item.file.isAnimatedSticker {
type = .lottie
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
type = .video
type = .video(isVP9: true)
} else if item.file.isVideo {
type = .video(isVP9: false)
} else {
type = .still
}
@ -2090,7 +2100,9 @@ public extension EmojiPagerContentComponent {
if item.file.isAnimatedSticker {
type = .lottie
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
type = .video
type = .video(isVP9: true)
} else if item.file.isVideo {
type = .video(isVP9: false)
} else {
type = .still
}
@ -2234,7 +2246,7 @@ public extension EmojiPagerContentComponent {
continue
}
let itemFile: TelegramMediaFile = item.effectSticker
let itemFile = item.effectSticker
var tintMode: Item.TintMode = .none
if itemFile.isCustomTemplateEmoji {
@ -2258,11 +2270,11 @@ public extension EmojiPagerContentComponent {
}
}
let animationData = EntityKeyboardAnimationData(file: TelegramMediaFile.Accessor(itemFile), partialReference: .none)
let animationData = EntityKeyboardAnimationData(file: itemFile, partialReference: .none)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
content: .animation(animationData),
itemFile: TelegramMediaFile.Accessor(itemFile),
itemFile: itemFile,
subgroupId: nil,
icon: icon,
tintMode: tintMode

View File

@ -81,7 +81,7 @@ final class PremiumBadgeView: UIView {
context: self.context,
userLocation: .other,
attemptSynchronousLoad: false,
file: customFile,
file: customFile._parse(),
cache: self.context.animationCache,
renderer: self.context.animationRenderer,
unique: false,

View File

@ -18,9 +18,9 @@ private func roundUp(_ numToRound: Int, multiple: Int) -> Int {
return numToRound + multiple - remainder
}
public func cacheVideoAnimation(path: String, width: Int, height: Int, writer: AnimationCacheItemWriter, firstFrameOnly: Bool, customColor: UIColor?) {
public func cacheVideoAnimation(path: String, hintVP9: Bool, width: Int, height: Int, writer: AnimationCacheItemWriter, firstFrameOnly: Bool, customColor: UIColor?) {
let work: () -> Void = {
guard let frameSource = makeVideoStickerDirectFrameSource(queue: writer.queue, path: path, width: roundUp(width, multiple: 16), height: roundUp(height, multiple: 16), cachePathPrefix: nil, unpremultiplyAlpha: false) else {
guard let frameSource = makeVideoStickerDirectFrameSource(queue: writer.queue, path: path, hintVP9: hintVP9, width: roundUp(width, multiple: 16), height: roundUp(height, multiple: 16), cachePathPrefix: nil, unpremultiplyAlpha: false) else {
return
}
let frameDuration = 1.0 / Double(frameSource.frameRate)

View File

@ -102,7 +102,7 @@ private final class EffectBadgeView: UIView {
}
let effectIconContent: ChatSendMessageScreenEffectIcon.Content
if let staticIcon = effect.staticIcon {
effectIconContent = .file(staticIcon)
effectIconContent = .file(staticIcon._parse())
} else {
effectIconContent = .text(effect.emoticon)
}