I have a video which I want to download from a server and stream it in a fixed view.
I've set a UIView in my storyboard with fixed constraints, and here is what I've done in code:
#IBOutlet weak var videoView: UIView!
var player: AVPlayer!
var avpController = AVPlayerViewController()
And in my viewDidLoad I've done this:
let url = URL(string:myURL)
player = AVPlayer(url: url!)
avpController.player = player
avpController.videoGravity = AVLayerVideoGravity.resizeAspect.rawValue
self.addChildViewController(avpController)
avpController.view.frame = videoView.frame
self.containerView.addSubview(avpController.view)
videoView.layer.masksToBounds = true
My problem is my video is not with the size that I've set to videoView and in every device my video is in a different size. In some devices, the video height is larger than the height that I've set and it overlays the items that I have below videoView. How can I play video in a view in a right way?
If you want to use AVPlayerViewController:
let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(url: videoURL!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
For AVPlayer:
let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(url: videoURL!)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.bounds
self.view.layer.addSublayer(playerLayer)
player.play()
the only way to add a video to a UIView with fixed constraints in storyboard, was this :
let url = URL(string:myURL)
player = AVPlayer(url: url!)
avpController.player = player
avpController.view.frame.size.height = videoView.frame.size.height
avpController.view.frame.size.width = videoView.frame.size.width
self.videoView.addSubview(avpController.view)
I hope other can use this! :)
You can try to use AVPlayerLayer in a AVPlayer.
let player = AVPlayer(url: video) // your video url
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = videoView.bounds
videoView.layer.addSublayer(playerLayer)
player.play()
This is how you can add and remove player in uiview.
var player: AVPlayer?
var playerController: AVPlayerViewController?
func removePlayer() {
player?.pause()
player = nil
playerController?.player?.pause()
playerController?.player = nil
if let view = playerController?.view {
videoView.willRemoveSubview(view)
}
playerController?.view.removeFromSuperview()
playerController = nil
}
func setVideo(url: URL) {
removePlayer()
player = AVPlayer(url: url)
playerController = AVPlayerViewController()
playerController?.player = player
self.videoView.addSubview((playerController?.view)!)
playerController?.view.frame = CGRect(x: 0, y: 0, width: self.videoView.bounds.width, height: self.videoView.bounds.height)
// player.play()
}
Related
The login screen I am designing is near complete but fails to properly display both the username and password textfields once the view controller loads
The following function executes when the view loads - it properly plays the video and displays both the image and loginButton correctly, it appears to also appears to display the textfields for a split second until the video fully loads and plays.
func playVideo() {
guard let path = Bundle.main.path(forResource: "videoFile", ofType: "mp4") else {
return
}
let asset: AVAsset = AVAsset(url: URL(fileURLWithPath: path))
let playerItem = AVPlayerItem(asset: asset)
let queuePlayer = AVQueuePlayer(playerItem: playerItem)
self.playerLooper = AVPlayerLooper(player: queuePlayer, templateItem: playerItem)
let playerLayer = AVPlayerLayer(player: queuePlayer)
playerLayer.frame = self.view.bounds
playerLayer.videoGravity = .resizeAspectFill
self.videoLayer.layer.addSublayer(playerLayer)
queuePlayer.play()
videoLayer.bringSubviewToFront(img)
videoLayer.bringSubviewToFront(usernameTF)
videoLayer.bringSubviewToFront(passwordTF)
videoLayer.bringSubviewToFront(signinButton)
}
Any ideas what could be causing this?
You can change this code according to your need.
var player : AVPlayer?
var playerViewController : AVPlayerViewController?
func playLiveUrl(url:String){
let videoURL = URL(string: "http://bla blah.com")
self.player = AVPlayer(url: videoURL!)
self.playerViewController = AVPlayerViewController()
playerViewController?.player = self.player
playerViewController?.view.frame = self.topPlayerView.frame
playerViewController?.player?.play()
self.topPlayerView.addSubview(playerViewController?.view ?? UIView()) // Container topPlayerView which contains a player
}
var topPlayerView : UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .black
return view
}()
I don't understand why it is not working. I pass a videoURL trough a segue to a another ViewController. This works fine.
In the other ViewController I want to play the video. But for some reason it is not working.
I unwrap the URL with optional binding. But playerLayer does not accept the URL. It says always nil.
This is the URL: VideoURL Optional(file:///var/mobile/Containers/Data/Application/517BA864-F5CB-4E2C-BE54-D42555569266/Documents/3d.mov)
My code:
var player: AVPlayer?
var playerLayer: AVPlayerLayer?
var videoURL: URL?
func playVideo() {
if let _videoURL = videoURL {
player = AVPlayer(url: _videoURL)
playerLayer = AVPlayerLayer(layer: player!)
playerLayer?.frame = contentView.layer.bounds
playerLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
self.contentView.layer.addSublayer(playerLayer!)
player?.play()
}
Try creating an AVURLAsset and an AVPlayerItem. Then pass that AVPlayerItem into the AVPlayer rather than trying to use the URL init.
I tested this with a sample video I downloaded from here. Note there is no sound in this video.
import UIKit
import AVFoundation
class ViewController: UIViewController {
private let videoUrl = Bundle.main.url(forResource: "file_example_MOV_1920_2_2MB", withExtension: "mov")!
private var videoPlayer: AVPlayer?
private var playerLayer: AVPlayerLayer?
override func viewDidLoad() {
super.viewDidLoad()
playVideo()
}
func playVideo() {
let asset = AVURLAsset(url: videoUrl)
let primaryPlayerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: primaryPlayerItem)
let videoLayer = AVPlayerLayer(player: player)
videoLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
videoLayer.frame = view.bounds
view.layer.addSublayer(videoLayer)
videoPlayer = player
playerLayer = videoLayer
videoPlayer?.play()
}
}
Try the below code. It's working.
var player: AVPlayer!
var playerLayer: AVPlayerLayer!
func playVideo() {
if let url = videoURL {
do {
let item:AVPlayerItem = AVPlayerItem(url: url)
player = AVPlayer(playerItem: item)
playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = contentView.bounds
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
self.contentView.layer.addSublayer(playerLayer)
player.play()
} catch {
print("Error1", error.localizedDescription)
}
}
}
i want to show .mov file in custom size. i have an xib file for my controller.
thats top view is subclass of UIView. i want to show video in this view.
there is my code for create video view. but there is problem in size of my video player. how can solve this problem.
there is my code :
private func playVideo() {
guard let path = Bundle.main.path(forResource: "video_2017-06-30_15-49-05", ofType:"mov") else {
debugPrint("video.m4v not found")
return
}
let player = AVPlayer(url: URL(fileURLWithPath: path))
let playerController = AVPlayerViewController()
playerController.player = player
let avPlayerLayer = AVPlayerLayer(player: player)
avPlayerLayer.frame = videoView.layer.frame
videoView.layer.insertSublayer(avPlayerLayer, at: 0)
}
If you want a native player to be added to your view with the seek bar and play pause button then use following code:
private func playVideo() {
guard let path = Bundle.main.path(forResource: "SampleVideo", ofType:"mp4") else {
debugPrint("video.m4v not found")
return
}
let player = AVPlayer(url: URL(fileURLWithPath: path))
let playerController = AVPlayerViewController()
playerController.player = player
playerController.view.frame = videoView.bounds
videoView.addSubview(playerController.view)
player.play()
}
and if you want just the video to be played in your view with AVPlayerLayer then you can do something like below:
var player : AVPlayer!
var avPlayerLayer : AVPlayerLayer!
#IBOutlet weak var videoView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
guard let path = Bundle.main.path(forResource: "SampleVideo", ofType:"mp4") else {
debugPrint("video.m4v not found")
return
}
player = AVPlayer(url: URL(fileURLWithPath: path))
avPlayerLayer = AVPlayerLayer(player: player)
avPlayerLayer.videoGravity = AVLayerVideoGravity.resize
videoView.layer.addSublayer(avPlayerLayer)
playVideo()
}
override func viewDidLayoutSubviews() {
avPlayerLayer.frame = videoView.layer.bounds
}
private func playVideo() {
player.play()
}
This worked perfect for me hope it works for you :)
I have a local video playing using AVPlayer and AVPlayerLayer (Swift, iOS 8.2), and i need to resize the AVPlayerLayer (introPlayerLayer) when its parent view (introView) is resized, including on orientation change. So far nothing I have tried seems to work and the playerLayer has the wrong size and position.
The AVPlayer is set up using a local mp4 video, and the AVPlayerLayer is initialized using that player. The layer is then added as a sublayer to the parent view.
Here is my code:
func playIntro() {
let path = NSBundle.mainBundle().pathForResource("intro", ofType: "mp4")
let url = NSURL.fileURLWithPath(path!)
let introPlayer = AVPlayer(URL: url)
introPlayer.allowsExternalPlayback = false
var introPlayerLayer = AVPlayerLayer(player: introPlayer)
introView.layer.addSublayer(introPlayerLayer)
introPlayerLayer.frame = introView.bounds
NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerDidFinishPlaying:", name: AVPlayerItemDidPlayToEndTimeNotification, object: introPlayer.currentItem)
introView.hidden = false
introPlayer.play()
}
Should I be adding the AVPlayerLayer as a sublayer of the UIView, or should I be subclassing the parent container (UIView) as shown in the "The Player View" section of https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/02_Playback.html. If so, how would I write that PlayerView subclass (shown in Objective-C) in Swift?
Thank you in advance for any assistance.
Swift 3.
private func playVideo() {
guard let path = Bundle.main.path(forResource: "video", ofType:"mp4") else {
debugPrint("video.m4v not found")
return
}
let player = AVPlayer(url: URL(fileURLWithPath: path))
var playerLayer: AVPlayerLayer?
playerLayer = AVPlayerLayer(player: player)
playerLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
playerLayer!.frame = self.view.frame
self.view!.layer.addSublayer(playerLayer!)
player.play()
}
I was able to do what you are trying to do, I think, in my own project. This is without subclassing. Here is my code:
override func viewWillLayoutSubviews() {
previewScene()
}
func previewScene() {
var firstAsset: AVAsset!, secondAsset: AVAsset!, thirdAsset: AVAsset!
firstAsset = MediaController.sharedMediaController.s3Shot1
secondAsset = MediaController.sharedMediaController.s3Shot2
thirdAsset = MediaController.sharedMediaController.s3Shot3
if firstAsset != nil && secondAsset != nil && thirdAsset != nil {
let assets = [firstAsset, secondAsset, thirdAsset]
var shots = [AVPlayerItem]()
for item in assets {
let shot = AVPlayerItem(asset: item)
shots.append(shot)
}
self.videoPlayer = AVQueuePlayer(items: shots)
self.playerLayer = AVPlayerLayer(player: self.videoPlayer)
self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
AVPlayerItemDidPlayToEndTimeNotification, object: self.videoPlayer.items().last)
self.videoPreviewLayer.layer.addSublayer(playerLayer)
self.playerLayer.frame = self.videoPreviewLayer.bounds
}
}
introView.layer.masksToBounds = true
may also be helpful
I have a View inside a ViewController that I want to add a move player controller to it. But so far I'm only getting a black screen.
I'm running this on the simulator, and using the apple dev stream which I tested in Safari and it works.
The videoView is added to the controller through an IBOutlet. I'm using Xcode 6 beta 7.
This is all inside a UIViewController.
Declaration of videoView 320x320 (global):
#IBOutlet var videoView: UIView!
Declaration of MPMoviePlayerController (global):
var videoPlayer : MPMoviePlayerController = MPMoviePlayerController()
Adding videoPlayer to View:
videoURLWithPath = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"
let videoURL = NSURL(fileURLWithPath: videoURLWithPath)
videoPlayer.movieSourceType = MPMovieSourceType.Streaming;
videoPlayer.contentURL = videoURL
videoPlayer.view.frame = videoView.bounds
videoView.addSubview(videoPlayer.view)
videoPlayer.controlStyle = MPMovieControlStyle.Embedded
videoPlayer.prepareToPlay()
videoPlayer.play()
Storyboard:
Simulator:
Update:
I've also tried doing this. Super simple. And I'm still getting the same result. The frame size is set that way so that I can see that the player has actually been added.
let streamURL = NSURL(string: "http://www.thumbafon.com/code_examples/video/segment_example/prog_index.m3u8")
var streamPlayer = MPMoviePlayerController(contentURL: streamURL)
streamPlayer.view.frame = CGRect(x: 10, y: 10, width: 200, height: 200)
streamPlayer.controlStyle = MPMovieControlStyle.Embedded
videoView.addSubview(streamPlayer.view)
streamPlayer.play()
I ended up ditching MPMoviePlayerController and opted to use AVFoundation instead.
Working example:
Global declarations:
var player : AVPlayer? = nil
var playerLayer : AVPlayerLayer? = nil
var asset : AVAsset? = nil
var playerItem: AVPlayerItem? = nil
inside viewDidLoad:
let videoURLWithPath = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"
let videoURL = NSURL(string: videoURLWithPath)
asset = AVAsset.assetWithURL(videoURL) as? AVAsset
playerItem = AVPlayerItem(asset: asset)
player = AVPlayer(playerItem: self.playerItem)
playerLayer = AVPlayerLayer(player: self.player)
playerLayer!.frame = videoView.frame
videoView.layer.addSublayer(self.playerLayer)
player!.play()
Rather than using MPMoviePlayerController, this works perfectly for me:
// import MediaPlayer
var moviePlayer : MPMoviePlayerViewController?
#IBAction func playVideo() {
let path = NSBundle.mainBundle().pathForResource("ra3", ofType:"mp4")
let url = NSURL.fileURLWithPath(path!)
let videoURL = url
moviePlayer = MPMoviePlayerViewController(contentURL: videoURL )
if let player = moviePlayer {
player.view.frame = self.view.bounds
self.presentViewController(moviePlayer!, animated: true, completion: nil)
}
else {
NSLog("no player")
}
}