Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw button on top of AVPlayer

I have to draw a label or button on top of video relay next previous , leave comment . List of video have it, once user select one item from the table,it need to play, Once player play finished, those buttons or label should come on top of video

Here is my code :

comPlayerControl = AVPlayerViewController()

if let player = comPlayerControl {

    let videoURL: String = "http://cdnapi.kaltura.com/p/11/sp/11/playManifest/entryId/"+selectedSubmission.transcodeRefId+"/format/applehttp/protocol/http/a.m3u8"
    let playerItem = AVPlayerItem(URL: NSURL(string: videoURL)! )
    commmentPlayer = AVPlayer(playerItem: playerItem)
    player.player = commmentPlayer
    player.view.frame = videoCell.frame
    player.view.sizeToFit()

    player.showsPlaybackControls = true
    NSNotificationCenter.defaultCenter().addObserver(
        self, 
        selector: #selector(CommentsTableViewController.playerDidFinishPlaying(_:)),
        name: AVPlayerItemDidPlayToEndTimeNotification, 
        object: playerItem
    )

    comPlayerControl.delegate = self
    videoCell.addSubview(player.view)
}

func playerDidFinishPlaying(note: NSNotification) {
    print("Video Finished")
    let DynamicView=UIView(frame: CGRectMake(100, 200, 100, 100))
    DynamicView.backgroundColor=UIColor.greenColor()
    DynamicView.layer.cornerRadius=25
    DynamicView.layer.borderWidth=2
    DynamicView.layer.zPosition = 1;
    comPlayerControl.view.addSubview(DynamicView)
}

requirement like this

requirement image

like image 587
Piraba Avatar asked Apr 02 '16 03:04

Piraba


4 Answers

You're using an AVPlayerViewController, so there's no reason to access your application's window like in Alessandro Ornano's answer. Why reinvent the wheel? Every AVPlayerViewController has a contentOverlayView property which allows you to place views between the player and the controls.

First, create a new AVPlayerItem and listen for the AVPlayerItemDidPlayToEndTimeNotification notification on that item. Load the item into your player and begin playback.

Once the item completes, the selector your specified to listen for the AVPlayerItemDidPlayToEndTimeNotification notification will be called. In that selector, access the contentOverlayView directly and add your buttons:

In some view controller or other object:

let playerVC = AVPlayerViewController()

// ...

func setupPlayer {

    let playerItem = AVPlayerItem(...)
    playerVC.player?.replaceCurrentItemWithPlayerItem(playerItem)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(VC.itemFinished), name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem)
    self.presentViewController(playerVC, animated: true) { 
        self.playerVC.player?.play()
    }
}

func itemFinished() {
    let btn = UIButton(type: .System)
    btn.addTarget(self, action: #selector(VC.buttonTapped), forControlEvents: .TouchUpInside)
    self.playerVC.contentOverlayView?.addSubview(btn)
}

func buttonTapped() {
    print("button was tapped")
    // replay/comment logic here
}

As stated in the comments (and a rejected edit), buttons may not work in the contentOverlayView. For an alternate solution, see Pyro's answer.

You could also subclass AVPlayerViewController and do everything inside an instance of your subclass, but Apple warns against that:

Do not subclass AVPlayerViewController. Overriding this class’s methods is unsupported and results in undefined behavior.

like image 96
JAL Avatar answered Nov 06 '22 19:11

JAL


I recommend looking up AVPlayerLayer as a way to show buttons and other content on top of your video.

See the Advances in AVFoundation Playback WWDC presentation.

Also, check out the AVFoundationSimplePlayer-iOS example project.

Essentially, you create a view to host your player, and you make the layer behind the view into an AVPlayerLayer.

class PlayerView: UIView {
    var player: AVPlayer? {
        get {
            return playerLayer.player
        }

        set {
            playerLayer.player = newValue
        }
    }

    var playerLayer: AVPlayerLayer {
        return layer as! AVPlayerLayer
    }

    override class var layerClass: AnyClass {
        return AVPlayerLayer.self
    }
}
like image 30
Chris Livdahl Avatar answered Nov 06 '22 18:11

Chris Livdahl


I think the best way to make the avplayer buttons is explained here: IOS 8 Video Playback using AVPlayer and AVPlayerViewController .

So , I prefeer and agree with these instructions, but if you still want to add these buttons you can try to add them to the self.window

if let app = UIApplication.sharedApplication().delegate as? AppDelegate, let window = app.window {
        let myFirstButton = UIButton()
        myFirstButton.setTitle("test", forState: .Normal)
        window.addSubview(myFirstButton)
        ...
}
like image 4
Alessandro Ornano Avatar answered Nov 06 '22 18:11

Alessandro Ornano


Based on the your question and from the comment/code of Ramis i have made a sample code which you may try

As mentioned by JAL the contentOverlayView should be the best option to display the control over the video in the AVPlayerController, but as per my sample demo the contentOverlayView don't have any user interaction for the buttons or other controls, as if you check in the 3D view of the AVPlayerController it has AVTouchIgnoringView/UIView in front of the contentOverlayView which may be problem in user interaction with contentOverlayView.

So another solution is to add the overlay view in the AVPlayerViewController

func addContentOverlayView() {

    OverlayView.frame = CGRectMake(0,30,AVPlayerVC.view.bounds.width, 100)
    OverlayView.hidden = true
    OverlayView.backgroundColor = UIColor ( red: 0.5, green: 0.5, blue: 0.5, alpha: 0.379 )

    let btnNext = UIButton(frame:CGRectMake(AVPlayerVC.view.bounds.width - 60,0,60,44))
    btnNext.setTitle(">>", forState:.Normal)
    btnNext.addTarget(self, action:"playNext", forControlEvents:.TouchUpInside)
    //        btnNext.layer.borderColor = UIColor ( red: 0.0, green: 0.0, blue: 1.0, alpha: 0.670476140202703 ).CGColor
    //        btnNext.layer.borderWidth = 1.0
    OverlayView.addSubview(btnNext)

    let btnReplay = UIButton(frame:CGRectMake((AVPlayerVC.view.bounds.width/2)-40,0,80,44))
    btnReplay.setTitle("Replay", forState:.Normal)
    btnReplay.addTarget(self, action:"replayVideo", forControlEvents:.TouchUpInside)
    OverlayView.addSubview(btnReplay)

    let btnPrevious = UIButton(frame:CGRectMake(0,0,80,44))
    btnPrevious.setTitle("<<", forState:.Normal)
    btnPrevious.addTarget(self, action:"previousVideo", forControlEvents:.TouchUpInside)
    OverlayView.addSubview(btnPrevious)

    let btnComment = UIButton(frame:CGRectMake((AVPlayerVC.view.bounds.width/2)-70,40,140,44))
    btnComment.setTitle("Comments", forState:.Normal)
    btnComment.addTarget(self, action:"openComments", forControlEvents:.TouchUpInside)
    OverlayView.addSubview(btnComment)

    AVPlayerVC.view.addSubview(OverlayView);

}

func playNext() {
    prevItem = AVPlayerVC.player?.currentItem
    OverlayView.hidden = true
    commmentQueuePlayer.advanceToNextItem()
}

func replayVideo() {
    OverlayView.hidden = true
    AVPlayerVC.player?.currentItem?.seekToTime(kCMTimeZero)
    AVPlayerVC.player?.play()
}

func previousVideo() {
    OverlayView.hidden = true
    if prevItem != AVPlayerVC.player?.currentItem {
        if (commmentQueuePlayer.canInsertItem(prevItem!, afterItem:AVPlayerVC.player?.currentItem)) {
            //commmentQueuePlayer.insertItem(prevItem!, afterItem:AVPlayerVC.player?.currentItem)
            commmentQueuePlayer.replaceCurrentItemWithPlayerItem(prevItem)
            prevItem = AVPlayerVC.player?.currentItem
            replayVideo()
        }
    } else {
        replayVideo()
        //Else display alert no prev video found
    }
}

func stopedPlaying() {
    if prevItem == nil {
        prevItem = AVPlayerVC.player?.currentItem
    }
    OverlayView.hidden = false
}

At the initial setup we set the AVPlayerController,AVQueuePlayer etc... at that time we can add the overlay on the AVPlayerController

For the previous item there is no direct available and as per documentation the item will be remove once it's next item is played , so we have two option like replaceCurrentItemWithPlayerItem or insertItem(item: AVPlayerItem, afterItem: AVPlayerItem?)

If you need to check complete code you can check it from : https://gist.github.com/Pyrolr/debb4fca8f608b1300e099a5b3547031

Note: This is just like prototype, it is not working perfectly in all the cases but it can help you in understanding the basic functionality you wnat and you can improve/optimise based on your requirements

like image 3
HardikDG Avatar answered Nov 06 '22 19:11

HardikDG