SceneKit – AVPlayer material crash - iphone

I'm using a video as the material for an SCNNode:
geo.materials.first?.diffuse.contents = AVPlayer(url: url)
This works fine on most iOS devices but crashes on the older iPhone 5s with the following error:
-[MTLTextureDescriptorInternal validateWithDevice:], line 781: error 'MTLTextureDescriptor has invalid pixelFormat (520).'
-[MTLTextureDescriptorInternal validateWithDevice:]:781: failed assertion `MTLTextureDescriptor has invalid pixelFormat (520).'
Is there a fix/workaround for this issue?

I think it's a hardware issue of iPhone 5s. Try to use a SKVideoNode as a workaround. SpriteKit's objects are much "lighter" for iPhone 5s.
var videoNode: SKVideoNode? = {
guard let urlString = Bundle.main.path(forResource: "file",
ofType: "m4v") else {
return nil
}
let url = URL(fileURLWithPath: urlString)
let item = AVPlayerItem(url: url)
let player = AVPlayer(playerItem: item)
return SKVideoNode(avPlayer: player)
}()
Hope this helps.

Related

Stream Spotify preview_url in iOS Swift

I am trying to stream the preview url Spotify provides from their Web API which is working well and I am getting correct links but they are not playing properly.
A sample url would be https://p.scdn.co/mp3-preview/757bc5732e5c92e36ea249d631120b381a4885e2?cid=e188f3e083e741659b2ef6cfb07cddbd.mp3 and I am attempting to the exact same code that is discussed in this question, and I can get it to work with the URL they provide in the question but it doesn't work with the Spotify samples. Any help would be much appreciated.
let url = URL(string: "https://p.scdn.co/mp3-preview/757bc5732e5c92e36ea249d631120b381a4885e2?cid=e188f3e083e741659b2ef6cfb07cddbd.mp3")
let playerItem:AVPlayerItem = AVPlayerItem(url: url!)
player = AVPlayer(playerItem: playerItem)
let playerLayer=AVPlayerLayer(player: player!)
playerLayer.frame=CGRect(x:0, y:0, width:10, height:50)
self.view.layer.addSublayer(playerLayer)
player.play()
The spotify preview url of of type only for 30 seconds. They can be played via AVPlayer,
import UIKit
import AVFoundation
class AudioVC : UIViewController {
var player = AVAudioPlayer()
override func viewDidLoad() {
let previewURL = "https://p.scdn.co/mp3-preview/757bc5732e5c92e36ea249d631120b381a4885e2?cid=e188f3e083e741659b2ef6cfb07cddbd.mp3"
downloadFileFromURL(url: URL(string: previewURL)!)
}
func downloadFileFromURL(url: URL){
var downloadTask = URLSessionDownloadTask()
downloadTask = URLSession.shared.downloadTask(with: url, completionHandler: {
customURL, response, error in
self.play(url: customURL!)
})
downloadTask.resume()
}
func play(url: URL) {
do {
player = try AVAudioPlayer(contentsOf: url)
player.prepareToPlay()
player.play()
}
catch{
print(error)
}}
}

Switching subtitles of hls on tvOS/swift

I am using AVplayer of swift for my tvOSApp.
When I use default player, subtitles of the video will be shown on "subtitle" bar on top and can easily switch subtitles.
So, how can I switch subtitles like that, without using the default playback controls?
I have buttons for switching subtitles on the screen and I'd like to switch during target method of these.
Here is my code for AVPlayer.
let asset = AVAsset(url: URL(string: videoUrl)!)
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
player.play()
self.bgMovieLayer = AVPlayerLayer(player: player)
self.bgMovieLayer.frame = view.bounds
self.bgMovieLayer.videoGravity = .resizeAspectFill
self.bgMovieLayer.zPosition = -1
self.view.layer.insertSublayer(self.bgMovieLayer, at: 0)
I am using the video below for a test.
http://184.72.239.149/vod/smil:BigBuckBunny.smil/playlist.m3u8
I read the documents regarding AVPlayer/AVPlayerItem and came into no answer. I would appreciate if someone can help this.
You have to load availableMediaCharacteristics first and after that look for AVMediaCharacteristic.legible.
Something like this:
let asset:AVAsset
let key = #keyPath(AVAsset.availableMediaCharacteristicsWithMediaSelectionOptions)
asset.loadValuesAsynchronously(forKeys: [key]) {
var error: NSError? = nil
let status = asset.statusOfValue(forKey: key, error: &error)
switch status {
case .loaded:
// Sucessfully loaded, continue processing
case .failed:
// Examine NSError pointer to determine failure
case .cancelled:
// Loading cancelled
default:
// Handle all other cases
}
}
let subtitlesGroup = asset.mediaSelectionGroup(forMediaCharacteristic: AVMediaCharacteristic.legible)

Playing music in Swift: Unexpectedly found nil while unwrapping an Optional value

Working on a project, I decided to add some music to play when a certain action is triggered. Here's what I've got:
var player : AVAudioPlayer?
several lines later...
func playSound(){
let alertSound = URL(fileURLWithPath: Bundle.main.path(forResource: "Kalimba", ofType: "wav")!)
print(alertSound)
try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try! AVAudioSession.sharedInstance().setActive(true)
try! player = AVAudioPlayer(contentsOf: alertSound)
player!.prepareToPlay()
player!.play()
}
Whenever I try this, xcode throws me a fatal error when the action is triggered, saying:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
You should check with your music file is attached with your target? -
let path = Bundle.main.path(forResource: "Kalimba", ofType: "wav")
if path != nil {
let url = URL(fileURLWithPath: path!)
print(url)
let player = AVPlayer(url: url)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.bounds
self.view.layer.addSublayer(playerLayer)
player.play()
} else {
print("File Not exist")
}

how can i add a progressbar to a mp3 player i created in swift using AVPlayer NOT AVAudioPlayer

here is my code of how im playing my mp3 from a live url i just cannot find any updated information for swift to use avplayer not avaudioplayer.. thank you in advance to all comments and helpers
var playerItem:AVPlayerItem?
var player = AVPlayer()
var error : NSError?
var sucess : Bool?
do{
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback,withOptions: .DefaultToSpeaker)
_ = try AVAudioSession.sharedInstance().setActive(true)
sucess = true
} catch let NotSucessError as NSError{error = NotSucessError
sucess = false}
if !sucess! {
NSLog("Fail to set audio session. Error:\(error)")
}
let url = NSURL(string: trackURL)
playerItem = AVPlayerItem(URL: url!)
player = AVPlayer(playerItem: playerItem!)
player.play()

How to record a video and make it slow motion

I am working on an iPhone app for school and need some help. The app should record video, make it slow motion (about 2x), then save it to the photo library. So far I have everything except how to make the video slow motion. I know it can be done as there is already an app in the App Store that does it.
How can I take a video I've saved to a temp url and adjust the speed before saving it to the photo library?
If you need to export your video then you need to use the AVMutableComposition Class
Then add your video as an AVAsset to an AVMutableComposition and scale it with:
- (void)scaleTimeRange:(CMTimeRange)timeRange toDuration:(CMTime)duration
Finally you export it using AVAssetExportSession Class
I written a code that makes your video in "slow motion" and saves it in Photos Library. "Main Thing This Code Works In Swift 5". Creating "Slow motion" video in iOS swift is not easy, that I came across many "slow motion" that came to know not working or some of the codes in them are depreciated. And so I finally figured a way to make slow motion in Swift.
This code can be used for 120fps are greater than that too. Just add the url of your video and make it slow
Here is the "code snippet I created for achieving slow motion"
func slowMotion(pathUrl: URL) {
let videoAsset = AVURLAsset.init(url: pathUrl, options: nil)
let currentAsset = AVAsset.init(url: pathUrl)
let vdoTrack = currentAsset.tracks(withMediaType: .video)[0]
let mixComposition = AVMutableComposition()
let compositionVideoTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)
let videoInsertError: Error? = nil
var videoInsertResult = false
do {
try compositionVideoTrack?.insertTimeRange(
CMTimeRangeMake(start: .zero, duration: videoAsset.duration),
of: videoAsset.tracks(withMediaType: .video)[0],
at: .zero)
videoInsertResult = true
} catch let videoInsertError {
}
if !videoInsertResult || videoInsertError != nil {
//handle error
return
}
var duration: CMTime = .zero
duration = CMTimeAdd(duration, currentAsset.duration)
//MARK: You see this constant (videoScaleFactor) this helps in achieving the slow motion that you wanted. This increases the time scale of the video that makes slow motion
// just increase the videoScaleFactor value in order to play video in higher frames rates(more slowly)
let videoScaleFactor = 2.0
let videoDuration = videoAsset.duration
compositionVideoTrack?.scaleTimeRange(
CMTimeRangeMake(start: .zero, duration: videoDuration),
toDuration: CMTimeMake(value: videoDuration.value * Int64(videoScaleFactor), timescale: videoDuration.timescale))
compositionVideoTrack?.preferredTransform = vdoTrack.preferredTransform
let dirPaths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).map(\.path)
let docsDir = dirPaths[0]
let outputFilePath = URL(fileURLWithPath: docsDir).appendingPathComponent("slowMotion\(UUID().uuidString).mp4").path
if FileManager.default.fileExists(atPath: outputFilePath) {
do {
try FileManager.default.removeItem(atPath: outputFilePath)
} catch {
}
}
let filePath = URL(fileURLWithPath: outputFilePath)
let assetExport = AVAssetExportSession(
asset: mixComposition,
presetName: AVAssetExportPresetHighestQuality)
assetExport?.outputURL = filePath
assetExport?.outputFileType = .mp4
assetExport?.exportAsynchronously(completionHandler: {
switch assetExport?.status {
case .failed:
print("asset output media url = \(String(describing: assetExport?.outputURL))")
print("Export session faiied with error: \(String(describing: assetExport?.error))")
DispatchQueue.main.async(execute: {
// completion(nil);
})
case .completed:
print("Successful")
let outputURL = assetExport!.outputURL
print("url path = \(String(describing: outputURL))")
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: outputURL!)
}) { saved, error in
if saved {
print("video successfully saved in photos gallery view video in photos gallery")
}
if (error != nil) {
print("error in saing video \(String(describing: error?.localizedDescription))")
}
}
DispatchQueue.main.async(execute: {
// completion(_filePath);
})
case .none:
break
case .unknown:
break
case .waiting:
break
case .exporting:
break
case .cancelled:
break
case .some(_):
break
}
})
}
slowmoVideo is an OSS project which appears to do this very nicely, though I don't know that it would work on an iPhone.
It does not simply make your videos play at 0.01× speed. You can
smoothly slow down and speed up your footage, optionally with motion
blur. How does slow motion work? slowmoVideo tries to find out where
pixels move in the video (this information is called Optical Flow),
and then uses this information to calculate the additional frames.