mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '2749d3a2feb6518a0bcfaa3ab3a52059729de8f3'
This commit is contained in:
commit
200523f50e
@ -190,13 +190,18 @@ open class ManagedAnimationNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.addSubnode(self.imageNode)
|
self.addSubnode(self.imageNode)
|
||||||
|
|
||||||
var previousTimestamp = CACurrentMediaTime()
|
|
||||||
displayLinkUpdate = { [weak self] in
|
displayLinkUpdate = { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let currentTimestamp = CACurrentMediaTime()
|
let currentTimestamp = CACurrentMediaTime()
|
||||||
strongSelf.delta = currentTimestamp - previousTimestamp
|
let delta: Double
|
||||||
|
if let previousTimestamp = strongSelf.previousTimestamp {
|
||||||
|
delta = currentTimestamp - previousTimestamp
|
||||||
|
} else {
|
||||||
|
delta = 1.0 / 60.0
|
||||||
|
}
|
||||||
|
strongSelf.delta = delta
|
||||||
strongSelf.updateAnimation()
|
strongSelf.updateAnimation()
|
||||||
previousTimestamp = currentTimestamp
|
strongSelf.previousTimestamp = currentTimestamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,6 +221,7 @@ open class ManagedAnimationNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.didTryAdvancingState = false
|
self.didTryAdvancingState = false
|
||||||
|
self.previousTimestamp = CACurrentMediaTime()
|
||||||
self.displayLink.isPaused = false
|
self.displayLink.isPaused = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,8 +85,6 @@ private final class EnhanceLightnessPass: DefaultRenderPass {
|
|||||||
|
|
||||||
renderCommandEncoder.endEncoding()
|
renderCommandEncoder.endEncoding()
|
||||||
|
|
||||||
//saveTexture(self.cachedTexture!, name: "lightness", device: device)
|
|
||||||
|
|
||||||
return self.cachedTexture!
|
return self.cachedTexture!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import UIKit
|
|||||||
import Display
|
import Display
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import AVFoundation
|
import AVFoundation
|
||||||
|
import VideoToolbox
|
||||||
|
|
||||||
public enum EditorToolKey: Int32 {
|
public enum EditorToolKey: Int32 {
|
||||||
case enhance
|
case enhance
|
||||||
@ -173,6 +174,10 @@ public final class MediaEditorValues: Codable {
|
|||||||
try container.encode(values, forKey: .toolValues)
|
try container.encode(values, forKey: .toolValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func makeCopy() -> MediaEditorValues {
|
||||||
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
||||||
|
}
|
||||||
|
|
||||||
func withUpdatedCrop(offset: CGPoint, scale: CGFloat, rotation: CGFloat, mirroring: Bool) -> MediaEditorValues {
|
func withUpdatedCrop(offset: CGPoint, scale: CGFloat, rotation: CGFloat, mirroring: Bool) -> MediaEditorValues {
|
||||||
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: offset, cropSize: self.cropSize, cropScale: scale, cropRotation: rotation, cropMirroring: mirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: offset, cropSize: self.cropSize, cropScale: scale, cropRotation: rotation, cropMirroring: mirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
||||||
}
|
}
|
||||||
@ -913,14 +918,18 @@ extension CodableToolValue: Codable {
|
|||||||
|
|
||||||
public func recommendedVideoExportConfiguration(values: MediaEditorValues) -> MediaEditorVideoExport.Configuration {
|
public func recommendedVideoExportConfiguration(values: MediaEditorValues) -> MediaEditorVideoExport.Configuration {
|
||||||
let compressionProperties: [String: Any] = [
|
let compressionProperties: [String: Any] = [
|
||||||
AVVideoAverageBitRateKey: 2000000
|
AVVideoAverageBitRateKey: 2000000,
|
||||||
|
//AVVideoProfileLevelKey: kVTProfileLevel_HEVC_Main_AutoLevel
|
||||||
|
AVVideoProfileLevelKey: AVVideoProfileLevelH264HighAutoLevel,
|
||||||
|
AVVideoH264EntropyModeKey: AVVideoH264EntropyModeCABAC
|
||||||
]
|
]
|
||||||
|
|
||||||
let videoSettings: [String: Any] = [
|
let videoSettings: [String: Any] = [
|
||||||
AVVideoCodecKey: AVVideoCodecType.h264,
|
AVVideoCodecKey: AVVideoCodecType.h264,
|
||||||
|
//AVVideoCodecKey: AVVideoCodecType.hevc,
|
||||||
AVVideoCompressionPropertiesKey: compressionProperties,
|
AVVideoCompressionPropertiesKey: compressionProperties,
|
||||||
AVVideoWidthKey: 1080,
|
AVVideoWidthKey: 720,
|
||||||
AVVideoHeightKey: 1920
|
AVVideoHeightKey: 1280
|
||||||
]
|
]
|
||||||
|
|
||||||
let audioSettings: [String: Any] = [
|
let audioSettings: [String: Any] = [
|
||||||
|
@ -14,7 +14,7 @@ enum ExportWriterStatus {
|
|||||||
|
|
||||||
protocol MediaEditorVideoExportWriter {
|
protocol MediaEditorVideoExportWriter {
|
||||||
func setup(configuration: MediaEditorVideoExport.Configuration, outputPath: String)
|
func setup(configuration: MediaEditorVideoExport.Configuration, outputPath: String)
|
||||||
func setupVideoInput(configuration: MediaEditorVideoExport.Configuration, inputTransform: CGAffineTransform?)
|
func setupVideoInput(configuration: MediaEditorVideoExport.Configuration)
|
||||||
func setupAudioInput(configuration: MediaEditorVideoExport.Configuration)
|
func setupAudioInput(configuration: MediaEditorVideoExport.Configuration)
|
||||||
|
|
||||||
func startWriting() -> Bool
|
func startWriting() -> Bool
|
||||||
@ -55,28 +55,17 @@ public final class MediaEditorVideoAVAssetWriter: MediaEditorVideoExportWriter {
|
|||||||
writer.shouldOptimizeForNetworkUse = configuration.shouldOptimizeForNetworkUse
|
writer.shouldOptimizeForNetworkUse = configuration.shouldOptimizeForNetworkUse
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupVideoInput(configuration: MediaEditorVideoExport.Configuration, inputTransform: CGAffineTransform?) {
|
func setupVideoInput(configuration: MediaEditorVideoExport.Configuration) {
|
||||||
guard let writer = self.writer else {
|
guard let writer = self.writer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let videoInput: AVAssetWriterInput
|
let videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: configuration.videoSettings)
|
||||||
if let transform = inputTransform {
|
|
||||||
let size = CGSize(width: configuration.videoSettings[AVVideoWidthKey] as! Int, height: configuration.videoSettings[AVVideoHeightKey] as! Int)
|
|
||||||
let transformedSize = size.applying(transform.inverted())
|
|
||||||
var videoSettings = configuration.videoSettings
|
|
||||||
videoSettings[AVVideoWidthKey] = abs(transformedSize.width)
|
|
||||||
videoSettings[AVVideoHeightKey] = abs(transformedSize.height)
|
|
||||||
videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
|
|
||||||
videoInput.transform = transform
|
|
||||||
} else {
|
|
||||||
videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: configuration.videoSettings)
|
|
||||||
}
|
|
||||||
videoInput.expectsMediaDataInRealTime = false
|
videoInput.expectsMediaDataInRealTime = false
|
||||||
|
|
||||||
let sourcePixelBufferAttributes = [
|
let sourcePixelBufferAttributes = [
|
||||||
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA,
|
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA,
|
||||||
kCVPixelBufferWidthKey as String: 1080,
|
kCVPixelBufferWidthKey as String: UInt32(configuration.dimensions.width),
|
||||||
kCVPixelBufferHeightKey as String: 1920
|
kCVPixelBufferHeightKey as String: UInt32(configuration.dimensions.height)
|
||||||
]
|
]
|
||||||
self.adaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: videoInput, sourcePixelBufferAttributes: sourcePixelBufferAttributes)
|
self.adaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: videoInput, sourcePixelBufferAttributes: sourcePixelBufferAttributes)
|
||||||
|
|
||||||
@ -285,10 +274,6 @@ public final class MediaEditorVideoExport {
|
|||||||
self.duration.set(CMTime(seconds: 3, preferredTimescale: 1))
|
self.duration.set(CMTime(seconds: 3, preferredTimescale: 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.configuration.values.requiresComposing {
|
|
||||||
self.composer = MediaEditorComposer(account: self.account, values: self.configuration.values, dimensions: self.configuration.dimensions)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch self.subject {
|
switch self.subject {
|
||||||
case let .video(asset):
|
case let .video(asset):
|
||||||
self.setupWithAsset(asset)
|
self.setupWithAsset(asset)
|
||||||
@ -297,6 +282,13 @@ public final class MediaEditorVideoExport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func setupComposer() {
|
||||||
|
guard self.composer == nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.composer = MediaEditorComposer(account: self.account, values: self.configuration.values, dimensions: self.configuration.dimensions)
|
||||||
|
}
|
||||||
|
|
||||||
private func setupWithAsset(_ asset: AVAsset) {
|
private func setupWithAsset(_ asset: AVAsset) {
|
||||||
self.reader = try? AVAssetReader(asset: asset)
|
self.reader = try? AVAssetReader(asset: asset)
|
||||||
guard let reader = self.reader else {
|
guard let reader = self.reader else {
|
||||||
@ -315,16 +307,14 @@ public final class MediaEditorVideoExport {
|
|||||||
|
|
||||||
let videoTracks = asset.tracks(withMediaType: .video)
|
let videoTracks = asset.tracks(withMediaType: .video)
|
||||||
if (videoTracks.count > 0) {
|
if (videoTracks.count > 0) {
|
||||||
let videoOutput: AVAssetReaderOutput
|
let outputSettings: [String : Any]
|
||||||
let inputTransform: CGAffineTransform?
|
if let videoTrack = videoTracks.first, videoTrack.preferredTransform.isIdentity && !self.configuration.values.requiresComposing {
|
||||||
if self.composer == nil {
|
outputSettings = [kCVPixelBufferPixelFormatTypeKey as String: [kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange]]
|
||||||
videoOutput = AVAssetReaderTrackOutput(track: videoTracks.first!, outputSettings: [kCVPixelBufferPixelFormatTypeKey as String: [kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange]])
|
|
||||||
inputTransform = videoTracks.first!.preferredTransform
|
|
||||||
} else {
|
} else {
|
||||||
videoOutput = AVAssetReaderTrackOutput(track: videoTracks.first!, outputSettings: [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA])
|
outputSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]
|
||||||
inputTransform = nil
|
self.setupComposer()
|
||||||
}
|
}
|
||||||
|
let videoOutput = AVAssetReaderTrackOutput(track: videoTracks.first!, outputSettings: outputSettings)
|
||||||
videoOutput.alwaysCopiesSampleData = false
|
videoOutput.alwaysCopiesSampleData = false
|
||||||
if reader.canAdd(videoOutput) {
|
if reader.canAdd(videoOutput) {
|
||||||
reader.add(videoOutput)
|
reader.add(videoOutput)
|
||||||
@ -334,7 +324,7 @@ public final class MediaEditorVideoExport {
|
|||||||
}
|
}
|
||||||
self.videoOutput = videoOutput
|
self.videoOutput = videoOutput
|
||||||
|
|
||||||
writer.setupVideoInput(configuration: self.configuration, inputTransform: inputTransform)
|
writer.setupVideoInput(configuration: self.configuration)
|
||||||
} else {
|
} else {
|
||||||
self.videoOutput = nil
|
self.videoOutput = nil
|
||||||
}
|
}
|
||||||
@ -363,12 +353,14 @@ public final class MediaEditorVideoExport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func setupWithImage(_ image: UIImage) {
|
private func setupWithImage(_ image: UIImage) {
|
||||||
|
self.setupComposer()
|
||||||
|
|
||||||
self.writer = MediaEditorVideoAVAssetWriter()
|
self.writer = MediaEditorVideoAVAssetWriter()
|
||||||
guard let writer = self.writer else {
|
guard let writer = self.writer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
writer.setup(configuration: self.configuration, outputPath: self.outputPath)
|
writer.setup(configuration: self.configuration, outputPath: self.outputPath)
|
||||||
writer.setupVideoInput(configuration: self.configuration, inputTransform: nil)
|
writer.setupVideoInput(configuration: self.configuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func finish() {
|
private func finish() {
|
||||||
|
@ -1534,7 +1534,7 @@ public final class MediaEditorScreen: ViewController {
|
|||||||
duration = 5.0
|
duration = 5.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.completion(.video(video: videoResult, coverImage: nil, values: mediaEditor.values, duration: duration, dimensions: PixelDimensions(width: 1080, height: 1920), caption: caption), { [weak self] in
|
self.completion(.video(video: videoResult, coverImage: nil, values: mediaEditor.values, duration: duration, dimensions: PixelDimensions(width: 720, height: 1280), caption: caption), { [weak self] in
|
||||||
self?.node.animateOut(finished: true, completion: { [weak self] in
|
self?.node.animateOut(finished: true, completion: { [weak self] in
|
||||||
self?.dismiss()
|
self?.dismiss()
|
||||||
})
|
})
|
||||||
|
@ -351,7 +351,7 @@ private final class MediaToolsScreenComponent: Component {
|
|||||||
guard let controller = environment.controller() as? MediaToolsScreen else {
|
guard let controller = environment.controller() as? MediaToolsScreen else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
controller.requestDismiss(animated: true)
|
controller.requestDismiss(reset: true, animated: true)
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
@ -379,7 +379,7 @@ private final class MediaToolsScreenComponent: Component {
|
|||||||
guard let controller = environment.controller() as? MediaToolsScreen else {
|
guard let controller = environment.controller() as? MediaToolsScreen else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
controller.requestDismiss(animated: true)
|
controller.requestDismiss(reset: false, animated: true)
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
@ -955,9 +955,12 @@ public final class MediaToolsScreen: ViewController {
|
|||||||
|
|
||||||
public var dismissed: () -> Void = {}
|
public var dismissed: () -> Void = {}
|
||||||
|
|
||||||
|
private var initialValues: MediaEditorValues
|
||||||
|
|
||||||
public init(context: AccountContext, mediaEditor: MediaEditor) {
|
public init(context: AccountContext, mediaEditor: MediaEditor) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.mediaEditor = mediaEditor
|
self.mediaEditor = mediaEditor
|
||||||
|
self.initialValues = mediaEditor.values.makeCopy()
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: nil)
|
super.init(navigationBarPresentationData: nil)
|
||||||
self.navigationPresentation = .flatModal
|
self.navigationPresentation = .flatModal
|
||||||
@ -977,7 +980,11 @@ public final class MediaToolsScreen: ViewController {
|
|||||||
super.displayNodeDidLoad()
|
super.displayNodeDidLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestDismiss(animated: Bool) {
|
func requestDismiss(reset: Bool, animated: Bool) {
|
||||||
|
if reset {
|
||||||
|
self.mediaEditor.values = self.initialValues
|
||||||
|
}
|
||||||
|
|
||||||
self.dismissed()
|
self.dismissed()
|
||||||
|
|
||||||
self.node.animateOutToEditor(completion: {
|
self.node.animateOutToEditor(completion: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user