I have an audio url (.m4a) that I create using the AVAudioRecorder. I want to share that audio on Instagram so I convert the audio to a video. The issue is after the conversion, when I save the video url to the Files app using the UIActivityViewController, I can replay the video, see the time (eg 7 seconds) and hear the audio with no problem. A black screen with a sound icon appears.
But when I save the video to the Photos Library using the UIActivityViewController, the video shows the 7 seconds but nothing plays, the video is all gray, and the sound icon doesn’t show.
Why is the video successfully saving/playing in the Files app but saving and not playing in the Photos Library?
let asset: AVURLAsset = AVURLAsset(url: audioURL)
let mixComposition = AVMutableComposition()
guard let compositionTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: CMPersistentTrackID()) else { return }
let track = asset.tracks(withMediaType: .audio)
guard let assetTrack = track.first else { return }
do {
try compositionTrack.insertTimeRange(CMTimeRangeMake(start: .zero, duration: assetTrack.timeRange.duration), of: assetTrack, at: .zero)
} catch {
print(error.localizedDescription)
}
guard let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetPassthrough) else { return }
let dirPath = NSTemporaryDirectory().appending("(UUID().uuidString).mov")
let outputFileURL = URL(fileURLWithPath: dirPath)
exporter.outputFileType = .mov
exporter.outputURL = outputFileURL
exporter.shouldOptimizeForNetworkUse = true
exporter.exportAsynchronously {
switch exporter.status {
// ...
guard let videoURL = exporter.outputURL else { return }
// present UIActivityViewController to save videoURL and then save it to the Photos Library via 'Save Video`
}
}
2
Answers
So it seems that although the code from my question did covert the audio file to a video file, there still wasn't a
video track
. I know this for a fact because after I got the exporter's videoURL from my question, I tried to add a watermark to it and in the watermark code it kept crashing onBasically the code from my question coverts audio to video but doesn't add a video track.
What I assume is happening is when the Files app reads the file, it knows that it's a .mov or .mp4 file and then it'll play the audio track even if the video track is missing.
Conversely, when the Photos app reads the file it also know's that it's a .mov or .mp4 file but if there isn't a video track, it won't play anything.
I had to combine these 2 answers to get the audio to play as a video in the Photos app.
1st- I added my app icon (you can add any image) as 1 image to an array of images to make a video track using the code from How do I export UIImage array as a movie? answered by @scootermg.
The code from @scootermg's answer is conveniently in 1 file at this GitHub by @dldnh. In his code, in the
ImageAnimator
class, in therender
function, instead of saving to the Library I returned thevideoWriter's output URL
in the completionHandler.2nd- I combined the app icon video that I just made with the audio url from my question using the code from Swift Merge audio and video files into one video answered by @TungFam
In the mixCompostion from TungFam's answer I used the audio url's asset duration for the length of the video.
As Lance rightfully pointed out, the issue is that while there was an export of a file in the
.mov
or.mp4
format, there was no video, it was just an audio playing.On reading a bit more, .mp4 for example is just a digital multimedia container format which can very well just be used for audio so it’s possible to save audio file as a .mp4 / .mov.
What was needed was to add an empty video track to the
AVMutableComposition
to succeed. Lance already posted a great solution works perfectly well and is moreself sustained
than an alternative solution I propose which relies on having a blank 1 second video.Overview of how it works
AVMutableComposition
which will be used to merge the audio and video tracksAVMutableCompositionTrack
with the audio track and add that to the mainAVMutableComposition
AVMutableVideoComposition
with the video trackAVAssetExportSession
to export the final video with theAVMutableComposition
and theAVMutableVideoComposition
The code
In most of the code below you will see multiple guard statements. You can create one guard, however, it can be useful to know with such types of tasks where the failure occurred as there could be several reason why an export could fail.
Configuring the audio track
Configuring the video track
Configure the video composition
Configure the AVAssetExportSession
Over here, one important thing to not is to set the exporter’s
present quality
to a movie present likeAVAssetExportPresetHighestQuality
orAVAssetExportPresetLowQuality
for example, something other thanAVAssetExportPresetPassthrough
which as per the documentation,So you would still get an audio mp4 or mov file since the current format of the composition is of an audio. I did not test this extensively but this is from a few tests.
Finally, you can bring it all the above functions together like so:
Final Thoughts