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.
Related
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?
In one of my ViewControllers, I have an AVPlayerViewController. In my viewDidLoad I have
self.videoPlayerController = [AVPlayerViewController new];
Then, I play a video using the following method
- (void)playVideo:(NSURL*)videoURL {
[self presentViewController:self.videoPlayerController animated:YES completion:^(){
AVPlayer *player = [[AVPlayer alloc] initWithURL:videoURL];
[self.videoPlayerController setVideoGravity:AVLayerVideoGravityResizeAspect];
[self.videoPlayerController setPlayer:player];
[self.videoPlayerController.player play];
}];
}
When playing a video for the first time, the AVPlayerViewController appears, but the video is stuck on the first frame, and will not play. No audio plays either.
In iOS 10.0, the seekbar in the on screen controls show that the video is playing (it will progress to the end). In iOS 10.2 however, the seekbar is stuck at 0:00 as well.
I am experiencing this problem on iPads with iOS versions 10.0 and 10.2, however, it works in the XCode simulator (both 10.0 and 10.2).
My problem is similar in nature to this.
Also, the video plays correctly if you close the ViewController containing the AVPlayerViewController, reopen it, and attempt to play the video again.
I guess that the problem is in your video file. Try to download another video mp4 video sample. Add it to your project and try.
while playing remote HLS videos,
I am re-initializing AVQueue player which is already initialized with items by using
(AVQueuePlayer *)initWithItems:(NSArray<AVPlayerItem *> *)items
However, by doing this sound plays in background but the AVPlayerLayer is stuck at the last frame of the previous video, the video does not update. In order to make sure that video gets updated, I need to remove the previous layer for UIView of video player, re-create the new AVPlayerLayer and assign it to the UIView for player using following :
[oldAVPlayerLayer removeFromSuperLayer]
[newAVPlayerLayer playerLayerWithPlayer: myAVQueuePlayer]
[myViewForPlayerLayer addSublayer : newAVPlayerLayer]
This causes a flicker on the screen, which is okay if the device was just an iPhone/iPad, but problem is with abrupt Airplay behaviour, causing the UISlider for sound to show in the remote controls.
Is there a way to re-initialize the AVQueuePlayer without recreating or reassigning the AVPlayerLayer?
Ended up using AVPlayer instead of AVQueuePlayer, and using method
replaceCurrentItemWithPlayerItem
Does not cause the glitch in airplay, and saves the memory as well since the items are instantiated as and when required.
I am trying to play a HLS stream using AVPlayer. The player plays the stream fine, however, after navigating away from the player view, it does not seem to stop downloading data for the HLS stream. I see a network data spinner on the status bar for a few minutes after navigating away from the AVPlayer view.
I have tried cancelPendingSeeks, cancelLoading, and tried removing the AVPlayerLayer from its superlayer using removeFromSuperLayer, however, none of these seems to solve the issue — there is still a spinner on the status bar.
This spinner is seen on actual device, but there is no spinner on the simulator. I am certain the video is being downloaded; I can see the data usage in network monitoring apps. How can I fix this?
Call pause on your AVPlayer object, then replace the item with a nil item, and set your video player to nil.
[anAVPlayerObject pause];
[anAVPlayerObject replaceCurrentItemWithPlayerItem:nil];
anAVPlayerObject = nil;
When initialising a SKVideoNode with a video URL in iOS9 the behaviour changed to automatically starting the video as soon as the node is added, i.s.o. after the play method is called in previous versions of iOS.
doing the following inside the SKScene init
SKVideoNode* videoNode = [SKVideoNode videoNodeWithVideoFileNamed:#"sample.m4v"];
[self addChild:videoNode];
is enough to see the video playing, while previous iOS versions (more logically) required to also call
[videoNode play];
before the video starts playing.
Is this an intended change? A possible workaround I see is always immediately calling pause after initialising a video but it's a bit weird this behaviour changed.
(it feels like a bug to be honest)
(I also found the iOS9 simulator to have issues with SKVideoNodes playing at all, you have to test this on a device)