Address grill follow-ups: dead code, UUID filename, continuation guard, DataRateLimits
N1: Delete unused CodecSelector.selectEncoder. VideoCompressor calls findEncoder directly; selectEncoder was dead since the initial commit. N2: Switch Android output filename from System.currentTimeMillis() to UUID.randomUUID(). Eliminates the collision risk when two compressions start in the same millisecond. N3: Guard CheckedContinuation against double-resume in both processVideoTrack and processAudioTrack. AVAssetWriter shouldn't re-invoke the requestMediaDataWhenReady block after markAsFinished, but if it did, the previous code would crash via CheckedContinuation's double-resume detection. Added a `finished` flag plus a local `finish` closure that no-ops on second call. N4: DataRateLimits window duration changed from Int `1` to Double `1.0`. VideoToolbox expects the duration value as a CFNumber with float semantics; Int bridges to NSNumber(int) which works on most iOS versions but is not spec-correct.
This commit is contained in:
@@ -113,7 +113,7 @@ class VideoCompressor {
|
||||
]
|
||||
let peakBytesPerSecond = Int(Double(effectiveBitrate) / 8.0 * 1.5)
|
||||
compressionProps[kVTCompressionPropertyKey_DataRateLimits as String] = [
|
||||
peakBytesPerSecond, 1
|
||||
peakBytesPerSecond, 1.0
|
||||
] as CFArray
|
||||
|
||||
let videoColorProps: [String: Any] = [
|
||||
@@ -259,20 +259,27 @@ class VideoCompressor {
|
||||
) async {
|
||||
var lastProgressTime: CFAbsoluteTime = 0
|
||||
var lastAppendedPTS: CMTime?
|
||||
var finished = false
|
||||
|
||||
await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in
|
||||
writerInput.requestMediaDataWhenReady(
|
||||
on: DispatchQueue(label: "com.bsky.videocompress.video")
|
||||
) {
|
||||
while writerInput.isReadyForMoreMediaData {
|
||||
if self.isCancelled {
|
||||
let finish = {
|
||||
if !finished {
|
||||
finished = true
|
||||
writerInput.markAsFinished()
|
||||
continuation.resume()
|
||||
}
|
||||
}
|
||||
while writerInput.isReadyForMoreMediaData {
|
||||
if finished { return }
|
||||
if self.isCancelled {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
guard let sampleBuffer = readerOutput.copyNextSampleBuffer() else {
|
||||
writerInput.markAsFinished()
|
||||
continuation.resume()
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -286,8 +293,7 @@ class VideoCompressor {
|
||||
lastAppendedPTS = pts
|
||||
|
||||
if !writerInput.append(sampleBuffer) {
|
||||
writerInput.markAsFinished()
|
||||
continuation.resume()
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -306,24 +312,31 @@ class VideoCompressor {
|
||||
readerOutput: AVAssetReaderOutput,
|
||||
writerInput: AVAssetWriterInput
|
||||
) async {
|
||||
var finished = false
|
||||
|
||||
await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in
|
||||
writerInput.requestMediaDataWhenReady(
|
||||
on: DispatchQueue(label: "com.bsky.videocompress.audio")
|
||||
) {
|
||||
while writerInput.isReadyForMoreMediaData {
|
||||
if self.isCancelled {
|
||||
let finish = {
|
||||
if !finished {
|
||||
finished = true
|
||||
writerInput.markAsFinished()
|
||||
continuation.resume()
|
||||
}
|
||||
}
|
||||
while writerInput.isReadyForMoreMediaData {
|
||||
if finished { return }
|
||||
if self.isCancelled {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
guard let sampleBuffer = readerOutput.copyNextSampleBuffer() else {
|
||||
writerInput.markAsFinished()
|
||||
continuation.resume()
|
||||
finish()
|
||||
return
|
||||
}
|
||||
if !writerInput.append(sampleBuffer) {
|
||||
writerInput.markAsFinished()
|
||||
continuation.resume()
|
||||
finish()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user