How to cache AVPlayer video? - ios

I have AVPlayers embedded into UITableViewCells and need a way to cache the video that's loaded so that when I refresh the table view, it doesn't have to load the videos again. The code I'm using at the moment to load videos is as follows:
let videoString = "http://www.someurl.com"
let videoURL = NSURL(string: videoString)
videoPlayer = AVPlayer(URL: videoURL!)
videoPlayer!.actionAtItemEnd = AVPlayerActionAtItemEnd.None
videoView.playerLayer.player = videoPlayer
I cache images by storing the returned image from a server in a dictionary with it's ID as the key. I'm looking for a similar way for videos, any help would be appreciated.

Ideally their is no in-built support to cache the vidoes,however depending upon the size of the video you may try to download it in background, once the video start playing.
However do note that this process will increase the cache size of the app, and may consume lot of space depending upon the size of the video, so you may cache few videos that the user has watched few minutes back, or you may restrict it to the 5-10 latest vidoes.

Related

Swift access to a file that is stored in another folder

I am creating a app, where you can record videos or images. You can record videos or images on your own or you can pick it from the UIImagePicker. The videos/images are listed in a collection view.
When you tab on a row in the collection view it shows the image or the video.
One thing I don't understand is, if I record a video to safe it, it shows up in the collection view, but when I choose the video that I recorded before, I only see a grey background and not the actually video.
If I choose a video from the gallery it shows up and play.
This is how I display the video
player = AVPlayer(url: arrayOfVideoUrls[i]!)
print(arrayOfVideoUrls[i]!)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.frame = view.frame
view.layer.addSublayer(playerLayer!)
player?.play()
My guess is, that I can't open the video, because it is saved in another folder.
This is the folder of my self recorded Video:
file:///private/var/mobile/Containers/Data/Application/E0EBF7F9-713C-451B-B764-D2056ECC6E48/tmp/7834C1AF-1417-4389-B455-92DA52DFF93F.mov
This is the folder of the video from the gallery:
file:///private/var/mobile/Containers/Data/PluginKitPlugin/1A977F99-6C5C-40F7-933D-E325D8E967E4/tmp/trim.31B4A909-E8FA-4CBE-B64F-30646A6366B3.MOV
You need to give the path whenever you save your recorded video and after saving you need to check that path whether its containing file or not.
And Please make sure, you give different name to your recording whenever you record a new video.And to play that video append the name of video with the path.

I want to design a screen which will show different number of videos on same screen based on certain condition

This is an iOS problem.
I want to design a screen which will show a video on full screen. After some time based on some backend condition if another video is available I have to show that by splitting the screen into two vertical halves. After some time if one more video is available I have to again split the screen and show the third video horizontally on the bottom of the screen.
I am new to iOS and I am not able to manage the screen split on runtime based on backend condition. please help me in this regard.
Using AVPlayer it possible to play multiple videos in a view. You can use Apple's AVPlayer.
An AVPlayer is a controller object used to manage the playback and
timing of a media asset. You can use an AVPlayer to play local and
remote file-based media, such as QuickTime movies and MP3 audio files,
as well as audiovisual media served using HTTP Live Streaming.

Play video in UITableViewCell or UICollectionViewCell iOS

There is so much stuff in Stackoverflow about playing videos in cell, that every person may feel confused, especially that most of question are not solved and it looks like that every developer gives up.
So I wanted to create new question where there will be up-to-date answers.
Objective:
Play video in UITableViewCell or UICollectionViewCell when user taps cell (yes, this is simplified version, this is not about autplay).
Solution:
I think everyone agrees that we should use AVPlayer instead of deprecated MPMoviePlayerController.
Cell should have layer where AVPlayer can be assigned, so in my code while creating cell I added this code:
VideoCell.swift
let layer = AVPlayerLayer()
layer.backgroundColor = UIColor.clear.cgColor
layer.videoGravity = AVLayerVideoGravityResizeAspectFill
Now when cell is tapped I'm using this code:
ViewController.swift
cell.playerLayer.player = player
player.replaceCurrentItem(with: AVPlayerItem(asset: asset))
player.play()
Where player is global instance of AVPlayer and asset is AVAsset initialized with video URL.
It would work fine, but AVPlayer needs time to download info and buffer some part of video, and what user gets is delay. So we can think about one solution, which is downloading video first and playing it locally when users taps in cell.
Question:
Is it really good approach to downloading every video in data source and then playing it locally? When should we remove it from device? Facebook and Instagram looks like they download only part of the video first, is there any who can share own experience?
Objective-C code will be appreciated too.

AVPlayer sometimes doesn't load a video

I have a one button and AVPlayer. After button click I record a video using DBAttachmentPickerController and I want to load it to the AVPlayer.
In function below I try to load it:
func refresh(attachmentInfo: AttachmentInfo) {
self.videoLayer.player = nil
if let url = attachmentInfo.url {
self.player = AVPlayer(url: url) // line A
self.videoLayer.player = self.player // line B
}
}
In 6/10 cases it works fine, but sometimes the video doesn't load to AVPlayer.
When I set breakpoints in line A and B it works always.
Any ideas?
I also hit this exact issue as yours. In my case the AVPlayer and AVPlayerLayer were inside tableview cells which made the problem worse. However, I was using an API which returned the actual video URL, and an Image URL which consisted of the video's first frame's image. In the tableview cell logic, I first attempt to load the video into AVPlayer and then check if the AVPlayer has any .video assets, if it didn't then I simply load the Image from the other URL into the UIView (using a UIImageView of course) with a "Play" button image in the center of the Image. When the user taps the play button the selector function should try to load the AVPlayer again with the video URL. If the video loads and AVPlayer has assets then play() else simply return (and possibly alert the user that the video can't be loaded).
If you do not have the image of the first frame of the video, you can simply use a placeholder image and a button.
The way to check if the player has a video or not-
if player.currentItem?.asset.tracks(withMediaType: .video).count == 0{
print("Oops! no video here")
//load an image, and add a button here
}else{
//do whatever needs to be done if video is available
}
Unfortunately, there isn't much else that can be done here unless you have some solid networking code where in you can download the video in a utility thread and store it in cache, but then again you have to be cognizant about the user's data usage, spawning too many download threads etc.
For image caching in the UITableView cell, I used SDWebImage library from Github so that I can be (somewhat) assured that my image (for the video) atleast would be cached in case of bad/slow network, or network interruptions.

Set cache size for AVPlayer

Is it possible to simply set the size of the cache for an AVPlayer? I've an app where the user will often go back and forth in the video and I'd like to make sure that there's enough caching happening. I've found that code that shows how to manually handle the network requests using an AVAssetResourceLoaderDelegate and that's pretty involved. Ideally I'm looking for something like
let player = AVPlayer(url: url)
player.urlSession = myConfiguredURLSession

Resources