@@ -13,7 +13,9 @@ public enum NextLevelSessionExporterError: Error, CustomStringConvertible {
1313 case readingFailure
1414 case writingFailure
1515 case cancelled
16-
16+ case unsupportedVideoOutputConfiguration
17+ case missingVideoTrackInOutput
18+
1719 public var description : String {
1820 get {
1921 switch self {
@@ -25,6 +27,10 @@ public enum NextLevelSessionExporterError: Error, CustomStringConvertible {
2527 return " Writing failure "
2628 case . cancelled:
2729 return " Cancelled "
30+ case . unsupportedVideoOutputConfiguration:
31+ return " The writer rejected the video output configuration "
32+ case . missingVideoTrackInOutput:
33+ return " Export finished without a video track in the output "
2834 }
2935 }
3036 }
@@ -249,7 +255,16 @@ extension NextLevelSessionExporter {
249255 }
250256 }
251257
252- self . setupVideoOutput ( withAsset: asset)
258+ // Fail loudly when the writer rejects the video output configuration.
259+ // Continuing here used to export only the audio track and still resolve
260+ // as a success (issue #400).
261+ guard self . setupVideoOutput ( withAsset: asset) else {
262+ DispatchQueue . main. async {
263+ self . _completionHandler ? ( . failure( NextLevelSessionExporterError . unsupportedVideoOutputConfiguration) )
264+ self . _completionHandler = nil
265+ }
266+ return
267+ }
253268 if !self . stripAudio {
254269 self . setupAudioOutput ( withAsset: asset)
255270 self . setupAudioInput ( )
@@ -316,11 +331,14 @@ extension NextLevelSessionExporter {
316331
317332extension NextLevelSessionExporter {
318333
319- private func setupVideoOutput( withAsset asset: AVAsset ) {
334+ /// Returns `false` when the asset has video tracks but a video writer input
335+ /// could not be created — exporting would silently produce an audio-only
336+ /// file (see numandev1/react-native-compressor#400).
337+ private func setupVideoOutput( withAsset asset: AVAsset ) -> Bool {
320338 let videoTracks = asset. tracks ( withMediaType: AVMediaType . video)
321-
339+
322340 guard videoTracks. count > 0 else {
323- return
341+ return true
324342 }
325343
326344 self . _videoOutput = AVAssetReaderVideoCompositionOutput ( videoTracks: videoTracks, videoSettings: self . videoInputConfiguration)
@@ -344,8 +362,8 @@ extension NextLevelSessionExporter {
344362 self . _videoInput = AVAssetWriterInput ( mediaType: AVMediaType . video, outputSettings: self . videoOutputConfiguration)
345363 self . _videoInput? . expectsMediaDataInRealTime = self . expectsMediaDataInRealTime
346364 } else {
347- print ( " Unsupported output configuration" )
348- return
365+ print ( " NextLevelSessionExporter, unsupported video output configuration, failing export instead of writing an audio-only file " )
366+ return false
349367 }
350368
351369 if let writer = self . _writer,
@@ -367,8 +385,9 @@ extension NextLevelSessionExporter {
367385
368386 self . _pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor ( assetWriterInput: videoInput, sourcePixelBufferAttributes: pixelBufferAttrib)
369387 }
388+ return true
370389 }
371-
390+
372391 private func setupAudioOutput( withAsset asset: AVAsset ) {
373392 let audioTracks = asset. tracks ( withMediaType: AVMediaType . audio)
374393 var audioTracksToUse : [ AVAssetTrack ] = [ ]
@@ -632,6 +651,22 @@ extension NextLevelSessionExporter {
632651 break
633652 }
634653
654+ // Guard against silently returning an audio-only file: when the source
655+ // has a video track and a video output was configured, the exported file
656+ // must contain a video track as well. A configuration the encoder rejects
657+ // at write time can still end with `.completed` while the video track is
658+ // dropped (issue #400) — surface that as an error instead of a success.
659+ if self . videoOutputConfiguration != nil ,
660+ let asset = self . asset,
661+ let outputURL = self . outputURL,
662+ asset. tracks ( withMediaType: AVMediaType . video) . count > 0 ,
663+ AVAsset ( url: outputURL) . tracks ( withMediaType: AVMediaType . video) . count == 0 {
664+ try ? FileManager . default. removeItem ( at: outputURL)
665+ self . _completionHandler ? ( . failure( NextLevelSessionExporterError . missingVideoTrackInOutput) )
666+ self . _completionHandler = nil
667+ return
668+ }
669+
635670 self . _completionHandler ? ( . success( self . status) )
636671 self . _completionHandler = nil
637672 }
0 commit comments