Exporting Mp4 Through Avassetexportsession Fails

Exporting mp4 through AVAssetExportSession fails

Seems like converting the AVAsset instance in a AVMutableComposition did the trick. If, please, anyone knows the reason why this works let me know.

This is the new _getDataFor(_:completion:) method implementation

func _getDataFor(_ item: AVPlayerItem, completion: @escaping (Data?) -> ()) {
guard item.asset.isExportable else {
completion(nil)
return
}

let composition = AVMutableComposition()
let compositionVideoTrack = composition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid))
let compositionAudioTrack = composition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid))

let sourceVideoTrack = item.asset.tracks(withMediaType: AVMediaTypeVideo).first!
let sourceAudioTrack = item.asset.tracks(withMediaType: AVMediaTypeAudio).first!
do {
try compositionVideoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, item.duration), of: sourceVideoTrack, at: kCMTimeZero)
try compositionAudioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, item.duration), of: sourceAudioTrack, at: kCMTimeZero)
} catch(_) {
completion(nil)
return
}

let compatiblePresets = AVAssetExportSession.exportPresets(compatibleWith: composition)
var preset: String = AVAssetExportPresetPassthrough
if compatiblePresets.contains(AVAssetExportPreset1920x1080) { preset = AVAssetExportPreset1920x1080 }

guard
let exportSession = AVAssetExportSession(asset: composition, presetName: preset),
exportSession.supportedFileTypes.contains(AVFileTypeMPEG4) else {
completion(nil)
return
}

var tempFileUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("temp_video_data.mp4", isDirectory: false)
tempFileUrl = URL(fileURLWithPath: tempFileUrl.path)

exportSession.outputURL = tempFileUrl
exportSession.outputFileType = AVFileTypeMPEG4
let startTime = CMTimeMake(0, 1)
let timeRange = CMTimeRangeMake(startTime, item.duration)
exportSession.timeRange = timeRange

exportSession.exportAsynchronously {
print("\(tempFileUrl)")
print("\(exportSession.error)")
let data = try? Data(contentsOf: tempFileUrl)
_ = try? FileManager.default.removeItem(at: tempFileUrl)
completion(data)
}
}

AVAssetExportSession is not exporting M4V files

AVAssetExportPresetHighestQuality only supports .mov files. You have to use AVAssetExportPresetPassthrough instead.

let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetPassthrough)

According to the Documentation, AVAssetExportPresetLowQuality, AVAssetExportPresetMediumQuality and AVAssetExportPresetHighQuality are for QuickTime .mov files only.

You can find out more by trying to print the contents of the variable supportedFileTypes of the AVAssetExportSession.

AVAssetExportSession fails on IOS 13, muxing together audio and video

Issue seems to be related to AVAssetExportPresetPassthrough (and a combination of dealing with an AAC, maybe)

Changing to AVAssetExportPresetLowQuality or AVAssetExportPresetHighestQuality and the video/audio are properly muxed into one. Again, this is just an IOS 13 issue, and likely a bug.

Why don't I get video when exporting a movie using AVAssetExportSession?

Thanks ChrisH, you were right! The Export was taking place on another thread so in the handler I need to get the main queue...

I needed to get the main thread after

case AVAssetExportSessionStatusCompleted:{
dispatch_async(dispatch_get_main_queue(), ^{
//post the notification!
});
break;
}

AVAssetExportSession throws error when exporting AVAsset to temporary iOS path

For anyone with the same problem: I could solve it using an AVMutableComposition():

// Access url
guard songUrl.startAccessingSecurityScopedResource() else {
print("failed to access path")
return
}

// Make sure you release the security-scoped resource when you are done.
defer { songUrl.stopAccessingSecurityScopedResource() }

// Use file coordination for reading and writing any of the URL’s content.
var error: NSError? = nil
NSFileCoordinator().coordinate(readingItemAt: songUrl, error: &error) { (url) in

// Set temporary file's path
let temporaryDirectoryUrl: URL = FileManager.default.temporaryDirectory
let temporaryFilename = ProcessInfo().globallyUniqueString
let temporaryFilepath = temporaryDirectoryUrl.appendingPathComponent("\(temporaryFilename).m4a")

// Prework
let originalAsset = AVURLAsset(url: url)
print(originalAsset)
let composition = AVMutableComposition()
let audioTrack: AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)!
let originalDuration = Int64(CMTimeGetSeconds(originalAsset.duration))
let startTime, stopTime: CMTime

// Shorten audio file if longer than 20 seconds
if originalDuration < 20 {
startTime = CMTimeMake(value: 0, timescale: 1)
stopTime = CMTimeMake(value: originalDuration, timescale: 1)
}
else {
let halftime: Int64 = (originalDuration/2)
startTime = CMTimeMake(value: (halftime-10), timescale: 1)
stopTime = CMTimeMake(value: (halftime+10), timescale: 1)
}

// Export shortened file
do {
try audioTrack.insertTimeRange(CMTimeRangeFromTimeToTime(start: startTime, end: stopTime), of: originalAsset.tracks(withMediaType: AVMediaType.audio)[0], at: CMTime.zero)
let assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A)!
if FileManager.default.fileExists(atPath: temporaryFilepath.absoluteString) {
try? FileManager.default.removeItem(atPath: temporaryFilepath.absoluteString)
print("removed existing file")
}
assetExport.outputFileType = AVFileType.m4a
assetExport.outputURL = temporaryFilepath
assetExport.shouldOptimizeForNetworkUse = true
assetExport.exportAsynchronously(completionHandler: {
switch assetExport.status {
case AVAssetExportSessionStatus.failed:

if let e = assetExport.error {
print("export failed \(e)")
}
case AVAssetExportSessionStatus.cancelled:
print("export cancelled \(String(describing: assetExport.error))")

default:
print("export completed")
}
})
}
catch {
print("error trying to shorten audio file")
}


Related Topics



Leave a reply



Submit