mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-04 13:38:21 +00:00
Video editor fixes
This commit is contained in:
parent
e6f7ed82fb
commit
310e71c71b
Binary file not shown.
@ -42,7 +42,6 @@
|
|||||||
@property (nonatomic, readonly) bool succeed;
|
@property (nonatomic, readonly) bool succeed;
|
||||||
|
|
||||||
- (instancetype)initWithAssetReaderOutput:(AVAssetReaderOutput *)assetReaderOutput assetWriterInput:(AVAssetWriterInput *)assetWriterInput;
|
- (instancetype)initWithAssetReaderOutput:(AVAssetReaderOutput *)assetReaderOutput assetWriterInput:(AVAssetWriterInput *)assetWriterInput;
|
||||||
- (instancetype)initWithUIImage:(UIImage *)image duration:(NSTimeInterval)duration assetWriterInput:(AVAssetWriterInput *)assetWriterInput;
|
|
||||||
|
|
||||||
- (void)startWithTimeRange:(CMTimeRange)timeRange progressBlock:(void (^)(CGFloat progress))progressBlock completionBlock:(void (^)(void))completionBlock;
|
- (void)startWithTimeRange:(CMTimeRange)timeRange progressBlock:(void (^)(CGFloat progress))progressBlock completionBlock:(void (^)(void))completionBlock;
|
||||||
- (void)cancel;
|
- (void)cancel;
|
||||||
@ -1210,7 +1209,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
|||||||
NSInteger channels = [self _audioChannelsCountForPreset:preset];
|
NSInteger channels = [self _audioChannelsCountForPreset:preset];
|
||||||
|
|
||||||
AudioChannelLayout acl;
|
AudioChannelLayout acl;
|
||||||
bzero( &acl, sizeof(acl));
|
bzero(&acl, sizeof(acl));
|
||||||
acl.mChannelLayoutTag = channels > 1 ? kAudioChannelLayoutTag_Stereo : kAudioChannelLayoutTag_Mono;
|
acl.mChannelLayoutTag = channels > 1 ? kAudioChannelLayoutTag_Stereo : kAudioChannelLayoutTag_Mono;
|
||||||
|
|
||||||
return @
|
return @
|
||||||
@ -1278,7 +1277,7 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
|
|||||||
return 300;
|
return 300;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 500;
|
return 900;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -92,7 +92,7 @@ class LegacyPaintStickerView: UIView, TGPhotoPaintStickerRenderView {
|
|||||||
|
|
||||||
self.animationNode?.visibility = true
|
self.animationNode?.visibility = true
|
||||||
let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||||
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0))
|
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 512.0, height: 512.0))
|
||||||
self.animationNode?.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: self.file.resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached)
|
self.animationNode?.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: self.file.resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,6 +53,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
|||||||
|
|
||||||
var frameCount: Int?
|
var frameCount: Int?
|
||||||
var frameRate: Int?
|
var frameRate: Int?
|
||||||
|
var totalDuration: Double?
|
||||||
|
|
||||||
let queue = Queue()
|
let queue = Queue()
|
||||||
let disposable = MetaDisposable()
|
let disposable = MetaDisposable()
|
||||||
@ -71,7 +72,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
|||||||
self.source = AnimatedStickerResourceSource(account: account, resource: file.resource)
|
self.source = AnimatedStickerResourceSource(account: account, resource: file.resource)
|
||||||
if let source = self.source {
|
if let source = self.source {
|
||||||
let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||||
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0))
|
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 512.0, height: 512.0))
|
||||||
self.disposable.set((source.cachedDataPath(width: Int(fittedDimensions.width), height: Int(fittedDimensions.height))
|
self.disposable.set((source.cachedDataPath(width: Int(fittedDimensions.width), height: Int(fittedDimensions.height))
|
||||||
|> deliverOn(self.queue)).start(next: { [weak self] path, complete in
|
|> deliverOn(self.queue)).start(next: { [weak self] path, complete in
|
||||||
if let strongSelf = self, complete {
|
if let strongSelf = self, complete {
|
||||||
@ -89,7 +90,10 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
|||||||
strongSelf.frameCount = frameSource.frameCount
|
strongSelf.frameCount = frameSource.frameCount
|
||||||
strongSelf.frameRate = frameSource.frameRate
|
strongSelf.frameRate = frameSource.frameRate
|
||||||
|
|
||||||
strongSelf.durationPromise.set(.single(Double(frameSource.frameCount) / Double(frameSource.frameRate)))
|
let duration = Double(frameSource.frameCount) / Double(frameSource.frameRate)
|
||||||
|
strongSelf.totalDuration = duration
|
||||||
|
|
||||||
|
strongSelf.durationPromise.set(.single(duration))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
@ -143,26 +147,66 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var currentFrameIndex: Int?
|
||||||
|
|
||||||
var cachedCIImage: CIImage?
|
var cachedCIImage: CIImage?
|
||||||
func image(for time: CMTime, fps: Int, completion: @escaping (CIImage?) -> Void) {
|
func image(for time: CMTime, fps: Int, completion: @escaping (CIImage?) -> Void) {
|
||||||
if self.animated {
|
if self.animated {
|
||||||
let frameQueue = self.frameQueue
|
let frameQueue = self.frameQueue
|
||||||
|
let duration = self.totalDuration
|
||||||
|
let frameCount = self.frameCount
|
||||||
|
|
||||||
|
let currentTime = CMTimeGetSeconds(time)
|
||||||
|
|
||||||
self.queue.async {
|
self.queue.async {
|
||||||
guard let frameQueue = frameQueue else {
|
guard let frameQueue = frameQueue, let duration = duration, let frameCount = frameCount else {
|
||||||
completion(nil)
|
completion(nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let maybeFrame = frameQueue.syncWith { frameQueue in
|
|
||||||
return frameQueue.take()
|
let relativeTime = currentTime - floor(currentTime / duration) * duration
|
||||||
}
|
print(relativeTime)
|
||||||
if let maybeFrame = maybeFrame, let frame = maybeFrame {
|
var t = relativeTime / duration
|
||||||
let image = self.render(width: frame.width, height: frame.height, bytesPerRow: frame.bytesPerRow, data: frame.data, type: frame.type)
|
t = max(0.0, t)
|
||||||
completion(image)
|
t = min(1.0, t)
|
||||||
|
|
||||||
|
let startFrame: Double = 0
|
||||||
|
let endFrame = Double(frameCount)
|
||||||
|
|
||||||
|
let frameOffset = Int(Double(startFrame) * (1.0 - t) + Double(endFrame - 1) * t)
|
||||||
|
let lowerBound: Int = 0
|
||||||
|
let upperBound = frameCount - 1
|
||||||
|
let frameIndex = max(lowerBound, min(upperBound, frameOffset))
|
||||||
|
|
||||||
|
let currentFrameIndex = self.currentFrameIndex
|
||||||
|
if currentFrameIndex != frameIndex {
|
||||||
|
let previousFrameIndex = currentFrameIndex
|
||||||
|
self.currentFrameIndex = frameIndex
|
||||||
|
|
||||||
|
var delta = 1
|
||||||
|
if let previousFrameIndex = previousFrameIndex {
|
||||||
|
delta = max(1, frameIndex - previousFrameIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
let maybeFrame = frameQueue.syncWith { frameQueue -> AnimatedStickerFrame? in
|
||||||
|
var frame: AnimatedStickerFrame?
|
||||||
|
for _ in 0 ..< delta {
|
||||||
|
frame = frameQueue.take()
|
||||||
|
}
|
||||||
|
return frame
|
||||||
|
}
|
||||||
|
if let maybeFrame = maybeFrame, let frame = maybeFrame {
|
||||||
|
let image = self.render(width: frame.width, height: frame.height, bytesPerRow: frame.bytesPerRow, data: frame.data, type: frame.type)
|
||||||
|
completion(image)
|
||||||
|
self.cachedCIImage = image
|
||||||
|
} else {
|
||||||
|
completion(nil)
|
||||||
|
}
|
||||||
|
frameQueue.with { frameQueue in
|
||||||
|
frameQueue.generateFramesIfNeeded()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
completion(nil)
|
completion(self.cachedCIImage)
|
||||||
}
|
|
||||||
frameQueue.with { frameQueue in
|
|
||||||
frameQueue.generateFramesIfNeeded()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -283,7 +327,23 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
|
|||||||
|
|
||||||
return combineLatest(durations)
|
return combineLatest(durations)
|
||||||
|> map { durations in
|
|> map { durations in
|
||||||
return min(6.0, Double(durations.reduce(1) { lcm(Int32($0), Int32($1)) }))
|
var result: Double
|
||||||
|
let minDuration: Double = 3.0
|
||||||
|
if durations.count > 1 {
|
||||||
|
result = min(6.0, Double(durations.reduce(1) { lcm(Int32($0), Int32($1)) }))
|
||||||
|
} else if let duration = durations.first {
|
||||||
|
result = duration
|
||||||
|
} else {
|
||||||
|
result = minDuration
|
||||||
|
}
|
||||||
|
if result < minDuration {
|
||||||
|
if result > 0 {
|
||||||
|
result = result * ceil(minDuration / result)
|
||||||
|
} else {
|
||||||
|
result = minDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user