I am currently playing a video from local with bundle URL.
private let videoURL = Bundle.main.path(forResource: "video", ofType:"mp4")
here is the setupPlayer method:
player = AVPlayer(url: URL(fileURLWithPath: url))
playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = videoContainerView.layer.bounds
playerLayer.videoGravity = .resize
I can preview the video and sound but Xcode generates some errors. After some searching on internet, I can not find anything about how to solve them.
2021-01-31 15:56:25.026534+0300 PixeryCase[72428:5712733] [] [15:56:25.026] FigSubtitleSampleCreateFromPropertyList signalled err=50 (kFigCFBadPropertyListErr) (NULL or bad plist) at /Library/Caches/com.apple.xbs/Sources/EmbeddedCoreMedia_Sim/EmbeddedCoreMedia-2765.6/Prototypes/ClosedCaptions/FigCaptionCommand.c:792
2021-01-31 15:56:25.233948+0300 PixeryCase[72428:5712809] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x600002a1be40>
2021-01-31 15:56:25.563638+0300 PixeryCase[72428:5712816] [] [15:56:25.564] VMC2SetProperty signalled err=-12823 (kVMCParameterErr) (not a CFString) at /Library/Caches/com.apple.xbs/Sources/EmbeddedCoreMedia_Sim/EmbeddedCoreMedia-2765.6/Prototypes/MediaConverter/VideoMediaConverter2.c:7105
please add
let playerLayer = AVPlayerLayer(player: player)
view.layer?.addSublayer(playerLayer)
A convenient way of using AVPlayerLayer in iOS ,
is as the backing layer for a UIView as illustrated in the following code example:
class PlayerView: UIView {
var player: AVPlayer? {
get {
return playerLayer.player
}
set {
playerLayer.player = newValue
}
}
var playerLayer: AVPlayerLayer {
return layer as! AVPlayerLayer
}
// Override UIView property
override static var layerClass: AnyClass {
return AVPlayerLayer.self
}
}
Related
I am making an app for playing podcasts.
the problem is when creating an AVPlayer with URL or AVPlayer item. a memory leak happens but deinit works well with no problem.
weak var presenter: AudioPlayerUpdaterProtocol?
private var audioSession: AVAudioSession?
private var audioPlayer: AVPlayer?
private var audioURL: URL?
private var playbackTimeUpdater: Timer?
deinit {
self.audioSession = nil
self.audioURL = nil
self.audioPlayer = nil
self.playbackTimeUpdater?.invalidate()
removeEndPlayingObserver()
print("deinit audio")
}
private func setupAudioPlayer(){
guard let url = audioURL else {
return
}
let playerItem = AVPlayerItem(url: URL)
// when comment the avplear init no memory leaks found.
audioPlayer = AVPlayer(playerItem: playerItem)
addEndPlayingObserver()
startPlaying()
}
when debugging with instruments I got this
enter image description here
I tried to debug this malloc 16 bytes on Xcode but I failed on this because the object is not at any memory graph.
This is because setting an AVPlayerItem on an AVPlayer creates a hidden strong reference between the two, so persisting the AVPlayerItem will hang onto the AVPlayer, causing a memory leak.
make share the AVPlayerItem and AVPlayer have a 1:1 relationship by creating a new AVPlayerItem when it needs to be assigned to an AVPlayer.
guard let url = audioURL else {
return
}
let originalAsset = AVAsset(url: url)
audioPlayer = AVPlayer(playerItem: AVPlayerItem(asset: originalAsset))
If the above approach doesn't help you try this on your viewDidDissapear:
func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.audioPlayer?.replaceCurrentItem(with: nil)
}
I'm having an issue getting an audio file to play when the function is called.
I am using an AVAudioPlayer to try and play the file following the instructions form here:
https://www.hackingwithswift.com/example-code/media/how-to-play-sounds-using-avaudioplayer
After the button is pressed in the view, it calls a func to play the sound, but from what I can tell, nothing is played. There are no errors thrown, and the file is found. The app also uses a speech synthesizer when a button is pushed, and that plays fine.
I looked around stack overflow and followed the instructions from here:
Where to place code for audio playback in a SwiftUI app
But still the audio is not played when the button is pushed.
Here is the func:
func playSound() {
var sound = AVAudioPlayer()
if let path = Bundle.main.path(forResource: "TryAgain", ofType: "wav") {
do {
sound = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
print("Playing sound")
sound.play()
} catch {
print( "Could not find file")
}
}
Here is the class:
class Player: BindableObject {
let willChange = PassthroughSubject<Player, Never>()
var isPlaying: Bool = false {
willSet {
willChange.send(self)
}
}
func playSound() {
var sound = AVAudioPlayer()
if let path = Bundle.main.path(forResource: "TryAgainWav", ofType: "wav") {
do {
sound = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
print("Playing sound")
sound.play()
} catch {
print( "Could not find file")
}
}
}
}
Update: Not sure if this helps, but I built this in with IB instead of SwiftUI and noticed the same message is printed in the console when I click the button to play the audio file:
2019-07-22 11:29:41.075568-0700 PlaySoundPrac[13952:46549155] [plugin] AddInstanceForFactory: No factory registered for id F8BB1C28-BAE8-11D6-9C31-00039315CD46
Any help would be greatly appreciated
I'm pretty new myself, but I'll do my best. What happens if you move the declaration of AVAudioPlayer outside the function? For example:
import Combine
class Player: ObservableObject {
var sound: AVAudioPlayer!
let willChange = PassthroughSubject<Player, Never>()
var isPlaying: Bool = false {
willSet {
willChange.send(self)
}
}
func playSound() {
if let path = Bundle.main.path(forResource: "TryAgainWav", ofType: "wav") {
do {
sound = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
print("Playing sound")
sound.play()
} catch {
print( "Could not find file")
}
}
}
}
Try this out and let me know if it works or not! Thanks.
I had a problem that audio was not played on iOS 13 Simulator in Xcode 11.5 while it was okay in Xcode SwiftUI preview and physical device.
I am using AVFoundation kit to play a local video
I tried this code:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player: AVPlayer?
#IBOutlet weak var videoViewContainer: UIView!
override func viewDidLoad() {
super.viewDidLoad()
initializeVideoPlayerWithVideo()
}
func initializeVideoPlayerWithVideo() {
// get the path string for the video from assets
let videoString:String? = Bundle.main.path(forResource: "Air Bike", ofType: "mov")
guard let unwrappedVideoPath = videoString else {return}
// convert the path string to a url
let videoUrl = URL(fileURLWithPath: unwrappedVideoPath)
// initialize the video player with the url
self.player = AVPlayer(url: videoUrl)
// create a video layer for the player
let layer: AVPlayerLayer = AVPlayerLayer(player: player)
// make the layer the same size as the container view
layer.frame = videoViewContainer.bounds
// make the video fill the layer as much as possible while keeping its aspect size
layer.videoGravity = AVLayerVideoGravity.resizeAspectFill
// add the layer to the container view
videoViewContainer.layer.addSublayer(layer)
}
#IBAction func playVideoButtonTapped(_ sender: UIButton) {
// play the video if the player is initialized
player?.play()
}
}
I've trying a few different approaches and I'm still getting the same error message can someone How can I resolve this issue?
func initializeVideoPlayerWithVideo() {
guard let path = Bundle.main.path(forResource: "jagdeep", ofType:".MOV") else {
debugPrint("video.m4v not found")
return
}
self.player = AVPlayer(url: URL(fileURLWithPath: path))
// create a video layer for the player
let layer: AVPlayerLayer = AVPlayerLayer(player: player)
// make the layer the same size as the container view
layer.frame = videoViewContainer.bounds
// make the video fill the layer as much as possible while keeping its aspect size
layer.videoGravity = AVLayerVideoGravity.resizeAspectFill
// add the layer to the container view
videoViewContainer.layer.addSublayer(layer)
player?.play()
}
HERE IS MY VIDEO NAME jagdeep and type .MOV AND its working on my side. It's problem in your code where you using type mov. I just drag a video name jagdeep.MOV to my project and use Your code. its ok
**use**
layer.frame = videoViewContainer.layer.bounds
instead of
// make the layer the same size as the container view
layer.frame = videoViewContainer.bounds
Thank you for your response seems like the file cannot be found here is a screenshot from my project what could be the reason the video is located in my main folder! Screenshot
I am trying to make a game with background music looping in it. I made the song file in Adobe Audition (which is similar to audacity) and when I play it in a loop in Adobe Audition it loops how I want it.
When I play it in Xcode however, it has a lag in between the loops. I am using AVFoundations for the sound playing.
I have searched everywhere but I can't find the solution for the problem.
Is there any way you can loop audio files without there being any lags in between ? (I believe its called "seamless looping" )
here is the code:
class GameScene: SKScene {
...// Other Code
var ButtonAudio = URL(fileURLWithPath: Bundle.main.path(forResource: "Gamescene(new)", ofType: "mp3")!)
var ButtonAudioPlayer = AVAudioPlayer()
... //Other Code
}
And When I Call it:
override func didMove(to view: SKView) {
...//Code
ButtonAudioPlayer = try! AVAudioPlayer(contentsOf: ButtonAudio, fileTypeHint: nil)
ButtonAudioPlayer.numberOfLoops = -1
ButtonAudioPlayer.prepareToPlay()
ButtonAudioPlayer.play()
...//More Code
}
Can someone help me with this issue ?
Thank you in advance!
You can use AVPlayerLooper and AVQueuePlayer to do this.
import UIKit
import AVFoundation
class ViewController: UIViewController {
var queuePlayer = AVQueuePlayer()
var playerLooper: AVPlayerLooper?
override func viewDidLoad() {
super.viewDidLoad()
guard let url = Bundle.main.url(forResource: "Gamescene(new)", withExtension: "mp3") else { return }
let playerItem = AVPlayerItem(asset: AVAsset(url: url))
playerLooper = AVPlayerLooper(player: queuePlayer, templateItem: playerItem)
queuePlayer.play()
}
}
The solution proposed by #dave234 only works in iOS > 10. Since I needed to make seamless playback in iOS > 9, I did something different:
Instead of AVPlayer, I created AVQueuePlayer and immediately added two identical melodies to the queue.
Next, I made a listener to the penultimate melody.
When the listener was triggered, I added another similar record to the queue after the last one.
In fact, in order to avoid delay, I always play the penultimate record.
My code:
var player: AVQueuePlayer?
override func viewDidLoad() {
super.viewDidLoad()
if let path = Bundle.main.path(forResource: "music_file", ofType: "mp3") {
player = createPlayer(url: URL(fileURLWithPath: path))
}
}
func createPlayer(url: URL) -> AVQueuePlayer {
let player = AVQueuePlayer(items: [AVPlayerItem(url: url), AVPlayerItem(url: url)])
loopPlayer(playerItem: player.items()[player.items().count - 2])
return player
}
func loopPlayer(playerItem: AVPlayerItem) {
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: playerItem, queue: .main) { _ in
if let player = self.player, let url = (playerItem.asset as? AVURLAsset)?.url {
player.insert(AVPlayerItem(url: url), after: player.items()[player.items().count - 1])
self.loopPlayer(playerItem: player.items()[player.items().count - 2])
}
}
}
I have implemented player AVPlayerViewController on tvOS using AVQueuePlayer. The playback of videos works as expected but on all videos following the first the scrubber / time slider shows thumbnails for the first video.
The player is being setup using the following code:
class TFLPlayerController: AVPlayerViewController, AVPlayerViewControllerDelegate {
var queuePlayer = AVQueuePlayer()
...
func addVideoToQueue(video: Video, after: AVPlayerItem?){
let mainVideo = AVPlayerItem(URL: NSURL(string: videoURL)!)
self.queuePlayer.insertItem(mainVideo, afterItem: nil)
}
func readyToPlay() {
self.addVideoToQueue(videoRecord, after: nil)
self.player = self.queuePlayer
if let currentItem = queuePlayer.currentItem {
// Set time to get make a call to the API for the next video
let callUpNextAPITime = CMTimeMakeWithSeconds(0.5, currentItem.asset.duration.timescale)
let callUpNextAPITimeValue = NSValue(CMTime: callUpNextAPITime)
let getUpNextObserver = queuePlayer.addBoundaryTimeObserverForTimes([callUpNextAPITimeValue], queue: dispatch_get_main_queue(), usingBlock: { () -> Void in
self.getUpNext()
})
}
self.player?.play()
}
func getUpNext(){
// Get the next video to play
let playlistId = presentingPlaylist?.identifier ?? nil
if let currentItem = self.queuePlayer.currentItem {
// Get the current items id
let currentVideoId = itemVideo[currentItem]?.identifier
if let currentVideoId = currentVideoId {
// Call API to get the next video to be played from the server
dataLayer.getNextVideo(currentVideoId, playlistIdentifier: playlistId) {
video, error in
...
if let nextVideo = video {
let currentVideo: AVPlayerItem = self.queuePlayer.currentItem!
self.addVideoToQueue(nextVideo, after: currentVideo)
}
}
}
}
}
I have also instantiated the AVQueuePlayer using the code below as I thought there might be an issue with the initial queue setup but the issue remain:
AVQueuePlayer(playerItem: mainVideo)