【问题标题】:AVPlayerItemVideoOutput copyPixelBufferForItemTime gives incorrect CVPixelBufferRef on iOS for particular videoAVPlayerItemVideoOutput copyPixelBufferForItemTime 在 iOS 上为特定视频提供不正确的 CVPixelBufferRef
【发布时间】:2017-10-26 01:37:32
【问题描述】:

您是否遇到过相同视频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 在两个平台上都返回 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 案例中处理错了每行填充(width_real*4 != CVPixelBufferGetBytesPerRow(pb) 时。你能展示你是如何创建纹理的吗?你到底在用 width_working 做什么? ?
  • @RhythmicFistman 看来我错误地命名了变量。 :) width_working 用于调试。更新了帖子。

标签: ios avfoundation avplayeritem core-video cvpixelbuffer


【解决方案1】:

像素缓冲区在 iOS 和 mac 上都有每行填充像素,大概是出于对齐的原因。不同之处在于 mac CVOpenGLTextureCacheCreateTextureFromImage 函数可以理解这一点,而 iOS createRGBATexture 函数不能,不是没有字节每行参数。

您可以在宽度中包含填充像素,然后将它们裁剪掉:

tex = algotest::MyGL::createRGBATexture(CVPixelBufferGetBytesPerRow(movieFrame)/4, bufferHeight, data, algotest::MyGL::KLinear);

或者您可以使用CVOpenGLESTextureCache,相当于CVOpenGLTextureCache,并将createRGBATexture() 替换为CVOpenGLESTextureCacheCreateTextureFromImage()。那么你的 mac 和 iOS 代码会相似,而且 iOS 代码甚至可能运行得更快,因为 iOS 上的纹理缓存可以避免纹理数据的冗余复制。

【讨论】:

    猜你喜欢
    • 2017-08-07
    • 1970-01-01
    • 1970-01-01
    • 2011-09-12
    • 1970-01-01
    • 1970-01-01
    • 2017-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多