2013-02-13 41 views
18

Tôi có một bộ nhớ lạ "bị rò rỉ" với AVAssetWriterInput appendSampleBuffer. Tôi đang viết video và âm thanh cùng một lúc, vì vậy tôi có một AVAssetWriter với hai đầu vào, một cho video và một cho âm thanh:appendSampleBuffer với bộ nhớ AVAsetWriterInput "leaks" âm thanh cho đến khi endSessionAtSourceTime

self.videoWriter = [[[AVAssetWriter alloc] initWithURL:[self.currentVideo currentVideoClipLocalURL] 
               fileType:AVFileTypeMPEG4 
               error:&error] autorelease]; 
... 
self.videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo 
                  outputSettings:videoSettings]; 
self.videoWriterInput.expectsMediaDataInRealTime = YES; 
[self.videoWriter addInput:self.videoWriterInput]; 
... 
self.audioWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio 
                  outputSettings:audioSettings]; 
self.audioWriterInput.expectsMediaDataInRealTime = YES; 
[self.videoWriter addInput:self.audioWriterInput]; 

Tôi bắt đầu viết và tất cả mọi thứ hoạt động tốt trên bề mặt. Các video và âm thanh được viết và được liên kết, vv Tuy nhiên, tôi đặt mã của tôi thông qua việc phân bổ cụ và chú ý những điều sau:

CoreMedia allocations

các byte âm thanh đang nhận được giữ lại trong bộ nhớ, như tôi sẽ chứng minh trong một giây. Đó là đoạn đường nối trong bộ nhớ. Các byte âm thanh chỉ được phát hành sau khi tôi gọi [self.videoWriter endSessionAtSourceTime:...], mà bạn thấy là giảm đáng kể trong việc sử dụng bộ nhớ. Đây là mã viết âm thanh của tôi, được gửi đi dưới dạng một khối vào hàng đợi nối tiếp:

@autoreleasepool 
{ 
    // The objects that will hold the audio data 
    CMSampleBufferRef sampleBuffer; 
    CMBlockBufferRef blockBuffer1; 
    CMBlockBufferRef blockBuffer2; 

    size_t nbytes = numSamples * asbd_.mBytesPerPacket; 

    OSStatus status = noErr; 
    status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, 
               data, 
               nbytes, 
               kCFAllocatorNull, 
               NULL, 
               0, 
               nbytes, 
               kCMBlockBufferAssureMemoryNowFlag, 
               &blockBuffer1); 

    if (status != noErr) 
    { 
     NLog(@"CMBlockBufferCreateWithMemoryBlock error at buffer 1"); 
     return; 
    } 

    status = CMBlockBufferCreateContiguous(kCFAllocatorDefault, 
              blockBuffer1, 
              kCFAllocatorDefault, 
              NULL, 
              0, 
              nbytes, 
              kCMBlockBufferAssureMemoryNowFlag | kCMBlockBufferAlwaysCopyDataFlag, 
              &blockBuffer2); 

    if (status != noErr) 
    { 
     NSLog(@"CMBlockBufferCreateWithMemoryBlock error at buffer 2"); 
     CFRelease(blockBuffer1); 
     return; 
    } 

    // Finally, create the CMSampleBufferRef 
    status = CMAudioSampleBufferCreateWithPacketDescriptions(kCFAllocatorDefault, 
                  blockBuffer2, 
                  YES, // Yes data is ready 
                  NULL, // No callback needed to make data ready 
                  NULL, 
                  audioFormatDescription_, 
                  1, 
                  timestamp, 
                  NULL, 
                  &sampleBuffer); 


    if (status != noErr) 
    { 
     NSLog(@"CMAudioSampleBufferCreateWithPacketDescriptions error."); 
     CFRelease(blockBuffer1); 
     CFRelease(blockBuffer2); 
     return; 
    } 

    if ([self.audioWriterInput isReadyForMoreMediaData]) 
    { 
     if (![self.audioWriterInput appendSampleBuffer:sampleBuffer]) 
     { 
      NSLog(@"Couldn't append audio sample buffer: %d", numAudioCallbacks_); 
     } 
    } else { 
     NSLog(@"AudioWriterInput isn't ready for more data."); 
    } 

    // One release per create 
    CFRelease(blockBuffer1); 
    CFRelease(blockBuffer2); 
    CFRelease(sampleBuffer); 
} 

Như bạn có thể thấy, tôi sẽ phát hành từng bộ đệm mỗi lần tạo. Tôi đã bắt nguồn từ sự "rò rỉ" xuống đường, nơi các bộ đệm âm thanh được nối:

[self.audioWriterInput appendSampleBuffer:sampleBuffer] 

tôi chứng minh điều này cho bản thân mình bằng cách bình luận ra rằng dòng, sau đó tôi nhận được "rò rỉ-free" Phân chia theo đồ thị (mặc dù đoạn video ghi lại tại không có âm thanh bây giờ, tất nhiên):

No leak

tôi đã cố gắng một điều khác, đó là thêm lại dòng appendSamplebuffer và thay vào đó kích đúp phát hành blockBuffer2:

CFRelease(blockBuffer1); 
CFRelease(blockBuffer2); 
CFRelease(blockBuffer2); // Double release to test the hypothesis that appendSamplebuffer is retaining this 
CFRelease(sampleBuffer); 

Việc làm này đã làm không nguyên nhân một đôi miễn phí, chỉ ra rằng blockBuffer2 's giữ lại đếm tại thời điểm đó là 2. Đây được sản xuất đồ thị cùng 'rò rỉ-free' phân bổ, với ngoại lệ mà khi tôi gọi [self.videoWriter endSessionAtSourceTime:...], tôi gặp sự cố từ bản phát hành kép (chỉ ra rằng self.videoWriter đang cố gắng giải phóng tất cả các con trỏ của nó tới số blockBuffer2 s đã được chuyển vào).

Nếu thay vào đó, tôi thử như sau:

CFRelease(blockBuffer1); 
CFRelease(blockBuffer2); 
CMSampleBufferInvalidate(sampleBuffer); // Invalidate sample buffer 
CFRelease(sampleBuffer); 

sau đó [self.audioWriterInput appendSampleBuffer:sampleBuffer] cuộc gọi đến thêm khung hình video bắt đầu thất bại cho mỗi cuộc gọi sau đó.

Vì vậy, kết luận của tôi là AVAssetWriter hoặc AVAssetWriterInput đang giữ lại blockBuffer2 cho đến khi video kết thúc ghi âm. Rõ ràng, điều này có thể gây ra vấn đề bộ nhớ thực nếu video được ghi lại đủ lâu. Tôi có làm điều gì sai?

Chỉnh sửa: Các byte âm thanh tôi nhận được là định dạng PCM, trong khi định dạng video tôi đang viết là MPEG4 và định dạng âm thanh cho video đó là MPEG4AAC. Có thể người viết video đang thực hiện định dạng PCM -> AAC khi đang di chuyển hay không và đó là lý do tại sao nó được lưu vào bộ đệm?

+0

Tôi chắc chắn bạn đã xem xét xung quanh nhưng bạn đã thấy hai câu hỏi/câu trả lời này chưa. Chúng có thể hữu ích/có liên quan. 1) http://stackoverflow.com/questions/4914853/help-fix-memory-leak-release 2) http://stackoverflow.com/questions/11274652/performance-issues-when-using-avcapturevideodataoutput-and-avcaptureaudiodataout – JSuar

+0

Cảm ơn các đề xuất @JSuar. Tôi đã cố gắng đầu tiên, nhưng gọi CMSampleBufferInvalidate dường như phá vỡ tất cả các ghi trong tương lai để các nhà văn video. Thứ hai trông thú vị, nhưng tôi không chắc chắn nếu hàng đợi đồng thời hoặc nối tiếp sẽ giải thích bộ nhớ "rò rỉ", mà dường như được gây ra bởi các văn bản video giữ lại các khối âm thanh. – kevlar

+0

Có thể bạn đang viết âm thanh nhanh hơn rất nhiều so với video, vì vậy nó cần phải được đệm để giữ cho xen kẽ chính xác? –

Trả lời

1

Vì bạn đã chờ đợi một tháng cho một câu trả lời, tôi sẽ cung cấp cho bạn một câu trả lời ít hơn lý tưởng nhưng khả thi.

Bạn có thể sử dụng các hàm ExtendedAudioFile để viết một tệp riêng biệt. Sau đó, bạn chỉ có thể phát lại video và âm thanh cùng với một AVComposition. Tôi nghĩ rằng bạn có thể sử dụng AVFoundation để tổng hợp các quán cà phê và video với nhau mà không cần mã hóa lại nếu bạn cần chúng kết hợp vào cuối quá trình ghi.

Điều đó sẽ giúp bạn tắt và chạy, sau đó bạn có thể giải quyết rò rỉ bộ nhớ khi rảnh rỗi.