MPMoviePlayerController doesn't work with remoteControlReceivedWithEvent - objective-c

I want to allow the controls from my keyboard to work in my app. The controls use Apple's Remote Control events (beginReceivingRemoteControlEvents, endReceivingRemoteControlEvents, and remoteControlReceivedWithEvent); however I cannot seem to get this to work with MPMoviePlayerController.
I do not see any events at the start of the program, even though beginReceivingRemoteControlEvents is called at the start.
I do not see any events during the playback of a video.
I do see events after I close the video.
From the above, it seems that the audio stream of MPMoviePlayerController disables the controls. However I do not know how to change this. I tried using [moviePlayer setUseApplicationAudioSession:NO]; to change the audio to use the system session, yet it does nothing.
Here is my setup. My app delegate is a UIViewController. I set the main window's root view controller to the app delegate, add views to the view controller and in the view controller for the parts which has to do with video.
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)tableView:(UITableView *)theTableView didSelectRowAtIndexPath:(NSIndexPath *)theIndexPath {
NSString *file = [[MGMFilesPath stringByExpandingTildeInPath] stringByAppendingPathComponent:[files objectAtIndex:[theIndexPath indexAtPosition:1]]];
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
NSLog(#"%d", [self isFirstResponder]);
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:file]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(exitedFullscreen:) name:MPMoviePlayerDidExitFullscreenNotification object:moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
if ([moviePlayer respondsToSelector:#selector(setFullscreen:animated:)]) {
[[self view] addSubview:[moviePlayer view]];
[moviePlayer setFullscreen:YES animated:YES];
[moviePlayer play];
} else {
[moviePlayer play];
}
[fileView deselectRowAtIndexPath:theIndexPath animated:NO];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
NSLog(#"remoteControlReceivedWithEvent: %#", event);
if (event.type==UIEventTypeRemoteControl) {
if (event.subtype==UIEventSubtypeRemoteControlPlay) {
NSLog(#"Play");
} else if (event.subtype==UIEventSubtypeRemoteControlPause) {
NSLog(#"Pause");
} else if (event.subtype==UIEventSubtypeRemoteControlTogglePlayPause) {
NSLog(#"Play Pause");
}
}
}
- (void)exitedFullscreen:(NSNotification*)notification {
[[moviePlayer view] removeFromSuperview];
[moviePlayer stop];
[moviePlayer release];
moviePlayer = nil;
[[AVAudioSession sharedInstance] setActive:NO error:nil];
}
- (void)playbackFinished:(NSNotification*)theNotification {
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerDidExitFullscreenNotification object:moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
NSNumber *reason = [[theNotification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
if ([reason intValue]!=MPMovieFinishReasonUserExited) {
[moviePlayer setFullscreen:NO animated:YES];
[[moviePlayer view] removeFromSuperview];
[moviePlayer stop];
[moviePlayer release];
moviePlayer = nil;
[[AVAudioSession sharedInstance] setActive:NO error:nil];
}
NSLog(#"%d", [self isFirstResponder]);
}
As you can see in the code above, I verified that it was first responder and it was, so I know it's not a first responder issue.
Can someone help me get this working?
Thanks

Apparently, MPMoviePlayerController isn't the way to go for this. What I ended up doing was using MPMoviePlayerViewController and override the remoteControlReceivedWithEvent to customize the controls. Below is my current code which I am using.
#interface MGMMoviePlayerViewController : MPMoviePlayerViewController
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
#end
#implementation MGMMoviePlayerViewController
- (void)remoteControlReceivedWithEvent:(UIEvent *)theEvent {
if (theEvent.type==UIEventTypeRemoteControl) {
if (theEvent.subtype==UIEventSubtypeRemoteControlPlay) {
[[self moviePlayer] play];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlPause) {
[[self moviePlayer] pause];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlTogglePlayPause) {
if ([[self moviePlayer] playbackState]==MPMoviePlaybackStatePlaying) {
[[self moviePlayer] pause];
} else {
[[self moviePlayer] play];
}
} else if (theEvent.subtype==UIEventSubtypeRemoteControlStop) {
[[self moviePlayer] stop];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlNextTrack) {
NSTimeInterval currentTime = [[self moviePlayer] currentPlaybackTime];
currentTime += 10;
if (currentTime>[[self moviePlayer] duration])
currentTime = [[self moviePlayer] duration];
[[self moviePlayer] setCurrentPlaybackTime:currentTime];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlPreviousTrack) {
NSTimeInterval currentTime = [[self moviePlayer] currentPlaybackTime];
currentTime -= 10;
if (currentTime<0)
currentTime = 0;
[[self moviePlayer] setCurrentPlaybackTime:currentTime];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlBeginSeekingBackward) {
[[self moviePlayer] beginSeekingBackward];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlBeginSeekingForward) {
[[self moviePlayer] beginSeekingForward];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlEndSeekingBackward || theEvent.subtype==UIEventSubtypeRemoteControlEndSeekingForward) {
[[self moviePlayer] endSeeking];
}
}
}
#end
- (void)tableView:(UITableView *)theTableView didSelectRowAtIndexPath:(NSIndexPath *)theIndexPath {
NSString *file = [[MGMFilesPath stringByExpandingTildeInPath] stringByAppendingPathComponent:[files objectAtIndex:[theIndexPath indexAtPosition:1]]];
moviePlayerView = [[MGMMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:file]];
[self presentMoviePlayerViewControllerAnimated:moviePlayerView];
[[moviePlayerView moviePlayer] play];
[fileView deselectRowAtIndexPath:theIndexPath animated:NO];
}

Related

how to get thumbnail of video url ios

i have tried below code. As result its gets image some time, not in every call of this method.
is there any solution.
-(UIImage *)thumbnailFromVideoAtURL:(NSString *)urlstr
{
NSURL *url = [NSURL URLWithString:urlstr];
AVAsset *asset = [AVAsset assetWithURL:url];
// Get thumbnail at the very start of the video
CMTime thumbnailTime = [asset duration];
thumbnailTime.value = 0;
// Get image from the video at the given time
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
CGImageRef imageRef = [imageGenerator copyCGImageAtTime:thumbnailTime actualTime:NULL error:NULL];
UIImage *thumbnail = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return thumbnail;
}
CustomMoviePlayerVC.h
#interface CustomMoviePlayerVC : UIViewController {
#public
MPMoviePlayerController *mp;
NSURL *movieURL;
}
#property (weak, nonatomic) UIView *playBtn;
- (id)initWithPath:(NSString *)moviePath tag:(int)tag;
- (void)startPlayer;
- (void)pausePlayer;
- (void)stopPlayer;
- (BOOL)isFullScreen;
- (UIImage *)getVideoThumbnail;
- (MPMoviePlaybackState)getVideoPlaybackState;
- (MPMovieLoadState)getVideoLoadState;
- (void)enterFullScreenAnimated:(BOOL)animated;
- (void)exitFullScreenAnimated:(BOOL)animated;
- (void)prepare;
#end
CustomMoviePlayerVC.m
#import "CustomMoviePlayerVC.h"
#interface CustomMoviePlayerVC ()
#end
#implementation CustomMoviePlayerVC
- (BOOL)isFullScreen
{
return mp.isFullscreen;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (id)initWithPath:(NSString *)moviePath tag:(int)tag
{
// Initialize and create movie URL
if (self = [super init]) {
movieURL = [NSURL URLWithString:moviePath];
mp = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
// Set movie player layout
if(tag == 1) {
[mp setControlStyle:MPMovieControlStyleNone];
}
[mp setShouldAutoplay:NO];
[mp setFullscreen:NO];
// May help to reduce latency
[mp prepareToPlay];
// Register that the load state changed (movie is ready)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateChanged:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector: #selector(MoviePlayerThumbnailImageRequestDidFinish:)
name: MPMoviePlayerThumbnailImageRequestDidFinishNotification
object: nil];
// registering for playback state change notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackStateDidChange:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:nil];
// registering for playback finish notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
// registering for playback finish notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackWillEnterFullscreen:)
name:MPMoviePlayerWillEnterFullscreenNotification
object:nil];
// registering for playback finish notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackDidExitFullscreen:)
name:MPMoviePlayerDidExitFullscreenNotification
object:nil];
}
return self;
}
- (void)MoviePlayerThumbnailImageRequestDidFinish:(NSNotification*)not
{
}
- (void)enterFullScreenAnimated:(BOOL)animated
{
[mp setFullscreen:YES animated:animated];
}
- (void)exitFullScreenAnimated:(BOOL)animated
{
[mp setFullscreen:NO animated:animated];
}
- (void)moviePlayerLoadStateChanged:(NSNotification *)notification
{
[mp setControlStyle:MPMovieControlStyleEmbedded];
// Unless state is unknown, start playback
if ([mp loadState] != MPMovieLoadStateUnknown) {
// Set frame of movie player
[[mp view] setFrame:self.view.frame];
// Add movie player as subview
[[self view] addSubview:[mp view]];
}
}
- (void)moviePlaybackDidFinish:(NSNotification *)notification
{
[self exitFullScreenAnimated:YES];
if (mp.currentPlaybackTime <= 0.1) {
dispatch_async(dispatch_get_main_queue(), ^{
[mp stop];
[mp play];
[mp pause];
});
}
}
- (void)moviePlaybackStateDidChange:(NSNotification *)notification
{
switch ([self getVideoPlaybackState]) {
case MPMoviePlaybackStatePlaying:
[self.playBtn setHidden:YES];
[self.playBtn setUserInteractionEnabled:NO];
break;
case MPMoviePlaybackStatePaused:
[self.playBtn setHidden:NO];
[self.playBtn setUserInteractionEnabled:YES];
break;
case MPMoviePlaybackStateStopped:
[self.playBtn setHidden:NO];
[self.playBtn setUserInteractionEnabled:YES];
break;
default:
break;
}
}
- (void)moviePlaybackWillEnterFullscreen:(NSNotification *)notification
{
}
- (void)moviePlaybackDidExitFullscreen:(NSNotification *)notification
{
}
- (void)startPlayer
{
[self.playBtn setHidden:YES];
[self.playBtn setUserInteractionEnabled:NO];
if (mp.loadState != MPMovieLoadStateUnknown) {
[mp play];
}
}
- (void)pausePlayer
{
[self.playBtn setHidden:NO];
[self.playBtn setUserInteractionEnabled:YES];
if (mp.loadState != MPMovieLoadStateUnknown) {
[mp pause];
}
}
- (void)stopPlayer
{
[self.playBtn setHidden:NO];
[self.playBtn setUserInteractionEnabled:YES];
if (mp.loadState != MPMovieLoadStateUnknown) {
[mp stop];
}
}
- (UIImage *)getVideoThumbnail
{
if (mp && mp.loadState != MPMovieLoadStateUnknown) {
return [mp thumbnailImageAtTime:0.3 timeOption:MPMovieTimeOptionExact];
}
return nil;
}
- (MPMoviePlaybackState)getVideoPlaybackState
{
return mp.playbackState;
}
- (MPMovieLoadState)getVideoLoadState
{
return mp.loadState;
}
- (void)prepare
{
[mp prepareToPlay];
}
#end
Use getVideoThumbnail to get image from video.

Take a picture in iOS without UIImagePicker and without preview it

Do you know any way / method to take a photo in iOS and saving it to camera Roll only with a simple button pressure without showing any preview?
I already know how to show the camera view but it show the preview of the image and the user need to click the take photo button to take the photo.
In few Words: the user click the button, the picture is taken, without previews nor double checks to take / save the photo.
I already found the takePicture method of UIIMagePickerController Class http://developer.apple.com/library/ios/documentation/uikit/reference/UIImagePickerController_Class/UIImagePickerController/UIImagePickerController.html#//apple_ref/occ/instm/UIImagePickerController/takePicture
Set the showsCameraControls-Property to NO.
poc = [[UIImagePickerController alloc] init];
[poc setTitle:#"Take a photo."];
[poc setDelegate:self];
[poc setSourceType:UIImagePickerControllerSourceTypeCamera];
poc.showsCameraControls = NO;
You also have to add your own Controls as a custom view on the top of poc.view. But that is very simple and you can add your own UI-style by that way.
You receive the image-data as usually within the imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:
To take the photo, you call
[poc takePicture];
from your custom button.
Hope, that works for you.
Assuming you want a point-and-shoot method, you can create an AVSession and just call the UIImageWriteToSavedPhotosAlbum method.
Here is a link that goes into that exact process: http://www.musicalgeometry.com/?p=1297
It's also worth noting that your users need to have given the app access to their camera roll or you may experience issues saving the images.
You need to design your own custom preview according to your size, on capture button pressed and call buttonPressed method and do stuff what you want
(void)buttonPressed:(UIButton *)sender {
NSLog(#" Capture Clicked");
[self.imagePicker takePicture];
//[NSTimer scheduledTimerWithTimeInterval:3.0f target:self
selector:#selector(timerFired:) userInfo:nil repeats:NO];
}
following is code that will take photo without showing preview screen. when i tried the accepted answer, which uses UIImagePickerController, the preview screen showed, then auto disappeared. with the code below, user taps 'takePhoto' button, and the devices takes photo with zero change to UI (in my app, i add a green check mark next to take photo button). the code below is from apple https://developer.apple.com/LIBRARY/IOS/samplecode/AVCam/Introduction/Intro.html with the 'extra functions' (that do not relate to taking still photo) commented out. thank you incmiko for suggesting this code in your answer iOS take photo from camera without modalViewController.
updating code, 26 mar 2015:
to trigger snap photo:
[self snapStillImage:sender];
in .h file:
#import <AVFoundation/AVFoundation.h>
#import <AssetsLibrary/AssetsLibrary.h>
// include code below in header file, after #import and before #interface
// avfoundation copy paste code
static void * CapturingStillImageContext = &CapturingStillImageContext;
static void * RecordingContext = &RecordingContext;
static void * SessionRunningAndDeviceAuthorizedContext = &SessionRunningAndDeviceAuthorizedContext;
// avfoundation, include code below after #interface
// avf - Session management.
#property (nonatomic) dispatch_queue_t sessionQueue; // Communicate with the session and other session objects on this queue.
#property (nonatomic) AVCaptureSession *session;
#property (nonatomic) AVCaptureDeviceInput *videoDeviceInput;
#property (nonatomic) AVCaptureMovieFileOutput *movieFileOutput;
#property (nonatomic) AVCaptureStillImageOutput *stillImageOutput;
// avf - Utilities.
#property (nonatomic) UIBackgroundTaskIdentifier backgroundRecordingID;
#property (nonatomic, getter = isDeviceAuthorized) BOOL deviceAuthorized;
#property (nonatomic, readonly, getter = isSessionRunningAndDeviceAuthorized) BOOL sessionRunningAndDeviceAuthorized;
#property (nonatomic) BOOL lockInterfaceRotation;
#property (nonatomic) id runtimeErrorHandlingObserver;
in .m file:
#pragma mark - AV Foundation
- (BOOL)isSessionRunningAndDeviceAuthorized
{
return [[self session] isRunning] && [self isDeviceAuthorized];
}
+ (NSSet *)keyPathsForValuesAffectingSessionRunningAndDeviceAuthorized
{
return [NSSet setWithObjects:#"session.running", #"deviceAuthorized", nil];
}
// call following method from viewDidLoad
- (void)CreateAVCaptureSession
{
// Create the AVCaptureSession
AVCaptureSession *session = [[AVCaptureSession alloc] init];
[self setSession:session];
// Check for device authorization
[self checkDeviceAuthorizationStatus];
// In general it is not safe to mutate an AVCaptureSession or any of its inputs, outputs, or connections from multiple threads at the same time.
// Why not do all of this on the main queue?
// -[AVCaptureSession startRunning] is a blocking call which can take a long time. We dispatch session setup to the sessionQueue so that the main queue isn't blocked (which keeps the UI responsive).
dispatch_queue_t sessionQueue = dispatch_queue_create("session queue", DISPATCH_QUEUE_SERIAL);
[self setSessionQueue:sessionQueue];
dispatch_async(sessionQueue, ^{
[self setBackgroundRecordingID:UIBackgroundTaskInvalid];
NSError *error = nil;
AVCaptureDevice *videoDevice = [ViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionFront];
AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
if (error)
{
NSLog(#"%#", error);
}
if ([session canAddInput:videoDeviceInput])
{
[session addInput:videoDeviceInput];
[self setVideoDeviceInput:videoDeviceInput];
dispatch_async(dispatch_get_main_queue(), ^{
// Why are we dispatching this to the main queue?
// Because AVCaptureVideoPreviewLayer is the backing layer for AVCamPreviewView and UIView can only be manipulated on main thread.
// Note: As an exception to the above rule, it is not necessary to serialize video orientation changes on the AVCaptureVideoPreviewLayer’s connection with other session manipulation.
});
}
/* AVCaptureDevice *audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
if (error)
{
NSLog(#"%#", error);
}
if ([session canAddInput:audioDeviceInput])
{
[session addInput:audioDeviceInput];
}
*/
AVCaptureMovieFileOutput *movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([session canAddOutput:movieFileOutput])
{
[session addOutput:movieFileOutput];
AVCaptureConnection *connection = [movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
if ([connection isVideoStabilizationSupported])
[connection setEnablesVideoStabilizationWhenAvailable:YES];
[self setMovieFileOutput:movieFileOutput];
}
AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
if ([session canAddOutput:stillImageOutput])
{
[stillImageOutput setOutputSettings:#{AVVideoCodecKey : AVVideoCodecJPEG}];
[session addOutput:stillImageOutput];
[self setStillImageOutput:stillImageOutput];
}
});
}
// call method below from viewWilAppear
- (void)AVFoundationStartSession
{
dispatch_async([self sessionQueue], ^{
[self addObserver:self forKeyPath:#"sessionRunningAndDeviceAuthorized" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:SessionRunningAndDeviceAuthorizedContext];
[self addObserver:self forKeyPath:#"stillImageOutput.capturingStillImage" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:CapturingStillImageContext];
[self addObserver:self forKeyPath:#"movieFileOutput.recording" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:RecordingContext];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]];
__weak ViewController *weakSelf = self;
[self setRuntimeErrorHandlingObserver:[[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureSessionRuntimeErrorNotification object:[self session] queue:nil usingBlock:^(NSNotification *note) {
ViewController *strongSelf = weakSelf;
dispatch_async([strongSelf sessionQueue], ^{
// Manually restarting the session since it must have been stopped due to an error.
[[strongSelf session] startRunning];
});
}]];
[[self session] startRunning];
});
}
// call method below from viewDidDisappear
- (void)AVFoundationStopSession
{
dispatch_async([self sessionQueue], ^{
[[self session] stopRunning];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]];
[[NSNotificationCenter defaultCenter] removeObserver:[self runtimeErrorHandlingObserver]];
[self removeObserver:self forKeyPath:#"sessionRunningAndDeviceAuthorized" context:SessionRunningAndDeviceAuthorizedContext];
[self removeObserver:self forKeyPath:#"stillImageOutput.capturingStillImage" context:CapturingStillImageContext];
[self removeObserver:self forKeyPath:#"movieFileOutput.recording" context:RecordingContext];
});
}
- (BOOL)prefersStatusBarHidden
{
return YES;
}
- (BOOL)shouldAutorotate
{
// Disable autorotation of the interface when recording is in progress.
return ![self lockInterfaceRotation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// [[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] setVideoOrientation:(AVCaptureVideoOrientation)toInterfaceOrientation];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == CapturingStillImageContext)
{
BOOL isCapturingStillImage = [change[NSKeyValueChangeNewKey] boolValue];
if (isCapturingStillImage)
{
[self runStillImageCaptureAnimation];
}
}
else if (context == RecordingContext)
{
BOOL isRecording = [change[NSKeyValueChangeNewKey] boolValue];
dispatch_async(dispatch_get_main_queue(), ^{
if (isRecording)
{
// [[self cameraButton] setEnabled:NO];
// [[self recordButton] setTitle:NSLocalizedString(#"Stop", #"Recording button stop title") forState:UIControlStateNormal];
// [[self recordButton] setEnabled:YES];
}
else
{
// [[self cameraButton] setEnabled:YES];
// [[self recordButton] setTitle:NSLocalizedString(#"Record", #"Recording button record title") forState:UIControlStateNormal];
// [[self recordButton] setEnabled:YES];
}
});
}
else if (context == SessionRunningAndDeviceAuthorizedContext)
{
BOOL isRunning = [change[NSKeyValueChangeNewKey] boolValue];
dispatch_async(dispatch_get_main_queue(), ^{
if (isRunning)
{
// [[self cameraButton] setEnabled:YES];
// [[self recordButton] setEnabled:YES];
// [[self stillButton] setEnabled:YES];
}
else
{
// [[self cameraButton] setEnabled:NO];
// [[self recordButton] setEnabled:NO];
// [[self stillButton] setEnabled:NO];
}
});
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark Actions
- (IBAction)toggleMovieRecording:(id)sender
{
// [[self recordButton] setEnabled:NO];
dispatch_async([self sessionQueue], ^{
if (![[self movieFileOutput] isRecording])
{
[self setLockInterfaceRotation:YES];
if ([[UIDevice currentDevice] isMultitaskingSupported])
{
// Setup background task. This is needed because the captureOutput:didFinishRecordingToOutputFileAtURL: callback is not received until AVCam returns to the foreground unless you request background execution time. This also ensures that there will be time to write the file to the assets library when AVCam is backgrounded. To conclude this background execution, -endBackgroundTask is called in -recorder:recordingDidFinishToOutputFileURL:error: after the recorded file has been saved.
[self setBackgroundRecordingID:[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil]];
}
// Update the orientation on the movie file output video connection before starting recording.
// [[[self movieFileOutput] connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] videoOrientation]];
// Turning OFF flash for video recording
[ViewController setFlashMode:AVCaptureFlashModeOff forDevice:[[self videoDeviceInput] device]];
// Start recording to a temporary file.
NSString *outputFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[#"movie" stringByAppendingPathExtension:#"mov"]];
[[self movieFileOutput] startRecordingToOutputFileURL:[NSURL fileURLWithPath:outputFilePath] recordingDelegate:self];
}
else
{
[[self movieFileOutput] stopRecording];
}
});
}
- (IBAction)changeCamera:(id)sender
{
// [[self cameraButton] setEnabled:NO];
// [[self recordButton] setEnabled:NO];
// [[self stillButton] setEnabled:NO];
dispatch_async([self sessionQueue], ^{
AVCaptureDevice *currentVideoDevice = [[self videoDeviceInput] device];
AVCaptureDevicePosition preferredPosition = AVCaptureDevicePositionUnspecified;
AVCaptureDevicePosition currentPosition = [currentVideoDevice position];
switch (currentPosition)
{
case AVCaptureDevicePositionUnspecified:
preferredPosition = AVCaptureDevicePositionBack;
break;
case AVCaptureDevicePositionBack:
preferredPosition = AVCaptureDevicePositionFront;
break;
case AVCaptureDevicePositionFront:
preferredPosition = AVCaptureDevicePositionBack;
break;
}
AVCaptureDevice *videoDevice = [ViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:preferredPosition];
AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:nil];
[[self session] beginConfiguration];
[[self session] removeInput:[self videoDeviceInput]];
if ([[self session] canAddInput:videoDeviceInput])
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:currentVideoDevice];
[ViewController setFlashMode:AVCaptureFlashModeAuto forDevice:videoDevice];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:videoDevice];
[[self session] addInput:videoDeviceInput];
[self setVideoDeviceInput:videoDeviceInput];
}
else
{
[[self session] addInput:[self videoDeviceInput]];
}
[[self session] commitConfiguration];
dispatch_async(dispatch_get_main_queue(), ^{
// [[self cameraButton] setEnabled:YES];
// [[self recordButton] setEnabled:YES];
// [[self stillButton] setEnabled:YES];
});
});
}
- (IBAction)snapStillImage:(id)sender
{
dispatch_async([self sessionQueue], ^{
// Update the orientation on the still image output video connection before capturing.
// [[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] videoOrientation]];
// Flash set to Auto for Still Capture
[ViewController setFlashMode:AVCaptureFlashModeAuto forDevice:[[self videoDeviceInput] device]];
// Capture a still image.
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer)
{
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
// do someting good with saved image
[self saveImageToParse:image];
}
}];
});
}
- (IBAction)focusAndExposeTap:(UIGestureRecognizer *)gestureRecognizer
{
// CGPoint devicePoint = [(AVCaptureVideoPreviewLayer *)[[self previewView] layer] captureDevicePointOfInterestForPoint:[gestureRecognizer locationInView:[gestureRecognizer view]]];
// [self focusWithMode:AVCaptureFocusModeAutoFocus exposeWithMode:AVCaptureExposureModeAutoExpose atDevicePoint:devicePoint monitorSubjectAreaChange:YES];
}
- (void)subjectAreaDidChange:(NSNotification *)notification
{
CGPoint devicePoint = CGPointMake(.5, .5);
[self focusWithMode:AVCaptureFocusModeContinuousAutoFocus exposeWithMode:AVCaptureExposureModeContinuousAutoExposure atDevicePoint:devicePoint monitorSubjectAreaChange:NO];
}
#pragma mark File Output Delegate
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
if (error)
NSLog(#"%#", error);
[self setLockInterfaceRotation:NO];
// Note the backgroundRecordingID for use in the ALAssetsLibrary completion handler to end the background task associated with this recording. This allows a new recording to be started, associated with a new UIBackgroundTaskIdentifier, once the movie file output's -isRecording is back to NO — which happens sometime after this method returns.
UIBackgroundTaskIdentifier backgroundRecordingID = [self backgroundRecordingID];
[self setBackgroundRecordingID:UIBackgroundTaskInvalid];
[[[ALAssetsLibrary alloc] init] writeVideoAtPathToSavedPhotosAlbum:outputFileURL completionBlock:^(NSURL *assetURL, NSError *error) {
if (error)
NSLog(#"%#", error);
[[NSFileManager defaultManager] removeItemAtURL:outputFileURL error:nil];
if (backgroundRecordingID != UIBackgroundTaskInvalid)
[[UIApplication sharedApplication] endBackgroundTask:backgroundRecordingID];
}];
}
#pragma mark Device Configuration
- (void)focusWithMode:(AVCaptureFocusMode)focusMode exposeWithMode:(AVCaptureExposureMode)exposureMode atDevicePoint:(CGPoint)point monitorSubjectAreaChange:(BOOL)monitorSubjectAreaChange
{
dispatch_async([self sessionQueue], ^{
AVCaptureDevice *device = [[self videoDeviceInput] device];
NSError *error = nil;
if ([device lockForConfiguration:&error])
{
if ([device isFocusPointOfInterestSupported] && [device isFocusModeSupported:focusMode])
{
[device setFocusMode:focusMode];
[device setFocusPointOfInterest:point];
}
if ([device isExposurePointOfInterestSupported] && [device isExposureModeSupported:exposureMode])
{
[device setExposureMode:exposureMode];
[device setExposurePointOfInterest:point];
}
[device setSubjectAreaChangeMonitoringEnabled:monitorSubjectAreaChange];
[device unlockForConfiguration];
}
else
{
NSLog(#"%#", error);
}
});
}
+ (void)setFlashMode:(AVCaptureFlashMode)flashMode forDevice:(AVCaptureDevice *)device
{
if ([device hasFlash] && [device isFlashModeSupported:flashMode])
{
NSError *error = nil;
if ([device lockForConfiguration:&error])
{
[device setFlashMode:flashMode];
[device unlockForConfiguration];
}
else
{
NSLog(#"%#", error);
}
}
}
+ (AVCaptureDevice *)deviceWithMediaType:(NSString *)mediaType preferringPosition:(AVCaptureDevicePosition)position
{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:mediaType];
AVCaptureDevice *captureDevice = [devices firstObject];
for (AVCaptureDevice *device in devices)
{
if ([device position] == position)
{
captureDevice = device;
break;
}
}
return captureDevice;
}
#pragma mark UI
- (void)runStillImageCaptureAnimation
{
/*
dispatch_async(dispatch_get_main_queue(), ^{
[[[self previewView] layer] setOpacity:0.0];
[UIView animateWithDuration:.25 animations:^{
[[[self previewView] layer] setOpacity:1.0];
}];
});
*/
}
- (void)checkDeviceAuthorizationStatus
{
NSString *mediaType = AVMediaTypeVideo;
[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
if (granted)
{
//Granted access to mediaType
[self setDeviceAuthorized:YES];
}
else
{
//Not granted access to mediaType
dispatch_async(dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:#"AVCam!"
message:#"AVCam doesn't have permission to use Camera, please change privacy settings"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
[self setDeviceAuthorized:NO];
});
}
}];
}

Correctly Stoping AVAudioPlayer. Currently runs in Background

I've been strugling with this problem for quite a while.
I'm trying to make a player that contains a playlist and plays only the music files stored inside the application.
Now, i'm using AVAudioPlayer to play the mp3 files. My problem is that when i load the playlist i can't stop the previous mp3 from playing and therefor i get a mixture of sounds between the first audio and all the other audio files that i load from the playlist.
so, here is my code:
#import "MainViewController.h"
#import <Foundation/Foundation.h>
#pragma mark Audio session callbacks_______________________
#implementation MainViewController
#synthesize artworkItem;
#synthesize userMediaItemCollection;
#synthesize playBarButton;
#synthesize pauseBarButton;
#synthesize musicPlayer;
#synthesize navigationBar;
#synthesize noArtworkImage;
#synthesize backgroundColorTimer;
#synthesize nowPlayingLabel, AudFile;
#synthesize appSoundButton;
#synthesize addOrShowMusicButton;
#synthesize appSoundPlayer;
#synthesize soundFileURL;
#synthesize interruptedOnPlayback;
#synthesize playedMusicOnce;
#synthesize playing;
#pragma mark Music control________________________________
- (IBAction) playOrPauseMusic: (id)sender {
}
- (IBAction) AddMusicOrShowMusic: (id) sender {
[audioPlayer stop];
// Load the Playlist direcly
MusicTableViewController *controller = [[MusicTableViewController alloc] initWithNibName: #"MusicTableView" bundle: nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController: controller animated: YES];
[controller release];
}
#pragma mark Application playback control_________________
- (IBAction) playAppSound: (id) sender {
// [appSoundPlayer play];
// playing = YES;
// [appSoundButton setEnabled: NO];
}
// delegate method for the audio route change alert view; follows the protocol specified
// in the UIAlertViewDelegate protocol.
- (void) alertView: routeChangeAlertView clickedButtonAtIndex: buttonIndex {
if ((NSInteger) buttonIndex == 1) {
[appSoundPlayer play];
} else {
[appSoundPlayer setCurrentTime: 0];
[appSoundButton setEnabled: YES];
}
[routeChangeAlertView release];
}
#pragma mark AV Foundation delegate methods____________
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) appSoundPlayer successfully: (BOOL) flag {
}
- (void) audioPlayerBeginInterruption: player {
}
- (void) audioPlayerEndInterruption: player {
}
#pragma mark Table view delegate methods________________
// Invoked when the user taps the Done button in the table view.
- (void) musicTableViewControllerDidFinish: (MusicTableViewController *) controller {
[self dismissModalViewControllerAnimated: YES];
}
#pragma mark Application setup____________________________
#if TARGET_IPHONE_SIMULATOR
#warning *** Simulator mode: iPod library access works only when running on a device.
#endif
//play audio 2
- (void)playAudio2:(NSString*) name type:(NSString*)type
{
[self stopAudio];
[audioPlayer stop];
[audioPlayer release];
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:name
ofType:type]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:url
error:&error];
if (error)
{
NSLog(#"Error in audioPlayer: %#",
[error localizedDescription]);
} else {
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
}
[audioPlayer play];
}
-(void)playAudio
{
[appSoundPlayer play];
}
- (void)stopAudio
{
[appSoundPlayer stop];
}
// Configure the application.
- (void) viewDidLoad {
[super viewDidLoad];
[self setPlayedMusicOnce: NO];
[self setNoArtworkImage: [UIImage imageNamed: #"no_artwork.png"]];
[self setPlayBarButton: [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemPlay
target: self
action: #selector (playOrPauseMusic:)]];
[self setPauseBarButton: [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemPause
target: self
action: #selector (playOrPauseMusic:)]];
[addOrShowMusicButton setTitle: NSLocalizedString (#"Add Music", #"Title for 'Add Music' button, before user has chosen some music")
forState: UIControlStateNormal];
[appSoundButton setTitle: NSLocalizedString (#"Play App Sound", #"Title for 'Play App Sound' button")
forState: UIControlStateNormal];
[nowPlayingLabel setText: NSLocalizedString (#"Instructions", #"Brief instructions to user, shown at launch")];
// Configure a timer to change the background color. The changing color represents an
// application that is doing something else while iPod music is playing.
[self setBackgroundColorTimer: [NSTimer scheduledTimerWithTimeInterval: 3.5
target: self
selector: #selector (updateBackgroundColor)
userInfo: nil
repeats: YES]];
[self setupAudioSession];
}
// Invoked by the backgroundColorTimer.
- (void) updateBackgroundColor {
[UIView beginAnimations: nil context: nil];
[UIView setAnimationDuration: 3.0];
CGFloat redLevel = rand() / (float) RAND_MAX;
CGFloat greenLevel = rand() / (float) RAND_MAX;
CGFloat blueLevel = rand() / (float) RAND_MAX;
self.view.backgroundColor = [UIColor colorWithRed: redLevel
green: greenLevel
blue: blueLevel
alpha: 1.0];
[UIView commitAnimations];
}
#pragma mark Application state management_____________
- (void) didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void) viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
-(void) setupAudioSession
{
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *setCategoryError = nil;
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
if (setCategoryError){/* Handle Error COndition*/}
NSError *activationError = nil;
[audioSession setActive:YES error:&activationError];
if (activationError){
/*handle error*/
}
}
// just for test , delete after
-(void) myInstanceMethod: (id)sender{
[self setupAudioSession];
[audioPlayer stop];
[audioPlayer release];
AudFile = sender;
NSLog(#"My Instance metthod called ok with item : %#", sender);
[self playAudio2:[NSString stringWithFormat:#"%#",AudFile] type:#"mp3"];
//[self setupApplicationAudio: sender];
NSLog(#"New Audfile is: %#", AudFile);
// [self setupApplicationAudio];
}
+(void) myClassMethod{
NSLog(#"Class Called ok");
}
- (void)dealloc {
/*
// This sample doesn't use libray change notifications; this code is here to show how
// it's done if you need it.
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMediaLibraryDidChangeNotification
object: musicPlayer];
[[MPMediaLibrary defaultMediaLibrary] endGeneratingLibraryChangeNotifications];
*/
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification
object: musicPlayer];
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMusicPlayerControllerPlaybackStateDidChangeNotification
object: musicPlayer];
[musicPlayer endGeneratingPlaybackNotifications];
[musicPlayer release];
[artworkItem release];
[backgroundColorTimer invalidate];
[backgroundColorTimer release];
[navigationBar release];
[noArtworkImage release];
[nowPlayingLabel release];
[pauseBarButton release];
[playBarButton release];
[soundFileURL release];
[userMediaItemCollection release];
[super dealloc];
}
I am sending the file name from my playlist to my player through
-(void) myInstanceMethod: (id)sender{
[self setupAudioSession];
[audioPlayer stop];
[audioPlayer release];
AudFile = sender;
NSLog(#"My Instance metthod called ok with item : %#", sender);
[self playAudio2:[NSString stringWithFormat:#"%#",AudFile] type:#"mp3"];
//[self setupApplicationAudio: sender];
NSLog(#"New Audfile is: %#", AudFile);
// [self setupApplicationAudio];
}
and i load my playlist from my mainviewcontroller using the UIModalTransition in the method
- (IBAction) AddMusicOrShowMusic: (id) sender {
[audioPlayer stop];
// Load the Playlist direcly
MusicTableViewController *controller = [[MusicTableViewController alloc] initWithNibName: #"MusicTableView" bundle: nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController: controller animated: YES];
[controller release];
}
As you can see when i load my playlist i tell the player to stop playing through
[audioPlayer stop];
but for some reason it failes to stop playing, therefore creating an overlap of sounds.
This is my problem which i'm trying to figure out.
Thank you
and best regards!

MPMoviePlayerViewController exits after background

When my app goes to background and back, modal view closes. Why is this happend? I tried with pause on and off. I have ARC enabled, if it is a useful info.
MPMoviePlayerViewController * player = [[MPMoviePlayerViewController alloc] initWithContentURL:targetURL];
[player.moviePlayer prepareToPlay];
[self presentMoviePlayerViewControllerAnimated:player];
In case anyone else stumbles across this (as I did before I found my own solution), I was able to prevent MPMoviePlayerViewController from exiting when the app backgrounds by subclassing it and removing it as an observer of UIApplicationDidEnterBackgroundNotification:
- (id)initWithContentURL:(NSURL *)contentURL {
self = [super initWithContentURL:contentURL];
if (self){
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}
return self;
}
You don't need to subclass MPMoviePlayerViewController - just do following after creating MPMoviePlayerViewController instance.
[[NSNotificationCenter defaultCenter] removeObserver:self.moviePlayerViewController name:UIApplicationDidEnterBackgroundNotification object:nil];
Here is full code that can help you
// Call this to start initialization and play movie
-(void)prepareMoviePlayer:(NSURL *)moviePath
{
moviePlayerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:moviePath];
if ([[moviePlayerViewController moviePlayer] respondsToSelector:#selector(loadState)])
{
[[moviePlayerViewController moviePlayer] setControlStyle:MPMovieControlStyleNone];
[[moviePlayerViewController moviePlayer] setFullscreen:YES];
[[moviePlayerViewController moviePlayer] prepareToPlay];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateDidChange:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
}
}
- (void) addPlayer
{
[[[moviePlayerViewController moviePlayer] view] setFrame:self.view.bounds];
[[self view] addSubview:[[moviePlayerViewController moviePlayer] view]];
}
static NSTimeInterval t;
// Call this on applicationWillResignActive
-(void) pauseMovieInBackGround
{
[[moviePlayerViewController moviePlayer] pause];
t = [[moviePlayerViewController moviePlayer] currentPlaybackTime];
[moviePlayerViewController.view removeFromSuperview];
}
// Call this on applicationWillEnterForeground
-(void) resumeMovieInFrontGround
{
[self addPlayer];
[[moviePlayerViewController moviePlayer] stop];
[[moviePlayerViewController moviePlayer] setInitialPlaybackTime:t];
[[moviePlayerViewController moviePlayer] play];
}
-(void)moviePlayerLoadStateDidChange:(NSNotification *)notification
{
if([[moviePlayerViewController moviePlayer] loadState] != MPMovieLoadStateUnknown)
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
[self addPlayer];
[[moviePlayerViewController moviePlayer] play];
}
}
-(void)videoPlayBackDidFinish:(NSNotification*)notification
{
[self dismissMoviePlayerViewControllerAnimated];
}
I am coming across this issue.
I've tried ChrisH's answer, but it didn't work for me until I put removeObserver into viewDidLoad() instead of init().
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}
Then it works. Enjoy it.

How to play video in Objective-C - Causes Jerk when loads

I am developing an application which loads video while the application launches. I observe a huge jerk while the video plays and removes from screen.
My code is as follow:
VideoPlayer.m
-(id)initWithVideo: (CGRect)frame file:(NSString *)videoFile
{
if (self = [super initWithFrame:frame])
{
NSArray *file = [videoFile componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"."]];
NSString *moviePath = [[NSBundle mainBundle] pathForResource:[file objectAtIndex:0] ofType:[file objectAtIndex:1]];
if (nil != moviePath)
{
if (nil != theMovie)
{
[theMovie.view removeFromSuperview];
}
theMovie = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:moviePath]];
theMovie.view.frame = self.bounds;
theMovie.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
theMovie.moviePlayer.controlStyle = MPMovieControlStyleNone;
theMovie.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
theMovie.moviePlayer.fullscreen = NO;
[self addSubview:theMovie.view];
}
}
return self;
}
Please guide me where I am missing it.
-(void)prepareMoviePlayer:(NSURL *)moviePath {
self.moviePlayerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:moviePath];
if ([[self.moviePlayerViewController moviePlayer] respondsToSelector:#selector(loadState)]) {
[[self.moviePlayerViewController moviePlayer] setControlStyle:MPMovieControlStyleEmbedded];
[[self.moviePlayerViewController moviePlayer] setFullscreen:NO];
[[self.moviePlayerViewController moviePlayer] prepareToPlay];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateDidChange:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
}
- (void)moviePlayerLoadStateDidChange:(NSNotification *)notification {
if ([[self.moviePlayerViewController moviePlayer] loadState] == MPMovieLoadStateStalled) {
NSLog(#"Movie Playback Stalled");
} else if([[self.moviePlayerViewController moviePlayer] loadState] != MPMovieLoadStateUnknown) {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
[[[self.moviePlayerViewController moviePlayer] view] setFrame:self.view.bounds];
[[self view] addSubview:[[self.moviePlayerViewController moviePlayer] view]];
[[self.moviePlayerViewController moviePlayer] play];
}
}
The NSMoviePlayerViewController prepareToPlay method seems to be the key here. I also suggest adding other notifications to handle playback completion and playback stopping. Also some of this code is designed to work from a subview of the window.