diff --git a/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift b/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift index 8342a6e194..412f39c1f3 100644 --- a/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift +++ b/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift @@ -1508,78 +1508,97 @@ public class VideoMessageCameraScreen: ViewController { let dimensions = PixelDimensions(width: 400, height: 400) - var thumbnailImage = video.thumbnail + let thumbnailImage: Signal if startTime > 0.0 { - let composition = composition(with: results) - let imageGenerator = AVAssetImageGenerator(asset: composition) - imageGenerator.maximumSize = dimensions.cgSize - imageGenerator.appliesPreferredTrackTransform = true - - if let cgImage = try? imageGenerator.copyCGImage(at: CMTime(seconds: startTime, preferredTimescale: composition.duration.timescale), actualTime: nil) { - thumbnailImage = UIImage(cgImage: cgImage) + thumbnailImage = Signal { subscriber in + let composition = composition(with: results) + let imageGenerator = AVAssetImageGenerator(asset: composition) + imageGenerator.maximumSize = dimensions.cgSize + imageGenerator.appliesPreferredTrackTransform = true + + imageGenerator.generateCGImagesAsynchronously(forTimes: [NSValue(time: CMTime(seconds: startTime, preferredTimescale: composition.duration.timescale))], completionHandler: { _, image, _, _, _ in + if let image { + subscriber.putNext(UIImage(cgImage: image)) + } else { + subscriber.putNext(video.thumbnail) + } + subscriber.putCompletion() + }) + + return ActionDisposable { + imageGenerator.cancelAllCGImageGeneration() + } } - } - - let values = MediaEditorValues(peerId: self.context.account.peerId, originalDimensions: dimensions, cropOffset: .zero, cropRect: CGRect(origin: .zero, size: dimensions.cgSize), cropScale: 1.0, cropRotation: 0.0, cropMirroring: false, cropOrientation: nil, gradientColors: nil, videoTrimRange: self.node.previewState?.trimRange, videoIsMuted: false, videoIsFullHd: false, videoIsMirrored: false, videoVolume: nil, additionalVideoPath: nil, additionalVideoIsDual: false, additionalVideoPosition: nil, additionalVideoScale: nil, additionalVideoRotation: nil, additionalVideoPositionChanges: [], additionalVideoTrimRange: nil, additionalVideoOffset: nil, additionalVideoVolume: nil, nightTheme: false, drawing: nil, entities: [], toolValues: [:], audioTrack: nil, audioTrackTrimRange: nil, audioTrackOffset: nil, audioTrackVolume: nil, audioTrackSamples: nil, qualityPreset: .videoMessage) - - var resourceAdjustments: VideoMediaResourceAdjustments? = nil - if let valuesData = try? JSONEncoder().encode(values) { - let data = MemoryBuffer(data: valuesData) - let digest = MemoryBuffer(data: data.md5Digest()) - resourceAdjustments = VideoMediaResourceAdjustments(data: data, digest: digest, isStory: false) - } - - let resource: TelegramMediaResource - let liveUploadData: LegacyLiveUploadInterfaceResult? - if let current = self.node.currentLiveUploadData { - liveUploadData = current } else { - liveUploadData = self.node.liveUploadInterface?.fileUpdated(true) as? LegacyLiveUploadInterfaceResult - } - if !hasAdjustments, let liveUploadData, let data = try? Data(contentsOf: URL(fileURLWithPath: video.videoPath)) { - resource = LocalFileMediaResource(fileId: liveUploadData.id) - self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true) - } else { - resource = LocalFileVideoMediaResource(randomId: Int64.random(in: Int64.min ... Int64.max), paths: videoPaths, adjustments: resourceAdjustments) + thumbnailImage = .single(video.thumbnail) } - var previewRepresentations: [TelegramMediaImageRepresentation] = [] - - let thumbnailResource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) - let thumbnailSize = video.dimensions.cgSize.aspectFitted(CGSize(width: 320.0, height: 320.0)) - if let thumbnailData = scaleImageToPixelSize(image: thumbnailImage, size: thumbnailSize)?.jpegData(compressionQuality: 0.4) { - self.context.account.postbox.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData) - previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(thumbnailSize), resource: thumbnailResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)) - } - - let tempFile = TempBox.shared.tempFile(fileName: "file") - defer { - TempBox.shared.dispose(tempFile) - } - if let data = compressImageToJPEG(thumbnailImage, quality: 0.7, tempFilePath: tempFile.path) { - context.account.postbox.mediaBox.storeCachedResourceRepresentation(resource, representation: CachedVideoFirstFrameRepresentation(), data: data) - } + let _ = (thumbnailImage + |> deliverOnMainQueue).startStandalone(next: { [weak self] thumbnailImage in + guard let self else { + return + } + let values = MediaEditorValues(peerId: self.context.account.peerId, originalDimensions: dimensions, cropOffset: .zero, cropRect: CGRect(origin: .zero, size: dimensions.cgSize), cropScale: 1.0, cropRotation: 0.0, cropMirroring: false, cropOrientation: nil, gradientColors: nil, videoTrimRange: self.node.previewState?.trimRange, videoIsMuted: false, videoIsFullHd: false, videoIsMirrored: false, videoVolume: nil, additionalVideoPath: nil, additionalVideoIsDual: false, additionalVideoPosition: nil, additionalVideoScale: nil, additionalVideoRotation: nil, additionalVideoPositionChanges: [], additionalVideoTrimRange: nil, additionalVideoOffset: nil, additionalVideoVolume: nil, nightTheme: false, drawing: nil, entities: [], toolValues: [:], audioTrack: nil, audioTrackTrimRange: nil, audioTrackOffset: nil, audioTrackVolume: nil, audioTrackSamples: nil, qualityPreset: .videoMessage) + + var resourceAdjustments: VideoMediaResourceAdjustments? = nil + if let valuesData = try? JSONEncoder().encode(values) { + let data = MemoryBuffer(data: valuesData) + let digest = MemoryBuffer(data: data.md5Digest()) + resourceAdjustments = VideoMediaResourceAdjustments(data: data, digest: digest, isStory: false) + } + + let resource: TelegramMediaResource + let liveUploadData: LegacyLiveUploadInterfaceResult? + if let current = self.node.currentLiveUploadData { + liveUploadData = current + } else { + liveUploadData = self.node.liveUploadInterface?.fileUpdated(true) as? LegacyLiveUploadInterfaceResult + } + if !hasAdjustments, let liveUploadData, let data = try? Data(contentsOf: URL(fileURLWithPath: video.videoPath)) { + resource = LocalFileMediaResource(fileId: liveUploadData.id) + self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true) + } else { + resource = LocalFileVideoMediaResource(randomId: Int64.random(in: Int64.min ... Int64.max), paths: videoPaths, adjustments: resourceAdjustments) + } + + var previewRepresentations: [TelegramMediaImageRepresentation] = [] + + let thumbnailResource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) + let thumbnailSize = video.dimensions.cgSize.aspectFitted(CGSize(width: 320.0, height: 320.0)) + if let thumbnailData = scaleImageToPixelSize(image: thumbnailImage, size: thumbnailSize)?.jpegData(compressionQuality: 0.4) { + self.context.account.postbox.mediaBox.storeResourceData(thumbnailResource.id, data: thumbnailData) + previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(thumbnailSize), resource: thumbnailResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)) + } + + let tempFile = TempBox.shared.tempFile(fileName: "file") + defer { + TempBox.shared.dispose(tempFile) + } + if let data = compressImageToJPEG(thumbnailImage, quality: 0.7, tempFilePath: tempFile.path) { + context.account.postbox.mediaBox.storeCachedResourceRepresentation(resource, representation: CachedVideoFirstFrameRepresentation(), data: data) + } - let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: Int64.random(in: Int64.min ... Int64.max)), partialReference: nil, resource: resource, previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.FileName(fileName: "video.mp4"), .Video(duration: finalDuration, size: video.dimensions, flags: [.instantRoundVideo], preloadSize: nil)]) - - - var attributes: [MessageAttribute] = [] - if self.cameraState.isViewOnceEnabled { - attributes.append(AutoremoveTimeoutMessageAttribute(timeout: viewOnceTimeout, countdownBeginTime: nil)) - } - - self.completion(.message( - text: "", - attributes: attributes, - inlineStickers: [:], - mediaReference: .standalone(media: media), - threadId: nil, - replyToMessageId: nil, - replyToStoryId: nil, - localGroupingKey: nil, - correlationId: nil, - bubbleUpEmojiOrStickersets: [] - ), silentPosting, scheduleTime) + let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: Int64.random(in: Int64.min ... Int64.max)), partialReference: nil, resource: resource, previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.FileName(fileName: "video.mp4"), .Video(duration: finalDuration, size: video.dimensions, flags: [.instantRoundVideo], preloadSize: nil)]) + + + var attributes: [MessageAttribute] = [] + if self.cameraState.isViewOnceEnabled { + attributes.append(AutoremoveTimeoutMessageAttribute(timeout: viewOnceTimeout, countdownBeginTime: nil)) + } + + self.completion(.message( + text: "", + attributes: attributes, + inlineStickers: [:], + mediaReference: .standalone(media: media), + threadId: nil, + replyToMessageId: nil, + replyToStoryId: nil, + localGroupingKey: nil, + correlationId: nil, + bubbleUpEmojiOrStickersets: [] + ), silentPosting, scheduleTime) + }) }) }