mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Various improvements
This commit is contained in:
@@ -5,6 +5,8 @@ import Display
|
||||
import SwiftSignalKit
|
||||
import Camera
|
||||
import MetalEngine
|
||||
import MediaEditor
|
||||
import TelegramCore
|
||||
|
||||
final class CameraVideoSource: VideoSource {
|
||||
private var device: MTLDevice
|
||||
@@ -80,3 +82,165 @@ final class CameraVideoSource: VideoSource {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final class LiveStreamMediaSource {
|
||||
private let pool: CVPixelBufferPool?
|
||||
|
||||
private(set) var mainVideoOutput: CameraVideoOutput!
|
||||
private(set) var additionalVideoOutput: CameraVideoOutput!
|
||||
private let composer: MediaEditorComposer
|
||||
|
||||
private var currentMainSampleBuffer: CMSampleBuffer?
|
||||
private var currentAdditionalSampleBuffer: CMSampleBuffer?
|
||||
|
||||
public private(set) var currentVideoOutput: CVPixelBuffer?
|
||||
private var onVideoUpdatedListeners = Bag<() -> Void>()
|
||||
|
||||
public private(set) var currentAudioOutput: Data?
|
||||
private var onAudioUpdatedListeners = Bag<() -> Void>()
|
||||
|
||||
public init() {
|
||||
let width: Int32 = 1080
|
||||
let height: Int32 = 1920
|
||||
|
||||
let dimensions = CGSize(width: CGFloat(width), height: CGFloat(height))
|
||||
|
||||
let bufferOptions: [String: Any] = [
|
||||
kCVPixelBufferPoolMinimumBufferCountKey as String: 3 as NSNumber
|
||||
]
|
||||
let pixelBufferOptions: [String: Any] = [
|
||||
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA as NSNumber,
|
||||
kCVPixelBufferWidthKey as String: UInt32(width),
|
||||
kCVPixelBufferHeightKey as String: UInt32(height)
|
||||
]
|
||||
|
||||
var pool: CVPixelBufferPool?
|
||||
CVPixelBufferPoolCreate(nil, bufferOptions as CFDictionary, pixelBufferOptions as CFDictionary, &pool)
|
||||
self.pool = pool
|
||||
|
||||
let topOffset = CGPoint(x: 267.0, y: 438.0)
|
||||
let additionalVideoPosition = CGPoint(x: dimensions.width - topOffset.x, y: topOffset.y)
|
||||
|
||||
self.composer = MediaEditorComposer(
|
||||
postbox: nil,
|
||||
values: MediaEditorValues(
|
||||
peerId: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(0)),
|
||||
originalDimensions: PixelDimensions(dimensions),
|
||||
cropOffset: .zero,
|
||||
cropRect: CGRect(origin: .zero, size: dimensions),
|
||||
cropScale: 1.0,
|
||||
cropRotation: 0.0,
|
||||
cropMirroring: false,
|
||||
cropOrientation: nil,
|
||||
gradientColors: nil,
|
||||
videoTrimRange: nil,
|
||||
videoIsMuted: false,
|
||||
videoIsFullHd: false,
|
||||
videoIsMirrored: false,
|
||||
videoVolume: nil,
|
||||
additionalVideoPath: nil,
|
||||
additionalVideoIsDual: true,
|
||||
additionalVideoPosition: additionalVideoPosition,
|
||||
additionalVideoScale: 1.625,
|
||||
additionalVideoRotation: 0.0,
|
||||
additionalVideoPositionChanges: [],
|
||||
additionalVideoTrimRange: nil,
|
||||
additionalVideoOffset: nil,
|
||||
additionalVideoVolume: nil,
|
||||
collage: [],
|
||||
nightTheme: false,
|
||||
drawing: nil,
|
||||
maskDrawing: nil,
|
||||
entities: [],
|
||||
toolValues: [:],
|
||||
audioTrack: nil,
|
||||
audioTrackTrimRange: nil,
|
||||
audioTrackOffset: nil,
|
||||
audioTrackVolume: nil,
|
||||
audioTrackSamples: nil,
|
||||
collageTrackSamples: nil,
|
||||
coverImageTimestamp: nil,
|
||||
coverDimensions: nil,
|
||||
qualityPreset: nil
|
||||
),
|
||||
dimensions: CGSize(width: 1080.0, height: 1920.0),
|
||||
outputDimensions: CGSize(width: 1080.0, height: 1920.0),
|
||||
textScale: 1.0,
|
||||
videoDuration: nil,
|
||||
additionalVideoDuration: nil
|
||||
)
|
||||
|
||||
self.mainVideoOutput = CameraVideoOutput(sink: { [weak self] buffer, mirror in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.currentMainSampleBuffer = try? CMSampleBuffer(copying: buffer)
|
||||
self.push(mainSampleBuffer: buffer, additionalSampleBuffer: self.currentAdditionalSampleBuffer)
|
||||
})
|
||||
|
||||
self.additionalVideoOutput = CameraVideoOutput(sink: { [weak self] buffer, mirror in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.currentAdditionalSampleBuffer = try? CMSampleBuffer(copying: buffer)
|
||||
})
|
||||
}
|
||||
|
||||
public func addOnVideoUpdated(_ f: @escaping () -> Void) -> Disposable {
|
||||
let index = self.onVideoUpdatedListeners.add(f)
|
||||
|
||||
return ActionDisposable { [weak self] in
|
||||
DispatchQueue.main.async {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.onVideoUpdatedListeners.remove(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func addOnAudioUpdated(_ f: @escaping () -> Void) -> Disposable {
|
||||
let index = self.onAudioUpdatedListeners.add(f)
|
||||
|
||||
return ActionDisposable { [weak self] in
|
||||
DispatchQueue.main.async {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.onAudioUpdatedListeners.remove(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
private func push(mainSampleBuffer: CMSampleBuffer, additionalSampleBuffer: CMSampleBuffer?) {
|
||||
let timestamp = mainSampleBuffer.presentationTimeStamp
|
||||
|
||||
guard let mainPixelBuffer = CMSampleBufferGetImageBuffer(mainSampleBuffer) else {
|
||||
return
|
||||
}
|
||||
let main: MediaEditorComposer.Input = .videoBuffer(VideoPixelBuffer(pixelBuffer: mainPixelBuffer, rotation: .rotate90Degrees, timestamp: timestamp), nil, 1.0, .zero)
|
||||
var additional: [MediaEditorComposer.Input?] = []
|
||||
if let additionalPixelBuffer = additionalSampleBuffer.flatMap({ CMSampleBufferGetImageBuffer($0) }) {
|
||||
additional.append(
|
||||
.videoBuffer(VideoPixelBuffer(pixelBuffer: additionalPixelBuffer, rotation: .rotate90DegreesMirrored, timestamp: timestamp), nil, 1.0, .zero)
|
||||
)
|
||||
}
|
||||
self.composer.process(
|
||||
main: main,
|
||||
additional: additional,
|
||||
timestamp: timestamp,
|
||||
pool: self.pool,
|
||||
completion: { [weak self] pixelBuffer in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
Queue.mainQueue().async {
|
||||
self.currentVideoOutput = pixelBuffer
|
||||
for onUpdated in self.onVideoUpdatedListeners.copyItems() {
|
||||
onUpdated()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user