2017-10-03 4 views
2

J'enregistre l'écran de mon iPhone sur mon Mac. En tant que couche de prévisualisation, je collectionne des tampons d'échantillons directement à partir d'un AVCaptureVideoDataOutput, à partir duquel je crée des textures et les restitue avec Metal. Le problème que j'ai est que le code qui a fonctionné dans macOS avant 10.13 a cessé de fonctionner après la mise à jour à 10.13. A savoir,CVMetalTextureCacheCreateTextureTromtureFromImage renvoie -6660 sur macOS 10.13

CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(_currentSampleBuffer); 

if (!imageBuffer) return; 

CVPixelBufferLockBaseAddress(imageBuffer,0); 
size_t width = CVPixelBufferGetWidth(imageBuffer); 
size_t height = CVPixelBufferGetHeight(imageBuffer); 

CVMetalTextureRef metalTexture = NULL; 
CVReturn result = CVMetalTextureCacheCreateTextureFromImage(nil, 
                  self.textureCache, 
                  imageBuffer, 
                  nil, 
                  self.pixelFormat, 
                  width, 
                  height, 
                  0, 
                  &metalTexture); 

if (result == kCVReturnSuccess) { 
    self.texture = CVMetalTextureGetTexture(metalTexture); 
} 

retours result = -6660, ce qui correspond à un kCVReturnError générique, comme on peut le voir on the official Apple docs, et le metalTexture = NULL.

Le format de pixel que j'utilise est MTLPixelFormatBGRG422, puisque les échantillons provenant de la caméra sont 2vuy.

Pour contourner ce problème à la création de metalTexturesampleBuffer, je suis maintenant la création d'un NSImage intermédiaire comme ceci:

CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(_currentSampleBuffer); 
    NSCIImageRep *imageRep = [NSCIImageRep imageRepWithCIImage:[CIImage imageWithCVImageBuffer:imageBuffer]]; 

    NSImage *image = [[NSImage alloc] initWithSize:[imageRep size]]; 
    [image addRepresentation:imageRep]; 

et la création d'un MTLTexture de cela. C'est évidemment une solution inférieure à l'utilisation directe de CVMetalTextureCacheCreateTextureFromImage.

Encore une fois, le code en question fonctionne parfaitement bien dans macOS < 10.13, je voudrais savoir si quelqu'un a des problèmes similaires, et si oui, avez-vous des idées pour y remédier?

Répondre

3

J'ai rencontré le même problème, le problème ne demandait pas la compatibilité métal lors de la configuration du AVCaptureVideoDataOutput. Je suppose que le système a commencé à vérifier cela dans macOS 10.13, peut-être pour appliquer une optimisation quand il n'est pas demandé. La solution consistait à ajouter kCVPixelBufferMetalCompatibilityKey à la propriété videoSettings de AVCaptureVideoDataOutput.

En Objective-C:

outputCapture.videoSettings = @{ 
    /* ... */ 
    (NSString *)kCVPixelBufferMetalCompatibilityKey: @YES 
}; 

Swift:

outputCapture.videoSettings = [ 
    /* ... */ 
    kCVPixelBufferMetalCompatibilityKey as String: true 
] 

Je pense que cela justifie un radar, demander Apple pour imprimer au moins un message d'avertissement lorsque cela se produit. Je mettrai à jour ceci si j'y arrive.

+0

génial, cela fonctionne! J'ai besoin de vérifier le format de sortie dans le tampon de pixels maintenant, car je reçois une image fractionnée et des couleurs étranges. Je posterai ma solution de contournement dans une autre réponse pour référence future. –

0

J'ai trouvé une solution de contournement pour cela, qui conserve le format 2vuy dans le tampon de pixels, mais la mauvaise chose est que vous faites une copie des données de tampon de pixel qui affecte les performances. Je poste ceci pour référence future, ou si quelqu'un d'autre le trouve utile. Fondamentalement, nous intercepter le tampon de pixels, puis ajouter des attributs lors de la copie des données.

NSDictionary *attributes = @{ 
          @"IOSurfaceCoreAnimationCompatibility": @YES 
          }; 
CVPixelBufferRef copy = NULL; 

CVPixelBufferCreate(kCFAllocatorDefault, 
        CVPixelBufferGetWidth(pixelBuffer), 
        CVPixelBufferGetHeight(pixelBuffer), 
        CVPixelBufferGetPixelFormatType(pixelBuffer), 
        (__bridge CFDictionaryRef)attributes, 
        &copy); 

CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly); 
CVPixelBufferLockBaseAddress(copy, 0); 

void *baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer); 
void *copyBaseAddress = CVPixelBufferGetBaseAddress(copy); 

memcpy(copyBaseAddress, baseAddress, CVPixelBufferGetDataSize(pixelBuffer)); 

CVPixelBufferUnlockBaseAddress(copy, 0); 
CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);