Sto tentando di utilizzare una combinazione di GPUImage
e AVVideoCompositing
per implementare un filtro chroma-key live tra due video. Questa operazione in modo ingenuo utilizzando CIImage
imageFromCVPixelBuffer
in CGImage
in GPUImage
su CGImage
a CIImage
a CVPixelBuffer
, è altamente inefficiente e causa problemi di memoria.Utilizzo di GPUImage con AVVideoCompositing
Ho notato che ci sono oggetti texture, destinazioni di rendering e frame buffer nel framework GPUImage
. Speravo di essere in grado di sfruttare CVOpenGLESTextureCacheCreateTextureFromImage
in iOS per mantenere tutto sulla GPU.
Non credo che sto abbastanza comprensione funzionamento interno del quadro, perché ho pensato che potrei creare una catena di filtro su un oggetto GPUImageTextureInput
e quindi ottenere il filtro del renderTarget
, che è un CVPixelBufferRef
. Lo renderTarget
di seguito è sempre nullo e chiamare imageFromCurrentFrameBuffer
mi darà una casella grigia, che non è la mia immagine.
Si prega di notare che l'esempio seguente non è chroma-key, ma un semplice filtro di luminosità su un singolo video per provare e dimostrare il concetto.
@implementation MyCustomCompositor : NSObject <AVVideoCompositing>
- (instancetype)init
{
self = [super init];
if (self) {
CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, [GPUImageContext sharedImageProcessingContext].context, NULL, &_textureCache);
}
return self;
}
- (NSDictionary<NSString *,id> *)requiredPixelBufferAttributesForRenderContext
{
return @{(NSString *)kCVPixelBufferPixelFormatTypeKey : @[@(kCVPixelFormatType_32BGRA)],
(NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES};
}
- (NSDictionary<NSString *,id> *)sourcePixelBufferAttributes
{
return @{(NSString *)kCVPixelBufferPixelFormatTypeKey : @[@(kCVPixelFormatType_32BGRA)],
(NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES};
}
- (void)startVideoCompositionRequest:(AVAsynchronousVideoCompositionRequest *)asyncVideoCompositionRequest
{
@autoreleasepool {
CVPixelBufferRef mePixelBuffer = [asyncVideoCompositionRequest sourceFrameByTrackID:200];
CVPixelBufferLockBaseAddress(mePixelBuffer, kCVPixelBufferLock_ReadOnly);
CVOpenGLESTextureRef meTextureRef = NULL;
size_t width = CVPixelBufferGetWidth(mePixelBuffer);
size_t height = CVPixelBufferGetHeight(mePixelBuffer);
CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCache, mePixelBuffer, NULL, GL_TEXTURE_2D, GL_BGRA, (int)width, (int)height, GL_BGRA, GL_UNSIGNED_BYTE, 0, &meTextureRef);
GPUImageTextureInput *meTextureInput = [[GPUImageTextureInput alloc] initWithTexture:CVOpenGLESTextureGetName(meTextureRef) size:CGSizeMake(width, height)];
GPUImageBrightnessFilter *filter = [[GPUImageBrightnessFilter alloc] init];
filter.brightness = 0.5;
[meTextureInput addTarget:filter];
[filter setFrameProcessingCompletionBlock:^(GPUImageOutput *imageOutput, CMTime time) {
[asyncVideoCompositionRequest finishWithComposedVideoFrame:((GPUImageBrightnessFilter *)imageOutput).renderTarget];
}];
[meTextureInput processTextureWithFrameTime:kCMTimeZero];
CFRelease(meTextureRef);
CVOpenGLESTextureCacheFlush(_textureCache, 0);
CVPixelBufferUnlockBaseAddress(mePixelBuffer, kCVPixelBufferLock_ReadOnly);
}
}
non sto usando i GPUMovieWriter
o video di API in GPUImage
perché ho bisogno di un controllo più granulare di mia composizione. La composizione può essere composta da più istruzioni chroma-key che fanno riferimento a un diverso overlay video verde in diversi intervalli di tempo e mi sembra che le API del film in GPUImage
siano limitate al filtraggio di un intero file video. Ho anche bisogno delle capacità della composizione per manipolare tracce e mix audio.
Ho provato a capovolgerlo facendo tutto questo in GL con shader personalizzati, ma ho pensato di sfruttare le strutture esistenti che sembrano fare ciò che sto cercando di fare.
Darò uno scatto! Grazie! – dhenke
Sono un po 'confuso da questo. Sembra che il codice sia quasi uscito da GPUImageMovie, che va bene, ma come adattarlo a una sottoclasse GPUImageOutput? Come si verifica la chiamata a createDataFBO? O mi mancano alcuni pezzi su come organizzare questa sottoclasse? Presumo che finirei per chiamare createDataFBO e assegnando quel riferimento a qualcosa? – dhenke
scusate. Ho dimenticato di dare l'output. : P Lasciami aggiustarlo. – econi