how to improve the performance of seek when using avplayer
I have found the solution.
If I use seekToTime
to do the scrubbing, it's pretty slow. What I should use is a method called stepByCount
from AVPlayerItem
.
UICollectionView & AVPlayer Performance
First I want to say it's a bit crazy to see several players in action at the same time: it's a heavy task of rendering anyway.
As far as I know, simply scaling/re-framing the video to smaller size doesn't make it less content to render: if you have a 100x100 picture to render and you render it in a frame of 10x10, it still consumes the same amount of memory as the original picture would consume; same thing goes for videos. So, try to make your video assets having similar resolution as the frame where you would present them.
The sound quality of slow playback using AVPlayer is not good enough even when using AVAudioTimePitchAlgorithmSpectral
I've been searching and trying to learn AudioKit and Audio Unit or even considering purchasing a third party time-stretch audio processing library to fix the quality issue of slow playback for the last 3 weeks.
Now finally I found a super easy solution.
AVPlayer can slow down audio with very good quality by setting AVPlayerItem.audioTimePitchAlgorithm
to AVAudioTimePitchAlgorithm.timeDomain
instead of AVAudioTimePitchAlgorithm.spectral
.
The documentation says:
timeDomain
is a modest quality pitch algorithm that is less computationally intensive. Suitable for voice.
This means spectral
is suitable for music. timeDomain
is suitable for voice.
That's why the voice files which my app uses was echoed.
And that's why Apple's Podcasts App's slowed down audio quality is very high.
It must also uses this time domain algorithm.
And that's why AudioKit, which seems to be developed for music use, plays voice audio with bad quality.
Smooth loading of videos in tableview
Thankfully, you're in luck. iOS is optimized for just these types of issues. Apple engineers have gone to great lengths to provide APIs to help you achieve buttery smooth scrolling and load your content at the same time.
Note: Solving this issue requires offloading tasks to different threads on the CPU. It can get complicated, and there's a lot to learn about it. I strongly recommend you read Apple's documentation.
First, know that the cellForRowAtIndexPath:
method should generally call your data source on the main thread. Meaning the call you have to DispatchQueue.main.async
is not appropriately used in this scenario.
Instead, what you'll need to do is offload your AVPlayer
caching to a separate, background thread and then come back into the main thread to update the cell's layer content. Additionally, you shouldn't be doing that in cellForRowAtIndexPath:
. You'll likely need to subclass a UITableViewCell
and write your own loading sequence within that - that way, you can quickly init
your custom cell, hand it back to cellForRowAtIndexPath:
(which can then continue along merrily), and keep loading things and updating from within the cell subclass.
To setup your AVPlayer in a background thread, do this:
DispatchQueue.global(qos: .background).async {
// Background thread
// Do your AVPlayer work here
// When you need to update the UI, switch back out to the main thread
DispatchQueue.main.async {
// Main thread
// Do your UI updates here
}
}
You may want to look at the quality of service value you pass in when you create your background thread. The userInitiated
QOS may be better for this specific case because the videos are being loaded as a result of a user-initiated action.
As for the actual caching of the videos. I am not too familiar with AVPlayer
or AVPlayerItem
, but from my understanding the more metadata (i.e. duration, tracks, etc.) you can give to AVPlayer
before trying to render the video in a layer, the faster it goes (see this related StackOverflow Question).
Additionally, you'll probably want to check out the newly introduced APIs in iOS 10 that all you to pre-fetch cells in a table view. If you take advantage of the pre-fetch optimizations, you could likely load everything you need for AVPlayer
in the background and well before the cells are ever requested for display in cellForRowAtIndexPath:
.
Anyhow, hope you can get started from there and solve the issue. Definitely take the time to read the documentation on AVKit
, GCD
, and UITableView
(specifically the new pre-fetching APIs).
Related Topics
How to Verify That I am Running on a Given Gcd Queue Without Using Dispatch_Get_Current_Queue()
Cfbundleversion Must Be Higher Than Previous Version
Facebook Login - iOS 9 - Without Safari
Proper Use of Loadview and Viewdidload with Uiviewcontroller Without Nibs/Xibs
How to Print Core Data Debug Values
How to Get Commoncrypto/Commoncrypto File From
Firebase .Indexon Dynamic Keys
Swift - Image Data from Ciimage Qr Code/How to Render Cifilter Output
How to Fill Uitableview with a Data from Dictionary. Swift
Simulator Slow-Motion Animations Are Now On
Convert Uiimage to Nsdata and Convert Back to Uiimage in Swift
How to Set the Full Width of Separator in Uitableview
Autolayout - Intrinsic Size of Uibutton Does Not Include Title Insets