Unable to play video using AVPlayer with Swift - swift

When I click to play video, it shows like this. Wondering why. No error is shown. I did import AVKit and AVFoundation. Also, I tested in my device and simulator. Still does not work. Any suggestions? Thanks a lot.
**Print log**
//<PFFile: 0x79d472f0>
//https://files.parsetfss.com/d9cdffff-4a1f-4bd9-b6ee-e60c07d49236/tfss-7e1636b9-5701-4737-9fa6-10609aec89e8-adsVido
//<AVPlayer: 0x786f39b0>
// Click cell to play video.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
if adsVideoArray[indexPath.row] != nil {
let theVideo:PFFile = adsVideoArray[indexPath.row]!
print(theVideo)
let url:NSURL = NSURL(string: theVideo.url!)!
theVideo.getDataInBackgroundWithBlock({ (data:NSData?, error: NSError?) -> Void in
if error == nil {
let player = AVPlayer(URL: url)
print(url)
print(player)
let playerController = AVPlayerViewController()
playerController.player = player
self.presentViewController(playerController, animated: true) {
player.play()
}
}
})
}
}
// load data from parse
func loadAdsFromParse() {
adsVideoArray.removeAll(keepCapacity: false)
let query = PFQuery(className: "user_ads")
query.findObjectsInBackgroundWithBlock({ (objects: [PFObject]?, error: NSError?) -> Void in
for object in objects! {
self.adsVideoArray.append(object.objectForKey("video") as? PFFile)
}
dispatch_async(dispatch_get_main_queue()) {
self.adsCollectionView.reloadData()
}
})
}
// the way to save video
self.tempVideo = info[UIImagePickerControllerMediaURL] as! NSURL!
let videoData = NSData(contentsOfFile:self.tempVideo.relativePath!)
let videoFile:PFFile = PFFile(name:"adsVido", data:videoData!)!
detailsObj["video"] = videoFile
detailsObj.saveInBackgroundWithBlock{ ... }
// I tried to play the video before upload it to Parse. It works.
func playImageTapped(pressed: UIGestureRecognizer) {
let player = AVPlayer(URL: tempVideo)
let playerController = AVPlayerViewController()
playerController.player = player
self.presentViewController(playerController, animated: true) {
player.play()
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let mediaType = info[UIImagePickerControllerMediaType] as! NSString
self.tempVideo = videoAdded

Did you look and read the documentation on this...
https://parse.com/docs/osx/api/Classes/PFFile.html
Are you sure your saving your data as a movie and not perhaps as an image? a wild guess?
I seem to recall a new article saying parse.com is being shutdown, so maybe it not a good idea to use it anyway...
http://blog.parse.com/announcements/moving-on/

Related

Swift: Parse does not load a video from URL

I am trying to stream a video from backend to my device.I have a video url from backend but screen displays nothing. However, youtube url it works. Can anyone guide me why this video is not playing and how can it be played? I am using pod 'YouTubePlayer' to play the video.
let cell: VideoTableViewCell = tableView.dequeueReusableCell(withIdentifier: "VideoTableViewCell") as! VideoTableViewCell
var query = PFQuery(className:"Videos")
query.getObjectInBackground(withId: "83kli72i62") { (parseObject, error) -> Void in
let videoFile = parseObject!["Question"] as! PFFileObject
self.videoUrl = videoFile.url
let url = NSURL(string: self.videoUrl! )
cell.playerView.loadVideoURL(url as! URL)
}
i have an app that is pulling videos from firebase and playing them with the avplayer, check out my code below and see how it works
class IsoLateralLowRowViewController: UIViewController {
#IBOutlet weak var playv: UIButton!
let avPlayerViewController = AVPlayerViewController()
var avPlayer:AVPlayer?
override func viewDidLoad() {
super.viewDidLoad()
self.view.addBackground()
let movieUrl:NSURL? = NSURL(string: "https://firebasestorage.googleapis.com/v0/b/messenger-test-d225b.appspot.com/o/test%2FTestVideo.mov?alt=media&token=bd4ccba3-b446-43bc-809e-b1152aa3c2ff")
if let url = movieUrl {
self.avPlayer = AVPlayer(url: url as URL)
self.avPlayerViewController.player = self.avPlayer
}
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: avPlayerViewController.player?.currentItem)
self.present(self.avPlayerViewController, animated: true) { () -> Void in
self.avPlayerViewController.player?.play() // Do any additional setup after loading the view.
}
}
#objc func playerDidFinishPlaying(note: NSNotification) {
self.avPlayerViewController.dismiss(animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}

Post Video to Facebook with swift SDK

I have been trying to figure this out all day and yesterday night, but no luck. I can confirm that the LinkShareContent works but when I try to share a video file. It gives me an error code "reserved" but nothing else.
This is the code for the link
var content = LinkShareContent(url: URL(string: "https://google.com")!)
showShareDialog(content)
and this is the code for the video that does not work at all.
let video = Video(url: url)
var content = VideoShareContent(video: video, previewPhoto: Photo(image: inProgressItem.firstImage, userGenerated: true))
showShareDialog(content)
This will show the share Sheet on the controller
Func showShareDialog<C: ContentProtocol>(_ content: C, mode: ShareDialogMode = .shareSheet) {
let dialog = ShareDialog(content: content)
dialog.presentingViewController = self
dialog.mode = mode
do{
try dialog.show()
}
catch (let error){
print(error)
}
}
I have confirmed that the video is on the local path and I'm testing the app on iPhone 8 11.1.2
Had exactly the same issue. It was working for LinkShareContent but didn't work for VideoShareContent.
The solution:
Make sure you are getting the right URL for the video. The right one is the URL for key "UIImagePickerControllerReferenceURL" from info dictionary that comes from UIImagePickerController delegate method.
Working Code:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
picker.dismiss(animated: true)
if let videoURL = info["UIImagePickerControllerReferenceURL"] as? URL {
let video = Video(url: videoURL)
let content = VideoShareContent(video: video)
let dialog = ShareDialog(content: content)
dialog.failsOnInvalidData = true
dialog.mode = .native
dialog.presentingViewController = self
do {
try dialog.show()
} catch {
print(error)
}
}
}
Extra info: initially I did not use this key "UIImagePickerControllerReferenceURL" cuz it's deprecated. Apple advises using UIImagePickerControllerPHAsset instead. But the URL from there also returns reserved error. Another try was to use key "UIImagePickerControllerMediaURL", but it also didn't succeed.
I use PHPickerViewController instead of UIPickerController.
private lazy var videoPickerController: PHPickerViewController = {
let photoLibrary = PHPhotoLibrary.shared()
var configuration = PHPickerConfiguration(photoLibrary: photoLibrary)
configuration.selectionLimit = 1
configuration.filter = .any(of: [.videos])
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
return picker
}()
Then using PHAsset for initialisation ShareVideo(videoAsset:).
private func facebookShare(content: Content) {
guard let schemaUrl = URL(string: "fb://") else {
return
}
if UIApplication.shared.canOpenURL(schemaUrl) {
let video = ShareVideo(videoAsset: content)
let content = ShareVideoContent()
content.video = video
let dialog = ShareDialog(
viewController: self,
content: content,
delegate: self
)
do {
try dialog.validate()
} catch let error as NSError {
presentAlert(message: (error.userInfo[ErrorDeveloperMessageKey] as? String) ?? error.localizedDescription)
} catch {
presentAlert(message: error.localizedDescription)
}
if dialog.canShow {
dialog.show()
}
} else {
presentAlert(message: "FB app not installed")
}
}
And PHPickerViewControllerDelegate looks something like this (I always select only 1 asset that's why I use fetchResult.firstObject)
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
let identifiers = results.compactMap(\.assetIdentifier)
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: identifiers, options: nil)
guard let videoAsset = fetchResult.firstObject else { return }
}
This solution works for iOS 14 and higher and if on your device Facebook app installed.
Also before upload video I login via FB.

AVPlayer with downloaded content doesn't work but streaming content does

I am trying to (1) download a piece of audio from a link, (2) add that newly-downloaded audio to an AVPlayer and (3) play it. Something is going wrong at step (3) and I'm looking for any guidance. Here's the code, including my alamofire and download functions, as I fear something may be going wrong at that stage.
import AVFoundation
class SettingAlarmViewController: UIViewController {
var player:AVPlayer!
override func viewDidLoad() {
super.viewDidLoad()
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
}
catch {
// report for an error
}
}
func getLatestPodcastURL(completion: #escaping (URL) -> ()) {
let RSSUrl: String = "https://www.npr.org/rss/podcast.php?id=510318"
Alamofire.request(RSSUrl).responseRSS() {response in
if let podcastURL: String = response.result.value?.items[0].enclosure!
{
let audioURL = URL(string: podcastURL)
completion(audioURL!)
}
else {
//error handling
}
}
}
func downloadSongAsynch(audioUrl: URL, completion: #escaping (URL) -> ()) {
let fileManager = FileManager.default
let documentsDirectoryURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("podcasts/")
do {
try fileManager.createDirectory(atPath: documentsDirectoryURL.path,
withIntermediateDirectories: true, attributes: nil)
} catch {
//error handling
}
let destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)
URLSession.shared.downloadTask(with: audioUrl, completionHandler: { (location, response, error) -> Void in
guard let location = location, error == nil else { return }
do {
try FileManager.default.moveItem(at: location, to: destinationUrl)
} catch {
//error handling
}
}).resume()
completion(destinationUrl)
}
#IBAction func SetUpBotton(_ sender: Any) {
getLatestPodcastURL() {response in
//Uses an asynchronous call to Alamofire to get the podcast URL
self.downloadPodcastAsynch(audioUrl: response){response2 in
self.player = AVPlayer(url: response2)
print(self.player.currentItem)
}
#IBAction func PlayButton(_ sender: Any) {
player.play()
print(player.currentItem)
}
The log consistently shows my current item: >
But nothing plays. I have checked that the audio is working by trying to use the URL to stream this content. That works fine. I am getting the following:
BoringSSL errors "[BoringSSL] Function boringssl_session_errorlog: line 2871 [boringssl_session_read] SSL_ERROR_ZERO_RETURN(6): operation failed because the connection was cleanly shut down with a close_notify alert
but from what I've read, this is just a bug in the latest update and shouldn't be impacting the download. Any thoughts on this?

Save Firebase Storage Video and Play with AVPlayerViewController

Building an app that allows users to upload media to Firebase Storage. Upload seems to be working fine, however I can't get video downloads to play.
I saved a file to the app to test the AVPlayer and it works perfect.
func handleGesture() {
print("handle gesture")
if detailMediaType == "Video"{
performSegueWithIdentifier("toVideoView", sender: self)
print("video segue called")
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "toVideoView"){
let path = NSBundle.mainBundle().pathForResource("Apartment Ceiling Collapse- Queens, NY", ofType: "mp4")
var movieUrl = NSURL(fileURLWithPath: path!)
let filename = getDocumentsDirectory().stringByAppendingPathComponent("movie")
let videoData = NSData(contentsOfURL: movieUrl)
videoData!.writeToFile(filename, atomically: true)
self.avPlayer = AVPlayer(URL: movieUrl)
self.avPlayerViewController.player = self.avPlayer
self.presentViewController(self.avPlayerViewController, animated: false) { () -> Void in self.avPlayerViewController.player?.play()
}
}
}
Edit: I am now trying to download using downloadURLWithCompletion
FIRStorage.storage().referenceForURL(detailFullsizeUrl).downloadURLWithCompletion { (URL, error) -> Void in
if (error != nil)
{
print(error!)
}
else
{
self.firebaseUrl = URL!
print("firebaseUrl")
print(self.firebaseUrl)
self.avPlayer = AVPlayer(URL: self.firebaseUrl)
self.avPlayerViewController.player = self.avPlayer
}
}
I get an AVPlayerViewController with a black screen. When I access the "firebaseUrl" from the web, it downloads a text file that looks like gibberish.
Solution:
Changed up my approach. No longer saving to device. Instead I grabbed the "downloadUrl" metadata from the Firebase Storage object and pass it directly to the AVPlayerViewController.
let avPlayerViewController = AVPlayerViewController()
var avPlayer:AVPlayer? = nil
override func viewDidLoad() {
super.viewDidLoad()
FIRStorage.storage().referenceForURL(detailFullsizeUrl).metadataWithCompletion { (metadata, error) in
if error != nil{
print("error getting metadata")
} else {
let downloadUrl = metadata?.downloadURL()
print(downloadUrl)
if downloadUrl != nil{
self.avPlayer = AVPlayer(URL: downloadUrl!)
self.avPlayerViewController.player = self.avPlayer
print("downloadUrl obtained and set")
}
}
}
}
func handleGesture() {
print("handle gesture")
self.presentViewController(self.avPlayerViewController, animated: true) { () -> Void in
self.avPlayerViewController.player?.play()
}
}
Please check question. I updated it with the correct solution found on YouTube here: YouTube

Impossible to stream video after downloading from Parse

It seems that I can't stream my videos once I downloaded them from Parse backend. However I know that the videos are working well as you can play it from Chrome but not from Safari ( I don't know why ...).
My code to play the video on the AVPlayer is also right since I test it for multiple NSUrl from local database.
Several posts about it confirm that there is a problem going on but no one has an answer.
iOS - Can't stream video from Parse Backend
Cant stream video (PFFile) from parse server
Thanks in advance if someone can help me.
The secret is to get the PFFIle data, save it locally with the proper extention (mov) and treaming the local file.
look at this entry [Cant stream video (PFFile) from parse server][1], the second anwser.
The PFFIle was created with the following code:
let videoPath = info[UIImagePickerControllerMediaURL] as! NSURL
let imageData = NSData (contentsOfURL:videoPath)! as NSData
do {
let file = try PFFile(name: "_mov", data: imageData, contentType: "video/quicktime")
videoSaveSelected(file )
} catch let error as NSError {
print("Error generating PFFile: \(error)")
}
This is the code for the player
import UIKit
import AVKit
import MobileCoreServices
import AssetsLibrary
import AVFoundation
import Parse
import ParseUI
class VideoPlayerViewController: UIViewController {
var videoUrl: NSURL!
var file: PFFile!
override func viewDidLoad() {
super.viewDidLoad()
// navigation
let backButtonCustom = UIButton( frame: CGRectMake(0, 0, 22, 22))
let backIcon = UIImage(named: "0836-arrow-left")?.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
backButtonCustom.setImage(backIcon, forState: UIControlState.Normal)
backButtonCustom.addTarget(self, action: #selector(ReqDataEntryLgViewController.doneButtonTapped), forControlEvents: UIControlEvents.TouchUpInside)
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backButtonCustom)
let doneButton = UIBarButtonItem(title: "Done", style: .Done, target: self, action: #selector(ReqDataEntryLgViewController.doneButtonTapped))
self.navigationItem.setRightBarButtonItems([doneButton], animated: true)
// video player
let playerController = AVPlayerViewController()
self.addChildViewController(playerController)
self.view.addSubview(playerController.view)
playerController.view.frame = self.view.frame
// get data from PFFile in database
file!.getDataInBackgroundWithBlock({
(movieData: NSData?, error: NSError?) -> Void in
if (error == nil) {
let documentsPath : AnyObject = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0]
let destinationPath:NSString = documentsPath.stringByAppendingString("/file.mov")
let filemanager = NSFileManager.defaultManager()
do {
try filemanager.removeItemAtPath(destinationPath as String)
} catch {
print("Ooops! Something went wrong: \(error)")
}
// write to local file
movieData!.writeToFile ( destinationPath as String, atomically:true)
// do {
// let attr : NSDictionary? = try NSFileManager.defaultManager().attributesOfItemAtPath(destinationPath as String)
//
// if let _attr = attr {
// let fileSize = _attr.fileSize()
// print ("Movie Size \(fileSize)" )
// }
// } catch {
// print("Ooops! Something went wrong getting size: \(error)")
// }
let playerItem = AVPlayerItem(asset: AVAsset(URL: NSURL(fileURLWithPath: destinationPath as String)))
let player = AVPlayer(playerItem: playerItem)
playerController.player = player
player.play()
} else {
print ("error on getting movie data \(error?.localizedDescription)")
}
})
}
func doneButtonTapped(){
navigationController?.popViewControllerAnimated(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}