Байт на строку неверен при создании CVPixelBuffer с шириной, кратной 90

Я обрабатываю необработанные данные кадров биплана yuv420, которые я получаю из сети, и мне нужно создать CVPixelBuffer, чтобы обработать его в основной образ, а также записать на диск с помощью AVAssetWriter.

Когда я пытаюсь создать CVPixelBuffer с кодом ниже с шириной, такой как 120, 240 или 480, он выделяет память и создает правильный CVPixelBuffer с правильными значениями bytePerRow для обеих плоскостей (например, ширина 120 дает значение 120 bytePerRow).

Однако, когда я ввожу кадр с шириной, такой как 90, 180 или 360, он создает ошибочный bytePerRow, такой как 192 bytePerRow для ширины кадра 180. Это вызывает проблемы с отрисовкой позже в CoreImage или AVAssetWriter.

См. приведенный ниже код для создания CVPixelBuffer.

CGSize frameSize = CGSizeMake(180,240);
CVPixelBufferRef pixelBuffer = NULL;
NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfaceOpenGLESFBOCompatibilityKey : (id)kCFBooleanTrue,
                                  (id)kCVPixelBufferIOSurfaceCoreAnimationCompatibilityKey : (id)kCFBooleanTrue,     
                                  (id)kCVPixelBufferIOSurfaceOpenGLESTextureCompatibilityKey : (id)kCFBooleanTrue,     
                                  (id)kCVPixelBufferOpenGLESCompatibilityKey: (id)kCFBooleanTrue};

CVReturn result = CVPixelBufferCreate(NULL, frameSize.width, frameSize.height, kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, (__bridge CFDictionaryRef _Nullable)(pixelAttributes), &pixelBuffer);

Обратите внимание, что я не могу использовать CVPixelBufferCreateWithPlanarBytes, который заставляет меня самостоятельно выделять память и вызывает утечку памяти позже при использовании с Core Image, который не является предметом этой проблемы.


person David Attias    schedule 22.10.2017    source источник


Ответы (1)


Я выяснил причину этой ошибки и одновременно получил ответ от Apple DTS, который соответствует моим интуициям. Вот ответы:

Согласно инженерам Core Video, причина, по которой количество байтов в строке округляется от 180 до 196, заключается в обязательном выравнивании по 16 байтам. 180/16 = 11,25; 192/16 = 12,0.

Есть способы принудительно указать точное количество байтов в строке, но здесь это звучит как плохая идея. Причина необходимого выравнивания заключается в том, что видеокарты имеют аппаратное ограничение. Похоже, вы хотите использовать CoreImage. Использование CVPixelBuffers, которые не выровнены, либо не будет работать, либо заставит где-то создать дополнительную копию.

Мы рекомендуем заполнять ваши буферы построчно. Что-то вроде этого:

int srcRowbytes = 180; // Or whatever it is from wherever
int dstRowbytes = CVPixelBufferGetBytesPerRowOfPlane( dstBuffer, plane );
void * dstBytes = CVPixelBufferGetBaseAddressOfPlane( dstBuffer, plane );
for( int line = 0; line < height; line++ ) {
    memcpy( dstBytes, srcBytes, srcRowbytes );
    srcBytes += srcRowbytes;
    dstBytes += dstRowbytes;
}
person David Attias    schedule 13.03.2018
comment
Я вижу что-то похожее на это, где CVPixelBuffer с фронтальной камеры имеет ширину 1440, но байтов на строку 1472. Последнее делится на 64; Интересно, увеличились ли требования к выравниванию или это что-то другое? - person icodestuff; 20.03.2021