Popping back to subview speeds up video - ios

I have a UIView with a video as its background. When I present another subview, and then pop back to the one with the video, this happens:
Video [11 seconds] (kept it a video since a GIF wouldn't have the same framerate, and the problem would be less clear.)
As you can see, the video speeds up, and then slows down when it reaches a certain point. What I'd like to accomplish is for the video to always keep playing at it's normal speed, and thus eliminate the speedup happening.
This is the code used for the showing of the video:
self.player = AVPlayer(url: URL(fileURLWithPath: path))
let playerLayer = AVPlayerLayer(player: self.player)
self.layer.addSublayer(playerLayer)
playerLayer.frame = self.bounds
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
Does AVPlayer perhaps have an option to disable this, or is there a way around it?
Thanks.

I would assume this is happening because the video keeps playing while the other view controller is presented on the screen.
What I would try to solve this is to pause the video in viewWillDisappear and then play it again in viewWillAppear.

Related

AVPlayer video is freezing for some reason on rate 1

I am trying to play local videos in my app using AVPlayer and AVPlayerViewController. The problem is that when I try to play the video at some parts the video just starts freezing and playing 1 or 2 frames per second, while the audio sounds perfectly fine. It is not a heavy video (4.5 MB, 35 seconds long), it was exported at 25 fps(using adobe premiere).
I tried a couple of things to fix it, some of them fixed the freezes, but are not a good solution:
I exported the video at 15 frames per second, this made it run fine, but it was choppy since it was 15 fps.
I tried exporting the video at 150% speed, it ran smoothly.
Setting the rate to 0.75 made the video run smoothly.
Setting the rate higher made it freeze way more often.
For some reason when I started the video half way through at 15 seconds it didn't freeze.
This is what the code looks like:
let videoURL: URL = Bundle.main.url(forResource: currentComic?.getVideo(), withExtension: "mp4")!
player = AVPlayer(url: videoURL)
videoPlayerController.player = player
videoPlayerController.showsPlaybackControls = true
videoPlayerController.videoGravity = AVLayerVideoGravity.resizeAspectFill
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
self.present(videoPlayerController, animated: true, completion: nil)
var item = videoPlayerController.player!.currentItem
var previousPageCMTimeTag = CMTimeMakeWithSeconds(0, preferredTimescale: 1)
videoPlayerController.player!.seek(to: previousPageCMTimeTag)
videoPlayerController.player!.play()
player.rate = 1
videoPlayerController is a variable of AVPlayerViewController, and player is a variable of AVPlayer. I really hope someone can help me with this; it has been driving me crazy for the past few days.
I recently ran into the same issue and spent about a week diagnosing it.
Setting showsPlaybackControls while the AVPlayerViewController is onscreen will cause the video to freeze while the player continues playing audio-only.
The documentation for this property warns that setting this property while the player is visible "creates or destroys user interface elements", but we never thought it would destroy video playback entirely!
It's hard to tell if your code is doing this without seeing how else videoPlayerController is used, but make sure your AVPlayerViewController is not onscreen when mutating this property.

AVPlayer on Swift app shows a black screen but plays audio when playing video

New to Swift! I am trying to have the app play a video from my Resources upon pressing a button. I have this method in my ViewController:
if let path = Bundle.main.path(forResource: "Cypress", ofType: "mov") {
let player = AVPlayer(url: URL(fileURLWithPath: path))
// Create a new AVPlayerViewController and pass it a reference to the player.
let controller = AVPlayerViewController()
controller.player = player
// Modally present the player and call the player's play() method when complete.
self.present(controller, animated: true) {
player.play()
}
}
However, when the video begins to play, it is a black screen but the audio is playing properly. Are there any quick fixes to this? I am using Xcode version 12.2. Any advice would be greatly appreciated thanks :)
The problem is with the video file itself / the encoding.
Deceptively, the Quicktime ".mov" format is not a video codec, but rather audio/video container format that can contain video and audio (and some other things) in any number of compression codecs (h.264, mpeg2, ProRes, MJPEG, AAC, mp3, etc.) … Your files don't work because they include video compressed with a codec which iOS does not support.
From #alexkent in this SO answer on another post.
I don't think a .mov is necessarily not going to work for you, but you'd have to make sure it was encoded in a way that is iOS-compatible. So as you mentioned in the comments, using .mp4 ensures the video is encoded in an iOS-compatible fashion.

iOS controls not reappearing when touching screen

I have a basic iOS AVPlayer configured as follows:
let player = AVPlayer(url: URL(string: <some video file URL>)!)
let controller = AVPlayerViewController()
controller.player = player
self.present(controller, animated: true, completion: { player.play() })
When this code is called with a video URL, a full-screen player opens with visible controls where the video appears and auto-plays. After a few seconds the controls auto-hide, and reappear when the screen is touched. (Tested with XCode 10.0)
Now I want to play audios in the same way, i.e. in full-screen and with the same controls. I saw in the documentation that AVPlayer also accepts mp3 files. Indeed, when I just pass an audio URL to the code above, it displays the control buttons and plays the audio. (NB: I first want things to work just with black screen and will later add a poster image.)
However: unlike with videos, when the controls disappear (for some reason they don't auto-hide but they can still disappear, e.g. maybe after locking/unlocking the screen), they do not reappear upon touching the screen. The user then has no way to pause or exit the player and is forced to kill the app.
How can I make sure that the controls show up when touching the screen?

Embedding videos in iOS app

I'm fairly new to iOS development, but I'm confident with the basics (basic interface, user interaction, logic). What I want to do now is create an app that streams/downloads a video from a personal recording website (so login required by user), and then allows basic editing (trimming) and sharing to different social media, like twitter, facebook, youtube, etc... I have absolutely no experience with this.
My research so far has pointed me towards webViews and use of AVKit import, and they seem appropriate, but I was hoping for more concrete advice.
What do I look into? Where can I start?
Its pretty easy to give a URL to AVPlayer and have it stream a video into the layer. I usually add the layer into a view and use autolayout on that view to resize it (although you can also subclass UIView and override layerClass and make the videoLayer the view's backing layer if you want). This code will stream from a remote URL or if you download the file to the documents directory and get a URL to it you can play a local file also.
let playerLayer = AVPlayerLayer()
let player = AVPlayer(playerItem: AVPlayerItem(asset: AVAsset(url: url), automaticallyLoadedAssetKeys: ["playable"]))
playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
playerLayer.frame = videoView.bounds
videoView.isHidden = false
videoView.layer.addSublayer(playerLayer)
playerLayer.player?.play()

AVPlayer blank video: playing sound but no video

This question has the same problem, but the solutions didn't work.
The AVPlayer sometimes plays a blank video: there is sound but no video.
While blank videos were played, we printed the frame and status of the player. The frame was non-zero and was correctly set. The status was also readyToPlay. The play function is also invoked on the main thread.
In other words, the frame for the player layer is valid, and the player is also ready to play. Yet no video appears, even though sound does.
The issue seems to be a timing one. If we wait 5-10 seconds before playing the video, the video works fine each time.
This issue appears on iOS 10, not iOS 8 or 9.
This thread on the Apple forums suggests it might be a bug related to
AVVideoCompositionCoreAnimationTool, which we also use.
Any solutions?
This happens more often on iPhone 7 devices than iPhone 5s devices.
Code:
fileprivate func playVideo(_ videoURL: String, prompt: String) {
// Show <playerView>
playerView.isHidden = false
// Use new video in player
playerItem = AVPlayerItem(url: URL(fileURLWithPath: videoURL))
print("STATUS: \(player.status == AVPlayerStatus.readyToPlay). FRAME: \(playerLayer.frame). MAIN THREAD: \(Thread.isMainThread)")
player.replaceCurrentItem(with: playerItem)
// Start playing video
player.seek(to: kCMTimeZero)
player.actionAtItemEnd = .none
player.play()
}
I think you need to play with a AVPlayerViewController or AVPlayerLayer.
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
//set player layer frame and attach it to our view
playerLayer.frame = self.containerView.bounds;
[self.containerView.layer addSublayer:playerLayer];
//play the video
[player play];
From Apple doc:
AVPlayer and AVPlayerItem are nonvisual objects meaning that on their
own are unable to present an asset’s video on screen. You have two
primary approaches you can use to present your video content on
screen:
AVKit: The best way to present your video content is by using the
AVKit framework’s AVPlayerViewController class in iOS and tvOS or the
AVPlayerView class in macOS. These classes present the video content,
along with playback controls and other media features giving you a
full-featured playback experience.
AVPlayerLayer: If you are building a custom interface for your player,
you use a Core Animation CALayer subclass provided by AVFoundation
called AVPlayerLayer. The player layer can be set as a view’s backing
layer or can be added directly to the layer hierarchy. Unlike
AVPlayerView and AVPlayerViewController, a player layer doesn’t
present any playback controls, but simply presents the visual content
on screen. It is up to you to build the playback transport controls to
play, pause, and seek through the media.
In case anyone encounters this issue, the problem seems related to an iOS bug. The problem doesn't occur on iOS 8/9 devices, only on new iOS 10 devices. Starting with iOS 10.2, the problem vanishes.
Unfortunately, still no programmatic solution for 10.0.x or 10.1.x.

Resources