0

目前我正在调试一些代码。它的作用是将电影文件读入帧数组,对帧应用一些转换并将所有内容编译回视频文件。我已经修复了我自己调用的所有内存泄漏,剩下的一个非常严重。处理后它会留下近 400 mb 的内存。这是泄漏的屏幕截图。

CVPixelBufferPoolCreatePixelBuffer 中的内存泄漏

如您所见,更高级别的调用仅在 VideoToolbox 库中。然而,我什至没有将这个库包含在我的项目中。我不相信 Apple 的库会出现这种泄漏,对此我无能为力。

这是唯一使用调用树中提到的与 h264 和解码相关的代码的代码。

-(void)writeImageAsMovie:(NSArray *)array toPath:(NSString*)path size:(CGSize)size
{

if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
    [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
}

NSError *error = nil;

// FIRST, start up an AVAssetWriter instance to write your video
// Give it a destination path (for us: tmp/temp.mov)
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path]
                                                       fileType:AVFileTypeQuickTimeMovie
                                                          error:&error];


NSParameterAssert(videoWriter);

NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                               AVVideoCodecH264, AVVideoCodecKey,
                               [NSNumber numberWithInt:size.width], AVVideoWidthKey,
                               [NSNumber numberWithInt:size.height], AVVideoHeightKey,
                               nil];

AVAssetWriterInput* writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
                                                                     outputSettings:videoSettings];

AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
                                                                                                                 sourcePixelBufferAttributes:nil];
NSParameterAssert(writerInput);
NSParameterAssert([videoWriter canAddInput:writerInput]);
[videoWriter addInput:writerInput];
//Start a SESSION of writing.
// After you start a session, you will keep adding image frames
// until you are complete - then you will tell it you are done.
[videoWriter startWriting];
// This starts your video at time = 0
[videoWriter startSessionAtSourceTime:kCMTimeZero];

CVPixelBufferRef buffer = NULL;


//int frameDuration = (1/fps)*600.0;
//NSLog(@"FRAME DURATION: %d",frameDuration);
int i = 0;
while (1)
{
    // Check if the writer is ready for more data, if not, just wait
    if(writerInput.readyForMoreMediaData){

        CMTime frameTime = CMTimeMake(1, fps);
        // CMTime = Value and Timescale.
        // Timescale = the number of tics per second you want
        // Value is the number of tics
        // For us - each frame we add will be 1/4th of a second
        // Apple recommend 600 tics per second for video because it is a
        // multiple of the standard video rates 24, 30, 60 fps etc.
        CMTime lastTime=CMTimeMake(i, fps);
        CMTime presentTime=CMTimeAdd(lastTime, frameTime);

        if (i == 0) {presentTime = CMTimeMake(0, 600);}
        // This ensures the first frame starts at 0.


        if (i >= [array count])
        {
            buffer = NULL;
        }
        else
        {
            // This command grabs the next UIImage and converts it to a CGImage

            CVPixelBufferRef tempBuffer = buffer;

            CVPixelBufferRelease(tempBuffer);

            buffer = [self pixelBufferFromCGImage:[[array objectAtIndex:i] CGImage]andSize:size];
        }


        if (buffer)
        {
            // Give the CGImage to the AVAssetWriter to add to your video
            [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime];
            i++;
        }
        else
        {
            //Finish the session:
            // This is important to be done exactly in this order
            [writerInput markAsFinished];
            // WARNING: finishWriting in the solution above is deprecated.
            // You now need to give a completion handler.
            [videoWriter finishWritingWithCompletionHandler:^{
                NSLog(@"Finished writing...checking completion status...");
                if (videoWriter.status != AVAssetWriterStatusFailed && videoWriter.status == AVAssetWriterStatusCompleted)
                {
                    NSLog(@"Video writing succeeded.");

                    // Move video to camera roll
                    // NOTE: You cannot write directly to the camera roll.
                    // You must first write to an iOS director then move it!
                    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
                    NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder

                    NSString *audioTemp = [documentsDirectory stringByAppendingPathComponent:@"/temp-audio.m4a"];
                    NSString *finalTemp = [documentsDirectory stringByAppendingPathComponent:@"/temp.mov"];

                    [self mergeVideoFromPath:[NSURL fileURLWithPath:path] withAudioFromPath:[NSURL fileURLWithPath:audioTemp] atPath:[NSURL fileURLWithPath:finalTemp]];

                } else
                {
                    NSLog(@"Video writing failed: %@", videoWriter.error);
                }

            }]; // end videoWriter finishWriting Block


            CVPixelBufferRelease(buffer);

            CVPixelBufferPoolRelease(adaptor.pixelBufferPool);

            NSLog (@"Done");
            break;
        }
    }
}
}
4

0 回答 0