How do you rotate a video from a URL in Swift? - swift

I have my AVAssetWriter's completion handler create an exporter after it has finished writing so that the video can present itself in a player so the user can save it if they wish. That is all well and good, but I'd like to alter the written video and simply rotate it after it has finished writing.
The answers I've found to this varies from rotating the video as it's recording or deprecated old Objective-C ways that don't apply anymore.
My completion handler and exporter looks something like this. The exporter knows the outputFileType so I thought I'd be able to rotate the video there:
assetWriter?.finishWriting(completionHandler: {[unowned self] () -> Void in
let firstAsset = AVURLAsset(url: self.movieURL() as URL)
guard let exporter = AVAssetExportSession(asset: firstAsset, presetName: AVAssetExportPresetHighestQuality) else { return }
exporter.outputURL = self.movieURL() as URL
exporter.outputFileType = AVFileType.mov
exporter.exportAsynchronously() {
DispatchQueue.main.async(){
// below here is where another class is presented with the
// video URL to display in a player with the option to save

Related

Audio playing but video freezes AVPlayer on slow internet

I load my AVAsset asynchronously through this method:
playerAsset.loadValuesAsynchronously(forKeys: ["duration", "playable", "hasProtectedContent"]) {
DispatchQueue.main.async {[weak self] in
guard let strongSelf = self else { return }
let playerItem = AVPlayerItem(asset: playerAsset)
self.player?.replaceCurrentItem(with: playerItem)
}
}
On slow internet, my asset sometimes plays the audio completely but freezes on a certain video frame, or plays the video without audio. On seeking back to the beginning, the video plays properly.
I have KVO observers for playbackBufferEmpty and playbackLikelyToKeepUp, but they are not called in this situation.

setting sharedInstance of audiosessions category options not working

I'm building an App where I want to play music from the local library AND use the AVQueuePlayer, to play a list of tracks, where once in a while there's a break between the track. The music works totally fine, now, Since I want everything to work in the background, my only option when playing the AVQueuePlayer and want a break, is to play a silent AVPlayerItem (an empty audiofile.) I want the Music to play normally when silent AVPlayerItems are playing, I achieved that by setting AVAudioSession category to .playback and with options: .mixWithOthers, and when a regular track (not silent) is played by the AVQueuePlayer, I want the music to be dimmed a little.
I've tried changing the the audio session like this: AVAudioSession.sharedInstance().setCategory(.playback, options: [.mixWithOthers, .duckOthers])
but it doesn't change anything. When I check if it's changed like this: if AVAudioSession.sharedInstance().categoryOptions == .mixWithOthers {
print("Music mixing with silence")
}
the session category options seem to have changed, but it doesn't affect the audio in the end.
#objc func playerDidFinishPlaying() {
print("Player finished!")
guard let queuePlayer = queuePlayer else { return }
if let index = queuePlayer.items().lastIndex(where: { (playerItem) -> Bool in
return playerItem == queuePlayer.currentItem
}) {
if let nextItem = queuePlayer.items()[index + 1].asset as? AVURLAsset {
if nextItem.url.absoluteString != oneSecondSilenceUrl?.absoluteString {
try? AVAudioSession.sharedInstance().setCategory(.playback, options: [.mixWithOthers, .duckOthers])
//When narrator is speaking
} else {
try? AVAudioSession.sharedInstance().setCategory(.playback, options: .mixWithOthers)
AVAudioSession.sharedInstance()
//When there's silence and only music should be playing
}
}
}
if AVAudioSession.sharedInstance().categoryOptions == .mixWithOthers {
print("Music mixing with silence")
}
try? AVAudioSession.sharedInstance().setActive(true)
}
enter code here
This method runs whenever the the AVQueuePlayer has finished playing one of its items. I use it to check and see if the NEXT item is a silent track or not. If its a silent track, I want .mixWithOthers, If its a track that is NOT silent and the track actually plays audio, I want category options: .duckOthers :)
Any help, response or answer is very much appreciated! :)
Switching to main thread seemed to fix the problem. Weird.
DispatchQueue.main.async {
if AVAudioSession.sharedInstance().categoryOptions != .duckOthers {
try? AVAudioSession.sharedInstance().setActive(false)
try? AVAudioSession.sharedInstance().setCategory(.playback, options: [ .duckOthers])
}
}

AVAudioPlayer does not play audio file - swift

I know it seems quite straightforward, but in a weird way AVAudioPlayer does not play audio file. I have this code. It is not go through catch and still sound does not play. I've checked on physical device, simulator and also checked sound volume. But still I can't hear sound.
//in ViewController as a property
let soundEffect: AVAudioPlayer!
//in viewDidLoad
let path = Bundle.main.path(forResource: "success.mp3", ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
soundEffect = try AVAudioPlayer(contentsOf: url)
soundEffect.prepareToPlay()
soundEffect.play()
} catch let error as NSError {
print(error.description)
}
I also tried let path = Bundle.main.path(forResource: "success", ofType:"mp3")! but it didn't make any difference.
Try making your AVAudioPlayer an instance variable. otherwise soundEffect is deallocated at the end of the do loop.

Swift 3/4 AVAudioPlayer:contentsOf: fails when loading same URL many times

I am working on a simple game in Swift 4, Xcode 9 Beta 6, and I get an error when attempting to load an Audio File from the same URL many times. Let me show you what I mean; I have a code that looks a little like this.
guard let url = Bundle.main.url(forResource: soundName, withExtension: ext) else {
return nil
}
do {
player = try AVAudioPlayer(contentsOf: url)
player.prepareToPlay()
} catch let error {
print("Could not create AVAudioPlayer with url: \(url.absoluteString)")
return nil
print("Error: \(error.localizedDescription")
}
Note: soundName and ext are String objects composing the name of the local audio file. player is a property of the type AVAudioPlayer.
The game creates a sound using this code, which works perfectly at first, but after a while, it kind of gets lazy and the player = try AVAudioPlayer(contentsOf: url) fails and prints:
Could not create AVAudioPlayer with url: url here
Error: The operation couldn't be completed. (NSOSStatusErrorDomain error -42.)
Anyone has any ideas?
EDIT 1:
I loaded the content of the URL into a Data object by using let data = try Data(contentsOf: url) and that seems to have fix the issue. I am not making it as resolved because I still wish to know what is wrong with using just a URL and why it stops working after loading the same URL several times. Additionally, loading the contents into a binary Data object first might take more resources and time?

TVOS getting ReferenceError: Can't find variable when calling SWIFT function

I am trying to playback youtube videos with tvml on my appleTV. It is based on:
https://gist.github.com/nickv2002/b7bb28cdccc000bdb910
The first time I start it, it is working, but after I play around (leaving the app), I get:
ReferenceError: Can't find variable: playYTblock
After rebooting/exit(0)ing the app the ATV it is working again... it seems, the context between the app<>tvjs is lost - anyone with ideas?
Here is my code:
in AppDelegate.swift
let playerVC = YTPlayerViewController()
in the application function:
playerVC.createPlayYT( appController! )
in presenter.js
if (youtubeUrl && (event.type === "play")) {
playYTblock(youtubeUrl);
}
in the template.xml.js
<listItemLockup youtubeUrl="H4O6oEaIDrs">
btw has anyone an idea why the event.type === select is fired right after loading the template (without clicking on my side)
Can't answer about that exact problem but,
Here is what i'm using is to play youtube video on tvos :
pod "AKYoutubeParser"
A parser to retrieve the actual youtube video urls.
And the video playback is handled by apple core stuff (AVFoundation, AVKit)
you can delete all the hud part if you don't use it.
import AKYoutubeParser
import AVFoundation
import AVKit
func displayTrailer(trailer: String) {
AKYoutubeParser.h264Streams(trailer) { [weak self] streams, error in
if let s = streams, v = AKYoutubeParser.getBestQuality(s) {
let playerVC = AVPlayerViewController()
let playerItem = AVPlayerItem(asset: AVAsset(URL: v.url))
let videoPlayer = AVPlayer(playerItem: playerItem)
playerVC.player = videoPlayer
self?.presentViewController(playerVC, animated: true) {
playerVC.player?.play()
}
}
}
}