Convert swift 2 video code into swift 3 video code - swift

The code below displays a video. It works perfect in swift 2 but in swift 3 xcode states that the MPMoivePlayerController code has been phased out. I just would like my video to be displayed in swift 3 like it was in swift 2.
import UIKit
import AVFoundation
import AVKit
import MediaPlayer
class video: UIViewController {
var moviePlayer : MPMoviePlayerController!
override func viewDidLoad() {
super.viewDidLoad()
let path = Bundle.main.path(forResource: "jxdo", ofType:"mp4")
let url = URL(fileURLWithPath: path!)
self.moviePlayer = MPMoviePlayerController(contentURL: url)
if let player = self.moviePlayer {
player.view.frame = CGRect(x: 67, y: 75, width: self.view.frame.size.width/2, height: self.view.frame.size.height / 5)
player.view.sizeToFit()
player.scalingMode = MPMovieScalingMode.aspectFit
player.isFullscreen = false
player.controlStyle = MPMovieControlStyle.default
player.movieSourceType = MPMovieSourceType.file
player.repeatMode = MPMovieRepeatMode.none
self.view.addSubview(player.view)

The MPMoviePlayerController has been deprecated and AVPlayerViewController should be used instead. See more on Apple's documentation page https://developer.apple.com/reference/mediaplayer/mpmovieplayercontroller
Also this thread might help in starting converting to the newer api: How to load MPMoviePlayerController contentUrl asynchronous when loading view?

Related

Video doesn't play full screen in a given view in swift. Need help fixing it

I have a view that plays video in app.
The constraints given are correct but some how in devices like iPhone 11, iPhone 11 pro the view leaves some space at trailing end.
Adding screenshots for reference.
*Need help fixing the video display to full view.
Constraints:
Align Trailing - Safe area
Align Top - Safe area
Align Leading - Safe area
Height Equals - 150
Code:
import UIKit
import AVFoundation
class VideoViewController: UIViewController {
#IBOutlet weak var videoView: UIView!
var player: AVQueuePlayer!
var playerItem: AVPlayerItem!
var playerLooper: AVPlayerLooper!
override func viewDidLoad() {
super.viewDidLoad()
videoView()
}
func videoViewForLogin() {
//video
guard let url = Bundle.main.url(forResource: "splashpanoslice", withExtension: "mp4") else {return}
let playerPath = AVPlayer(url: url)
player = AVQueuePlayer()
let playerLayer = AVPlayerLayer(player: player)
playerItem = AVPlayerItem(url: url)
let duration = Int64( ( (Float64(CMTimeGetSeconds(AVAsset(url: url).duration)) * 10.0) - 1) / 10.0 )
playerLayer.frame = videoView.bounds
playerLooper = AVPlayerLooper(player: player, templateItem: playerItem, timeRange: CMTimeRange(start: CMTime.zero, end: CMTimeMake(value: duration, timescale: 1)) )
playerLayer.videoGravity = .resizeAspectFill
videoView.layer.insertSublayer(playerLayer, at: 1)
player.play()
}
}
The function code is taken from a reference - How do i make a looping video in swift
Since you're using frames, I think you should try moving layout code later than viewDidLoad(). Perhaps, viewDidLayoutSubviews(), when the view size is determined and also invalidated when displaying parameters are changed (e.g. the screen orientation has changed).

Is there a good way to implement RealityKit into a Swift playground?

I want to be able to add a file created in Reality Composer into a Swift Playground for testing purposes. I also think it would be interesting to use as a supplement to a playbook. How would one go about adding an rcproject into a playground like the Experience.rcproject Apple provides with the scene “Box”?
You can read a .reality file format in Playground using the following code:
import Cocoa
import RealityKit
import PlaygroundSupport
let arView = ARView(frame: CGRect(x: 0, y: 0, width: 800, height: 200))
arView.environment.background = .color(.black)
let fileURL = Bundle.main.url(forResource: "main", withExtension: "reality")
let bowlingScene = try! Entity.load(contentsOf: fileURL!)
let anchor = AnchorEntity()
anchor.addChild(bowlingScene)
anchor.scale = [4,4,4]
anchor.position.y = -0.5
arView.scene.anchors.append(anchor)
PlaygroundPage.current.liveView = arView
So, supply a .playground file with a main.reality scene, making it nested.
About Swift Playgrounds for iPad read here.

Swift Mac OS - How to play another video/change the URL of the video with AVPlayer upon a button click?

I am new to swift and I am trying to make a Mac OS app that loops a video from the app's resources using AVPlayer as the background of the window once the app has been launched. When the user selects a menu item/clicks a button the background video will instantly change to a different video from the app's resources and start looping that video as the window's background.
I was able to play the first video once the app launches following this tutorial: (https://youtu.be/QgeQc587w70) and I also successfully made the video loop itself seamlessly following this post: (Looping AVPlayer seamlessly).
The problem I am now facing is changing the video to the other one once a menu item was selected/a button was clicked. The approach I was going for is to change the url and create a new AVPlayer using the new URL and affect it to the playerView.player following this post: (Swift How to update url of video in AVPlayer when clicking on a button?). However every time the menu item is selected the app crashes with the error "thread 1 exc_bad_instruction (code=exc_i386_invop subcode=0x0)". This is apparently caused by the value of playerView being nil. I don't really understand the reason for this as playerView is an AVPlayerView object that I created using the xib file and linked to the swift file by control-dragging and I couldn't seem to find another appropriate method of doing the thing I wanted to do. If you know the reason for this and the way of fixing it please provide me some help or if you know a better method of doing what I've mention above please tell me as well. Any help would be much appreciated!
My code is as follow, the line that crashes the app is at the bottom:
import Cocoa
import AppKit
import AVKit
import AVFoundation
struct videoVariables {
static var videoName = "Test_Video" //declaring the video name as a global variable
}
var videoIsPlaying = true
var theURL = Bundle.main.url(forResource:videoVariables.videoName, withExtension: "mp4") //creating the video url
var player = AVPlayer.init(url: theURL!)
class BackgroundWindow: NSWindowController {
#IBOutlet weak var playerView: AVPlayerView! // AVPlayerView Linked using control-drag from xib file
#IBOutlet var mainWindow: NSWindow!
#IBOutlet weak var TempBG: NSImageView!
override var windowNibName : String! {
return "BackgroundWindow"
}
//function used for resizing the temporary background image and the playerView to the window’s size
func resizeBG() {
var scrn: NSScreen = NSScreen.main()!
var rect: NSRect = scrn.frame
var height = rect.size.height
var width = rect.size.width
TempBG.setFrameSize(NSSize(width: Int(width), height: Int(height)))
TempBG.frame.origin = CGPoint(x: 0, y: 0)
playerView!.setFrameSize(NSSize(width: Int(width), height: Int(height)))
playerView!.frame.origin = CGPoint(x: 0, y: 0)
}
override func windowDidLoad() {
super.windowDidLoad()
self.window?.titleVisibility = NSWindowTitleVisibility.hidden //hide window’s title
self.window?.styleMask = NSBorderlessWindowMask //hide window’s border
self.window?.hasShadow = false //hide window’s shadow
self.window?.level = Int(CGWindowLevelForKey(CGWindowLevelKey.desktopWindow)) //set window’s layer as desktopWindow layer
self.window?.center()
self.window?.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
if let screen = NSScreen.main() {
self.window?.setFrame(screen.visibleFrame, display: true, animate: false) //resizing the window to cover the whole screen
}
resizeBG() //resizing the temporary background image and the playerView to the window’s size
startVideo() //start playing and loop the first video as the window’s background
}
//function used for starting the video again once it has been played fully
func playerItemDidReachEnd(notification: NSNotification) {
playerView.player?.seek(to: kCMTimeZero)
playerView.player?.play()
}
//function used for starting and looping the video
func startVideo() {
//set the seeking time to be 2ms ahead to prevent a black screen every time the video loops
let playAhead = CMTimeMake(2, 100);
//loops the video
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object:
playerView.player?.currentItem, queue: nil, using: { (_) in
DispatchQueue.main.async {
self.playerView.player?.seek(to: playAhead)
self.playerView.player?.play()
}
})
var playerLayer: AVPlayerLayer?
playerLayer = AVPlayerLayer(player: player)
playerView?.player = player
print(playerView?.player)
playerLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
player.play()
}
//changing the url to the new url and create a new AVPlayer then affect it to the playerView.player once the menu item is being selected
#IBAction func renderBG(_ sender: NSMenuItem) {
videoVariables.videoName = "Test_Video_2"
var theNewURL = Bundle.main.url(forResource:videoVariables.videoName, withExtension: "mp4")
player = AVPlayer.init(url: theNewURL!)
//!!this line crashes the app with the error "thread 1 exc_bad_instruction (code=exc_i386_invop subcode=0x0)" every time the menu item is being selected!!
playerView.player = player
}
}
Additionally, the background video is not supposed to be interactive(E.g. User cannot pause/ fast-forward the video), so any issues that might be caused by user interactivity can be ignored. The purpose of the app is to play a video on the user's desktop creating the exact same effect of running the command:
"/System/Library/Frameworks/ScreenSaver.framework/Resources/
ScreenSaverEngine.app/Contents/MacOS/ScreenSaverEngine -background" in terminal.
Any help would be much appreciated!
You don't need to create AVPlayer from url. There is AVPlayerItem class to manipulate player playback queue.
let firstAsset = AVURLAsset(url: firstVideoUrl)
let firstPlayerItem = AVPlayerItem(asset: firstAsset)
let player = AVPlayer(playerItem: firstPlayerItem)
let secondAsset = AVURLAsset(url: secondVideoUrl)
let secondPlayerItem = AVPlayerItem(asset: secondAsset)
player.replaceCurrentItem(with: secondPlayerItem)
Docs about AVPlayerItem

AVPlayer not showing startup spinner

I am trying to play a remote mp4 video on tvOS in my application. There is a small problem, when i set the AVPlayerViewController.view.frame = self.view.frame then the spinner doesn't appear until the videos loads up. However, if I set AVPlayerViewController.view.frame = CGRectMake(0.0, 0.0, 1920.0, 1079.0) it works perfectly fine. The spinner loads up in the start and then the video appears.
import UIKit
import AVKit
class PlayViewController : UIViewController {
var avplayerVC : AVPlayerViewController?
var videoUrlStr : String?
override func viewDidLoad() {
super.viewDidLoad()
print("In PlayViewController View Did Load")
avplayerVC = AVPlayerViewController()
let avAsset = AVAsset(URL: NSURL.init(string: videoUrlStr!)!)
let avPlayerItem = AVPlayerItem(asset: avAsset)
avplayerVC?.player = AVPlayer(playerItem: avPlayerItem)
avplayerVC?.player?.seekToTime(kCMTimeZero)
avplayerVC?.player?.addObserver(self, forKeyPath: "status", options: .New, context: nil)
avplayerVC?.player?.play()
print("Status 1: " + "\(avplayerVC?.player?.status.rawValue)")
print(self.view?.frame)
// doesn't work
//avplayerVC?.view.frame = self.view.frame
// doesn't work
//avplayerVC?.view.frame = CGRectMake(0.0, 0.0, 1920.0, 1080.0)
// works fine
avplayerVC?.view.frame = CGRectMake(0.0, 0.0, 1920.0, 1079.0)
self.view.addSubview((avplayerVC?.view!)!)
}
}
I also tried to put log for print(self.view?.frame) in viewDidLoad and it prints out (0.0 0.0; 1920.0,1080.0).

MPMoviePlayerController ignores MPMovieControlStyle.None in Swift

I'm trying to autoplay a video in my app. The video needs to play without the controls.
I've set up the video and the settings, including MPMovieControlStyle.None but the video controls appear for about 2 seconds before disappearing. I have no idea why.
I've used this code (exact code) for another project and it works well, but here for some reason it will not.
override func viewDidLoad() {
super.viewDidLoad()
generateVideo()
}
func generateVideo () {
let movieURL = NSBundle.mainBundle().pathForResource("video", ofType: "mp4")
let videoFilePath = NSURL(fileURLWithPath: movieURL!)
self.view.addSubview(MoviePlayerViewController.moviePlayer.view)
self.view.sendSubviewToBack(MoviePlayerViewController.moviePlayer.view)
MoviePlayerViewController.moviePlayer.contentURL = videoFilePath
MoviePlayerViewController.moviePlayer.shouldAutoplay = true
MoviePlayerViewController.moviePlayer.prepareToPlay()
MoviePlayerViewController.moviePlayer.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)
MoviePlayerViewController.moviePlayer.fullscreen = true
MoviePlayerViewController.moviePlayer.controlStyle = MPMovieControlStyle.None
MoviePlayerViewController.moviePlayer.play()
MoviePlayerViewController.moviePlayer.repeatMode = MPMovieRepeatMode.One
MoviePlayerViewController.moviePlayer.scalingMode = MPMovieScalingMode.AspectFit
}
Any idea why this is happening?
After checking how the view is loaded I'm sure the problem is there.
I used a different layout with one Storyboard calling another storyboard and that was the source of the problem.