IOS4: AVFoundation: как получить сырые кадры из фильма - PullRequest
1 голос
/ 01 августа 2010

Как я могу получить доступ к необработанному материалу из фильмов, снятых моей камерой, чтобы я мог редактировать или преобразовать исходный материал (например, сделать его черно-белым).

Я знаю, что вы можете загрузить мов с AVAsset сделать композицию с различными AVAsset's а затем экспортируйте его в новый фильм, но как мне получить доступ к нему, чтобы я мог отредактировать фильм?

Ответы [ 2 ]

5 голосов
/ 15 ноября 2010

Вам необходимо прочитать видеокадры из входного актива, создать CGContextRef для каждого кадра, чтобы выполнить рисование, а затем записать кадры в новый видеофайл.Основные шаги приведены ниже.Я пропустил весь код наполнителя и обработку ошибок, поэтому основные шаги легче читать.

// AVURLAsset to read input movie (i.e. mov recorded to local storage)
NSDictionary *inputOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
AVURLAsset *inputAsset = [[AVURLAsset alloc] initWithURL:inputURL options:inputOptions];

// Load the input asset tracks information
[inputAsset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:@"tracks"] completionHandler: ^{

    // Check status of "tracks", make sure they were loaded    
    AVKeyValueStatus tracksStatus = [inputAsset statusOfValueForKey:@"tracks" error:&error];
    if (!tracksStatus == AVKeyValueStatusLoaded)
        // failed to load
        return;

    // Fetch length of input video; might be handy
    NSTimeInterval videoDuration = CMTimeGetSeconds([inputAsset duration]);
    // Fetch dimensions of input video
    CGSize videoSize = [inputAsset naturalSize];


    /* Prepare output asset writer */
    self.assetWriter = [[[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeQuickTimeMovie error:&error] autorelease];
    NSParameterAssert(assetWriter);
    assetWriter.shouldOptimizeForNetworkUse = NO;


    // Video output
    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                       AVVideoCodecH264, AVVideoCodecKey,
                       [NSNumber numberWithInt:videoSize.width], AVVideoWidthKey,
                       [NSNumber numberWithInt:videoSize.height], AVVideoHeightKey,
                       nil];
    self.assetWriterVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
                            outputSettings:videoSettings];
    NSParameterAssert(assetWriterVideoInput);
    NSParameterAssert([assetWriter canAddInput:assetWriterVideoInput]);
    [assetWriter addInput:assetWriterVideoInput];


    // Start writing
    CMTime presentationTime = kCMTimeZero;

    [assetWriter startWriting];
    [assetWriter startSessionAtSourceTime:presentationTime];


    /* Read video samples from input asset video track */
    self.reader = [AVAssetReader assetReaderWithAsset:inputAsset error:&error];

    NSMutableDictionary *outputSettings = [NSMutableDictionary dictionary];
    [outputSettings setObject: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA]  forKey: (NSString*)kCVPixelBufferPixelFormatTypeKey];
    self.readerVideoTrackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:[[inputAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
                        outputSettings:outputSettings];


    // Assign the tracks to the reader and start to read
    [reader addOutput:readerVideoTrackOutput];
    if ([reader startReading] == NO) {
        // Handle error
    }


    dispatch_queue_t dispatch_queue = dispatch_get_main_queue();

    [assetWriterVideoInput requestMediaDataWhenReadyOnQueue:dispatch_queue usingBlock:^{
        CMTime presentationTime = kCMTimeZero;

        while ([assetWriterVideoInput isReadyForMoreMediaData]) {
            CMSampleBufferRef sample = [readerVideoTrackOutput copyNextSampleBuffer];
            if (sample) {
                presentationTime = CMSampleBufferGetPresentationTimeStamp(sample);

                /* Composite over video frame */

                CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sample); 

                // Lock the image buffer
                CVPixelBufferLockBaseAddress(imageBuffer,0); 

                // Get information about the image
                uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer); 
                size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
                size_t width = CVPixelBufferGetWidth(imageBuffer); 
                size_t height = CVPixelBufferGetHeight(imageBuffer); 

                // Create a CGImageRef from the CVImageBufferRef
                CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
                CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);

                /*** Draw into context ref to draw over video frame ***/

                // We unlock the  image buffer
                CVPixelBufferUnlockBaseAddress(imageBuffer,0);

                // We release some components
                CGContextRelease(newContext); 
                CGColorSpaceRelease(colorSpace);

                /* End composite */

                [assetWriterVideoInput appendSampleBuffer:sample];
                CFRelease(sample);

            }
            else {
                [assetWriterVideoInput markAsFinished];

                /* Close output */

                [assetWriter endSessionAtSourceTime:presentationTime];
                if (![assetWriter finishWriting]) {
                    NSLog(@"[assetWriter finishWriting] failed, status=%@ error=%@", assetWriter.status, assetWriter.error);
                }

            }

        }
    }];

}];
0 голосов
/ 07 октября 2010

Я не знаю всего процесса, но знаю немного:

Возможно, вам придется использовать AV Foundation Framework и, возможно, Core Video Framework для обработки отдельных кадров.Вы, вероятно, будете использовать AVWriter:

AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:
                              [NSURL fileURLWithPath:path]
                                            fileType:AVFileTypeQuickTimeMovie
                                               error:&error];

. Вы можете сохранить пиксельный буфер, используя AVFoundation или CV, а затем записать его как (этот пример для CV):

[pixelBufferAdaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];

Чтобы получитькадров, AVAssetStillImageGenerator на самом деле недостаточно.

В качестве альтернативы, Может существовать фильтр или инструкция, которые можно использовать с AVVideoMutableComposition, AVMutableComposition или AVAssetExportSession.

Если вы добились прогресса с тех пор, как просили в августе, напишите, пожалуйста, как мне интересно!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...