PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0
Showing posts with label avplayerviewcontroller. Show all posts
Showing posts with label avplayerviewcontroller. Show all posts

Thursday, September 29, 2022

[FIXED] How can I make my video loop in swift with playerViewController?

 September 29, 2022     avplayerviewcontroller, swift, tvos, video, xcode     No comments   

Issue

I am trying to loop a video with playerViewController on Swift for TVOS. I have the video playing fine, but I want to loop the video. Here is my code so far:

override func viewDidAppear(_ animated: Bool) {
    let videoURL = URL(string: "https://url-to-video.com/video.mp4")
    let player = AVPlayer(url: videoURL!)
    let playerViewController = AVPlayerViewController()
    playerViewController.player = player        self.present(playerViewController, animated: true) {
        playerViewController.player!.play()
    }
}

Any help is appreciated. Thanks


Solution

The quickest way to do this is to use an AVQueuePlayer with an AVPlayerLooper. You can set the player on your player view controller the same as you would with an ordinary AVPlayer, but you need to keep a persistent reference around to the looper so it’ll keep working. In other words, add this to your view controller’s interface:

var looper: AVPlayerLooper?

…and in your viewDidAppear, replace this:

let player = AVPlayer(url: videoURL!)

with this:

let player = AVQueuePlayer()
looper = AVPlayerLooper(player: player, templateItem: AVPlayerItem(asset: AVAsset(url: videoURL!)))

Then, once you start the player playing, its video will loop indefinitely.



Answered By - Noah Witherspoon
Answer Checked By - Pedro (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

[FIXED] How to listen to Apple TV Remote in Objective-C?

 September 29, 2022     avplayer, avplayerviewcontroller, objective-c, tvos, uitapgesturerecognizer     No comments   

Issue

This seems like it should be pretty straight-forward but I'm having trouble finding a working example, good documentation, or even many StackOverflow posts that are helpful.

I have a custom view which contains an AVPlayer, like so:

@implementation
{
    @private
    AVPlayerViewController *controller
}

- (id) init
{
    self = [super init];
    if (self)
    {
        controller = [[AVPlayerViewController alloc] init];
        controller.view.frame = self.view.bounds;
        [self.view addSubview:controller.view];
    }
    return self;
}

@end

(I have a few other views like a message that overlays the player, a poster that I display while swapping videos, etc - but this is the basic setup)

When I integrated the IMA SDK, I started to have issues. If you press the pause button on the remote control during an ad, it pauses the ad just fine. But if you press the pause button again it doesn't unpause the ad, but instead unpauses my content player behind the ad. I don't hear any audio, but I know the content player was unpaused because I have ID3 metadata in my video and an NSLog() statement when I hit it, and I begin to see these logs. If I press the pause button again, the logs pause. I press it a fourth time, the logs start up again.

To try and fix this I wanted to bind a listener to the remote's play/pause button and make sure that if I was playing an ad then the ad was resumed, not the content. So I tried adding the following to my init method on my view:

        UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self.view action:@selector(tapped:)];
        [tapRecognizer setAllowedPressTypes:@[ [NSNumber numberWithInt:UIPressTypePlayPause] ]];
        [self.view addGestureRecognizer:tapRecognizer];

I then created the following method:

- (void) tapped: (UITapGestureRecognizer *) sender
{
    NSLog(@"Tapped");
}

This isn't being called. I'm pretty confident I made a simple mistake, but the documentation isn't very clear, so I'm not sure what I should be doing instead. The official documentation on detecting button presses uses Swift and says:

    let tapRecognizer = UITapGestureRecognizer(target: self, action: "tapped:")
    tapRecognizer.allowedPressTypes = [NSNumber(integer: UIPressType.PlayPause.rawValue)];
    self.view.addGestureRecognizer(tapRecognizer)

I believe I translated those three lines well. The documentation then doesn't show what the tapped method should look like, but instead goes on a tangent about working with low-level event handling. So to get the appropriate method signature I looked at the documentation on UITagGestureRecognizer which had the following (Swift) example for writing a handler:

func handleTap(sender: UITapGestureRecognizer) {
    if sender.state == .ended {
        // handling code
    }
}

This is why I went with - (void) tapped: (UITapGestureRecognizer *) sender

Still, after all of that, it's not working.

Quick Update

I tried replacing:

initWithTarget:self.view

With:

initWithTarget:controller.view

And:

self.view addGestureRecognizer

With:

controller.view addGestureRecognizer

And this time it looks like something actually happened when I pressed the play/pause button. The app crashed and Xcode gave me the following error:

2019-12-17 12:16:50.937007-0500 Example tvOS App[381:48776] -[_AVPlayerViewControllerContainerView tapped:]: unrecognized selector sent to instance 0x10194e060

So it seems like (correct me if I'm wrong):

  • The AVPlayerViewController has the focus, not my view
  • The gesture recognizer calls the selector on whatever class you register it to, rather than the class that did the registering

So I guess an alternative question to my original would be: How do I allow my class to handle a gesture on some other class (e.g. AVPlayerViewController)?


Solution

The target does not need to equal the view that the gesture recognizer is attached to. You can set the target to MyView but still attach the gesture recognizer to controller.view

To work around the unrecognized selector crash, you need to make sure you're providing the correct object as the target for your gesture recognizer. The way UIGestureRecognizer works is that when the gesture is recognized, it will invoke the given selector on the given target object. In other words, when gesture fires, it's going to perform the equivalent of:

[target selector:self];

(You seem to be treating the target as the view that the gesture will be attached to, which isn't how it works)

So if you implemented tapped: on your class MyView, then the target you pass to the gesture recognizer initializer should be an instance of MyView. You probably want to provide self, not self.view.



Answered By - Justin Voss
Answer Checked By - Willingham (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Wednesday, September 28, 2022

[FIXED] How to manage focus handling in AVPlayerViewController with custom controls?

 September 28, 2022     avplayerviewcontroller, tvos, uifocusguide     No comments   

Issue

I try to add a skip-intro-button (like Netflix) to the AVPlayerViewController of a tvOS movie app. I added it as subview to the contentOverlayView and when I let it appear I force giving it the focus with preferredFocusEnvironments. Everything's fine... Until the user navigates somewhere else (e.g. seek bar or video asset info view). The button then loses focus (expected) and never can be focused again by user interaction. I tried to:

  • add a UIFocusGuide()
  • put my button directly on the AVPlayerViewController's view
  • add a own subview, which contains the buttons to the AVPlayerViewController's view
  • add a own subview, which contains the buttons to the contentOverlayView
  • add several other buttons next to, below, above my button on the same subview (for each of the cases above)

The last approach shows that none of the other buttons can ever get focus by user interaction, so it seems, that, for the same reason, the skip-intro-button cannot be focused by the user. But what is this reason? What is the right practice to add custom interaction elements to AVPlayerViewController? Anyone any ideas?


Solution

Try to answer my main question "What is the right practice to add custom interaction elements to AVPlayerViewController?" myself:

Since I posted this question, 1.5 years ago, I didn't change the implementation of the skip intro feature very much. So whenever the user uses the remote, the button will lose focus and the only thing I changed is, that I hide the button whenever this happens, by implementing didUpdateFocus(in:with:), similar to this:

if let previouslyFocusedView = context.previouslyFocusedView {
    if previouslyFocusedView == skipIntroButton {
        changeSkipIntroButtonVisibility(to: 0.0)//animates alpha value
    }
}

(I'm not completely sure, why I don't set it to isHidden = true)

However, in the meantime I had to implement a more complex overlay to our player, i.e. a "Start Next Video / Watch Credits" thing, with a teaser, some buttons, a countdown/progress bar and more. With the problems described above, it is obvious, that I couldn't go with the contentOverlayView approach. So I decided to implement it the "traditional way", by presenting a complete UIViewController on top of the player's view, like this:

func showNextVideoOverlay() {
    guard let nextVideoTeaser = nextVideoTeaser else { return }
    let nextVideoOverlay = NextVideoAnnouncementViewController(withTeaser: nextVideoTeaser, player: player)
    nextVideoOverlay.nextVideoAnnouncementDelegate = self
    nextVideoOverlay.modalPresentationStyle = .overFullScreen
    present(nextVideoOverlay, animated: true, completion: nil)
}

Of course the NextVideoAnnouncementViewController is transparent, so video watching is still possible. I turned out that this straight forward approach works pretty well and I really don't know, why I haven't thought about it, when implementing skip intro.

My colleagues in QA found one tricky thing, you should be aware of (and I think, I remember, that this is different with different Devices and different remotes and on different tvOS versions - try it):

The overlying view controller blocks most of the commands coming from the remote, respectively you can navigate inside the view controller without affecting the player - except the play/pause button. That one will pause the player, but it's not possible to resume from there. This is, because a playing (av)player always listens to this button, while a paused one doesn't. So I also had to implement something like this:

func addRemoteButtonRecognizer() {
    let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(playPauseButtonPressed))
    tapRecognizer.allowedPressTypes = [NSNumber(value: UIPress.PressType.playPause.rawValue)]
        self.view.addGestureRecognizer(tapRecognizer)
}

@objc func playPauseButtonPressed(sender: AnyObject) {
    nextVideoAnnouncementDelegate?.remotePlayButtonPressed()
}

func remotePlayButtonPressed() {
    if player?.playerStatus == .paused {
        player?.play()
    } else {
        player?.pause()
    }
}

I hope this helps some of you, who come by here and find no other answer.



Answered By - Kai Huppmann
Answer Checked By - Robin (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

[FIXED] How to handle Menu Button action in tvOS remote

 September 28, 2022     avplayerviewcontroller, focus, presentviewcontroller, swift, tvos     No comments   

Issue

I am facing the strange problem with my application. Actually when i am presenting a view controller for play the video. At the video load time user press the menu button the application goes to background. While i have overwrite the Menu Button Action.

This is my code.

override func viewWillAppear(animated: Bool) {
    let menuPressRecognizer = UITapGestureRecognizer()
    menuPressRecognizer.addTarget(self, action: #selector(VideoPlayerViewController.menuButtonAction(_:)))
    menuPressRecognizer.allowedPressTypes = [NSNumber(integer: UIPressType.Menu.hashValue)]
    self.playerController.view.addGestureRecognizer(menuPressRecognizer)
}

func menuButtonAction(ges:UITapGestureRecognizer) {
    self.dismissView()
 }

Solution

This is my code and working for me.

Swift 3

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let menuPressRecognizer = UITapGestureRecognizer()
    menuPressRecognizer.addTarget(self, action: #selector(YourViewController.menuButtonAction(recognizer:)))
    menuPressRecognizer.allowedPressTypes = [NSNumber(value: UIPressType.menu.rawValue)]
    self.view.addGestureRecognizer(menuPressRecognizer)
}

func menuButtonAction(recognizer:UITapGestureRecognizer) {
    self.dismiss(animated: true, completion: nil)
}

Swift 4

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let menuPressRecognizer = UITapGestureRecognizer()
    menuPressRecognizer.addTarget(self, action: #selector(YourViewController.menuButtonAction(recognizer:)))
    menuPressRecognizer.allowedPressTypes = [NSNumber(value: UIPressType.menu.rawValue)]
    self.view.addGestureRecognizer(menuPressRecognizer)
}

@objc func menuButtonAction(recognizer:UITapGestureRecognizer) {
    self.dismiss(animated: true, completion: nil)
}

Swift 4.2 & 5

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let menuPressRecognizer = UITapGestureRecognizer()
    menuPressRecognizer.addTarget(self, action: #selector(YourViewController.menuButtonAction(recognizer:)))
    menuPressRecognizer.allowedPressTypes = [NSNumber(value: UIPress.PressType.menu.rawValue)]
    self.view.addGestureRecognizer(menuPressRecognizer)
}

@objc func menuButtonAction(recognizer:UITapGestureRecognizer) {
    self.dismiss(animated: true, completion: nil)
}


Answered By - anas.p
Answer Checked By - Gilberto Lyons (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

[FIXED] How to detect user selection of subtitles when using AVPlayerViewController

 September 28, 2022     avplayerviewcontroller, ios, tvos     No comments   

Issue

When using the AVPlayerViewController, the user is allowed to select whether the subtitles are on a specific language, off, or set to auto. Setting the requiresFullSubtitles property I can force the display of subtitles, but that is not what I want.

Is there a way to detect what the user has selected for the subtitle setting, whether a language is selected, off, or auto?

Now Playing Info Center


Solution

You can grab the currently selected language options & also grab the language info when it's used to set the subtitle or audio track, as described in "Adding Subtitles and Alternative Audio Tracks."

Available subtitles & audio tracks are found in an array of availableMediaCharacteristics for the video asset.

They're grouped in an AVMediaSelectionGroup by whether they are AVMediaCharacteristicAudible or AVMediaCharacteristicLegible ...

The currently selected option is found by:

`func selectedMediaOption(in mediaSelectionGroup: AVMediaSelectionGroup) -> AVMediaSelectionOption?`

It could return nil so "none," or it would return whatever language is selected. So you could set up some custom 'didChange' listener on that property. Doesn't seem to be any sort of publicly available notification for this, so you'd have to make your own.

Whenever you would select/set the subtitle option on the player, you could capture and use that same information to do whatever it is you intend to do with it:

if let group = asset.mediaSelectionGroup(forMediaCharacteristic: AVMediaCharacteristicLegible) {
    let locale = Locale(identifier: "es-ES")
    let options =
        AVMediaSelectionGroup.mediaSelectionOptions(from: group.options, with: locale)
    if let option = options.first {

        /*** DO WHATEVER YOU WANT HERE AFTER CAPTURING THE LANGUAGE SELECTION  & RETRIEVING AN AVAILABLE SUBTITLE ***/ 

       playerItem.select(option, in: group)
    }
}


Answered By - mc01
Answer Checked By - Willingham (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Older Posts Home
View mobile version

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
All Comments
Atom
All Comments

Copyright © PHPFixing