2025-02-27 12:23:14 +01:00

119 lines
4.1 KiB
Swift

import Foundation
import UIKit
import Display
import BatchVideoRendering
import AccountContext
import TelegramCore
import AVFoundation
import SwiftSignalKit
import PhotoResources
open class GifVideoLayer: AVSampleBufferDisplayLayer, BatchVideoRenderingContext.Target {
private let context: AccountContext
private let batchVideoContext: BatchVideoRenderingContext
private let userLocation: MediaResourceUserLocation
private let file: FileMediaReference?
private var batchVideoTargetHandle: BatchVideoRenderingContext.TargetHandle?
public var batchVideoRenderingTargetState: BatchVideoRenderingContext.TargetState?
private var thumbnailDisposable: Disposable?
private var isReadyToRender: Bool = false
public var started: (() -> Void)?
public var shouldBeAnimating: Bool = false {
didSet {
if self.shouldBeAnimating == oldValue {
return
}
self.updateShouldBeRendering()
}
}
public init(context: AccountContext, batchVideoContext: BatchVideoRenderingContext, userLocation: MediaResourceUserLocation, file: FileMediaReference?, synchronousLoad: Bool) {
self.context = context
self.batchVideoContext = batchVideoContext
self.userLocation = userLocation
self.file = file
super.init()
self.videoGravity = .resizeAspectFill
if let file = self.file {
if let dimensions = file.media.dimensions {
self.thumbnailDisposable = (mediaGridMessageVideo(postbox: context.account.postbox, userLocation: userLocation, videoReference: file, synchronousLoad: synchronousLoad, nilForEmptyResult: true)
|> deliverOnMainQueue).start(next: { [weak self] transform in
guard let strongSelf = self else {
return
}
let boundingSize = CGSize(width: 93.0, height: 93.0)
let imageSize = dimensions.cgSize.aspectFilled(boundingSize)
if let image = transform(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: boundingSize, intrinsicInsets: UIEdgeInsets(), resizeMode: .fill(.clear)))?.generateImage() {
Queue.mainQueue().async {
if let strongSelf = self {
strongSelf.contents = image.cgImage
strongSelf.setupVideo()
strongSelf.started?()
}
}
} else {
strongSelf.setupVideo()
}
})
} else {
self.setupVideo()
}
}
}
override public init(layer: Any) {
guard let layer = layer as? GifVideoLayer else {
preconditionFailure()
}
self.context = layer.context
self.batchVideoContext = layer.batchVideoContext
self.userLocation = layer.userLocation
self.file = layer.file
super.init(layer: layer)
}
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.thumbnailDisposable?.dispose()
}
private func setupVideo() {
self.isReadyToRender = true
self.updateShouldBeRendering()
}
private func updateShouldBeRendering() {
let shouldBeRendering = self.shouldBeAnimating && self.isReadyToRender
if shouldBeRendering, let file = self.file {
if self.batchVideoTargetHandle == nil {
self.batchVideoTargetHandle = self.batchVideoContext.add(target: self, file: file, userLocation: self.userLocation)
}
} else {
self.batchVideoTargetHandle = nil
}
}
public func setSampleBuffer(sampleBuffer: CMSampleBuffer) {
if #available(iOS 17.0, *) {
self.sampleBufferRenderer.enqueue(sampleBuffer)
} else {
self.enqueue(sampleBuffer)
}
}
}