Reputation: 2262
Have you met the problem when for the same video copyPixelBufferForItemTime
is incorrect on iOS?
I have AVPlayerItemVideoOutput
, linked to appropriate AVPlayerItem
.
I call copyPixelBufferForItemTime
, receive CVPixelBufferRef
and then retrieve OpenGL texture from it.
CVPixelBufferRef pb = [_playerVideoOutput copyPixelBufferForItemTime:currentTime itemTimeForDisplay:nil];
For this sample video there's bug with CVPixelBufferRef:
int bpr = (int)CVPixelBufferGetBytesPerRow(pb);
int width_real = (int)CVPixelBufferGetWidth(pb);
int width_working = (int)CVPixelBufferGetBytesPerRow(pb)/4;
Mac output:
bpr = 2400
width_real = 596
width_working = 600
iOS output:
bpr = 2432
width_real = 596
width_working = 608
CVPixelBufferGetPixelFormatType
returns BGRA
on both platforms.
Edit
When creating texture on iOS, I read data from pixel buffer via CVPixelBufferGetBaseAddress
and use provided size CVPixelBufferGetWidth
/CVPixelBufferGetHeight
:
- (GLuint)createTextureFromMovieFrame:(CVPixelBufferRef)movieFrame
{
int bufferWidth = (int) CVPixelBufferGetWidth(movieFrame);
int bufferHeight = (int) CVPixelBufferGetHeight(movieFrame);
// Upload to texture
CVPixelBufferLockBaseAddress(movieFrame, 0);
CVOpenGLTextureRef texture=0;
GLuint tex = 0;
#if TARGET_OS_IOS==1
void * data = CVPixelBufferGetBaseAddress(movieFrame);
CVReturn err = 0;
tex = algotest::MyGL::createRGBATexture(bufferWidth, bufferHeight, data, algotest::MyGL::KLinear);
#else
CVReturn err = CVOpenGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
getGlobalTextureCache(), movieFrame, 0, &texture);
#endif
CVPixelBufferUnlockBaseAddress(movieFrame, 0);
return tex;
}
So width_working
is just for debug. As it mismatch width_real
, and passing neither width_working
not width_real
doesn't work, I suppose that it's a bug with pixel buffer.
Upvotes: 1
Views: 1141
Reputation: 36084
The pixel buffers have per-line padding pixels on both iOS and mac, presumably for alignment reasons. The difference is that the mac CVOpenGLTextureCacheCreateTextureFromImage
function understands this, while the iOS createRGBATexture
function can not, not without a bytes-per-row argument.
You could either include the padding pixels in the width, and crop them out later:
tex = algotest::MyGL::createRGBATexture(CVPixelBufferGetBytesPerRow(movieFrame)/4, bufferHeight, data, algotest::MyGL::KLinear);
Or you could use CVOpenGLESTextureCache
, the iOS equivalent of CVOpenGLTextureCache
and replace createRGBATexture()
with CVOpenGLESTextureCacheCreateTextureFromImage()
. Then your mac & iOS code would be similar & the iOS code might even run faster as texture caches on iOS can avoid redundant copying of texture data.
Upvotes: 2