Why not init two MPMoviePlayerController in a view? - ios

System: iOS 7.0
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *audioPath = [[docPaths objectAtIndex:0] stringByAppendingPathComponent:#"test.mp4"];
if (YES == [fileManager fileExistsAtPath:audioPath])
{
MPMoviePlayerController *moviePlayer = nil;
//1
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL: [NSURL fileURLWithPath:audioPath]];
[moviePlayer setScalingMode:MPMovieScalingModeAspectFit];
[moviePlayer setControlStyle: MPMovieControlStyleEmbedded];
[moviePlayer.view setBackgroundColor:[UIColor clearColor]];
[moviePlayer.view setFrame: CGRectMake(20, 240, 80, 80)];
moviePlayer.shouldAutoplay = NO;
[moviePlayer prepareToPlay];
self.abcd = moviePlayer;
[self.view addSubview: moviePlayer.view];
//2
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL: [NSURL fileURLWithPath:audioPath]];
[moviePlayer setScalingMode:MPMovieScalingModeAspectFit];
[moviePlayer setControlStyle: MPMovieControlStyleEmbedded];
[moviePlayer.view setBackgroundColor:[UIColor clearColor]];
[moviePlayer.view setFrame: CGRectMake(20, 40, 80, 80)];
moviePlayer.shouldAutoplay = NO;
[moviePlayer prepareToPlay];
self.edf = moviePlayer;
[self.view addSubview: moviePlayer.view];
}
When I init two MPMoviePlayerControllers, why does it only display one? If I only init #1, it's ok, and if only init #2, it's also ok, but if I init both #1 and #2, it only displays #2. Why is this happening? Thanks.

Can you elaborate on what you mean by it will only "display" one? You can add both views, but according to Apple's documentation:
Note: Although you can create multiple MPMoviePlayerController objects and present their views in your interface, only one movie player at a time can play its movie.
source: https://developer.apple.com/library/ios/documentation/mediaplayer/reference/MPMoviePlayerController_Class/Reference/Reference.html

EDIT: See Sean's answer, that's probably the issue.
You need to create two different instances of MPMoviePlayerController. What you are doing is creating an instance of MPMoviePlayerController called moviePlayer and then overwriting it when you create the second. You want to create two unique instances, like:
MPMoviePlayerController *moviePlayer1 = nil;
MPMoviePlayerController *moviePlayer2 = nil;
//1
moviePlayer1 = [[MPMoviePlayerController alloc] initWithContentURL: [NSURL fileURLWithPath:audioPath]];
[moviePlayer1 setScalingMode:MPMovieScalingModeAspectFit];
[moviePlayer1 setControlStyle: MPMovieControlStyleEmbedded];
[moviePlayer1.view setBackgroundColor:[UIColor clearColor]];
[moviePlayer1.view setFrame: CGRectMake(20, 240, 80, 80)];
moviePlayer1.shouldAutoplay = NO;
[moviePlayer1 prepareToPlay];
self.abcd = moviePlayer1;
[self.view addSubview: moviePlayer1.view];
//2
moviePlayer2 = [[MPMoviePlayerController alloc] initWithContentURL: [NSURL fileURLWithPath:audioPath]];
[moviePlayer2 setScalingMode:MPMovieScalingModeAspectFit];
[moviePlayer2 setControlStyle: MPMovieControlStyleEmbedded];
[moviePlayer2.view setBackgroundColor:[UIColor clearColor]];
[moviePlayer2.view setFrame: CGRectMake(20, 40, 80, 80)];
moviePlayer2.shouldAutoplay = NO;
[moviePlayer2 prepareToPlay];
self.edf = moviePlayer2;
[self.view addSubview: moviePlayer2.view];
Another example of what you're doing is this:
NSString *string = nil; // first string is nil
string = #"red"; // then you create another string "red" and set it to string
string = #"blue"; // then you create another string "blue" and set it to string
No matter what you do, after this string will ALWAYS be "blue" and "red" is basically gone.

Related

MOV on iOS App shows QuickTime Logo At Beginning

In my app I use, I loop a video over and over again. It will always show the QuickTime logo at the beginning of the video each time. I have checked, and there isn't anything like that in the video. Thoughts to how I can get rid of that?
NSURL *videoURL = [[NSBundle mainBundle] URLForResource:#"warpspeed" withExtension:#"mov"];
UIView *patternView = [[UIView alloc] initWithFrame:self.view.bounds];
patternView.backgroundColor = [UIColor blackColor];
[self.moviePlayer2.backgroundView addSubview:patternView];
self.moviePlayer2 = [[MPMoviePlayerController alloc] initWithContentURL:videoURL];
[self.moviePlayer2 setControlStyle:MPMovieControlStyleDefault];
self.moviePlayer2.controlStyle = MPMovieControlStyleNone;
self.moviePlayer2.scalingMode = MPMovieScalingModeAspectFit;
self.moviePlayer2.movieSourceType = MPMovieSourceTypeFile;
[self.moviePlayer2 setAllowsAirPlay:YES];
self.moviePlayer2.view.frame = self.view.frame;

Playing stacked videos

I have multiple imageview subviews getting stacked based on my incoming data. Basically all these subviews are either set to an image or a video layer based on my incoming data. The problem i have is playing videos. i can play the first video in the stack but every video after that is just the sound of the first video. How can i play each accordingly?
the views are navigated through with a tap event like snapchat. see below:
#interface SceneImageViewController ()
#property (strong, nonatomic) NSURL *videoUrl;
#property (strong, nonatomic) AVPlayer *avPlayer;
#property (strong, nonatomic) AVPlayerLayer *avPlayerLayer;
#end
#implementation SceneImageViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.mySubviews = [[NSMutableArray alloc] init];
self.videoCounterTags = [[NSMutableArray alloc] init];
int c = (int)[self.scenes count];
c--;
NSLog(#"int c = %d", c);
self.myCounter = [NSNumber numberWithInt:c];
for (int i=0; i<=c; i++) {
//create imageView
UIImageView *imageView =[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
[imageView setUserInteractionEnabled:YES]; // <--- This is very important
imageView.tag = i; // <--- Add tag to track this subview in the view stack
[self.view addSubview:imageView];
NSLog(#"added image view %d", i);
//get scene object
PFObject *sceneObject = self.scenes[i];
//get the PFFile and filetype
PFFile *file = [sceneObject objectForKey:#"file"];
NSString *fileType = [sceneObject objectForKey:#"fileType"];
//check the filetype
if ([fileType isEqual: #"image"])
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//get image
NSURL *imageFileUrl = [[NSURL alloc] initWithString:file.url];
NSData *imageData = [NSData dataWithContentsOfURL:imageFileUrl];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:imageData];
});
});
}
//its a video
else
{
// the video player
NSURL *fileUrl = [NSURL URLWithString:file.url];
self.avPlayer = [AVPlayer playerWithURL:fileUrl];
self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
//self.avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[self.avPlayer currentItem]];
CGRect screenRect = [[UIScreen mainScreen] bounds];
self.avPlayerLayer.frame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height);
[imageView.layer addSublayer:self.avPlayerLayer];
NSNumber *tag = [NSNumber numberWithInt:i+1];
NSLog(#"tag = %#", tag);
[self.videoCounterTags addObject:tag];
//[self.avPlayer play];
}
}
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewTapped:)];
[self.view bringSubviewToFront:self.screen];
[self.screen addGestureRecognizer:tapGesture];
}
- (void)viewTapped:(UIGestureRecognizer *)gesture{
NSLog(#"touch!");
[self.avPlayer pause];
int i = [self.myCounter intValue];
NSLog(#"counter = %d", i);
for(UIImageView *subview in [self.view subviews]) {
if(subview.tag== i) {
[subview removeFromSuperview];
}
}
if ([self.videoCounterTags containsObject:self.myCounter]) {
NSLog(#"play video!!!");
[self.avPlayer play];
}
if (i == 0) {
[self.avPlayer pause];
[self.navigationController popViewControllerAnimated:NO];
}
i--;
self.myCounter = [NSNumber numberWithInt:i];
NSLog(#"counter after = %d", i);
}
What Brooks Hanes said is correct you keep overriding the avplayer.
This is what i suggest for you to do:
Add the tap gesture to the imageView instead of the screen (or for a cleaner approach use UIButton instead):
UIImageView *imageView =[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
[imageView setUserInteractionEnabled:YES]; // <--- This is very important
imageView.tag = i; // <--- Add tag to track this subview in the view stack
[self.view addSubview:imageView];
NSLog(#"added image view %d", i);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:imageView action:#selector(viewTapped:)];
[imageView addGestureRecognizer:tapGesture];
This way in your viewTapped: method you could get the tag of the pressed image like so: gesture.view.tag instead of using the myCounter.
To get the video working you could create a new AVPlayer for each video but that might turn quite expensive memory wise. A better approach will be to use AVPlayerItem and switch the AVPlayer's AVPlayerItem when changing the video.
So in the for loop do something like this where self.videoFiles is a NSMutableDictionary property:
// the video player
NSNumber *tag = [NSNumber numberWithInt:i+1];
NSURL *fileUrl = [NSURL URLWithString:file.url];
//save your video file url paired with the ImageView it belongs to.
[self.videosFiles setObject:fileUrl forKey:tag];
// you only need to initialize the player once.
if(self.avPlayer == nil){
AVAsset *asset = [AVAsset assetWithURL:fileUrl];
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset];
self.avPlayer = [[AVPlayer alloc] initWithPlayerItem:item];
self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[self.avPlayer currentItem]];
}
// you don't need to keep the layer as a property
// (unless you need it for some reason
AVPlayerLayer* avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
CGRect screenRect = [[UIScreen mainScreen] bounds];
avPlayerLayer.frame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height);
[imageView.layer addSublayer:avPlayerLayer];
NSLog(#"tag = %#", tag);
[self.videoCounterTags addObject:tag];
Now in your viewTapped:
if ([self.videoCounterTags containsObject:gesture.view.tag]) {
NSLog(#"play video!!!");
AVAsset *asset = [AVAsset assetWithURL:[self.videoFiles objectForKey:gesture.view.tag]];
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset];
self.avPlayer replaceCurrentItemWithPlayerItem: item];
[self.avLayer play];
}
Or use the self.videoFiles instead and then you don't need self.videoCounterTags at all:
NSURL* fileURL = [self.videoFiles objectForKey:gesture.view.tag];
if (fileURL!=nil) {
NSLog(#"play video!!!");
AVAsset *asset = [AVAsset assetWithURL:fileURL];
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset];
self.avPlayer replaceCurrentItemWithPlayerItem: item];
[self.avLayer play];
}
That's the gist of it.
Take a look at the way you're setting up the myCounter variable. It is set one time and never changes until a view is tapped, and then it is set to the count of scenes, -1.
In addition, try looking at the way you're setting to the _avPlayer pointer var. It's always being set, over and over, and it seems that in a for loop you'd want to be storing references instead of simply updating the same pointer to the value latest in collection of scenes.
Also, from Apple's documentation:
You can create arbitrary numbers of player layers with the same AVPlayer object. Only the most recently created player layer will actually display the video content on-screen.
So, it's possible that since you're using the same AVPlayer object to create all these AVPlayer layers, that you're never going to see any more than one actual video layer work.

Image doesn't show on top of a MPMoviePlayerController [duplicate]

I have a controller where I displays a video using MPMoviePlayerController. And I need to put an image over the video.
I am trying with the following code, but it doesn't show up. What I am missing?
// method to play the video
- (void)playVideoInLoopMode:(BOOL)loop {
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"myvideo" ofType:#"m4v"]];
MPMoviePlayerController *mp = [[MPMoviePlayerController alloc] initWithContentURL:url];
mp.controlStyle = MPMovieControlStyleNone;
if (loop) {
mp.repeatMode = MPMovieRepeatModeOne;
}
mp.view.frame = CGRectMake(0.0, 0.0, self.view.bounds.size.width, self.view.bounds.size.height);
self.player = mp;
[self.view addSubview:self.player.view];
[self.player prepareToPlay];
[self.player play];
}
// method to add the image
- (void) addImageLayer {
image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"myimage"]];
image.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
[self.view addSubview:image];
}
First I am running the video with the method: [self playVideoInLoopMode:YES] and after 5 seconds I am trying to put the image layer with the method [self addImageLayer];
In my AppDelegate.h I have this code in the didFinishLaunchingWithOptions:
MyViewController *myVC = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
[self.window addSubview:myVC.view];
[self.window makeKeyAndVisible];
Try adding the image view to the mp.view and then u add the mp.view to the general view
for example if the image will be always the same u can add it in your starting code and delete the method to add the view...
// method to play the video
- (void)playVideoInLoopMode:(BOOL)loop
{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"myvideo" ofType:#"m4v"]];
MPMoviePlayerController *mp = [[MPMoviePlayerController alloc] initWithContentURL:url];
mp.controlStyle = MPMovieControlStyleNone;
if (loop)
{
mp.repeatMode = MPMovieRepeatModeOne;
}
mp.view.frame = CGRectMake(0.0, 0.0, self.view.bounds.size.width, self.view.bounds.size.height);
self.player = mp;
[self.view addSubview:self.player.view];
image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"myimage.png"]];
image.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
[self.player addSubview:image];
[self.player prepareToPlay];
[self.player play];
}

Run multiple video file in objective c

There are two video file.When I want to see these two video
1) Only the last video file can play,see in fullscreen mode and also minimise when done button clicked..but first video file can't .
2) After a few time the first video file also see in black screen
- (void)viewDidLoad
{
[super viewDidLoad];
MPMoviePlayerController *moviePlayer;
NSArray *filename=#[#"nissan1",#"nissan5"];
//n![enter image description here][1]issan1,nissan5 are mp4 file
NSURL *fileURL1 = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:[filename objectAtIndex:0] ofType:#"mp4"]];
moviePlayer= [[MPMoviePlayerController alloc] initWithContentURL:fileURL1];
[moviePlayer.view setFrame:CGRectMake(5, 50, 100,100)];
moviePlayer.shouldAutoplay = NO;
moviePlayer.repeatMode = MPMovieRepeatModeOne;
moviePlayer.initialPlaybackTime = -1.0;
moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[moviePlayer prepareToPlay];
[self.view addSubview:moviePlayer.view];
/* second video file*/
NSURL *fileURL2 = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:[filename objectAtIndex:1] ofType:#"mp4"]];
moviePlayer= [[MPMoviePlayerController alloc] initWithContentURL:fileURL2];
[moviePlayer.view setFrame:CGRectMake(200, 50, 100,100)];
moviePlayer.shouldAutoplay = NO;
moviePlayer.repeatMode = MPMovieRepeatModeNone;
moviePlayer.initialPlaybackTime = -1.0;
moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[moviePlayer prepareToPlay];
[self.view addSubview:moviePlayer.view];
}
You should try with two instances. As Cristik pointed out, ARC targets it for deallocation once the method ends and you are using same variable.
Since you asked for sample code, try this:
- (void)viewDidLoad
{
[super viewDidLoad];
MPMoviePlayerController *moviePlayer1;
MPMoviePlayerController *moviePlayer2;
//filename is a name array
NSURL *fileURL1 = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:[filename objectAtIndex:0] ofType:#"mp4"]];
moviePlayer1= [[MPMoviePlayerController alloc] initWithContentURL:fileURL1];
[moviePlayer1.view setFrame:CGRectMake(5, 50, 100,100)];
moviePlayer1.shouldAutoplay = NO;
moviePlayer1.repeatMode = MPMovieRepeatModeOne;
moviePlayer1.initialPlaybackTime = -1.0;
moviePlayer1.movieSourceType = MPMovieSourceTypeFile;
[moviePlayer1 prepareToPlay];
[self.view addSubview:moviePlayer1.view];
/* second video file*/
NSURL *fileURL2 = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:[filename objectAtIndex:1] ofType:#"mp4"]];
moviePlayer2= [[MPMoviePlayerController alloc] initWithContentURL:fileURL2];
[moviePlayer2.view setFrame:CGRectMake(200, 50, 100,100)];
moviePlayer2.shouldAutoplay = NO;
moviePlayer2.repeatMode = MPMovieRepeatModeNone;
moviePlayer2.initialPlaybackTime = -1.0;
moviePlayer2.movieSourceType = MPMovieSourceTypeFile;
[moviePlayer2 prepareToPlay];
[self.view addSubview:moviePlayer2.view];
}

What is the best way playing MOV file?

I have generated that MOV file from the screen shots of the UI and record the sound. Combined both video and audio and generate a MOV formatted movie.
I have seen quite a lot of MPMoviePlayerViewController sample but it just shows me black screen. I tried AVPlayer but I can't get it work.
I'm new to playing movie file in iOS, please help.
Here is my code:
NSString *fileNamePath = mVideo;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *oldappSettingsPath = [documentsDirectory stringByAppendingPathComponent:fileNamePath];
NSURL *path = [NSURL fileURLWithPath:oldappSettingsPath];
self.mPlayer = [[MPMoviePlayerController alloc] initWithContentURL:path];
self.mPlayer.controlStyle = MPMovieControlStyleFullscreen;
self.mPlayer.fullscreen = YES;
self.mPlayer.scalingMode = MPMovieScalingModeFill;
[[self.mPlayer view] setFrame: CGRectMake(0, 0, 480, 320)];
[self.view addSubview:[self.mPlayer view]];
[self.mPlayer prepareToPlay];
[self.mPlayer play];
I have found the fixed to my MPMoviePlayerController :
NSURL *path = [NSURL fileURLWithPath:oldappSettingsPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:oldappSettingsPath]) {
NSLog(#"Exist");
self.mPlayer = [[MPMoviePlayerController alloc] initWithContentURL:path];
self.mPlayer.movieSourceType = MPMovieSourceTypeFile;
self.mPlayer.controlStyle = MPMovieControlStyleFullscreen;
self.mPlayer.fullscreen = YES;
self.mPlayer.scalingMode = MPMovieScalingModeFill;
[[self.mPlayer view] setFrame: CGRectMake(0, 0, 480, 320)];
[self.view addSubview:[self.mPlayer view]];
[self.mPlayer prepareToPlay];
[self.mPlayer play];
} else {
NSLog(#"Don't Exist");
}
I added also:
self.mPlayer.movieSourceType = MPMovieSourceTypeFile;
in my case the player shows black screen since the file i played is not there, so i added a checking first if the file exist or not.

Resources