保存过长的录制视频时,应用程序崩溃 [英] When saving recorded video that is too long, app crashes

查看:25
本文介绍了保存过长的录制视频时,应用程序崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:

保存在我的应用中录制的视频时,如果视频大小/持续时间太大/太长,我的应用会崩溃而没有日志/异常.

When saving a video that is recorded in my app, if the video size/duration is too big/long, my app crashes without a log/exception.

我的设置:

在我的应用程序中,我使用 UIImagePickerController 来录制视频.现在我注意到,如果我制作的视频长度很长(例如,使用 UIImagePickerControllerQualityTypeMedium 时为 30 分钟,或者使用 UIImagePickerControllerQualityTypeIFrame1280x720 时超过一分钟),则在保存视频时,应用程序会崩溃.有时有警告,有时没有警告.现在我开始调试并注意到它与内存有关(malloc_error).

In my App I use a UIImagePickerController to record videos. Now I have noticed that if I make my videos very long in length (for example 30minutes with UIImagePickerControllerQualityTypeMedium, or more than a minute with UIImagePickerControllerQualityTypeIFrame1280x720), when saving the video, the app crashes. Sometimes with and sometimes without a warning. Now I started to debug and noticed it had something to do with memory (malloc_error).

我使用分析器实时检查分配,并注意到当它要保存视频时,分配突然变得非常大(我猜这与视频的临时内存使用有关?)最终崩溃.这是分析器的屏幕截图:

I used the profiler to check allocations live, and noticed that when it was going to save the video, the allocation suddenly became very big (I guess something to do with temporary memory usage for the video?) before it ultimately crashed. Here is a screenshot from the profiler:

该应用必须能够录制最长 1 小时的视频(以任何指定的质量).

The app must be able to record video with a maximum duration of 1 hour (in any quality specified).

我尝试过的:

  • 将 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
    }    
}

以及选择图片时的代码:

And code when the image is picked:

- (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;

}

我在 iOS 5.1.1 中使用 ARC

I am using ARC with iOS 5.1.1

更新:我在 malloc_error_break 上放了一个断点,在仪器中我可以看到它是从以下位置调用的:

Update: I have put a breakpoint on malloc_error_break, and in instruments I can see it is called from:

#   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

Solution: As lawicko & john.k.doe said, I tried to load the video from it's path into an NSData variable. This caused the whole video to be loaded into memory. Instead of doing that, I now just move the file (& rename) copyItemAtPath

NSError *error = nil;
if (![fileManager copyItemAtPath:path toPath:fullPath error:&error])
    NSLog(@"Error: %@", error);

推荐答案

你的问题是这一行:

[NSData dataWithContentsOfPath:self.tempVideoPath]

您显然是想一次将这个文件的内容全部加载到内存中,但 iOS 绝不会让您一次加载那么多.您的 saveVideo 方法似乎只将文件从临时位置复制到文档目录.如果这是您唯一需要做的事情,请查看 copyItemAtPath:toPath:error 方法的 NSFileManager.您可以更改 saveVideo 方法以将临时文件路径作为参数,而不是数据.

You are clearly trying to load the contents of this file to memory all at once, but iOS will never let you load that much at one time. Your saveVideo method seems to only copy the file from temporary location to the documents directory. If this is the only thing that you need to do there, then take a look at copyItemAtPath:toPath:error method of NSFileManager. Your could change the saveVideo method to take the temporary file path as a parameter, rather than the data.

这篇关于保存过长的录制视频时,应用程序崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆