I've been working on a small project that involves downloading a video file from a web server, copying said file to the documents directory and then playing it via AVPlayer.
Downloading the file to the documents directory hasn't been an issue. I'm able to download the file and save it without issue. However, when it comes to loading the file into AVPlayer, and in doing that I'm playing it in an instance of AVPlayerViewController, the vide controller pops up as it should, but video doesn't load.
I realize that when testing in the simulator the documents directory changes each time you rebuild the project. Which is why I check to see if the file is present before I play, and though I know the file is present, it still refuses to play.
Here is what my player code looks like:
let fileName = downloadURL.characters.split("/").map(String.init).last as String!
let fileNameHD = downloadURLHD.characters.split("/").map(String.init).last as String!
let downloadFilePath = getDocumentsDirectory() + "/" + "\(fileNameHD)"
let checkValidation = NSFileManager.defaultManager()
if checkValidation.fileExistsAtPath(downloadFilePath){
print("video found")
}
let videoFile = NSURL(string:downloadFilePath)
let player = AVPlayer(URL: videoFile!)
let playerController = AVPlayerViewController()
playerController.player = player
playerController.view.frame = self.view.frame
player.play()
self.presentViewController(playerController, animated: true) {
playerController.player!.play()
}
Every time when we rebuild the application Our Document Directory Path change.
So you can't play the video from the old document directory path. So instead of that you have to save the last path component of your URL. Like your document directory url look like this after downloaded the video on this path:-
let videoURL = "/var/mobile/Containers/Data/Application/1F6CDF42-3796-4153-B1E8-50D09D7F5894/Documents/2019_02_20_16_52_47-video.mp4"
var videoPath = ""
if let url = videoURL {
videoPath = url.lastPathComponent
}
print(videoPath)
// It will print the last path of your video url: - "2019_02_20_16_52_47-video.mp4"
Now save this path either in the Core Database or Sqlite or User Defaults where ever you want. Then if you want to play the video again. So you have to get this path from where you save it.
Note:- In Below function you have to pass the last path component of your video. How to call this function.
func playVideo() {
self.startVideoFrom(videoPath:"2019_02_20_16_52_47-video.mp4")
}
// Play Video from path
func startVideoFrom(videoPath: String) {
let outputMineURL = self.createNewPath(lastPath: videoPath)
let player = AVPlayer(url: outputMineURL)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
}
/// Generate the new document directory path everytime when you rebuild the app and you have to append the last component of your URL.
func createNewPath(lastPath: String) -> URL {
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let destination = URL(fileURLWithPath: String(format: "%#/%#", documentsDirectory,lastPath))
return destination
}
For more reference, you can see this question:- https://stackoverflow.com/q/47864143/5665836
Try AVPlayer instead of AVPlayerViewController like,
let videoURL = NSURL(string: "your url string")
let player = AVPlayer(URL: videoURL!)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.bounds
self.view.layer.addSublayer(playerLayer)
player.play()
And import AVKit, import AVFoundation.
OR With viewController like this,
let player = AVPlayer(URL: url)
let playerController = AVPlayerViewController()
playerController.player = player
self.addChildViewController(playerController)
self.view.addSubview(playerController.view)
playerController.view.frame = self.view.frame
player.play()
func listVideos() -> [URL] {
let fileManager = FileManager.default
let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
let files = try? fileManager.contentsOfDirectory(
at: documentDirectory,
includingPropertiesForKeys: nil,
options: [.skipsSubdirectoryDescendants, .skipsHiddenFiles]
).filter {
[".mp4", ".mkv"].contains($0.pathExtension.lowercased())
}
return files ?? []
}
And Then Play Video Like this I am only playing first URL
let videosURLs = self.listVideos()
let player = AVPlayer(url: videosURLs[0])
let playerViewController = AVPlayerViewController()
playerViewController.player = player
present(playerViewController, animated: true) { () -> Void in
player.play()
}
Related
I am using AVPlayer to play a video with the localPath URL but it is not playing on AVPlayer.
And i am getting localPath with this code:
var selectedAssets = [TLPHAsset]()
for abcd in self.selectedAssets {
let asset = abcd
if asset.type == .video {
//------------- Video Path --------------------//
let fm = FileManager.default
let docsurl = try! fm.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let url = docsurl.appendingPathComponent(stringUrl!)
}
}
here is the path:-
file:///var/mobile/Containers/Data/Application/915BA33E-5DB9-42C4-B5CD-3898D81FBDC5/Documents/77666c29-75a3-4d89-aecf-15d0f47fbe83.mp4
let video = dbImageDataModel[indexPath.row].fileUrl
print(video)
playerView = AVPlayer(url: URL(fileURLWithPath: video))
playerViewController.player = playerView
self.present(playerViewController, animated: true, completion: {
self.playerViewController.player!.play()
})
You are using the wrong API.
absoluteString returns the URL string including the file:// scheme. To create a new URL you have to use URL(string rather than URL(fileURLWithPath.
To clarify
absoluteString returns file:///var/mobile/Containers/Data/Application.... To create an URL use URL(string:
path returns /var/mobile/Containers/Data/Application.... To create an URL use URL(fileURLWithPath:
I am trying to play a video form my Server but when I try to do so I get a Crossed mark on pay button.
All other files like .ppt,.keynote etc work fine when I use them with my Server url and use a WKWebview to show them but .mp4 files are not working.
I tried 2 methods.
1) Playing directly using WKWebview.
2) Download the file and saving it in a local path and then using AVPlayer to play the file.
In both cases I get same crossed mark on the play button.
func playVideo(url:String){
var newUrl:String = url
if !( url.hasPrefix("http") || url.hasPrefix("https") ){
let host = kGetHostName()
newUrl = host + newUrl
}
do
{
let videoData = NSData(contentsOf: URL(string: newUrl)!)
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
let path = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("myMove.mp4")
if videoData == nil{
print("No data in this")
return
}
videoData?.write(toFile: path.absoluteString, atomically: true)
let playeritem = AVPlayerItem(url: path)
let player = AVPlayer(playerItem: playeritem)
let controller = AVPlayerViewController()
controller.player = player
self.present(controller, animated: true) {
player.play()
}
} catch {
print(error)
}
And when trying with WKWebview
func loadWebView(url:String){
var newUrl:String = url
if !( url.hasPrefix("http") || url.hasPrefix("https") ){
let host = kGetHostName()
newUrl = host + newUrl
}
self.webView.load(URLRequest(url: URL(string: newUrl)!))
}
Both cases fail and get this. Is there any way I can play the video without changing my plist settings as I want to download and play ?
1.Screen Shot
2.Screen Shot
I am creating video player application in ios,if i store mp4 file in bundle resource or if i stream url it is working fine but if i store a file in document direcory and i am trying to play with avplayer it is not playing should i handle differently with offline file in document directory
code:
let fileManager = FileManager()
let destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appendingFormat("/myvideo.mp4"))
self.playVideo(filePath: destinationURLForFile.path)
func playVideo(filePath:String)
{
var playerItem = AVPlayerItem.init(url:URL.init(string: filePath)!)
var player = AVPlayer(playerItem: playerItem)
var playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.frame
self.view.layer.addSublayer(playerLayer)
player.play()
}
Try this, written in Swift 3.0,
let fm = FileManager.default
let docsurl = try! fm.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let path = docsurl.appendingPathComponent("myvideo.mp4")
playVideo(filePath: path)
func playVideo(filePath:String)
{
var playerItem = AVPlayerItem(url: URL(fileURLWithPath: filePath)
var player = AVPlayer(playerItem: playerItem)
var playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.frame
self.view.layer.addSublayer(playerLayer)
player.play()
}
swift 3/4 100%%%%%%% workable
Recorder open video camera
#IBAction func RecordAction(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera){
print("CameraAvailable")
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .camera
imagePicker.mediaTypes = [kUTTypeMovie as String]
imagePicker.allowsEditing = false
imagePicker.showsCameraControls = true
self.present(imagePicker,animated: true, completion: nil)
}
else{
print("CameraNotAvailable")
}
}
save to document directory
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// recover video URL
let url = info[UIImagePickerControllerMediaURL] as? URL
// check if video is compatible with album
let compatible: Bool = UIVideoAtPathIsCompatibleWithSavedPhotosAlbum((url?.path)!)
// save
if compatible {
UISaveVideoAtPathToSavedPhotosAlbum((url?.path)!, self, nil, nil)
print("saved!!!! \(String(describing: url?.path))")
}
videopath = url //save url to send next function play video
dismiss(animated: true, completion: nil)
}
// error
func video(_ videoPath: String, didFinishSavingWithError error: Error?, contextInfo: UnsafeMutableRawPointer) {
}
play video from Document directory
#IBAction func playvideo(_ sender: Any)
{
let player = AVPlayer(url: videopath!) // video path coming from above function
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
}
I tried several methods including the above, but found that the documents path changes for the app each time it is launched, which changes the first part of the URL.
This helped me to get the current location of my file:
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let playerItem = AVPlayerItem(url: URL(fileURLWithPath: documentsPath.appendingFormat("/\(clipId).mp4")))
player = AVPlayer(playerItem: playerItem)
I am using a library called Gallery to select one video from Photos. Whenever a video is selected, I would like to play that selected video (silently) somewhere in my UIViewController.
The for this question relevant part of the plugin is the function func galleryController(_ controller: GalleryController, didSelectVideo video: Video) which is called when a video is selected. I initially tried using the function which you'll find under this link (presented by the library) to test if it would work but nothing happened: No controller was presented. After having done some research I believed I needed to transfer the temporary file (found under tempPath) to the documents directory - which doesn't seem to work either. You'll find the code I am currently using below.
If I print tempPath (the temporary path) and videoFileUrl (the URL the file is supposed to be transferred to) I get the following URLs respectively:
tempPath:
Optional(file:///private/var/mobile/Containers/Data/Application/D9B0DCB6-8F99-4284-9BFF-52A284C6F1AE/tmp/F3DC43D0-491A-4548-9960-D01686B54ACB.mp4)
videoFileUrl:
file:///var/mobile/Containers/Data/Application/D9B0DCB6-8F99-4284-9BFF-52A284C6F1AE/Documents/F3DC43D0-491A-4548-9960-D01686B54ACB.mp4
Code
internal var gallery: GalleryController?
internal let editor: VideoEditing = VideoEditor()
func galleryController(_ controller: GalleryController, didSelectVideo video: Video) {
controller.dismiss(animated: true, completion: nil)
editor.edit(video: video) { (editedVideo: Video?, tempPath: URL?) in
DispatchQueue.main.async {
guard let temporaryPath = tempPath else { return }
let fileName = temporaryPath.lastPathComponent
let fileManager = FileManager.default
let videoFileUrl = try! fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(fileName)
if fileManager.fileExists(atPath: videoFileUrl.path) == false {
try! fileManager.copyItem(at: temporaryPath, to: videoFileUrl)
}
let player = AVPlayer(url: videoFileUrl)
//print(tempPath)
//print(videoFileUrl)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.frame
self.view.layer.addSublayer(playerLayer)
}
}
gallery = nil
}
I have an audio files, stored in Document directory. I want play it using AVPlayer but it is not playing. I am using Swift3.
var myurl : NSURL!
var audioPlayer = AVPlayer()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Getting sound from Document directory
let fileManager = FileManager.default
let docsurl = try! fileManager.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
myurl = docsurl.appendingPathComponent("/\(songName!)")
playSound(url: myurl! as NSURL)
}
// Playing Sound
func playSound(url:NSURL){
let asset = AVURLAsset(url: url as URL, options: nil)
let playerItem = AVPlayerItem(asset: asset)
self.audioPlayer.replaceCurrentItem(with: playerItem)
let durationInSeconds = CMTimeGetSeconds(asset.duration)
self.getSeconds = Int(durationInSeconds)
self.audioPlayer.play()
}
I am getting url from document directory, but it is not playing. Don't know why?
Thanks in Advance.
Put this code in AppDelegate.swift file in application:didFinishLaunchingWithOptions: method and see if you can hear the audio:
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
}catch {
print(error)
}