I have to implement a pause screen while recording with AVFoundation in cocoa
For starting video I am using this function:
-(void)takeScreenRecording:(CGRect)rect saveAtPath:(NSURL*)destPath {
// Create a capture session
mSession = [[AVCaptureSession alloc] init];
// Set the session preset as you wish
mSession.sessionPreset = AVCaptureSessionPresetPhoto;
CGDirectDisplayID displayId = kCGDirectMainDisplay;
// Create a ScreenInput with the display and add it to the session
AVCaptureScreenInput *input =
[[AVCaptureScreenInput alloc] initWithDisplayID:displayId];
[input setCropRect:rect];
if (!input) {
mSession = nil;
return;
}
if ([mSession canAddInput:input])
[mSession addInput:input];
// Create a MovieFileOutput and add it to the session
mMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([mSession canAddOutput:mMovieFileOutput])
[mSession addOutput:mMovieFileOutput];
// Start running the session
[mSession startRunning];
// Delete any existing movie file first
if ([[NSFileManager defaultManager] fileExistsAtPath:[destPath path]])
{
NSError *err;
if ( ![[NSFileManager defaultManager] removeItemAtPath:[destPath path]
error:&err] )
{
NSLog(#"Error deleting existing movie %#",[err localizedDescription]);
}
}
[mMovieFileOutput startRecordingToOutputFileURL:destPath
recordingDelegate:self];
}
For stopping Screen recording I am using these functions:
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
fromConnections:(NSArray *)connections
error:(NSError *)error {
NSLog(#"Did finish recording to %# due to error %#",
[outputFileURL description], [error description]);
[mSession stopRunning];
mSession = nil;
}
-(void)finishRecord {
// Stop recording to the destination movie file
NSLog(#"Stopping record");
[mMovieFileOutput stopRecording];
}
But I am unable to get logic for pause functionality. Can anyone tell me how I can implement a pause Screen when recording?
Related
Due to the customer can't implement just few downloads in his server in a short time and backgroundDownloadTaks were very inconsistent when there are so much files (500-1000 downloads) I decide to use NSURLDownloadTask without background NSURLSession.
It works quite well with a large amount of files, but there is an inconvenience. Memory usage is always growing untill I get a memory warning. When I get it I cancel pending tasks and free NSURLCache but memory is not released so when you resume the downloads you get the same memory warning.
I'm not using cancelWithResumeData for cancelling the tasks.
This is my code
- (void) startDownloadFiles:(NSMutableArray*)arrayFiles
{
if([[UIDevice currentDevice] isMultitaskingSupported])
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (!self.session)
{
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
sessionConfiguration.timeoutIntervalForRequest = 0;
sessionConfiguration.timeoutIntervalForResource = 0;
sessionConfiguration.requestCachePolicy = NSURLCacheStorageNotAllowed;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:nil];
}
//Resetting session
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
for (NSURLSessionTask *_task in downloadTasks)
{
[_task cancel];
}
[self.session resetWithCompletionHandler:^{
for (id<FFDownloadFileProtocol> file in self.selectedCatalogProducto.downloadInfo.arrayFiles)
{
if (cancel)
break; //Do not create more taks
if (![file isDownloaded])
[self startDownloadFile:file];
}
}];
}];
});
}
}
- (void) startDownloadFile:(id<FFDownloadFileProtocol>)file
{
if (![file isDownloading])
{
if ([file taskIdentifier] == -1
&& ! cancel)
{
NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:[file downloadSource]];
if (task)
{
[file setDownloadTask:task];
[file setTaskIdentifier:[file downloadTask].taskIdentifier];
[[file downloadTask] resume];
}
else
{
NSLog(#"Error creando tarea para descargar %#", [file downloadSource]);
}
}
}
}
#pragma mark - Auxiliar Methods
-(id<FFDownloadFileProtocol>)getFileDownloadInfoIndexWithTaskIdentifier:(unsigned long)taskIdentifier
{
for (id<FFDownloadFileProtocol> file in self.selectedCatalogProducto.downloadInfo.arrayFiles)
{
if (file.taskIdentifier == taskIdentifier) {
return file;
}
}
return nil;
}
#pragma mark - NSURLSessionDownloadTaskDelegate
- (void) URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
if (totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown) {
NSLog(#"Unknown transfer size");
}
else
{
// Locate the FileDownloadInfo object among all based on the taskIdentifier property of the task.
id<FFDownloadFileProtocol> file = [self getFileDownloadInfoIndexWithTaskIdentifier:downloadTask.taskIdentifier];
// Calculate the progress.
file.downloadProgress = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
// [[NSOperationQueue mainQueue] addOperationWithBlock:^{
// NSLog("%# ; %f", [file fileName], [file downloadProgress]);
// }];
}
}
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
id<FFDownloadFileProtocol> file = [self getFileDownloadInfoIndexWithTaskIdentifier:downloadTask.taskIdentifier];
if (file)
{
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *destinationURL = [[NSURL fileURLWithPath:tempPath] URLByAppendingPathComponent:[file fileName]];
if ([fileManager fileExistsAtPath:[destinationURL path]]) {
NSError *delError = nil;
[fileManager removeItemAtURL:destinationURL error:nil];
if (delError)
{
NSLog(#"Error borrando archivo temporal en %#", [destinationURL path]);
}
}
BOOL success = [fileManager copyItemAtURL:location
toURL:destinationURL
error:&error];
if (success) {
// Change the flag values of the respective FileDownloadInfo object.
file.isDownloading = NO;
file.isDownloaded = YES;
// Set the initial value to the taskIdentifier property of the file object,
// so when the start button gets tapped again to start over the file download.
}
else
{
NSLog(#"Unable to copy temp file to %# Error: %#", [destinationURL path], [error localizedDescription]);
}
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive)
{
indexFile++;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self numFilesDownloaded:indexFile];
}];
}
}
}
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
id<FFDownloadFileProtocol> file = [self getFileDownloadInfoIndexWithTaskIdentifier:task.taskIdentifier];
if (error != nil
&& error.code != -999)
{
//No se ha producido error o se ha cancelado la tarea bajo demanda
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(#"Download: %#. \n Downlonad completed with error: %#", [task.response.URL absoluteString], [error localizedDescription]);
if (!cancel)
{
NSString *alertBody = #"Se ha producido un error en la descarga, por favor reanúdela manualmente";
if ([error.domain isEqualToString:#"NSPOSIXErrorDomain"] && (error.code == 1) )
{
alertBody = #"Se ha interrumpido la descarga debido a que su iPad está bloqueado por código. Por favor reanude la descarga manualmente y evite que el iPad se bloquee";
}
// Show a local notification when all downloads are over.
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = alertBody;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
[self errorDownloading:error.localizedDescription];
}
}];
}
else if (file)
{
NSLog(#"%# download finished successfully.", [[file downloadSource] absoluteString]);
file.taskIdentifier = -1;
// In case there is any resume data stored in the file object, just make it nil.
file.taskResumeData = nil;
file.downloadTask = nil;
}
else if (cancel)
{
NSLog(#"Tarea cancelada");
}
if (self.selectedCatalogProducto.downloadInfo.arrayFiles.count == indexFile
&& !cancel)
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if (!complete)
{
complete = YES;
[self downloadComplete];
}
}];
}
task = nil;
}
#pragma mark - Memory warning
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
if (_isDownloading)
{
[self storeCatalogProductInfo:self.selectedCatalogProducto andDownloadInfo:YES];
[self stopDownloading];
}
[[NSURLCache sharedURLCache] removeAllCachedResponses];
[self.session.configuration.URLCache removeAllCachedResponses];
}
And these are two snapshot of memory usage
Memory usage increasing when files are downloading
Download tasks are stopped but memory is not released
Why can't I release memory?
Thanks for any help provided
You need to call the invalidateAndCancel method on your NSURLSession instance when you're done using it, otherwise it will leak memory.
I am new to IOS development. At the moment I'm building an iPad app, what gets data back from the webservice, saves it in a core database and shows it in a tableview using NSFetchedResultController.
What is the problem. In IOS6 it al works like a charm, in IOS 5.0 it saves the data but not showing it in the tableview. It gives the following error.
CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. The NIB data is invalid. with userInfo (null)
And when I test in IOS 5.1 it does not do anything. It does not shows data in a tableview and data is not being stored in core database.
Here is what I do. In my view did appear I check if there is a document I can use.
if (!self.genkDatabase) { // we'll create a default database if none is set
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:#"Default appGenk Database"];
self.genkDatabase = [[UIManagedDocument alloc] initWithFileURL:url]; // setter will create this for us on disk
}
Then it goes to my setter. And next in usedocument gonna check in which state my document is.
- (void)setGenkDatabase:(UIManagedDocument *)genkDatabase
{
if (_genkDatabase != genkDatabase) {
_genkDatabase = genkDatabase;
[self useDocument];
}
NSLog(#"Comes in the setdatabase methode.");
}
- (void)useDocument
{
NSLog(#"Comses in the use document");
if (![[NSFileManager defaultManager] fileExistsAtPath:[self.genkDatabase.fileURL path]]) {
// does not exist on disk, so create it
[self.genkDatabase saveToURL:self.genkDatabase.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
NSLog(#"create");
[self setupFetchedResultsController];
NSLog(#"create 2");
[self fetchNewsIntoDocument:self.genkDatabase];
NSLog(#"create 3");
}];
} else if (self.genkDatabase.documentState == UIDocumentStateClosed) {
NSLog(#"closed news");
// exists on disk, but we need to open it
[self.genkDatabase openWithCompletionHandler:^(BOOL success) {
[self setupFetchedResultsController];
}];
} else if (self.genkDatabase.documentState == UIDocumentStateNormal) {
NSLog(#"normal");
// already open and ready to use
[self setupFetchedResultsController];
}
}
Finally I fetch my data in my document using the following function.
- (void)fetchNewsIntoDocument:(UIManagedDocument *)document
{
dispatch_queue_t fetchNews = dispatch_queue_create("news fetcher", NULL);
dispatch_async(fetchNews, ^{
NSArray *news = [GenkData getNews];
[document.managedObjectContext performBlock:^{
int newsId = 0;
for (NSDictionary *genkInfo in news) {
newsId++;
[News newsWithGenkInfo:genkInfo inManagedObjectContext:document.managedObjectContext withNewsId:newsId];
NSLog(#"news inserted");
}
[document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];
}];
});
dispatch_release(fetchNews);
}
For the problem in IOS 5.0 is this my NSFetchResultController method.
- (void)setupFetchedResultsController // attaches an NSFetchRequest to this UITableViewController
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"News"];
request.sortDescriptors = [NSArray arrayWithObjects:[NSSortDescriptor sortDescriptorWithKey:#"date" ascending:YES],nil];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.genkDatabase.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
}
I am doing this like the example from Paul Hegarty in stanford university. You can find the example Photomania over here.
Hope anyone can help me!
Kind regards
I am beginner of iPhone. I have taken two audio file but how to play first finished then next play only one method...
this is my code is....
-(IBAction)onclicksound
{
path=[[NSBundle mainBundle]pathForResource:#"Animalfile" ofType:#"plist"];
dict=[[NSDictionary alloc]initWithContentsOfFile:path];
NSError *error;
animalaudio=[dict valueForKey:#"Animalsound"];
NSLog(#"animalaudio:%#",animalaudio);
NSLog(#"currentsound=%d",currentsound);
selectanimalaudio=[animalaudio objectAtIndex:currentsound];
NSString *soundpath=[[NSBundle mainBundle]pathForResource:selectanimalaudio ofType:#""];
NSLog(#"selectaudio:%#",selectanimalaudio);
AVAudioPlayer *audioplayer=[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:soundpath] error:&error];
if (error)
{
NSLog(#"Error in audioPlayer: %#",
[error localizedDescription]);
}
else
{
self.audiosound=audioplayer;
[audioplayer release];
//audiosound.numberOfLoops=currentsound;
//[self.audiosound setDelegate:self];
[audiosound play];
NSLog(#"audioplayer:%#",audiosound);
}
NSError *err;
animalsecaudio=[dict valueForKey:#"Birdsound"];
NSLog(#"animalaudio:%#",animalsecaudio);
// NSLog(#"currentsound=%d",currentsound);
selectanimalsecaudio=[animalsecaudio objectAtIndex:currentsound];
NSLog(#"selectanimalsecaudio:%#",selectanimalsecaudio);
NSString *soundsecpath=[[NSBundle mainBundle]pathForResource:selectanimalsecaudio ofType:#""];
AVAudioPlayer *audioplayerr=[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:soundsecpath] error:&err];
if (err)
{
NSLog(#"Error in audioPlayer: %#",
[err localizedDescription]);
}
else
{
self.animalsecsound=audioplayerr;
[audioplayerr release];
//audiosound.numberOfLoops=currentsound;
[animalsecsound play];
[animalsecsound prepareToPlay];
// [self.animalsecsound setDelegate:self];
NSLog(#"audioplayer:%#",animalsecsound);
}
}
so, second avaudioplayer how to play after one finished avaudioplayer give any suggestion and source code..
You can call AVAudioPlayer's delegate method audioPlayerDidFinishPlaying:
For example:
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)sender successfully:(BOOL)success
{
if (success)
{
//code to play next sound
}
}
I am using AVFoundation to capture video. All seems to be well in my app until I get to here:
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
fromConnections:(NSArray *)connections
error:(NSError *)error
{
NSLog(#"didFinishRecordingToOutputFileAtURL - enter");
BOOL RecordedSuccessfully = YES;
if ([error code] != noErr)
{
// A problem occurred: Find out if the recording was successful.
id value = [[error userInfo] objectForKey:AVErrorRecordingSuccessfullyFinishedKey];
if (value)
{
RecordedSuccessfully = [value boolValue];
}
}
if (RecordedSuccessfully)
{
//----- RECORDED SUCESSFULLY -----
NSLog(#"didFinishRecordingToOutputFileAtURL - success");
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:outputFileURL])
{
[library writeVideoAtPathToSavedPhotosAlbum:outputFileURL
completionBlock:^(NSURL *assetURL, NSError *error)
{
if (error)
{
}
}];
}
[library release];
}
}
When running it on a device I receive the "didFinishRecordingToOutputFileAtURL - success" message, and then it crashes and I get this error:
Video /private/var/mobile/Applications/EDC62CED-3710-45B2-A658-A2FE9238F517/tmp/output.mov cannot be saved to the saved photos album: Error Domain=NSOSStatusErrorDomain Code=-12950 "Movie could not be played." UserInfo=0xe6749b0 {NSLocalizedDescription=Movie could not be played.}
I haven't been able to find a whole lot of information about this anywhere and am not really sure what's going on.
Here's the code with the temporary output URL:
NSString *outputPath = [[NSString alloc] initWithFormat:#"%#%#", NSTemporaryDirectory(), #"output.mov"];
NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:outputPath];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:outputPath])
{
NSError *error;
if ([fileManager removeItemAtPath:outputPath error:&error] == NO)
{
//Error - handle if requried
}
}
[outputPath release];
//Start recording
[movieFileOutput startRecordingToOutputFileURL:outputURL recordingDelegate:self];
[outputURL release];
I've already tried releasing the outputURL elsewhere after it saves, and that didn't help, so I don't think that's it.
I figured this out. I was an idiot and kept overlooking the fact that I didn't actually connect the video input to the capture session. Whoops.
Source
So, I have a QTCaptureSession set up thusly:
//Setup Camera
cameraSession = [[QTCaptureSession alloc] init];
QTCaptureDevice *camera = [QTCaptureDevice deviceWithUniqueID: cameraID];
BOOL success = [camera open: &error];
if (!success || error)
{
NSLog(#"Could not open device %#.", cameraID);
NSLog(#"Error: %#", [error localizedDescription]);
return nil;
}
//Setup Input Session
QTCaptureDeviceInput *cameraInput = [[QTCaptureDeviceInput alloc] initWithDevice: camera];
success = [cameraSession addInput: cameraInput error: &error];
if (!success || error)
{
NSLog(#"Could not initialize input session.");
NSLog(#"Error: %#", [error localizedDescription]);
return nil;
}
//Setup Output
QTCaptureDecompressedVideoOutput *cameraOutput = [[QTCaptureDecompressedVideoOutput alloc] init];
[cameraOutput setDelegate: self];
success = [cameraSession addOutput: cameraOutput error: &error];
if (!success || error)
{
NSLog(#"Could not initialize output session.");
NSLog(#"Error: %#", [error localizedDescription]);
return nil;
}
And the QTCaptureDecompressedVideoOutput delegate's captureOutput:didOutputVideoFrame:WithSampleBuffer:fromConnection: thusly:
- (void)captureOutput:(QTCaptureOutput *)captureOutput didOutputVideoFrame:(CVImageBufferRef)videoFrame withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection
{
NSLog(#"starting convert\n");
}
I then start the capture processing using:
[cameraSession startRunning];
All of the variables initialize fine, and the session starts fine, but captureOutput:didOutputVideoFrame:withSampleBuffer:fromConnection: never gets called.
Context
This is a command-line app, compiled with the GCC. It's linked against the following frameworks:
Foundation
Cocoa
QTKit
QuartzCore
Relevant Miscellany
The frame is not likely dropping because captureOutput:didDropVideoFrameWithSampleBuffer:fromConnection: is also not getting called.
So, with some help from Mike Ash, I managed to figure out that my program was terminating immediately and not waiting for the delegate callback (which, according to Apple's QTKit docs, might occur on a separate thread).
My solution was to add a BOOL properties to my object named captureIsFinished, then add this to the main() function:
//Wait Until Capture is Finished
while (![snap captureIsFinished])
{
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 1]];
}
Which effectively perpetuates the run-loop of the app for 1 second, checks to see if the capture is finished, then runs for another second.