Videos: Reading a video's duration with Swift on iOS
One of the more daunting aspects of feature development on iOS surrounds the use of media files. There are many nuances to take into consideration, and one of these is how the app should consider the duration of the media being played back. For some apps it may be enough to just play the media and let it run to completion; other apps may use multiple media files in composite for a more complete experience. You may also be using a single media file, but have a custom interface for controlling playback, instead of relying on the playback controls provided by iOS.
In this case, it may be important to find the duration of the media file being consumed. Whilst we may already have access to this information (such as in a separate metadata or manifest file), there are occasions where we have to fetch the duration ourselves from the file metadata.
Whilst initially the concepts sound difficult, and using cross platform frameworks such as React Native can introduce additional levels of complexity, we can look at this code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
import Foundation import AVFoundation internal struct GetDurationResult { let duration: Double let playable: Bool func asDictionary() -> [AnyHashable: Any] { [ "duration": duration, "playable": playable ] } } internal struct DurationGenerator { internal func getDuration(for fileName: String) -> GetDurationResult { let asset = AVAsset(url: URL(fileURLWithPath: fileName)) let duration = CMTimeGetSeconds(asset.duration) let isPlayable = asset.isPlayable return GetDurationResult(duration: duration, playable: isPlayable) } }
and see how in reality, fetching video durations is straightforward!
In our "getDuration" method, we read in the video file with
1
let asset = AVAsset(url: URL(fileURLWithPath: fileName))
This takes a file from a path (which in our example, is a path of a video file we already know exists), and initialises an "AVAsset" object.
From this object, we can get the duration in seconds with
1
let duration = CMTimeGetSeconds(asset.duration)
This takes the asset's duration (as a "CMTime" value), and gets the value in seconds.
In the above example, we also determine if the asset is playable, with
1
let isPlayable = asset.isPlayable
This is important in our example, as the video the user has selected may be corrupted or otherwise unusable, and the app consuming the video needs to know this.
Finally, we build a Swift struct "GetDurationResult" with the values:
1
return GetDurationResult(duration: duration, playable: isPlayable)
This is especially important when using React Native, as this allows us to clearly define the function return, instead of returning an abstract key-value map. When we pass this struct's value to the native bridge to return to the JS layer, we can use ".asDictionary()" to get a React Native compatible map, which the bridge will convert to a JS object.
In conclusion...
It is surprisingly straightforward to get a video's duration & playback information on iOS - with a few lines of Swift code we can read the video file & get the duration value. AVAsset also contains a wide range of other properties beyond duration and playback availability.
Ultimately, there are still some aspects to consider, such as:
- Do we need the duration information? Whilst this code does not have a large performance impact, there will always be some impact when ran at scale across batches of files.
- Does our video player already provide this information to us? When passing a video file in to the player, it may already have the video duration.
- Can we get the video duration from elsewhere? We may have a separate metadata or manifest file containing information for the video files, in which case reading that file may be more performant.
Next...
Want to see the full React Native module we use in Perception to handle videos? Check out react-native-video-manager!
Looking for more to read? Check out our other posts here!
Want to check out our other projects? Find them here!
Got an idea for a new app to improve our world? Say hi here!
Found this post helpful? Follow the author on LinkedIn!