Video is not playing in AVPlayer with - ios

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:

Related

Why can I play videos from my app bundle but not videos that were downloaded to the file system?

My objective is to read a video media I downloaded and stored to my iOS device file system. Unfortunately, the video player stalls with the following code:
#IBAction func playVideo(_ sender: UIButton) {
if let video = detailItem {
do {
let url = try FileManager.default.url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: false)
.appendingPathComponent(video.uuid)
debugPrint("url: \(url)")
// Create an AVPlayer, passing it the HTTP Live Streaming URL.
let player = AVPlayer(url: url)
// Create a new AVPlayerViewController and pass it a reference to the player.
let controller = AVPlayerViewController()
controller.player = player
// Modally present the player and call the player's play() method when complete.
present(controller, animated: true) {
player.play()
}
} catch {
print("Error: \(error)")
}
}
}
I assumed it was a video format problem and the codec of my video wasn't supported.
But, when I bundle the exact same video within the app, and switch to this code, everything works fine:
#IBAction func playVideo(_ sender: UIButton) {
let url = Bundle.main.url(forResource: "myvideo", withExtension: "mp4")!
// if let video = detailItem {
do {
// let url = try FileManager.default.url(for: .documentDirectory,
// in: .userDomainMask,
// appropriateFor: nil,
// create: false).appendingPathComponent(video.uuid)
debugPrint("url: \(url)")
// Create an AVPlayer, passing it the HTTP Live Streaming URL.
let player = AVPlayer(url: url)
// Create a new AVPlayerViewController and pass it a reference to the player.
let controller = AVPlayerViewController()
controller.player = player
// Modally present the player and call the player's play() method when complete.
present(controller, animated: true) {
player.play()
}
} catch {
print("Error: \(error)")
}
// }
}
I have no idea what I am missing here and could get some help. 🙏
EDIT: The code in charge of the download is here:
let downloadTask = URLSession.shared.downloadTask(with: video.downloadURL, completionHandler: { (tempPathURL, urlResponse, error) in
guard let tempPathURL = tempPathURL else {
return
}
do {
let documentsDirectoryURL = try FileManager.default.url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: false)
try FileManager.default.moveItem(at: tempPathURL, to: documentsDirectoryURL.appendingPathComponent(video.uuid))
} catch {
print("Error: \(error)")
}
})
downloadTask.resume()
You are using the wrong URL for playing downloaded video. Please check your code carefully and notice that you are using the documents directory URL for the player, instead of the actual video.
you should use fileURLWithPath to run video from app files, like this:
func PlayVideo() {
let docPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let player = AVPlayer(url: URL(fileURLWithPath: docPath).appendingPathComponent("IMG_3039.mp4"))
let controller = AVPlayerViewController()
controller.player = player
self.present(controller, animated: true) {
player.play()
}
}

Local notification custom sound from URL iOS Swift

I have successfully recorded and played the voice for the local notification sound and it also get played on calling that function.
But problem is when i give sound's link to the notification sound property, it do not work.
notification.sound = UNNotificationSound.init(named: "martian-gun copy.m4a")
Above code works perfectly. But when i gave it URL(in the form of string) it do not play the exact sound.
Code not working is follows:
let fm = FileManager.default
let docsurl = try! fm.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let myurl = docsurl.appendingPathComponent("sound.m4a")
notification.sound = UNNotificationSound.init(named: myurl)
myurl have same path at which voice play on playButton.
Finally question is how to set notification custom sound from the sound URL?
According to the document of UNNotificationSound, you need to place a copy of your audio file in the Library/Sounds folder of your app’s container directory.
let docsurl = try FileManager.default.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let myurl = docsurl.appendingPathComponent("sound.m4a")
let filename = myurl.lastPathComponent
let targetURL = try FileManager.default.soundsLibraryURL(for: filename)
// copy audio file to /Library/Sounds
if !FileManager.default.fileExists(atPath: targetURL.path) {
try FileManager.default.copyItem(at: sourceURL, to: targetURL)
}
let content = UNMutableNotificationContent()
content.sound = UNNotificationSound(named: UNNotificationSoundName(filename))
extension FileManager {
func soundsLibraryURL(for filename: String) throws -> URL {
let libraryURL = try url(for: .libraryDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let soundFolderURL = libraryURL.appendingPathComponent("Sounds", isDirectory: true)
if !fileExists(atPath: soundFolderURL.path) {
try createDirectory(at: soundFolderURL, withIntermediateDirectories: true)
}
return soundFolderURL.appendingPathComponent(filename, isDirectory: false)
}
}

AVPlayer is not playing audio from Document directory using Swift3

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)
}

Can't play video from documentsDirectory in iOS

I'm trying to play a video downloaded to the device's document directory. For some reason, it won't happen. All I get is this symbol:
Here's my code:
let documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let videoFileUrl = URL(fileUrlWithPath: documentPath)
let videoFilePath = videoFileUrl.appendingPathComponent("somVideo.mp4").path
if FileManager.default.fileExists(atPath: videFilePath){
let player = AVPlayer(url: URL(string: videoFilePath)!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
}
else {
print("File doesn't exist")
}
The file exists at the location - I have checked my documents directory for the simulator - and the else statement isn't fired. Nothing else is printed to the console.
Any help would be appreciated.
Here's the answer the OP edited into the question (and which was subsequently rolled back because answers should be answers). If OP posts a separate answer, I'll remove this one.
I managed to get it working with a little help from a colleague of mine. Here's the answer if anyone should be interested:
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
if let docDir : URL = urls.first {
let videoUrl = docDir.appendingPathComponent("\(objectId).mp4")
do {
let videoExists : Bool = try videoUrl.checkResourceIsReachable()
if videoExists {
let player = AVPlayer(url: videoUrl)
let playerController = AVPlayerViewController()
playerController.player = player
self.present(playerController, animated: true) {
playerController.player!.play()
}
}
else {
print("Video doesn't exist")
}
}
catch let error as NSError {
print(error)
}
}

AVPlayer & video from documents directory

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()
}

Resources