I am trying to play an hls live stream from a url that looks like this: "http://ip.address:port/my%20video.m3u8". Whenever the url does not involve any spaces the video plays fine otherwise it does not play. There is no error logged from the player but the player itself is just a black screen. I enabled "Allow Arbitrary Loads" and still no dice. When I try loading the urls with spaces in safari the video will play. Here is my code to load and play the video:
DispatchQueue.main.async {
var player = AVPlayer(url: url!)
var playerLayer: AVPlayerLayer!
playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = .resize
self.videoView.layer.addSublayer(playerLayer)
playerLayer.frame = self.videoView.bounds
player.play()
}
What I also find odd is when I try sending the stream to a AVPlayerViewController the player pops up but does not play. Here is how I am sending it to the view controller:
DispatchQueue.main.async {
let player = AVPlayer(url: urlTwo)
let playerController = AVPlayerViewController()
playerController.player = player
present(playerController, animated: true) {
player.play()
}
}
Please check the m3u8 file may be the content in m3u8 have some directory issue. .ts segment and .key file was mentioned in m3u8 file. And when you pass m3u8 to avplayer it fetch the key and .ts file automatically and decrypt the .ts with the mentioned key. Just cross check you m3u8 for key and .ts file.
Also, .key and .ts files need to be in same folder along with m3u8 otherwise it will not fetch and player keep looking for the key and ts.
#EXTM3U
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-VERSION:4
#EXT-X-KEY:METHOD=AES-128,URI="title.key"
#EXTINF:10.0100,
#EXT-X-BYTERANGE:943584#0
title.ts
Something like this.
Note: Sometimes m3u8 and key file have additional encryption which you need to decrypt on run time. I suggest open it in text editor and see if you can see something like given structure above. If it has something unreadable then you need to decrypt it first on run time. If you are using local server and loading file from cache then save the m3u8 file after decryption with Encoding.utf8 and .key file with Encoding.macOSRoman. Otherwise it will not gonna work. Cheers.
Related
I am having trouble playing online mp3 files as AVPlayerItems which have previously failed to play due to data connection issues.
For example:
I try play online mp3 file "FILE_A" with poor data connection and the associated AVPlayerItem fails to play. The AVPlayerItem will then not load and my AVPlayer will stay paused (which is fine for now).
Let's say that after a period of time I gain better data connection and play a different online mp3 file "FILE_B" as an AVPlayerItem. The AVPlayer plays this AVPlayerItem with no issues.
I then try play the failed file "FILE_A" on good data connection. The AVPlayerItem for "FILE_A" will always refuse to play. I can even close/kill the app and try again and "FILE_A" will not play. The only work around is to do a fresh re-install of the app.
I have 3 questions:
Why does a failed AVPlayerItem never become playable, is there a AVPlayerItem cache in the AVPlayer that always tries to play the failed item?
Is there a way to refresh an unplayable AVPlayerItem to make it play again?
What is the best way to deinitialize an AVPLayer? Currently I am using self.player = nil to deinitialize the player in the deint of my view controller or when a user logs out of their account in the app.
This is how I set up the AVPlayer:
self.player = AVPlayer()
self.player?.actionAtItemEnd = .pause
self.player?.automaticallyWaitsToMinimizeStalling = false
self.player?.addObserver(self, forKeyPath: "status", options: .new, context: nil)
This is how I set up an AVPlayerItem and set it as the AVPlayer's currentItem:
let url = URL(string: onlineAudioFileUrl)
currentPlayerItem = AVPlayerItem(url: url)
player?.replaceCurrentItem(with: currentPlayerItem)
The onlineAudioFileUrl above is String url representing the url of an online mp3 file stored on a server. It has the form:
https://ourserver.com/audio_file_name.mp3?Expires=NUMERIC_EXPIRE_TIME&Key-Pair-Id=KEY_PAIR_ID_STRING&Signature=VERY_LONG_SIGNATURE_STRING
In my project I use a Google Drive API. I get a list of the user's files and can save them to the device memory.
I also want to be able to play audio files directly from Google Drive, but I just can't do it. The AVPlayer doesn't want to play the audio file using the URL link, which I transfer to him. But if I paste this link into any browser, then the track is played.
Has anyone encountered this and knows how to fix the problem? I would be grateful for any help.
My code looks like this (it's a simplified version):
import AVKit
class MyVC: UIViewController {
...
var player: AVPlayer!
...
private func playTrack() {
let url = URL(string: "https://drive.google.com/uc?export=open&id=XXXXX" //where XXXXX is an item id
let playerItem: AVPlayerItem = AVPlayerItem(url: url!)
player = AVPlayer(playerItem: playerItem)
player!.play()
}
}
For example URL link which I transfer to the AVPlayer looks like this:
https://drive.google.com/uc?export=open&id=1JzuAhQ-7R01wLhtD8zEN_sC5nvFlt7wU
But if I paste it into the browser it automatically changes and looks like this:
https://doc-0g-1s-docs.googleusercontent.com/docs/securesc/anu2dlv0j1ugsoh1pb6b8qpkkt7k1j6k/hp3dnmru336i1cpkk4f5p4bstc83b30f/1602827400000/02426681720429398713/02426681720429398713/1JzuAhQ-7R01wLhtD8zEN_sC5nvFlt7wU?e=open&authuser=0&nonce=4dd9dhoo6he8g&user=02426681720429398713&hash=o87f0k3t4iv19ugae899urmcjd14ogiq
Maybe it's important.
You files should be shared by a direct link in Google Drive to play it so you can make it manually or using API e.g.:
And then use direct links in format: https://drive.google.com/uc?export=open&id=XXXXX.
I am trying to play a video from my iOS app when tapping a button, but I was wondering how and where I can host my video (for free) so that I can play the video in an AVPlayer using the URL. I tried hosting the video on youtube, and setting the AVPlayer URL to the youtube video URL, but the player loads forever. I included my code, it's functional, I just need to know where I can upload my video to get a proper URL.
#IBAction func didTapPlayButton(_ sender: UIButton) {
guard let url = URL(string: "") else {
return
}
// 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()
}
}
You need to host and serve your video as a binary file.
You can use an object storage (e.g. Firebase Storage or AWS S3) or serve the file through a web API.
Just set the correct Content-Type (e.g. "video/mp4" to help the player recognise the binary file type)
You can then initiate your AVPlayer with the URL of the video.
Please note that Firebase Storage has a very generous free tier, it might be all you need.
For example:
You can take a look at this video file:
https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_480_1_5MG.mp4
This file is hosted as a binary and the Content-Type is set to video/mp4.
Try to initiate your AVPlayer with the above URL and see that it works.
I'm trying to play an m4a file on an iOS device programatically. The file is downloaded from a server and stored. When the user presses a button, it is played. The file, when copied from the device to OSX does play fine. I am using the code
var player:AVAudioPlayer = AVAudioPlayer()
func playAudio(sender: UIButton!) {
let audioPath = FileUtils.getPath(audioPaths[sender.tag])
print("PATH " + audioPath)//The printed path IS DEFINETLY correct
do{
player = try! AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: audioPath))
player.prepareToPlay()
player.play()
}
}
The path is correct so I'm not sure why it won't work. Could it be the format (even though it plays on OSX)?
An example file: https://www.dropbox.com/s/csewwg6n9vzan5z/131015-08%3A13%3A30.m4a?dl=0
That file won't play on iOS because it's encoded in AMR NarrowBand, which is no longer supported.
I would try re-encoding the m4a files as AAC, or switch to mp3.
It's likely just a feature of the way this m4a file is compressed. The simple fact is that not every m4a file, even if it is a perfectly valid file, will play on your device. (For example, perhaps this file is very compressed.) And to make things more complicated, it differs from device to device! And to make things even more complicated, the file might play in the Music app but not in an AVAudioPlayer!!
To test this theory, recode the file as a more middle-of-the-road m4a and see if that plays.
I have used an AVPlayer object to fetch the .m3u8 file from a remote server and play the video. My application has to stream live data, wherein the .m3u8 file would be updated (either new .ts files are added to the existing contents or the old ones are removed prior adding new .ts files) regularly. How do I make my AVPlayer respond to changing contents on server data. Precisely how to re-assign the url to AVPlayer. Below is the concise code. Please advise.
-(void) playVideo{
AVPlayerItem *contentPlayerItem = [[AVPlayerItem alloc]initWithURL:[NSURL URLWithString:contentURL]]; // contentURL contains the path of live streaming data.
self.contentPlayer = [AVPlayer playerWithPlayerItem:contentPlayerItem]; //content player is an object of type AVPlayer
AVPlayerLayer *avPlayerLayer =
[AVPlayerLayer playerLayerWithPlayer:self.contentPlayer];
//Then I add the AVPlayerLayer object onto my current view after setting its frame.
}
The question is when and how do I refresh the url, assuming the video is being played currently?