通过NSURLSession上传大型视频会导致内存压力崩溃

时间:2022-10-14 21:35:05

I use the following codes to upload video to server, which requires me to convert the video from video format to NSData. However, when the video is large (e.g. 10 minute video), the App crashes due to memory pressure. How can I resolve this?

我使用以下代码将视频上传到服务器,这需要我将视频格式的视频转换为NSData。但是,当视频很大(例如10分钟视频)时,应用程序会因内存压力而崩溃。我该如何解决这个问题?

- (void)uploadVideo {
    NSDictionary *params = nil;
    NSString *NSURLSessionIdentifier = [NSString stringWithFormat:@"%@%@",@"my.bundle.identifier.",[self getTimeString]];
    NSURLSessionConfiguration *sessionConfig;
    // SessionConfiguration With iOS Version
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
        sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:NSURLSessionIdentifier];
    } else {
        sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:NSURLSessionIdentifier];
    }
    sessionConfig.HTTPMaximumConnectionsPerHost = 1;

    NSURLSession *uploadSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue new]];
    OMGMultipartFormData *multipartFormData = [OMGMultipartFormData new];

    NSString *url = @"SOME_UPLOAD_URL";
    // ========= PROBLEMATIC LINE below =========
    self.video_data = [NSData dataWithContentsOfURL:self.video_url];
    // ========= PROBLEMATIC LINE above =========
    [multipartFormData addFile:self.video_data parameterName:@"file" filename:@"file.mp4" contentType:@"video/mp4"];

    NSURLRequest *rq = [OMGHTTPURLRQ POST:url:multipartFormData];
    id path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"upload.NSData"];
    [rq.HTTPBody writeToFile:path atomically:YES];
    [[uploadSession uploadTaskWithRequest:rq fromFile:[NSURL fileURLWithPath:path]] resume];

}

p.s. self.video_url is a file URL given by UIImagePickerController which filters only video to choose. I then choose a 10-minute video.

附: self.video_url是UIImagePickerController提供的文件URL,仅过滤要选择的视频。然后我选择一个10分钟的视频。

p.s. I got AFNetworking in same App too, can it help with background transfer?

附:我也在相同的应用程序中获得了AFNetworking,它可以帮助进行后台传输吗?

2 个解决方案

#1


1  

You should be able to this by using a NSMutableURLRequest and utilizing its setHTTPBodyStream setter.

您应该可以通过使用NSMutableURLRequest并使用其setHTTPBodyStream setter来实现此目的。

The following are snippets adapted from some code of mine. It handled well for video way over 10 mins. mostly large videos of 60 - 90 minutes.

以下是根据我的一些代码改编的片段。它处理视频的方式超过10分钟。大多数是60-90分钟的大型视频。

NSData *movieData = [NSData dataWithContentsOfFile:theMovieSourceString];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

[request setHTTPMethod:@"POST"];
[request setValue:@"video/quicktime" forHTTPHeaderField:@"Content-Type"];
[request setValue:[NSString stringWithFormat:@"attachment; filename=\"%@\"",yourMovieSourceString] forHTTPHeaderField:@"Content-Disposition"];
[request setValue:[NSString stringWithFormat:@"%ld",(unsigned long)[movieData length]] forHTTPHeaderField:@"Content-Length"];
[request setHTTPBodyStream:[NSInputStream inputStreamWithFileAtPath:yourMovieSourceString]];

You can now use this request with your NSURLConnection

您现在可以将此请求与NSURLConnection一起使用

NSURLConnection *connection =[[NSURLConnection alloc] initWithRequest:request delegate:self];

#2


0  

Issue is obvious - 10 min video file is too big to be stored in a memory what

问题很明显 - 10分钟的视频文件太大,无法存储在内存中

self.video_data = [NSData dataWithContentsOfURL:self.video_url];

does.

确实。

Solution is not to store all request body in a memory. The simplest way is to use NSURLRequest's HTTPBodyStream property. You can create NSInputStream yourself but since you already have AFNetworking it is much easier to use it. In my project I do it this way:

解决方案不是将所有请求主体存储在内存中。最简单的方法是使用NSURLRequest的HTTPBodyStream属性。您可以自己创建NSInputStream,但由于您已经拥有AFNetworking,因此使用它更加容易。在我的项目中,我这样做:

// data.fields is a dictionary with params

NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer]
                                multipartFormRequestWithMethod:@"POST"
                                URLString:[url absoluteString]
                                parameters:nil
                                constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
                                {
                                    [data.fields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                                        [formData appendPartWithFormData:[obj dataUsingEncoding:NSUTF8StringEncoding] name:key];
                                    }];
                                    [formData appendPartWithFileURL:fileURL name:@"file_0" error:&error2];
                                }
                                error:&error];

#1


1  

You should be able to this by using a NSMutableURLRequest and utilizing its setHTTPBodyStream setter.

您应该可以通过使用NSMutableURLRequest并使用其setHTTPBodyStream setter来实现此目的。

The following are snippets adapted from some code of mine. It handled well for video way over 10 mins. mostly large videos of 60 - 90 minutes.

以下是根据我的一些代码改编的片段。它处理视频的方式超过10分钟。大多数是60-90分钟的大型视频。

NSData *movieData = [NSData dataWithContentsOfFile:theMovieSourceString];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

[request setHTTPMethod:@"POST"];
[request setValue:@"video/quicktime" forHTTPHeaderField:@"Content-Type"];
[request setValue:[NSString stringWithFormat:@"attachment; filename=\"%@\"",yourMovieSourceString] forHTTPHeaderField:@"Content-Disposition"];
[request setValue:[NSString stringWithFormat:@"%ld",(unsigned long)[movieData length]] forHTTPHeaderField:@"Content-Length"];
[request setHTTPBodyStream:[NSInputStream inputStreamWithFileAtPath:yourMovieSourceString]];

You can now use this request with your NSURLConnection

您现在可以将此请求与NSURLConnection一起使用

NSURLConnection *connection =[[NSURLConnection alloc] initWithRequest:request delegate:self];

#2


0  

Issue is obvious - 10 min video file is too big to be stored in a memory what

问题很明显 - 10分钟的视频文件太大,无法存储在内存中

self.video_data = [NSData dataWithContentsOfURL:self.video_url];

does.

确实。

Solution is not to store all request body in a memory. The simplest way is to use NSURLRequest's HTTPBodyStream property. You can create NSInputStream yourself but since you already have AFNetworking it is much easier to use it. In my project I do it this way:

解决方案不是将所有请求主体存储在内存中。最简单的方法是使用NSURLRequest的HTTPBodyStream属性。您可以自己创建NSInputStream,但由于您已经拥有AFNetworking,因此使用它更加容易。在我的项目中,我这样做:

// data.fields is a dictionary with params

NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer]
                                multipartFormRequestWithMethod:@"POST"
                                URLString:[url absoluteString]
                                parameters:nil
                                constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
                                {
                                    [data.fields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                                        [formData appendPartWithFormData:[obj dataUsingEncoding:NSUTF8StringEncoding] name:key];
                                    }];
                                    [formData appendPartWithFileURL:fileURL name:@"file_0" error:&error2];
                                }
                                error:&error];