How to add an overlay to a AVPlayer? - ios

I want to play a video in AVPlayer but want to open the AVPlayer in a UIView so that I can add a overlay on it.
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:#"Play" forState:UIControlStateNormal];
[button sizeToFit];
button.center = CGPointMake(320/2, 60);
[button addTarget:self action:#selector(buttonPressed:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
-(void)buttonPressed:(UIButton *)button
{
NSURL *urlVideoFile = [NSURL fileURLWithPath:#"https://www.rmp-streaming.com/media///bbb-360p.mp4"];
NSAssert(urlVideoFile, #"Expected not nil video url");
_playerViewController = [[AVPlayerViewController alloc] init];
_playerViewController.player = [AVPlayer playerWithURL:urlVideoFile];
_playerViewController.view.frame = self.view.bounds;
_playerViewController.showsPlaybackControls = YES;
[self.view addSubview:_playerViewController.view];
self.view.autoresizesSubviews = YES;
}
It's playing the video in a player, but I want to open the video in a UIView so that I can add the overlay on it.

Take IBOutlet of Your UIView for Example
IBOutlet UIView *videoView;
And Call this method
-(void)buttonPressed:(UIButton *)button
{
NSURL *videoURL = [NSURL fileURLWithPath:filePath];
AVPlayer *player = [AVPlayer playerWithURL:videoURL];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
playerLayer.frame = videoView.bounds;
[videoView.layer addSublayer:playerLayer];
[player play];
player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[player currentItem]];
}
- (void)playerItemDidReachEnd:(NSNotification *)notification
{
AVPlayerItem *p = [notification object];
[p seekToTime:kCMTimeZero];
}

Related

How to play video using Mpmovie player in the exactly in the view

I want play an video in the view(6,60,412,229)
I Added below code.
cell.movieplayer = [[MPMoviePlayerController alloc]initWithContentURL:app.array1[row]];
cell.videoview.hidden=NO;
cell.img.hidden=YES;
// [[cell.movieplayer view]setFrame:CGRectMake(0.0f, 0.0f, 412.0f, 221.0f)];
cell.movieplayer.view.frame = cell.img.frame;
[cell.videoview addSubview:cell.movieplayer.view];
NSLog(#"%#",cell.movieplayer);
[cell.movieplayer play];
But video is not playing at the same position and it is playing -30 position.please help me out.
img is the image view and video view is view and both are at the same position.
In iOS 9, MPMoviePlayerViewController will be deprecated. It's probably about time to move away from it, in favour of the AVKit classes, like AVKitPlayerViewController. This could be cause for some refactoring, since AVKitPlayerViewController cannot be subclassed, but if this keeps XCDYouTubeKit working in the future (and with features like Picture-in-Picture), then it should be worth the effort in the long run.
// grab a local URL to our video
NSURL *videoURL = [NSURL URLWithString:#"Your_Url"];
// create an AVPlayer
AVPlayer *player = [AVPlayer playerWithURL:videoURL];
// create a player view controller
AVPlayerViewController *controller = [[AVPlayerViewController alloc]init];
controller.player = player;
[player play];
// show the view controller
[self addChildViewController:controller];
[self.view addSubview:controller.view];
controller.view.frame = self.view.frame;
if you want to play the video in cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
cell.videoItem = [AVPlayerItem playerItemWithURL:url];
dispatch_sync(dispatch_get_main_queue(), ^{
cell.videoPlayer = [AVPlayer playerWithPlayerItem:cell.videoItem];
cell.avLayer = [AVPlayerLayer playerLayerWithPlayer:cell.videoPlayer];
cell.videoPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[cell.videoItem addObserver:self forKeyPath:#"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
[cell.videoItem addObserver:self forKeyPath:#"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemDidBufferPlaying:) name:AVPlayerItemPlaybackStalledNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
cell.avLayer.frame = CGRectMake(5, 9, 310, 310);
[cell.contentView.layer addSublayer: cell.avLayer];
[ cell.videoPlayer play];
[cell.contentView addSubview:cell.videoActivity];
});
});
}
You probably don't want to use MPMoviePlayerController since it's old and deprecated in iOS 9.
Check out AVPlayer instead.

UISlider added on AVPlayerViewController contentOverlayView is not responding

I am trying to add a UISlider to control volume in AVPlayerViewController, for this i have added a UISlider on 'AVPlayerViewController.contentOverlayView'. UISlider is not allowing me to drag as if it is not enabled and its selector action method 'changeVolumeLevelOfPlayer' is not getting called.
Here is my code:
-(void)viewDidLoad {
[super viewDidLoad];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
AVPlayerViewController *avPlayerViewController = [[AVPlayerViewController alloc] init];
AVPlayer *player = [AVPlayer playerWithURL:[self getVideoURLAtIndex:[self.indexOfCurrentTrailer intValue]]];
avPlayerViewController.player = player;
avPlayerViewController.delegate = self;
[player play];
avPlayerViewController.view.frame = CGRectMake(0, 0, 300, 250);
UISlider *sliderForVolumeControl = [[UISlider alloc] initWithFrame:CGRectMake(0, avPlayerViewController.view.frame.size.height/2, 100, 40)];
[sliderForVolumeControl setMinimumValue:0.0];
[sliderForVolumeControl setMaximumValue:1.0];
[sliderForVolumeControl setValue:0.5];
sliderForVolumeControl.continuous = YES;
[sliderForVolumeControl setBackgroundColor:[UIColor orangeColor]];
[sliderForVolumeControl addTarget:self action:#selector(changeVolumeLevelOfPlayer:) forControlEvents:UIControlEventValueChanged];
[sliderForVolumeControl setUserInteractionEnabled:YES];
[sliderForVolumeControl setEnabled:YES];
[avPlayerViewController.contentOverlayView addSubview:sliderForVolumeControl];
[self addChildViewController:avPlayerViewController];
[self.view addSubview:avPlayerViewController.view];
[avPlayerViewController didMoveToParentViewController:self];
[player addObserver:self forKeyPath:#"status" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial) context:nil];
}
-(void)changeVolumeLevelOfPlayer:(UISlider *)sender {
player.volume = sender.value;
}
From the apple docs:
Use the content overlay view to add additional custom views between
the video content and the controls.
So it looks like this: (with a bunch of other layers over your UISlider)
To make it work just change this line:
[avPlayerViewController.contentOverlayView addSubview:sliderForVolumeControl];
to this:
[avPlayerViewController.view addSubview:sliderForVolumeControl];

Adding a UITapGestureRecognizer to MPMoviePlayerController

Nothing happens when I tap on my MPMoviePlayerController. Can anyone see what I am doing wrong in setting up the UITapGestureRecognizer?
- (void) playMovie : (NSString *) urlString{
self.movieURLString = urlString;
NSURL *movieURL = [NSURL URLWithString:self.movieURLString];
self.moviePlayer = [[MPMoviePlayerController alloc] init];
[self.moviePlayer setShouldAutoplay:YES];
[self.moviePlayer setContentURL:movieURL.absoluteURL];
[self.moviePlayer setMovieSourceType:MPMovieSourceTypeFile];
self.moviePlayer.controlStyle = MPMovieControlStyleNone;
self.moviePlayer.view.frame = self.movieView.frame;
/* add tap handler */
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(showControls:)];
singleFingerTap.delegate = self;
//EDIT: this line somehow didn't make into my OP
[self.moviePlayer.view addGestureRecognizer:singleFingerTap];
self.moviePlayer.view.backgroundColor = [UIColor clearColor];
[self.view addSubview:self.moviePlayer.view];
[self.moviePlayer prepareToPlay];
// respond to changes in movie player status
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myMovieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];
}
- (void) showControls : (UITapGestureRecognizer *) recognizer {
NSLog(#"here");
self.moviePlayer.controlStyle = MPMovieControlStyleEmbedded;
}
You never added the gesture recognizer to a view, that's what's wrong.
[self.moviePlayer.view addGestureRecognizer:singleFingerTap];
There's also no need to set the delegate unless you're going to implement some of the methods in the UIGestureRecognizerDelegate protocol.

iCarousel AVPlayerItem Instances not displaying correctly

What I am trying to achieve
I would like to display a carousel of videos that play independently. No more than 10 at a time. as well as having their own play button per carousel object to play independently.
What I am getting
After 3 Items display in the carousel it displays the same three over and over again until it reaches the end of the 10 items.
I am assigning the AVAsset like below:
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:[_videoURLS objectAtIndex:index]] options:nil];
_videoURLS is an NSMutableArray of NSStrings it returns a 10 count to populate 10 items in the carousel like below.
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
//return the total number of items in the carousel
return [_videoURLS count];
}
Now to populate the Video View I am doing the below:
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:[_videoURLS objectAtIndex:index]] options:nil];
//create new view if no view is available for recycling
if (view == nil)
{
//don't do anything specific to the index within
//this `if (view == nil) {...}` statement because the view will be
//recycled and used with other index values later
UIView *mainView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 370.0f)];
view = mainView;
CGFloat mainViewWidth = mainView.bounds.size.width;
//Video Player View
_videoView = [[UIView alloc] initWithFrame:CGRectMake(0,0, mainViewWidth, 220)];
_videoView.backgroundColor = [UIColor colorWithRed:123/255.0 green:123/255.0 blue:123/255.0 alpha:1.0];
_videoView.center = CGPointMake(100, 170);//170
_videoView.tag = 20;
[view addSubview:_videoView];
//AV Asset Player
AVPlayerItem * playerItem = [[AVPlayerItem alloc] initWithAsset:asset];
_player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
playerLayer.frame = _videoView.bounds;
[_videoView.layer addSublayer:playerLayer];
[_player seekToTime:kCMTimeZero];
//Play Button
_playButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 60.0f, 60.0f)];
[_playButton setBackgroundImage:[UIImage imageNamed:#"play-icon-grey.png"] forState:UIControlStateNormal];
[_playButton addTarget:self action:#selector(playVideo:) forControlEvents:UIControlEventTouchUpInside];
_playButton.center = CGPointMake(100, 160);
_playButton.tag = 1;
[view addSubview:_playButton];
}
else
{
//get a reference to the label in the recycled view
_playButton = (UIButton *) [view viewWithTag:1];
_videoView = (UIView *) [view viewWithTag:20];
}
//set item label
//remember to always set any properties of your carousel item
//views outside of the `if (view == nil) {...}` check otherwise
//you'll get weird issues with carousel item content appearing
//in the wrong place in the carousel
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didFinishPlaying:) name:MPMoviePlayerPlaybackDidFinishNotification object:_player];
return view;
}
I handle the play button like below:
-(IBAction)playVideo:(id)sender {
if (_playButton.isHidden) {
[_playButton setHidden:NO];
}else{
[_playButton setHidden:YES];
[_player play];
}
}
Though when I press the play button it plays the second video in the carousel.
What is the proper way to handle this and have all the videos play single handed?

MpMovieplayerController tap gesture recognizer doesn't trigger when in fullscreen

I´m trying to use UITapGestureRecognizer in order to handle the taps on my fullscreen video. If I omit [self.player setFullscreen:YES animated:NO]; it works, but then my video won't scale to fit the screen.
From my .m:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *videoPath = [[NSBundle mainBundle] pathForResource:#"test" ofType:#"mov"];
player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:videoPath]];
player.shouldAutoplay = NO;
player.view.frame = self.view.bounds;
player.scalingMode = MPMovieScalingModeAspectFit;
player.controlStyle = MPMovieControlStyleNone;
player.fullscreen = YES;
self.player = player;
[self.player prepareToPlay];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
UIView *aView = [[UIView alloc] initWithFrame:player.view.bounds];
[aView addGestureRecognizer:tapGesture];
[self.player.view addSubview:aView];
}
- (IBAction)playMovie:(id)sender {
//add the MPMoviePlayerViewController to this view (as subview)
//Play movie
[self.view addSubview:self.player.view];
[self.player setFullscreen:YES animated:NO]; //commenting out this will make it work
[self.player play];
}
- (void)handleTap:(UITapGestureRecognizer *)recognizer {
NSLog(#"tap tap");
}
From my .h:
#property (retain, nonatomic) MPMoviePlayerController *player;
- (void)handleTap:(UITapGestureRecognizer *)recognizer;
You can try this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(willEnterFullScreen:)
name:MPMoviePlayerWillEnterFullscreenNotification
object:nil];
- (void)willEnterFullScreen:(NSNotification*)notification
{
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
UIView *aView = [[UIView alloc] initWithFrame:self.player.backgroundView.bounds];
[aView addGestureRecognizer:tapGesture];
[self.view.window addSubview:aView];
}
and then remove your subview when MPMoviePlayerWillExitFullscreenNotification is posted
In my comment, I drafted how to get that covered when using proper fullscreen ([self.player setFullscreen:YES animated:NO];).
I would suggest that instead you simply resize the player view to cover the entire screen by setting its frame accordingly.
You initialising code would have to get rid of that player.fullscreen = YES;, but that I guess is obvious by now.

Resources