Как получить текстуру openGL из видео с помощью AVFoundation?

Создание 64-битного родного приложения OSX (не iOS) для версии 10.7+. Несколько новичок в работе с видеофайлами во вселенной Cocoa.

Я хотел бы иметь возможность открывать видеофайл и отображать вывод внутри рендеринга openGL (IE, я хотел бы иметь эффективный доступ к фреймбуферу видео и превращать каждый кадр в текстуру opengl).

Концептуально это кажется простым, но мне трудно пробираться через различные (старые и устаревшие) примеры и варианты, все из которых, похоже, недавно устарели в пользу AVFoundation. Возможно, я что-то упустил, но примеры использования AVFoundation с OpenGL кажутся незначительными.

Чтобы немного уточнить, этот пример приложения (QTCoreVideo101 от Apple) делает более или менее то, что я хочу, за исключением того, что он построен вокруг поэтому устаревший QTKit даже не будет компилироваться в 64-битной версии.

Я читаю документы AVFoundation прямо сейчас, но я все еще не уверен, что имеет смысл пытаться получить glTexture из AVFoundation или мне следует искать в другом месте.

ОБНОВЛЕНИЕ

Это решение, с которым я в итоге пошел. «thisLayer.layerSource.videoPlayerOutput» — это объект AVPlayerItemVideoOutput.

if ([thisLayer.layerSource.videoPlayerOutput hasNewPixelBufferForItemTime:playerTime]){

    frameBuffer= [thisLayer.layerSource.videoPlayerOutput copyPixelBufferForItemTime:playerTime itemTimeForDisplay:NULL];

    CVReturn result= CVOpenGLTextureCacheCreateTextureFromImage(NULL,
                                           textureCache,
                                           frameBuffer,
                                           NULL,
                                           &textureRef);
    if(result == kCVReturnSuccess){
            // These appear to be GL_TEXTURE_RECTANGLE_ARB
            thisLayer.layerSource.vid_glTextureTarget=CVOpenGLTextureGetTarget(textureRef);
            thisLayer.layerSource.vid_glTexture=CVOpenGLTextureGetName(textureRef);
            thisLayer.layerSource.vid_glTextureSize=NSMakeSize(CVPixelBufferGetWidth(frameBuffer), CVPixelBufferGetHeight(frameBuffer));
            thisLayer.layerSource.vid_ciimage=[CIImage imageWithCVImageBuffer:frameBuffer];
            CFRelease(textureRef);
            CVOpenGLTextureCacheFlush(textureCache, 0);
    }else{
            NSLog(@"INTERNAL ERROR FAILED WITH CODE: %i",result);
    }
    CVBufferRelease(frameBuffer);
}

person andrew    schedule 12.03.2014    source источник


Ответы (2)


AVAssetReaderTrackOutput (добавленный к вашему AVAssetReader) выведет CVPixelBufferRef, из которых вы можете указать предпочитаемый формат для загрузки в OpenGL через glTexImage или glTexSubImage.

person jgh    schedule 17.03.2014

Я тоже смотрел на это, это мое текущее решение:

- (BOOL) renderWithCVPixelBufferForTime: (NSTimeInterval) time
{
    CMTime vTime = [self.playeroutput itemTimeForHostTime:CACurrentMediaTime()];

    if ([self.playeroutput hasNewPixelBufferForItemTime:vTime]) {
        if (_cvPixelBufferRef) {
            CVPixelBufferUnlockBaseAddress(_cvPixelBufferRef, kCVPixelBufferLock_ReadOnly);
            CVPixelBufferRelease(_cvPixelBufferRef);
        }
        _cvPixelBufferRef = [self.playeroutput copyPixelBufferForItemTime:vTime itemTimeForDisplay:NULL];

        CVPixelBufferLockBaseAddress(_cvPixelBufferRef, kCVPixelBufferLock_ReadOnly);
        GLsizei       texWidth    = CVPixelBufferGetWidth(_cvPixelBufferRef);
        GLsizei       texHeight   = CVPixelBufferGetHeight(_cvPixelBufferRef);
        GLvoid *baseAddress = CVPixelBufferGetBaseAddress(_cvPixelBufferRef);


        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textureName);
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
        glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, texWidth, texHeight, 0, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, baseAddress);

        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
    } 
    return YES;
} 

Однако мне интересно, нет ли более эффективного решения, у меня также есть вопрос по той же теме с несколькими подходами:

Лучший путь от AVPlayerItemVideoOutput до текстуры openGL

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

person George Brown    schedule 05.08.2014
comment
Хорошо... В итоге я сделал что-то подобное (используя пиксельный буфер и помещая его в кеш текстур). На самом деле я не пробовал профилировать ваш код по сравнению с моим, поэтому я не уверен, что быстрее, но я опубликую код в другом ответе через мгновение (слишком длинный для комментария). Я не делал никаких блокировок — возможно, мне следовало бы, но какое-то время нормально работал в производственной среде, запуская даже несколько HD-видео одновременно. - person andrew; 07.08.2014