AVPlayerItemVideoOutput copyPixelBufferForItemTime 在 iOS 上为特定视频提供了不正确的 CVPixelBufferRef
AVPlayerItemVideoOutput copyPixelBufferForItemTime gives incorrect CVPixelBufferRef on iOS for particular video
您是否遇到过同一视频 copyPixelBufferForItemTime
在 iOS 上不正确的问题?
我有AVPlayerItemVideoOutput
,链接到合适的AVPlayerItem
。
我调用 copyPixelBufferForItemTime
,接收 CVPixelBufferRef
,然后从中检索 OpenGL 纹理。
CVPixelBufferRef pb = [_playerVideoOutput copyPixelBufferForItemTime:currentTime itemTimeForDisplay:nil];
为此 sample video CVPixelBufferRef 存在错误:
int bpr = (int)CVPixelBufferGetBytesPerRow(pb);
int width_real = (int)CVPixelBufferGetWidth(pb);
int width_working = (int)CVPixelBufferGetBytesPerRow(pb)/4;
Mac 输出:
bpr = 2400
width_real = 596
width_working = 600
iOS 输出:
bpr = 2432
width_real = 596
width_working = 608
它在 iOS 上的呈现方式:
在 Mac 上的呈现方式:
CVPixelBufferGetPixelFormatType
returns BGRA
在两个平台上。
编辑
在 iOS 上创建纹理时,我通过 CVPixelBufferGetBaseAddress
从像素缓冲区读取数据并使用提供的大小 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;
}
所以width_working
只是为了调试。由于它不匹配 width_real
,并且既不传递 width_working
也不传递 width_real
都不起作用,我认为这是像素缓冲区的错误。
像素缓冲区在 iOS 和 mac 上都有每行填充像素,大概是出于对齐的原因。不同之处在于 mac CVOpenGLTextureCacheCreateTextureFromImage
函数可以理解这一点,而 iOS createRGBATexture
函数不能,因为没有字节每行参数。
您可以在宽度中包含填充像素,然后再将它们剪掉:
tex = algotest::MyGL::createRGBATexture(CVPixelBufferGetBytesPerRow(movieFrame)/4, bufferHeight, data, algotest::MyGL::KLinear);
或者您可以使用 CVOpenGLESTextureCache
,相当于 CVOpenGLTextureCache
的 iOS,并将 createRGBATexture()
替换为 CVOpenGLESTextureCacheCreateTextureFromImage()
。那么您的 mac 和 iOS 代码将是相似的并且 iOS 代码甚至可能 运行 更快,因为 iOS 上的纹理缓存可以避免纹理数据的冗余复制。
您是否遇到过同一视频 copyPixelBufferForItemTime
在 iOS 上不正确的问题?
我有AVPlayerItemVideoOutput
,链接到合适的AVPlayerItem
。
我调用 copyPixelBufferForItemTime
,接收 CVPixelBufferRef
,然后从中检索 OpenGL 纹理。
CVPixelBufferRef pb = [_playerVideoOutput copyPixelBufferForItemTime:currentTime itemTimeForDisplay:nil];
为此 sample video CVPixelBufferRef 存在错误:
int bpr = (int)CVPixelBufferGetBytesPerRow(pb);
int width_real = (int)CVPixelBufferGetWidth(pb);
int width_working = (int)CVPixelBufferGetBytesPerRow(pb)/4;
Mac 输出:
bpr = 2400
width_real = 596
width_working = 600
iOS 输出:
bpr = 2432
width_real = 596
width_working = 608
它在 iOS 上的呈现方式:
在 Mac 上的呈现方式:
CVPixelBufferGetPixelFormatType
returns BGRA
在两个平台上。
编辑
在 iOS 上创建纹理时,我通过 CVPixelBufferGetBaseAddress
从像素缓冲区读取数据并使用提供的大小 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;
}
所以width_working
只是为了调试。由于它不匹配 width_real
,并且既不传递 width_working
也不传递 width_real
都不起作用,我认为这是像素缓冲区的错误。
像素缓冲区在 iOS 和 mac 上都有每行填充像素,大概是出于对齐的原因。不同之处在于 mac CVOpenGLTextureCacheCreateTextureFromImage
函数可以理解这一点,而 iOS createRGBATexture
函数不能,因为没有字节每行参数。
您可以在宽度中包含填充像素,然后再将它们剪掉:
tex = algotest::MyGL::createRGBATexture(CVPixelBufferGetBytesPerRow(movieFrame)/4, bufferHeight, data, algotest::MyGL::KLinear);
或者您可以使用 CVOpenGLESTextureCache
,相当于 CVOpenGLTextureCache
的 iOS,并将 createRGBATexture()
替换为 CVOpenGLESTextureCacheCreateTextureFromImage()
。那么您的 mac 和 iOS 代码将是相似的并且 iOS 代码甚至可能 运行 更快,因为 iOS 上的纹理缓存可以避免纹理数据的冗余复制。