AVPlayer doesn't play video from my parse - parse-platform

I'm trying to play video from my parse server
I'm getting empty video player
And when i print the url i get the correct video url
let thevideo:PFFile! = (self.selectedmsg["file"] as! PFFile)
let url:NSURL = NSURL(string: thevideo.url!)!
let player = AVPlayer(URL: url)
let playercontroller = AVPlayerViewController()
playercontroller.player = player
self.presentViewController(playercontroller, animated: true) {
player.play()
}
Any help?

I had the same issue, tried to search around for solution, but cannot, the only workable solution is save the file to device, and play it locally.

Related

AR View freezes for couple seconds while video in AVPlayer loads

I am creating a plane with VideoMaterial when AR Reference Image is detected. I play the video inside an AVPlayer and I want to load the video from URL, instead of local resources. It all works well, however when the image is detected and the place is created, the app freezes for couple of seconds while the video gets loaded.
I don't know how to get rid of the freezing, instead I would like to show SimpleMaterial plane until the video is loaded.
Can anybody help me with this, please?
Code that I use to play the video when reference image is detected:
class Coordinator: NSObject, ARSessionDelegate{
var parent: ARViewContainer
var videoPlayer: AVPlayer!
init(parent: ARViewContainer) {
self.parent = parent
}
func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
guard let imageAnchor = anchors[0] as? ARImageAnchor else { return }
let playerItem = AVPlayerItem(url: URL(string: "https://swiftanytime-content.s3.ap-south-1.amazonaws.com/SwiftUI-Beginner/Video-Player/iMacAdvertisement.mp4")!)
videoPlayer = AVPlayer(playerItem: playerItem)
let videoMaterial = VideoMaterial(avPlayer: videoPlayer)
let videoPlane = ModelEntity(mesh: .generatePlane(width: Float(imageAnchor.referenceImage.physicalSize.width), depth: Float(imageAnchor.referenceImage.physicalSize.height), cornerRadius: 10), materials: [videoMaterial])
if let imageName = imageAnchor.name, imageName == "referenceimg1" {
let anchor = AnchorEntity(anchor: imageAnchor)
anchor.addChild(videoPlane)
parent.arView.scene.addAnchor(anchor)
videoPlayer.play()
}
}

I have an audio player that starts on my home screen

Whenever I go back to my home screen it replays the music over the already playing music. I tried making an if statements that 'obviously' doesn't work (because I barely know any swift!). Here is my home screen code:
var myAudioPlayer = AVAudioPlayer()
override func viewDidLoad() {
let myFilePathString =
NSBundle.mainBundle().pathForResource("16 March of the Resistance", ofType: "m4a")
if let myFilePathString = myFilePathString
{
let myFilePathURL = NSURL(fileURLWithPath: myFilePathString)
do{
try myAudioPlayer = AVAudioPlayer(contentsOfURL: myFilePathURL)
myAudioPlayer.play()
}catch
{
print("error")
}
}
}
How can I stop it from playing on top of itself?
Here is a picture of my storyboard
enter image description here
The music player is on StartScreen, but when I click the back button, it starts another music player over the current one.
I need code which says
is myAudioPlayer playing?
if yes do not play song again
else play "16 March of the resistance"
enter image description here
You need to check if you are already playing. You can do this by the playing property of the AVAudioPlayer class.
Guard your viewDidLoad with say:
if !myAudioPlayer.playing
Note that I don't know any Swift.
I'm not sure what you mean by "my home screen", is it the device or your main VC? Why are you overriding viewDidLoad()? A previous player could never be playing in the viewDidLoad() call, unless for a leak which is what's needing fixing.
Otherwise, you just need to declare your player as an optional, rather than creating it in the declaration. As for the replaying or overlapping, just check if you player exists, although you wouldnt do this in your viewDidLoad(). ViewDidLoad() is called when the view of the VC is created and the view loaded, which doesn't relate to your lifecycle of the audio.
Depending on your requirements, you might want to create the player somewhere else that is plays throughout the app, rather than restarting when visiting that VC. Otherwise the code below will avoid the duplication. The problem was this var myAudioPlayer = AVAudioPlayer() which would duplicate players and one wasn't being released.
var myAudioPlayer: AVAudioPlayer?
func viewDidLoad() {
// this should never be needed with correct player setup
if let player = myAudioPlayer where player.playing {
return
}
if let pathString = NSBundle.mainBundle().pathForResource("16 March of the Resistance", ofType: "m4a")
{
let url = NSURL(fileURLWithPath: pathString)
do{
try myAudioPlayer = AVAudioPlayer(contentsOfURL: url)
myAudioPlayer?.play()
} catch {
print("error")
}
}
}
Update
So there is no need to make the VC do this. Create a Class of e.g. AudioController, which could even be a singleton. Initialise it in your AppDelegate and trigger this player setup code after initialisation. Your view controllers dont need to know about the audio controller. IF e.g. you do want to modify the volume from a setting page, you just access the singleton object and set its volume.
This way you keep all your audio controller code nicely separated. Dont just think of functionality, think of overall software architecture, with objects having clear responsibilities. Keep your ViewControllers light, they shouldnt be doing much processing.
Take a look at this Singletons , its really easy to setup a singleton in Swift nowadays.
class AudioController {
static let sharedInstance = AudioController()
var audioPlayer: AVAudioPlayer?
let kVolumeKey = "VolumeKey"
let kHasSavedInitialVolumeKey = "HasSavedInitialVolumeKey"
var volume: Float = 0.5
func setup() {
self.loadVolume()
self.setupPlayer()
}
func updatePlayerVolume(volume: Float) {
self.audioPlayer?.volume = volume
self.volume = volume
self.saveVolume()
}
func saveVolume() {
NSUserDefaults.standardUserDefaults().setBool(true, forKey: kHasSavedInitialVolumeKey)
NSUserDefaults.standardUserDefaults().setFloat(self.volume, forKey: kVolumeKey)
NSUserDefaults.standardUserDefaults().synchronize()
}
func loadVolume() {
if NSUserDefaults.standardUserDefaults().boolForKey(kHasSavedInitialVolumeKey) {
self.volume = NSUserDefaults.standardUserDefaults().floatForKey(kVolumeKey)
}
}
func setupPlayer() {
if let pathString = NSBundle.mainBundle().pathForResource("16 March of the Resistance", ofType: "m4a")
{
let url = NSURL(fileURLWithPath: pathString)
do{
try audioPlayer = AVAudioPlayer(contentsOfURL: url)
audioPlayer?.volume = self.volume
audioPlayer?.play()
} catch {
print("error")
}
}
}
}
So, you can just setup the player from your AppDelegate's didFinishLaunching
AudioController.sharedInstance.setupPlayer()
And then you can access the AudioController using AudioController.sharedInstance.whatever when you need to get or set. Also, you will need to implement the players delegate methods for handling the end of the song, possibly triggering a new song to play from a playlist(create a new object for this) or whatever. Your player delegate code is also nicely separated now.
Looking at your storyboard it seems that when you click the Back button on the second ViewController you allocate another start screen and you push it on the screen.
It seems that you're using a UINavigationController if so when the back button is tapped you should call:
self.navigationController?.popViewControllerAnimated(true)
If your showing it as a modal you should dismiss is like this:
self.dismissViewControllerAnimated(true, completion: nil)

Swift 2 - Share video with UIActivityViewController

I am trying to share a video from a URL using UIActivityViewController.
If I try with an Image I have not problems.
Share Image Works:
let imageThump = NSURL(string: "https://example.com/image.png")
let imageData = NSData(contentsOfURL: imageThump!)
let objectsToShare = [comment!, imageData!]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
Share Video is not working. Why?
let videoShare = NSURL(string: "https://example.com/video.mp4")
let videoData = NSData(contentsOfURL: videoShare!)
let objectsToShare = [comment!, videoData!]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
THIS IS HOW YOU DO IT ...
guard let urlData = NSData(contentsOfURL: NSURL(string:"https://example.com/video.mov)")!) else {
return
}
print(urlData)
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let docDirectory = paths[0]
let filePath = "\(docDirectory)/tmpVideo.mov"
urlData?.writeToFile(filePath, atomically: true)
// File Saved
let videoLink = NSURL(fileURLWithPath: filePath)
let objectsToShare = [videoLink] //comment!, imageData!, myWebsite!]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
activityVC.setValue("Video", forKey: "subject")
// New Excluded Activities Code
if #available(iOS 9.0, *) {
activityVC.excludedActivityTypes = [UIActivityTypeAirDrop, UIActivityTypeAddToReadingList, UIActivityTypeAssignToContact, UIActivityTypeCopyToPasteboard, UIActivityTypeMail, UIActivityTypeMessage, UIActivityTypeOpenInIBooks, UIActivityTypePostToTencentWeibo, UIActivityTypePostToVimeo, UIActivityTypePostToWeibo, UIActivityTypePrint]
} else {
// Fallback on earlier versions
activityVC.excludedActivityTypes = [UIActivityTypeAirDrop, UIActivityTypeAddToReadingList, UIActivityTypeAssignToContact, UIActivityTypeCopyToPasteboard, UIActivityTypeMail, UIActivityTypeMessage, UIActivityTypePostToTencentWeibo, UIActivityTypePostToVimeo, UIActivityTypePostToWeibo, UIActivityTypePrint ]
}
self.presentViewController(activityVC, animated: true, completion: nil)
Remember that a video is usually a big file, so it'll take some time for it to be downloaded and saved. Here I used part of the first answer but adding some GCD. You'll get better results.
This is how I did it to avoid the App to stay frozen until the video is downloaded and saved:
let url = NSURL(string: "https://example.com/video.mov")
//Show activity indicator
DispatchQueue.global(qos: .background).async {
guard let urlData = NSData(contentsOf: url) else { return }
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let filePath="\(documentsPath)/tempFile.mov"
DispatchQueue.main.async {
urlData.write(toFile: filePath, atomically: true)
//Hide activity indicator
let activityVC = UIActivityViewController(activityItems: [NSURL(fileURLWithPath: filePath)], applicationActivities: nil)
activityVC.excludedActivityTypes = [.addToReadingList, .assignToContact]
self.present(activityVC, animated: true, completion: nil)
}
}
It is not working because this class does not allow NSData to be passed to the Facebook activity type.
"UIActivityTypePostToFacebook
The object posts the provided content to the user’s wall on Facebook.
When using this service, you can provide NSString, NSAttributedString, UIImage, ALAsset, and NSURL objects as data for the activity items. You may also specify NSURL objects whose contents use the assets-library scheme."
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIActivity_Class/index.html#//apple_ref/doc/constant_group/Built_in_Activity_Types
I have been trying to get this to work as well. Haven't figured out how to get it to work; however, this is why your code is not working.

Cannot invoke initializer for type 'AVPlayer'

I'm having an issue getting my video to play via AVPlayer. For some reason I'm getting the error 'Cannot invoke initializer for type 'AVPlayer' with an argument list of type '(URL:NSURL)'
The weird thing is, this exact code snippet works in another one of my projects. I do have the AVKit and AVFoundation frameworks imported.
Well, I realized my dumb mistake. I had a local variable (player), so it died instantly before it could even play. I moved it up a level to be an instance variable so it persists as long as the view controller persists.
var MoviePlaying:Bool = false
let path = NSBundle.mainBundle().pathForResource("big_buck_bunny_720p_50mb", ofType:"mp4")
var player: AVPlayer = AVPlayer()
let playerController = AVPlayerViewController()
#IBAction func PlayTapped(sender: UIButton) {
let moviePlayerController = AVPlayerViewController()
let path = NSBundle.mainBundle().pathForResource("big_buck_bunny_720p_50mb", ofType:"mp4")
let url = NSURL.fileURLWithPath(path!)
let playerVC = AVPlayerViewController()
var player: AVPlayer = AVPlayer()
playerVC.player = AVPlayer(URL: url)
self.presentViewController(playerVC, animated: true, completion: nil)

Paste gif image into NSPasteboard

I am developing osx application. I want to paste an Gif image into pasteboard. How can I do that?
What I have is
NSImage
NSPasteboard
What I want to do is to paste that image into pasteboard. I am able to paste PNG image but what I need is to paste GIF image.
My existing code
let imageURL = imageObject.imageURL!
let fileName = imageURL.lastPathComponent
var saveURL = NSURL(string: "file://" + NSTemporaryDirectory())
saveURL = saveURL?.URLByAppendingPathComponent(fileName!)
// I have data now
let data = NSData(contentsOfURL: imageURL)
pasteboard.declareTypes([NSTIFFPboardType], owner: nil)
pasteboard.setData(data!, forType: "com.compuserve.gif")
About 10 years ago same one asked How do I put a GIF onto an NSPasteboard?
in an Apple discussion group and here is my answer. Although 10 years old and the NSPasteboard methods changed since that time my answer still works. I confess: my advice is a bit dirty.
Okay I got it working after spending 6 hours searching online.
Basically I have to download the image file and paste it as a filename.
let imageURL = imageObject.imageURL!
let fileName = imageURL.lastPathComponent
var saveURL = NSURL(string: "file://" + NSTemporaryDirectory())
saveURL = saveURL?.URLByAppendingPathComponent(fileName!)
let data = NSData(contentsOfURL: imageURL)
data?.writeToURL(saveURL!, atomically: true)
pasteboard.declareTypes([NSFilenamesPboardType], owner: nil)
pasteboard.writeObjects([saveURL!])
I managed to get this working using the following code:
let pb = NSPasteboard.general
do {
let fileType = try NSWorkspace.shared.type(ofFile: localPath.path)
let pasteboardType = NSPasteboard.PasteboardType.init(fileType)
pb.declareTypes([pasteboardType], owner: nil)
pb.writeObjects([localPath as NSURL])
} catch {
return
}

Resources