@@ -41,13 +41,12 @@ actor SampleWriter {
4141
4242 // MARK: Internal state
4343
44- private let reader : AVAssetReader
45- private let writer : AVAssetWriter
44+ private var reader : AVAssetReader ?
45+ private var writer : AVAssetWriter ?
4646 private var audioOutput : AVAssetReaderAudioMixOutput ?
4747 private var audioInput : AVAssetWriterInput ?
4848 private var videoOutput : AVAssetReaderVideoCompositionOutput ?
4949 private var videoInput : AVAssetWriterInput ?
50- private var isCancelled = false
5150
5251 nonisolated init (
5352 asset: sending AVAsset,
@@ -107,34 +106,39 @@ actor SampleWriter {
107106 }
108107
109108 func writeSamples( ) async throws {
109+ guard let reader, let writer else { throw CancellationError ( ) }
110110 try Task . checkCancellation ( )
111111
112+ // Clear all of these properties otherwise when we get cancelled then we leak a bunch of
113+ // pixel buffers.
114+ defer {
115+ if Task . isCancelled {
116+ reader. cancelReading ( )
117+ writer. cancelWriting ( )
118+ }
119+ self . reader = nil
120+ self . writer = nil
121+ audioInput = nil
122+ audioOutput = nil
123+ videoInput = nil
124+ videoOutput = nil
125+ }
126+
112127 progressContinuation. yield ( 0.0 )
113128
114129 writer. startWriting ( )
115130 writer. startSession ( atSourceTime: timeRange. start)
116131 reader. startReading ( )
132+
117133 try Task . checkCancellation ( )
118134
119135 startEncodingAudioTracks ( )
120136 startEncodingVideoTracks ( )
121137
122138 while reader. status == . reading, writer. status == . writing {
123- guard !Task. isCancelled else {
124- // Flag so that we stop writing samples
125- isCancelled = true
126- throw CancellationError ( )
127- }
128-
129139 try await Task . sleep ( for: . milliseconds( 10 ) )
130140 }
131141
132- guard !isCancelled, reader. status != . cancelled, writer. status != . cancelled else {
133- log. debug ( " Cancelled before writing samples " )
134- reader. cancelReading ( )
135- writer. cancelWriting ( )
136- throw CancellationError ( )
137- }
138142 guard writer. status != . failed else {
139143 reader. cancelReading ( )
140144 throw Error . writeFailure ( writer. error)
@@ -169,15 +173,15 @@ actor SampleWriter {
169173 let audioOutput = AVAssetReaderAudioMixOutput ( audioTracks: audioTracks, audioSettings: nil )
170174 audioOutput. alwaysCopiesSampleData = false
171175 audioOutput. audioMix = audioMix
172- guard reader. canAdd ( audioOutput) else {
176+ guard let reader , reader. canAdd ( audioOutput) else {
173177 throw Error . setupFailure ( . cannotAddAudioOutput)
174178 }
175179 reader. add ( audioOutput)
176180 self . audioOutput = audioOutput
177181
178182 let audioInput = AVAssetWriterInput ( mediaType: . audio, outputSettings: audioOutputSettings)
179183 audioInput. expectsMediaDataInRealTime = false
180- guard writer. canAdd ( audioInput) else {
184+ guard let writer , writer. canAdd ( audioInput) else {
181185 throw Error . setupFailure ( . cannotAddAudioInput)
182186 }
183187 writer. add ( audioInput)
@@ -193,15 +197,15 @@ actor SampleWriter {
193197 )
194198 videoOutput. alwaysCopiesSampleData = false
195199 videoOutput. videoComposition = videoComposition
196- guard reader. canAdd ( videoOutput) else {
200+ guard let reader , reader. canAdd ( videoOutput) else {
197201 throw Error . setupFailure ( . cannotAddVideoOutput)
198202 }
199203 reader. add ( videoOutput)
200204 self . videoOutput = videoOutput
201205
202206 let videoInput = AVAssetWriterInput ( mediaType: . video, outputSettings: videoOutputSettings)
203207 videoInput. expectsMediaDataInRealTime = false
204- guard writer. canAdd ( videoInput) else {
208+ guard let writer , writer. canAdd ( videoInput) else {
205209 throw Error . setupFailure ( . cannotAddVideoInput)
206210 }
207211 writer. add ( videoInput)
@@ -234,13 +238,6 @@ actor SampleWriter {
234238 }
235239
236240 private func writeAllReadySamples( ) {
237- guard !isCancelled else {
238- log. debug ( " Cancelled while writing samples " )
239- reader. cancelReading ( )
240- writer. cancelWriting ( )
241- return
242- }
243-
244241 if let audioInput, let audioOutput {
245242 let hasMoreAudio = writeReadySamples ( output: audioOutput, input: audioInput)
246243 if !hasMoreAudio { log. debug ( " Finished encoding audio " ) }
@@ -252,13 +249,7 @@ actor SampleWriter {
252249
253250 private func writeReadySamples( output: AVAssetReaderOutput , input: AVAssetWriterInput ) -> Bool {
254251 while input. isReadyForMoreMediaData {
255- guard !isCancelled else {
256- log. debug ( " Cancelled while writing samples " )
257- reader. cancelReading ( )
258- writer. cancelWriting ( )
259- return false
260- }
261- guard reader. status == . reading && writer. status == . writing,
252+ guard reader? . status == . reading && writer? . status == . writing,
262253 let sampleBuffer = output. copyNextSampleBuffer ( ) else {
263254 input. markAsFinished ( )
264255 return false
0 commit comments