2012-06-15 73 views
6

問題:當保存錄制的視頻太長,應用程序崩潰,

當保存該記錄在我的應用程序的視頻,如果視頻大小/持續時間過大/長,沒有我的應用程序崩潰日誌/例外。

我的設置:

在我的應用我使用的UIImagePickerController錄製視頻。現在我注意到,如果我製作的視頻長度很長(例如UIImagePickerControllerQualityTypeMedium爲30分鐘,或UIImagePickerControllerQualityTypeIFrame1280x720超過一分鐘),則在保存視頻時,應用程序會崩潰。有時會有,有時沒有警告。現在我開始調試並注意到它與內存有關(malloc_error)。

我使用profiler來檢查分配情況,並注意到當它要保存視頻時,分配突然變得非常大(我猜這是與視頻的臨時內存使用情況有關?),然後才最終崩潰。這裏是探查器的屏幕截圖: Allocations screenshot

該應用程序必須能夠記錄最長持續1小時的視頻(以指定的任何質量)。

我曾嘗試:

  • 設置picker.videoMaximumDuration短/長
  • 調試與分析器/儀器
  • 檢查是否有泄漏
  • 關閉了所有打開的應用程序&刪除應用程序上設備(用於存儲清潔)以獲得更多內存

代碼:

- (void)openCamera:(id)sender context:(NSManagedObjectContext*)context { 
    self.context = context; 
    //Set self as delegate (UIImagePickerControllerDelegate) 
    [self.picker setDelegate:self]; 
    //If the device has a camera 
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { 
     self.picker.sourceType = UIImagePickerControllerSourceTypeCamera; 
     self.picker.allowsEditing = YES; 
     self.picker.videoQuality = [Settings videoQualitySetting]; 
     //If the camera can record video 
     NSString *desired = (NSString *)kUTTypeMovie; 
     if ([[UIImagePickerController availableMediaTypesForSourceType:self.picker.sourceType] containsObject:desired]) { 
      //Let the user record video 
      self.picker.mediaTypes = [NSArray arrayWithObject:desired]; 
      self.picker.videoMaximumDuration = MaxDuration; 
     } 
     else { 
      NSLog(@"Can't take videos with this device"); //debug 
     } 
     //Present the picker fullscreen/in popover 
     if ([Settings shouldDisplayFullScreenCamera]){ 
      [self presentModalViewController:self.picker animated:YES]; 
      [self.masterPopoverController dismissPopoverAnimated:YES]; 
     } 
     else { 
      if (!_popover){ 
       _popover = [[UIPopoverController alloc] initWithContentViewController:self.picker]; 
      } 
      [_popover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; 
     } 
    } 
    else { 
     NSLog(@"Does not have a camera"); //debug 
    }  
} 

和代碼時,被攝像:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info 
    { 
    NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType]; 

    // Save the video, and close the overlay 
    if (CFStringCompare ((__bridge CFStringRef) mediaType, kUTTypeMovie, 0) 
     == kCFCompareEqualTo) { 

     self.tempVideoPath = [[info objectForKey: 
           UIImagePickerControllerMediaURL] path]; 
     [LocalVideoStorage saveVideo:[NSData dataWithContentsOfPath:self.tempVideoPath name:self.videoName]; 
     [_picker dismissModalViewControllerAnimated: YES]; 
     [[_picker parentViewController] dismissModalViewControllerAnimated:YES]; 
     [_popover dismissPopoverAnimated:YES]; 
    } 
} 

最後,當它被保存:

+ (NSString*)saveVideo:(NSData*)video:(NSString*)videoName { 
    NSFileManager *fileManager = [NSFileManager defaultManager];//create instance of NSFileManager 

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //create an array and store result of our search for the documents directory in it 

    NSString *documentsDirectory = [paths objectAtIndex:0]; //create NSString object, that holds our exact path to the documents directory 

    NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.MOV", videoName]]; //add our video to the path 

    [fileManager createFileAtPath:fullPath contents:video attributes:nil]; //finally save the path (video) 

    NSLog(@"Video saved!"); 
    return fullPath; 

} 

我使用ARC與iOS 5.1 .1

更新: 我已經把上malloc_error_break斷點,並在儀器我可以看到它是由被稱爲:

# Address Category Timestamp Live Size Responsible Library Responsible Caller 
0 0x10900000 Malloc 473,29 MB 02:08.951.332 • 496283648 Foundation -[NSData(NSData) initWithContentsOfFile:] 

解決方案: 作爲lawicko & john.k.doe說,我試圖加載從視頻它是進入NSData變量的路徑。這導致整個視頻被加載到內存中。相反,這樣做的,我現在只是移動文件(&重命名)copyItemAtPath

​​
+0

你能找到哪種類型的對象有最大的活動字節? – nhahtdh

+0

@nhahtdh它說,它被稱爲上:'#\t地址\t類別\t時間戳\t直播\t尺寸\t負責圖書館\t負責來電 0x10900000 \t的malloc 473,29 MB \t 02:08.951.332 \t•基金會\t - [NSData(NSData)initWithContentsOfFile:] ' – Thermometer

+1

'[LocalVideoStorage saveVideo:[NSData dataWithContentsOfPath:self.tempVideoPath] ...'您正在將整個臨時文件讀入一個NSData對象,僅將其保存到磁盤。難道你不能把臨時文件複製到你選擇的永久存儲文件夾中嗎? – Rog

回答

10

你的問題是這樣的一行:

[NSData dataWithContentsOfPath:self.tempVideoPath] 

你都清楚地試圖此文件的內容加載到內存一次,但iOS永遠不會讓你一次加載多少。您的saveVideo方法似乎只將文件從臨時位置複製到文檔目錄。如果這是你需要做的唯一事情,那麼請看看NSFileManager的copyItemAtPath:toPath:error方法。您可以更改saveVideo方法,將臨時文件路徑作爲參數,而不是數據。

+0

比我更好的答案,因爲它更具體。獎勵這裏的賞金... –

+0

非常感謝!只有我需要改變的是 '[fileManager createFileAtPath:fullPath contents:video attributes:nil];'到 'NSError * error = nil;如果(![fileManager copyItemAtPath:path toPath:fullPath error:&error]) NSLog(@「Error:%@」,error);' – Thermometer

+0

棒極了!非常感謝。 –

2

何苦拉從
[[info objectForKey:UIImagePickerControllerMediaURL] path]媒體流的全部內容爲NSData*,然後寫他們回來了?您的媒體流將會非常龐大​​!

保存時發生這種情況的原因是因爲您正在記錄數據,它將要「磁盤」,然後將其讀入內存以將其寫回到另一個磁盤文件。

您是否考慮過使用NSFileManager將文件從[[info objectForKey:UIImagePickerControlMediaURL] path]複製到您創建的名稱(fullPath)?這應該避免把整個事物拉回到記憶中;它應該是一個「文件到文件」的傳輸。

相關問題