Error on video recording in objective-c - objective-c

I played with the AVCam demo sample in order to add a player (MPMoviePlayerController) that allows the preview of the recorded video
I added a play button in the xib and the corresponding IBOutlet and IBActions + a player:
#property (nonatomic,retain) IBOutlet UIBarButtonItem *playerButton;
#property (nonatomic, assign) MPMoviePlayerController *player;
- (IBAction)playVideo:(id)sender;
I do initialize the player in the viewdidload:
player = [[MPMoviePlayerController alloc] init];
the play Action is as follows
- (IBAction)playVideo:(id)sender {
if(player) {
[player stop];
}
// Create a new movie player object.
[player setContentURL:[[[self captureManager] recorder] outputFileURL]];
player.movieSourceType = MPMovieSourceTypeFile;
[player prepareToPlay];
CGRect viewInsetRect = CGRectMake( 0, 0, 200, 300);
// Inset the movie frame in the parent view frame.
[[player view] setFrame:viewInsetRect];
player.scalingMode = MPMovieScalingModeAspectFill;
player.controlStyle = MPMovieControlStyleNone;
//player.useApplicationAudioSession = NO;
//[self.view addSubview: [_player view]];
[self.view addSubview:player.view];
if(player) {
[player play];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playComplete) name:MPMoviePlayerPlaybackDidFinishNotification object:player];
}
and the playComplete called when play is finished:
-(void)playComplete {
[player.view removeFromSuperview];
}
result:
When I launch the app, I can record as many videos as I want.
when I play the last recorded video, I can play it without problems
but after playing the video, if i try to record again, I encounter this error as soon as it starts recording:
Error Domain=AVFoundationErrorDomain Code=-11803 "Cannot Record" UserInfo=0x152e60 {NSLocalizedRecoverySuggestion=Try recording again., AVErrorRecordingSuccessfullyFinishedKey=false, NSLocalizedDescription=Cannot Record}
i thought it was a problem on the temp output file, but it seems not.
I'm wondering if introducing a MPMoviePlayerController breaks the behavior of the app in some way that I cannot figure out.
do some of you have any idea?
Thanks
P

found that the -11803 was due to the fact that the captureManager session was not running (found the answer on Stackoverflow but i did not understand it very fast...)
at the end of the video preview play, in playComplete, I added a test to check the capture manager session status, to make it run if this was not the case anymore.
-(void)playComplete {
[player.view removeFromSuperview];
if(![[[self captureManager] session] isRunning]) {
// Start the session. This is done asychronously since -startRunning doesn't return until the session is running.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[[self captureManager] session] startRunning];
});
}
}
It is working now, but if anyone knows why the video preview stops the captureManager session, I would be happy to understand it.
P

Related

MPMoviePlayerViewController not playing on 2nd run

I created a MPMoviePlayerViewController which plays a live video. However, if I play the video twice meaning opening the player, clicking done, and playing the stream again. The result is only a black screen with no controls of the MPMoviePlayerViewController. And I need to stop the simulator cause I think the application is crashing. Here's how I did it
- (void) playUrl:(NSURL *)movieInfo
{
NSURL *streamUrl = movieInfo;
MPMoviePlayerViewController *mpvc = [[MPMoviePlayerViewController alloc] initWithContentURL:streamUrl];
[[mpvc view] setFrame:self.view.bounds];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
mpvc.moviePlayer.movieSourceType = MPMovieSourceTypeStreaming;
[mpvc.moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
[mpvc.moviePlayer setShouldAutoplay:YES];
[mpvc.moviePlayer setFullscreen:NO animated:YES];
[mpvc setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[mpvc.moviePlayer setScalingMode:MPMovieScalingModeNone];
[mpvc.moviePlayer setUseApplicationAudioSession:NO];
[self presentMoviePlayerViewControllerAnimated:mpvc];
}
- (void) movieFinishedCallback:(NSNotification*) aNotification
{
MPMoviePlayerController *player = [aNotification object];
[player stop];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
[player.view removeFromSuperview];
NSLog(#"stopped?");
}
I see that in your movieFinishedCallback: implementation, you remove the MPMoviePlayerController view, but in your playUrl: implementation, you are only setting the view's frame, presumably after you have already added the view in viewDidLoad.
One obvious change which is worth trying, is update you code to use the AVPictureInPictureController or AVPlayerViewController class from the AVKit framework, or the WKWebView class from WebKit. According to the MPMoviePlayerViewController docs, it is deprecated as of iOS 9:
The MPMoviePlayerViewController class is formally deprecated in iOS 9. (The MPMoviePlayerController class is also formally deprecated.) To play video content in iOS 9 and later, instead use the AVPictureInPictureController or AVPlayerViewController class from the AVKit framework, or the WKWebView class from WebKit.
Try moving the line where you add the view to the hierarchy, to the playUrl: method. Generally, it is good practice to have countering implementations in opposing methods for your event counterparts. For instance, implement a method to build and add a view when an event starts, and have a corresponding method where you tear down and remove the same view when the same event ends. But, I say 'generally' because there are always exceptions, and you may have very compelling reasons for not doing so. So, in this case, the opposing calls are presentMoviePlayerViewControllerAnimated: and dismissMoviePlayerViewControllerAnimated:, available from the UIViewController category.
After changing the view access to using dot-notation, to be consistent with your callback implementation, here is what your new playUrl: implemntation would look like, assuming you're adding the view to self.view:
- (void) playUrl:(NSURL *)movieInfo
{
NSURL *streamUrl = movieInfo;
MPMoviePlayerViewController *mpvc = [[MPMoviePlayerViewController alloc] initWithContentURL:streamUrl];
[mpvc.view setFrame:self.view.bounds];
[self.view addSubview:mpvc.view];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
mpvc.moviePlayer.movieSourceType = MPMovieSourceTypeStreaming;
[mpvc.moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
[mpvc.moviePlayer setShouldAutoplay:YES];
[mpvc.moviePlayer setFullscreen:NO animated:YES];
[mpvc setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[mpvc.moviePlayer setScalingMode:MPMovieScalingModeNone];
[mpvc.moviePlayer setUseApplicationAudioSession:NO];
[self presentMoviePlayerViewControllerAnimated:mpvc];
}
Another option is to simply not remove the player's view in your callback method. If that is not the culprit, then the next thing I would investigate is check if you are sending messages to nil objects. Also, see what happens when you take out all the implementation from movieFinishedCallback:, except for getting and stopping the player.
I hope that helps!
Fixed the issue by removing the [player.view removeFromSuperview] line

UIWebView youtube video player DONE button dismisses View Controller to main app rootViewController

The Problem..
My app is taking me back to my main screen of the app (rootViewController) everytime I press the done button after a youtube (embedded in an iframe) video gets launched from a UIWebView which is not what I want it to do. I just want to get back to the View Controller from where this youtube video launched and display all the content within that view.
I tried using notifications to catch the state of the UIMoviePlayerController to present the previous View Controller where the youtube vide launched. But, I'm also using a navigation controller, plus this View Controller depends on a previous controller selection which uses some data to display the content within the View Controller.
I REALLY NEED SOME HELP HERE, I DON'T KNOW WHAT'S THE PROBLEM..!!
Suggestions?
Do I need to set my own MPMoviePlayerController? if so, do I have to implement some delegates to be able to controller its states and what its doing?
This is how I set my UIWebView to one of the rows in my TableView
self.videoView = [[UIWebView alloc] initWithFrame:CGRectMake(kElementX, kElementY, kElementWidth, 120)];
self.videoView.backgroundColor = [UIColor clearColor];
self.videoView.opaque = NO;
self.videoView.scalesPageToFit = YES;
//self.videoView.delegate = self;
[self.videoView setTranslatesAutoresizingMaskIntoConstraints:YES];
self.videoView.allowsInlineMediaPlayback = YES;
[cell.contentView addSubview:self.videoView];
NSString *youtubeURL = [NSString stringWithFormat:#"%#", self.url];
NSLog(#"youtube link -> %#", youtubeURL);
NSString *videoHTML = [NSString stringWithFormat:#"\
<html>\
<head>\
<style type=\"text/css\">\
iframe {position:absolute; top:0%%; margin-top:0px;}\
body {background-color:#000; margin:0;}\
</style>\
</head>\
<body>\
<div id=\"player\">\
<iframe class=\"youtube-player\" type=\"text/html\" width=\"100%%\" height=\"420px\" src=\"%#\" frameborder=\"0\" allowfullscreen></iframe>\
</div>\
<script>\
var tag = document.createElement('script');\
tag.src = \"https://www.youtube.com/iframe_api\";\
var firstScriptTag = document.getElementsByTagName('script')[0];\
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);\
var player;\
var myVideoId = document.getElementById('%#')\
function onYouTubeIframeAPIReady() {\
player = new YT.Player('player', {\
height: '100%%',\
width: '100%%',\
videoId: myVideoId,\
playerVars:{\
'autoplay':0,\
'controls':1,\
'enablejsapi':1,\
'playsinline':1,\
'showinfo':0\
events: {\
'onReady': onPlayerReady,\
}\
});\
}\
</script>\
</body>\
</html>", youtubeURL, self.url];
[self.videoView loadHTMLString:videoHTML baseURL:nil];
viewDidLoad method...
-(void)viewDidLoad{
// Using notifications to get the state of the UIMoviePlayerController
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieIsPlaying:) name:#"UIMoviePlayerControllerDidEnterFullscreenNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieStopedPlaying:) name:#"UIMoviePlayerControllerDidExitFullscreenNotification" object:nil];
}
// Trying to stop the dismiss of the View Controller
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (self.videoLaunched) {
[super viewWillDisappear:NO];
[self dismissViewControllerAnimated:NO completion:nil];
}
}
// apparently this function besides the notifications functions is the only one which gets call after the done button is pressed (here I tried to attempt loading back the View Controller) not much luck
-(void)viewWillDisappear:(BOOL)animated{
if(self.videoLaunched)
[super viewWillDisappear:NO];
}
// Starts playing the video
- (void)movieIsPlaying:(NSNotification *)notification
{
self.videoLaunched = YES;
}
// The video stop and exit player
- (void)movieStopedPlaying:(NSNotification *)notification
{
self.videoLaunched = NO;
}
I really hope someone has come across with this problem and be able to share the solution with me.. Thanks! :)
The whole problem was that someone the the viewDidAppear or actually the NavigationViewController was getting call and because it's set to take you back to the main or actually the rootViewController of the app. It's was clearing up all the previous ViewControllers and taking me back there.
I debugged with a break point and found the problem.. So, the solution for me was setting a variable in the userDefaults just before the video is about to finish with this notification UIMoviePlayerControllerWillExitFullscreenNotification and calling the function to set this variable, and afterwards skipping the code with an if condition in my viewDidAppear which all the re-settings of ViewController whats happening in my case..
Well, I hope it helps someone else with the same or similar problem..

UIImagePickerController delegate is not calling

Iam using the following code for taking the picture automatically from IPAD front camera:
UIImagePickerController *imgPkr = [[UIImagePickerController alloc] init];
imgPkr.sourceType = UIImagePickerControllerSourceTypeCamera;
imgPkr.delegate = self;
imgPkr.cameraDevice=UIImagePickerControllerCameraDeviceFront;
[self presentModalViewController:imgPkr animated:YES];
imgPkr.showsCameraControls = NO;
[imgPkr takePicture];
But this code Dont take any picture and dont call the delegate:
-(void)imagePickerController:(UIImagePickerController*)picker
didFinishPickingMediaWithInfo:(NSDictionary*)info
Any idea what is wrong with the code
My first guess is that [imgPkr takePicture]; is being called before the picker is done being presented. Try it like this:
UIImagePickerController *imgPkr = [[UIImagePickerController alloc] init];
imgPkr.sourceType = UIImagePickerControllerSourceTypeCamera;
imgPkr.delegate = self;
imgPkr.cameraDevice=UIImagePickerControllerCameraDeviceFront;
[self presentModalViewController:imgPkr animated:YES];
imgPkr.showsCameraControls = NO;
[self performSelector:#selector(takePicture) withObject:self afterDelay:1.0];
OR
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(takePicture)
name:AVCaptureSessionDidStartRunningNotification
object:nil];
&
- (void)takePicture
{
[imgPkr takePicture];
}
I bet that you get a message in your logs saying that
UIImagePickerController: ignoring request to take picture; camera is
not yet ready.
This is a common problem because the underlying capture session needs some time to start, so you just have to be sure that the camera is ready to take a picture and then call takePicture method. Now, a way to get notified is explained in detail in my answer here: How to know if iPhone camera is ready to take picture?
Note though that this method will work on iOS5+ (there is a bug in older versions that prevents the system notifications for this event, contrary to what is described in the documentation). I hope that this helps.
another way to wait for camera ready until take picture is completion block ->
[self presentViewController:imagePicker animated:YES
completion:^ {
[imagePicker takePicture];
}];
thank you 'GrandSteph' at
iOS taking photo programmatically

Trying to play video using MPMoviePlayerController, only get audio

I want to play a video in my iPhone app. I used this code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *movieUrl = [NSURL fileURLWithPath:
[[NSBundle mainBundle] pathForResource:#"Myvideo"
ofType:#"mp4"]];
//create a new instance of MPMoviePlayerController
MPMoviePlayerController* myMovie=[[MPMoviePlayerController alloc]
initWithContentURL:movieUrl];
//disable scaling of our movie
myMovie.scalingMode = MPMovieScalingModeNone;
//don't show any controls
// myMovie.movieControlMode = MPMovieControlModeHidden;
//you can specify at which time the movie should
//start playing (default is 0.0)
myMovie.initialPlaybackTime = 2.0;
//register a callback method which will be called
//after the movie finished
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieFinished:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:myMovie];
//start the movie (asynchronous method)
[myMovie play];
// Do any additional setup after loading the view from its nib.
}
Only the sound works with this code. Can someone help me please?
You need to allocate a frame to your movie and add it to the view. See here.
So you can add:
[myMoview.view setFrame: self.view.bounds]; // player's frame must match parent's
[self.view addSubview:myMovie.view];
Apple Technical Q&A 1240:
MPMoviePlayerController plays movie audio but not video
Q: I'm able to successfully play movies using MPMoviePlayerController on iOS 3.1.3. When I run this same code on the iPad and on the iPhone with iOS 4 I can hear the movie audio, but the video is no longer displayed. What's going on?
A: Starting with iPhone iOS 3.2, calling the -play: method still starts playback of the movie but it does not ensure that the movie is visible. In order to display a movie, you must get the new view property from your MPMoviePlayerController object and add that view to your view hierarchy. Here's a code snippet:
Listing 1 How to add the MPMoviePlayerController view property to your view hierarchy to play a movie.
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
[[player view] setFrame:[myView bounds]]; // size to fit parent view exactly
[myView addSubview:[player view]];
[player play];
See Important Porting Tip for Using the Media Player Framework and the MPMoviePlayerController Class Reference for more information.

MPMoviePlayerController: How can I make my video loop?

Thank you in advance for any help, I am a newbie and would appreciate any help here..
I have this code to play a movie and it works great. Can somebody PLEASE tell me how to make this movie loop and replay from the beginning non stop ( any code would help). Also I would like to know how to play 2 movies, one after the other, preferably with a fade or smooth transition. Thank you for any help
#import "MyAppViewController.h"
#implementation MyAppViewController
-(IBAction)button:(id)sender{
NSString *path = [[NSBundle mainBundle]
pathForResource:#"mymovie" ofType:#"mp4"];
player = [[MPMoviePlayerViewController alloc]
initWithContentURL:[NSURL fileURLWithPath:path]];
[self presentMoviePlayerViewControllerAnimated:player];
}
Set the repeatMode property of your MPMoviePlayerController to MPMovieRepeatModeOne
player = [[MPMoviePlayerViewController alloc]
initWithContentURL:[NSURL fileURLWithPath:path]];
player.moviePlayer.repeatMode = MPMovieRepeatModeOne;
MPMovieRepeatModeOne is nice but it doesn't loop the video very smoothly. Try this below (copied from another post) :
(I just got this working on my iPad 3 running iOS 5.1.1, base SDK iOS 5.1.)
When setting up the movie player, set the repeat mode to MPMovieRepeatModeNone then add the notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];
Then set up your selector to filter when the movie finishes playing:
- (void)moviePlayerDidFinish:(NSNotification *)note
{
if (note.object == self.moviePlayer) {
NSInteger reason = [[note.userInfo objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] integerValue];
if (reason == MPMovieFinishReasonPlaybackEnded)
{
[self.moviePlayer play];
}
}
}
For the timer you can create an Int variable that has the value of your slider and then use a performSelector afterDelay:
int delayInt = 8; // Substitute the 8 for the value of your slider
[self performSelector:#selector(myMethod) withObject:nil afterDelay:delayInt];
And then in your "myMethod"
-(void) myMethod{
//the code to stop your player and remove view controller
}