I am trying to load a short movie file (.m4v) before the application starts
However, when I using the ipad simulator, only the sound plays. There is no video running.
If I change the simulator to iphone simulator, the video plays just fine.
I use MPMoviePlayerController to play the movie file
I even downloaded the sample mediaPlayer from Apple, and the result is the same. With the sample movie file (.m4v) the iphone simulator can play the movie, but the ipad simulator cannot
Please help!
Here is my solution if you need it:
The solution is integrated with cocos2d, but it should be relatively easy to modify it regardless.
Please refer to the following website for general usage:
Getting MPMoviePlayerController to Work with iOS4, 3.2 (iPad) and Earlier Versions of iPhone SDK
iPad iOS: 3.2.2
#implementation MovieLayer
/*
* name: movie file name
* type: movie file type
* target: target class to handle the selectors
* finish: selector called when the movie is finished
* load: selector called when the movie loading state is changed
*/
+ (id)layerWithMovieName:(NSString*)name type:(NSString*)movieType target:(id)target
finish:(SEL)finishSelector load:(SEL)loadSelector
{
return [[[self alloc] initWithMovieName:name type:movieType target:target
finish:finishSelector load:loadSelector] autorelease];
}
- (id)initWithMovieName:(NSString*)name type:(NSString*)movieType target:(id)target
finish:(SEL)finishSelector load:(SEL)loadSelector
{
if ((self = [super init]) != nil)
{
NSBundle *bundle = [NSBundle mainBundle];
NSString *moviePath = [bundle pathForResource:name ofType:movieType];
if (moviePath)
{
NSURL *moviePathURL = [NSURL fileURLWithPath:moviePath];
[self loadMovieAtURL:moviePathURL];
// Movie finish loading notification
[[NSNotificationCenter defaultCenter]
addObserver:target
selector:loadSelector
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
// Movie finish Notification
[[NSNotificationCenter defaultCenter]
addObserver:target
selector:finishSelector
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
}
}
return self;
}
- (void)dealloc
{
[theMovie.view removeFromSuperview];
theMovie.initialPlaybackTime = -1;
[theMovie stop];
[theMovie release];
[super dealloc];
}
- (void)loadMovieAtURL:(NSURL*)theURL
{
CGSize size = [[CCDirector sharedDirector] winSize];
theMovie = [[MPMoviePlayerController alloc] initWithContentURL:theURL];
[theMovie prepareToPlay];
// > 3.2
[theMovie respondsToSelector:#selector(loadState)];
theMovie.scalingMode = MPMovieScalingModeAspectFill;
[theMovie setFullscreen:TRUE animated:TRUE];
theMovie.controlStyle = MPMovieControlStyleNone;
theMovie.view.frame = CGRectMake(0, 0, size.width, size.height);
theMovie.view.backgroundColor = [UIColor clearColor];
// Transform
theMovie.view.transform = CGAffineTransformMakeRotation(-270.0f * (M_PI/180.0f));
theMovie.view.center = [[CCDirector sharedDirector] openGLView].center;
[[[CCDirector sharedDirector] openGLView] addSubview:theMovie.view];
}
- (void)play
{
[theMovie play];
}
#end
Basic usage using cocos2d
MovieLayer *player = [MovieLayer layerWithMovieName:LOGO_ANIMATION
type:LOGO_ANIMATION_FILE_EXT
target:self
finish:#selector(myMovieFinishedCallback:)
load:#selector(myMovieLoadCallback:)];
[self addChild:player z: 0 tag:1];
}
return self;
}
- (void)myMovieLoadCallback:(NSNotification*)notification
{
MPMovieLoadState state = [(MPMoviePlayerController*)notification.object loadState];
// Remove observer
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
if (state & MPMovieLoadStateUnknown)
{
[self myMovieFinishedCallback:nil];
}
else if (state & MPMovieLoadStatePlayable)
{
[(MovieLayer*)[self getChildByTag:1] play];
}
else if (state & MPMovieLoadStatePlaythroughOK)
{
[(MovieLayer*)[self getChildByTag:1] play];
}
else if (state & MPMovieLoadStateStalled)
{
[self myMovieFinishedCallback:nil];
}
}
- (void)myMovieFinishedCallback:(NSNotification*)notification
{
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
[self removeChildByTag:1 cleanup:YES];
}
Almost certain this is a know bug/limitation in the simulator.
Related
I have an app that plays local videos using the AVPlayerViewController.
But when the video has finished playing I want it to close automatically (like the MPMoviePlayerViewController used to do).
After posting this question, I managed to solve this partially thanks to the answers below and partially from Apples "Guides and Sample code".
This is the code that worked for me:
#import "ViewController.h"
#import AVFoundation;
#import AVKit;
#interface ViewController ()
#property(nonatomic, readonly) AVPlayerItem *currentItem;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)playerItemDidReachEnd:(NSNotification *) notification {
//remove the player
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)playVideo:(id)sender {
// grab a local URL to our video
NSURL *videoURL = [[NSBundle mainBundle]URLForResource:#"bagare" withExtension:#"mp4"];
// create an AVPlayer
AVPlayer *player = [AVPlayer playerWithURL:videoURL];
// create a player view controller
AVPlayerViewController *controller = [[AVPlayerViewController alloc]init];
controller.player = player;
[player play];
[self presentViewController:controller animated:YES completion:nil];
// show the view controller
controller.view.frame = self.view.frame;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:_currentItem];
}
#end
NSURL *url=[NSURL URLWithString:#"URLLINK"];
AVAsset *avAsset = [AVAsset assetWithURL:url];
AVPlayerItem *playerItem = [[AVPlayerItem alloc]initWithAsset:avAsset];
Subscribe to the AVPlayerItem's DidPlayToEndTime notification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
Pass the AVPlayerItem to a new player
AVPlayer *player = [AVPlayer playerWithURL:videoURL]
AVPlayerViewController *controller=[[AVPlayerViewController alloc]init];
controller.player=player;
[player play];
[self presentViewController:controller animated:YES completion:nil];
Here remove Player dismiss or Player added view
-(void)itemDidFinishPlaying:(NSNotification *) notification {
[self dismissViewControllerAnimated:YES completion:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
}
This should work:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoDidFinish:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[controller.player currentItem]];
- (void)videoDidFinish:(id)notification
{
AVPlayerItem *p = [notification object];
//do something with player if you want
[[NSNotificationCenter defaultCenter] removeObserver:self];
//fade out / remove subview
}
In .h file
#property(nonatomic, strong)AVPlayerViewController *controller;
In .m file:
- (IBAction)playVideo:(id)sender {
// grab a local URL to our video
NSURL *videoURL = [[NSBundle mainBundle]URLForResource:#"bagare" withExtension:#"mp4"];
// create an AVPlayer
AVPlayer *player = [AVPlayer playerWithURL:videoURL];
// create a player view controller
self.controller = [[AVPlayerViewController alloc]init];
controller.player = player;
[player play];
[self presentViewController:controller animated:YES completion:nil];
// show the view controller
controller.view.frame = self.view.frame;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:_currentItem];
}
And for dismiss:
- (void)playerItemDidReachEnd:(NSNotification *)notification {
[self.controller dismissViewControllerAnimated:YES completion:nil];
}
The problem video can be seen in :
http://app.bowerchat.com/images/118_1435046739658.mp4
MPMoviePlayerViewController Dismissing immediately without play.
What can be reason?Some videos are loaded nicely and playing.
How can i check the video can be played or not?
I tried
NSLog(#"%lu",(unsigned long)self.mpController.moviePlayer.loadState);
NSLog(#"%d",self.mpController.moviePlayer == nil);
Results always 0 - 0
MY Code to play video
self.mpController = [[MPMoviePlayerViewController alloc] initWithContentURL:moveUrl];
[self.mpController.moviePlayer prepareToPlay];
NSLog(#"%lu",(unsigned long)self.mpController.moviePlayer.loadState);
NSLog(#"%d",self.mpController.moviePlayer == nil);
[parent presentMoviePlayerViewControllerAnimated:self.mpController];
The reason could be that movie that has extention *.mp4 is actually of different type.
Also try to add the following:
self.mpController.moviePlayer.shouldAutoplay = YES;
[self.mpController.moviePlayer play];
Try this snippet :
-(void)setupMovie
{
NSURL *movieURL = [NSURL fileURLWithPath:movieURL];
self.mpController = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
self. mpController.scalingMode = MPMovieScalingModeAspectFill;
self. mpController.controlStyle = MPMovieControlStyleNone;
self.mpController.view.frame = self.view.frame;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerPlaybackStateDidChange:) name:MPMediaPlaybackIsPreparedToPlayDidChangeNotification object:nil];
[self.view addSubview:self.mpController.view];
[self.mpController prepareToPlay];
}
- (void)moviePlayBackDidFinish:(MPMoviePlayerController *)player
{
[self.mpController.view removeFromSuperview];
}
- (void)moviePlayerPlaybackStateDidChange:(NSNotification*)notification
{
if (self. mpController.isPreparedToPlay) {
[self. mpController play];
}
}
And make sure movieURL is correct and video exist by this provided url
I try to use a simple 13 sec mp4 video as background loop for my login screen.
I want the Video to autoplay and loop. It has no Audio and I don´t need controls.
I need buttons and other objects in front of it.
I tried to use a WebView and make the MP4 a GIF file from this Tutorial : https://medium.com/swift-programming/ios-make-an-awesome-video-background-view-objective-c-swift-318e1d71d0a2
But the problem is that my 5 MB MP4 has (converted to a GIF) a size of 95 MB.
I can´t use this method.
Is there any "Easy to Use" way ?
EDIT :
Okay this is what I did now.
I imported AVFoundation.
This is the Code in the View
- (void)viewDidLoad {
[super viewDidLoad];
NSURL* mURL = [[NSBundle mainBundle] URLForResource:#"App-BG-Loop" withExtension:#"mp4"];
AVPlayer* player = [AVPlayer playerWithURL:mURL];
player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[player currentItem]];
AVPlayerLayer* playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
playerLayer.frame = _videoView.bounds;
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
playerLayer.needsDisplayOnBoundsChange = YES;
[_videoView.layer addSublayer:playerLayer];
_videoView.layer.needsDisplayOnBoundsChange = YES;
[player play];
// Do any additional setup after loading the view, typically from a nib.}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
[p seekToTime:kCMTimeZero];}
This works great in the iOS Simulator but when I try to start it on a device it wont start and or play the video. The View just stays white. No Error nothing.
Any Idea?
EDIT 2 :
Problem with not playing on device was the size of the video it was to big. Apple only supports 1080p on the devices.
I recently had to use an animation too. I tried it with a UIImageView first but the memory management was not too good with that. I ended up making a .mp4 from it and use it in a MPMoviePlayerController:
-(void)setupDashboardAnimation
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(checkMovieStatus:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
NSBundle *bundle = [NSBundle mainBundle];
NSString *moviePath = [bundle pathForResource:#"some_movie" ofType:#"some_extention"];
NSURL *movieURL = [NSURL fileURLWithPath:moviePath];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
_backgroundAnimationMoviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
_backgroundAnimationMoviePlayer.controlStyle = MPMovieControlStyleNone;
_backgroundAnimationMoviePlayer.repeatMode = MPMovieRepeatModeOne;
_backgroundAnimationMoviePlayer.view.backgroundColor = [UIColor clearColor];
for (UIView *aSubView in _backgroundAnimationMoviePlayer.view.subviews)
{
aSubView.backgroundColor = [UIColor clearColor];
}
[_backgroundAnimationMoviePlayer.view setFrame:imv_background.frame];
[_backgroundAnimationMoviePlayer prepareToPlay];
}
-(void)checkMovieStatus:(NSNotification *)notification
{
if (_backgroundAnimationMoviePlayer.loadState & (MPMovieLoadStatePlayable | MPMovieLoadStatePlaythroughOK) && _backgroundAnimationMoviePlayer.playbackState != MPMoviePlaybackStatePlaying)
{
[self.view insertSubview:_backgroundAnimationMoviePlayer.view aboveSubview:imv_background];
[_backgroundAnimationMoviePlayer play];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
dashboardAnimationDidSetup = YES;
}
}
Hi everyone I am working on an application in which I have a url of video and I have to play a video from that url. I have done this job from this code
- (IBAction)btnPlayVideo:(id)sender
{
NSString *fileName = #"Server Address/Vdieo.flv";
NSURL *streamURL = [NSURL URLWithString:fileName];
mPlayerVC = [[MPMoviePlayerViewController alloc] initWithContentURL:streamURL];
[self.view addSubview:mPlayerVC.view];
//play movie
MPMoviePlayerController *player = [mPlayerVC moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
player.view.frame = self.view.frame;
[player setFullscreen:YES animated:YES];
[self.view addSubview:player.view];
[player prepareToPlay];
[player play];
}
//============Other Methods====================
- (void)willEnterFullscreen:(NSNotification*)notification {
NSLog(#"willEnterFullscreen");
}
- (void)enteredFullscreen:(NSNotification*)notification {
NSLog(#"enteredFullscreen");
}
- (void)willExitFullscreen:(NSNotification*)notification {
NSLog(#"willExitFullscreen");
}
- (void)exitedFullscreen:(NSNotification*)notification {
NSLog(#"exitedFullscreen");
[mPlayerVC.view removeFromSuperview];
mPlayerVC = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)playbackFinished:(NSNotification*)notification {
NSNumber* reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
switch ([reason intValue]) {
case MPMovieFinishReasonPlaybackEnded:
NSLog(#"playbackFinished. Reason: Playback Ended");
break;
case MPMovieFinishReasonPlaybackError:
NSLog(#"playbackFinished. Reason: Playback Error");
break;
case MPMovieFinishReasonUserExited:
NSLog(#"playbackFinished. Reason: User Exited");
NSLog(#"exitedFullscreen");
[[NSNotificationCenter defaultCenter] removeObserver:self];
break;
default:
break;
}
[mPlayerVC.view removeFromSuperview];
mPlayerVC = nil;
}
My problem is that when this code run video player open and start loading and it takes too much time to run a video. Can anybody guide me how to run video in fast way from internet?
There's nothing in the code that suggests that lag is anything other than the time it takes to make the request and sufficiently buffer. The most common technique to improve UE is to start loading as early as possible, even before the user requests playback.
If this is possible, the code should be reorganized as follows:
// hang on to the movie player
#property(nonatomic,retain) MPMoviePlayerController *mp;
// call this as soon as its possible to know the user might want to see the video
- (void)primeVideo {
NSString *fileName = #"Server Address/Vdieo.flv";
NSURL *streamURL = [NSURL URLWithString:fileName];
MPMoviePlayerController *mp = [[MPMoviePlayerViewController alloc] initWithContentURL:streamURL];
// do this also in dealloc
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
mp.shouldAutoplay = NO;
[mp prepareToPlay];
self.mp = mp;
}
That does as much prep as possible without changing the UI. The rest of your code from the button action is left, tweaked a little...
- (IBAction)btnPlayVideo:(id)sender {
// if there's any way that the user can request playback before
// you've called primeVideo, check for that here. But hopefully you
// can call primeVideo before user even sees the play button
if (!self.mp) [self primeVideo];
self.mp.view.frame = self.view.frame;
[self.mp setFullscreen:YES animated:YES];
[self.view addSubview:self.mp.view];
MPMovieLoadState state = [self.mp loadState];
if (state & MPMovieLoadStatePlaythroughOK) [self.mp play];
else self.mp.shouldAutoplay = YES;
}
Im using AVQueuePlayer to loop through an array of AVPlayerItems.
The way I'm looping it, I listen to the AVPlayerItemDidPlayToEndTimeNotification and every time its called, I add the current object to the end of the queue.
heres the code:
viewWillAppear
{
...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[_queuePlayer currentItem]];
[_queuePlayer play];
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
AVPlayerItem *fakeNew = [[AVPlayerItem alloc] initWithAsset:p.asset];
if (_queuePlayer.items.count == 1)
{
[p seekToTime:kCMTimeZero];
[_queuePlayer play];
}
else
{
[_queuePlayer insertItem:fakeNew afterItem:[_queuePlayer.items lastObject]];
}
NSLog(#"array of items to play:%lu", (unsigned long)_queuePlayer.items.count);
}
The problem is, that the method is called only for the first video that plays, after that, the method stops getting called, so if for example i have 2 movies in the array, it would play them both+the first one again, any idea why is this happening?
More Info:
also tried to make a new player every time and set it to layer. failed to send the notification more than once just the same
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
[self.playList removeObjectAtIndex:0];
[self.playList addObject:p];
AVPlayer *newPlayer = [[AVPlayer alloc] initWithPlayerItem:[self.playList objectAtIndex:0]];
_player = newPlayer;
self.AVPlayerLayerView.layer.player = self.player;
[_player play];
}
After a lot of messing around, apparently for whatever reason, the view unregistered as observer every time, I just removed and added observer after every notification:
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
AVPlayerItem *fakeNewItem = [[AVPlayerItem alloc] initWithAsset:p.asset];
[self.playList removeObjectAtIndex:0];
[self.playList addObject:fakeNewItem];
AVPlayer *newPlayer = [[AVPlayer alloc] initWithPlayerItem:[self.playList objectAtIndex:0]];
_player = newPlayer;
self.AVPlayerLayerView.layer.player = self.player;
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[_player currentItem]];
[_player play];
}
For a clean approach to resolve this issue. I approached with the next piece of code instead
The first is you have to add the code necessary to receive a feedback from the AVPlayer when the reproduction time changes.
- (void)addPeriodicTimeObserverForReproductionChanges {
#weakify(self);
[self.player
addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(kBQDefaultTimeIntervalReproductionChanges, NSEC_PER_SEC)
queue:self.eventsQueue
usingBlock:^(CMTime time) {
#strongify(self);
[self dispatchBlockOnMainQueue:^{
if ([self.delegate respondsToSelector:#selector(playerItemController:didChangeReproductionTime:)])
[self.delegate playerItemController:self
didChangeReproductionTime:time];
[self checkForItemPlayToEnd];
}];
}];
}
- (void)checkForItemPlayToEnd
{
CMTime durationScaled = CMTimeConvertScale(self.duration,self.player.currentTime.timescale, kCMTimeRoundingMethod_Default);
if (CMTIME_COMPARE_INLINE(durationScaled, ==, self.player.currentTime)) {
[self playerDidFinishReproducingItem];
}
}