Держите несколько кадров в памяти перед отправкой их в AVAssetWriter - PullRequest
5 голосов
/ 03 июня 2011

Мне нужно удерживать некоторые видеокадры из captureSession в памяти и записывать их в файл, когда «что-то» происходит.

Аналогично этому решению , я использую этот код для помещения фрейма в NSMutableArray:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection
{       
    //...
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    uint8 *baseAddress = (uint8*)CVPixelBufferGetBaseAddress(imageBuffer);
    NSData *rawFrame = [[NSData alloc] initWithBytes:(void*)baseAddress length:(height * bytesPerRow)];
    [m_frameDataArray addObject:rawFrame];
    [rawFrame release];
    //...
}

А это для записи видеофайла:

-(void)writeFramesToFile
{
    //...
    NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSNumber numberWithInt:640], AVVideoWidthKey,
                                    [NSNumber numberWithInt:480], AVVideoHeightKey,
                                    AVVideoCodecH264, AVVideoCodecKey,
                                    nil ];
    AVAssetWriterInput *bufferAssetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:outputSettings];
    AVAssetWriter *bufferAssetWriter = [[AVAssetWriter alloc]initWithURL:pathURL fileType:AVFileTypeQuickTimeMovie error:&error];
    [bufferAssetWriter addInput:bufferAssetWriterInput];

    [bufferAssetWriter startWriting];
    [bufferAssetWriter startSessionAtSourceTime:startTime];
    for (NSInteger i = 1; i < m_frameDataArray.count; i++){
        NSData *rawFrame = [m_frameDataArray objectAtIndex:i];
        CVImageBufferRef imgBuf = [rawFrame bytes];
        [pixelBufferAdaptor appendPixelBuffer:imgBuf withPresentationTime:CMTimeMake(1,10)]; //<-- EXC_BAD_ACCESS
        [rawFrame release];
    }
    //... (finishing video file)
}

Но что-то не так с ссылкой на imgBuf. Какие-либо предложения? Заранее спасибо.

Ответы [ 2 ]

4 голосов
/ 04 июня 2011

Вы должны заблокировать базовый адрес перед доступом к свойствам imageBuffer.

CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CVPixelBufferLockBaseAddress(imageBuffer, 0);
uint8 *baseAddress = (uint8*)CVPixelBufferGetBaseAddress(imageBuffer);
NSData *rawFrame = [[NSData alloc] initWithBytes:(void*)baseAddress length:(height * bytesPerRow)];
[m_frameDataArray addObject:rawFrame];
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
2 голосов
/ 13 февраля 2015

Это довольно старый, но чтобы помочь тем, кто придет, есть несколько проблем, которые нужно исправить:

  1. Блокировка / разблокировка базового адреса при копировании в соответствии с предложением ответа Алекса
  2. CVImageBufferRef - абстрактный тип базового класса. Вы хотите использовать CVPixelBufferCreateWithBytes для создания экземпляра, а не просто типизировать необработанные пиксельные байты. (Система должна знать размер / формат этих пикселей)
  3. Вы должны создать и сохранить новый CVPixelBuffer непосредственно из исходных данных, а не использовать промежуточные NSData для хранения. Таким образом, вам нужно сделать только одну копию вместо двух.
...