Почему я могу обработать эффект оттенков серого в AVCaptureSession, а не в AVAssetReader? - PullRequest
0 голосов
/ 28 октября 2011

Я работаю над приложением для iPhone.Я хочу применить некоторые фильтры к видео из библиотеки.После исследования я начал с этого поста http://www.sunsetlakesoftware.com/2010/10/22/gpu-accelerated-video-processing-mac-and-ios и его источника ColorTracking.Из этого кода я могу применить фильтр градаций серого в реальном времени с помощью AVCaptureSession.Правильно.Но я хочу сделать то же самое с видео из библиотеки.Поэтому я использую AVAssetReader для чтения исходного видео.Как с AVCaptureSession, я могу получить CVImageBufferRef.Он имеет ту же ширину, высоту и размер данных, что и AVCaptureSession, но мое представление openGL всегда черное.

Мой источник для захвата Frame:

    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {


    [self dismissModalViewControllerAnimated:NO];


    /// incoming video
    NSURL *videoURL = [info valueForKey:UIImagePickerControllerMediaURL];
    NSLog(@"Video : %@", videoURL);

    // 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:videoURL options:inputOptions];

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


        NSError *error = nil;

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




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

        NSMutableDictionary *outputSettings = [NSMutableDictionary dictionary];
        [outputSettings setObject: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA]  forKey: (NSString*)kCVPixelBufferPixelFormatTypeKey];
        AVAssetReaderTrackOutput *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
            NSLog(@"Error reading");
        }

        NSAutoreleasePool *pool = [NSAutoreleasePool new];
        while (reader.status == AVAssetReaderStatusReading) {

            CMSampleBufferRef sampleBufferRef = [readerVideoTrackOutput copyNextSampleBuffer];
            if (sampleBufferRef) {
                CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBufferRef);
                [self processNewCameraFrame:pixelBuffer];

                CMSampleBufferInvalidate(sampleBufferRef);
                CFRelease(sampleBufferRef);
            }
        }
        [pool release];

        NSLog(@"Finished");
    }];
}

Вот код для обработки кадра:

- (void)processNewCameraFrame:(CVImageBufferRef)cameraFrame {


    CVPixelBufferLockBaseAddress(cameraFrame, 0);
    int bufferHeight = CVPixelBufferGetHeight(cameraFrame);
    int bufferWidth = CVPixelBufferGetWidth(cameraFrame);

    NSLog(@"Size : %i %i %zu", bufferWidth, bufferHeight, CVPixelBufferGetDataSize(cameraFrame));


    // Create a new texture from the camera frame data, display that using the shaders
    glGenTextures(1, &videoFrameTexture);
    glBindTexture(GL_TEXTURE_2D, videoFrameTexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // This is necessary for non-power-of-two textures
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    // Using BGRA extension to pull in video frame data directly
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bufferWidth, bufferHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, CVPixelBufferGetBaseAddress(cameraFrame));

    GLenum err = glGetError();
    if (err != GL_NO_ERROR)
        NSLog(@"Error uploading texture. glError: 0x%04X", err);

    [self drawFrame];

    glDeleteTextures(1, &videoFrameTexture);

    CVPixelBufferUnlockBaseAddress(cameraFrame, 0);
}

Для рисования рамки в OpenGL View:

- (void)drawFrame {    
    // Replace the implementation of this method to do your own custom drawing.
    static const GLfloat squareVertices[] = {
        -1.0f, -1.0f,
        1.0f, -1.0f,
        -1.0f,  1.0f,
        1.0f,  1.0f,
    };

    static const GLfloat textureVertices[] = {
        1.0f, 1.0f,
        1.0f, 0.0f,
        0.0f,  1.0f,
        0.0f,  0.0f,
    };

    [glView setDisplayFramebuffer];
    glUseProgram(grayScaleProgram);         

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, videoFrameTexture);

    // Update uniform values
    glUniform1i(uniforms[UNIFORM_VIDEOFRAME], 0);   

    // Update attribute values.
    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GL_FLOAT, 0, 0, textureVertices);
    glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITON);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);



    [glView presentFramebuffer];
}

Я не добавляю код, но при необходимости, чтобы помочь мне, я могу ... У вас есть способ помочь мне?

Спасибо!

Ответы [ 2 ]

1 голос
/ 24 ноября 2011

Когда вы сказали, что фильтр в оттенках серого означает, что вы используете kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange видеокадры?Если так, то я предполагаю, что вы связываете текстуру как GL_LUMINANCE.Однако в вашем AVAssetReader вы используете пиксельный формат kCVPixelFormatType_32BGRA, а в методе обработки вы привязываете текстуру как GL_RGBA.

. Однажды я наткнулся на такое неправильное сочетание формата пикселя захвата видео и привязки текстуры.и в итоге с черным экраном.Проверьте настройки AVCaptureVideoDataOutput в коде установки AVCaptureSession.Пиксельный формат и текстурное связывание должны быть одинаковыми.

Редактировать: Другая возможная причина черного экрана заключается в том, что контекст OpenGL не является общим для потоков.Если для видеокадров камеры используется очередь, отличная от основной очереди dispatch_get_main_queue(), это означает, что метод

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
       fromConnection:(AVCaptureConnection *)connection  

вызывается в фоновом потоке, из которого невозможно обновить пользовательский интерфейс.

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

AVCaptureVideoDataOutput *videoOut = [[AVCaptureVideoDataOutput alloc] init];
// set video settings, frame rate .. etc
[videoOut setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
0 голосов
/ 28 октября 2011

Похоже, что вы не связываете свою фоторамку с видеокадром.
CVImageBufferRef image;
glBindTexture( CVOpenGLTextureGetTarget( image ), CVOpenGLTextureGetName( image ) );

...