为什么 ANativeWindow_Buffer.stride 对于不同的设备是不同的
Why ANativeWindow_Buffer.stride is different for different devices
我正在使用 ffmpeg 为 android 编写简单的视频播放器。以下是我遵循的步骤
- 从文件中读取 AVFrame
- 使用
sws_scale
将AVFrame转换为RGB565格式
- 使用
av_image_copy_to_buffer
获取缓冲区
- 通过将缓冲区复制到
ANativeWindow_Buffer
,将此缓冲区显示到 SurfaceView
大多数视频都可以正常播放,但分辨率低于 window 的视频存在问题。例如,当我在我的 OnePlus 7T (2206x1080) 上播放 656x480 视频时,视频看起来失真了。同一视频在模拟器上播放良好 (2160x1080)。
当我调试整个管道时,我发现在OP7T上,锁定ANativeWindow
后,ANativeWindow_Buffer.stride
设置为704而不是656。对于所有正常播放的视频,步幅与宽度相同缓冲区。 Android 模拟器的情况不同。
我做了一些试验,尝试将宽度缩放到 600,然后步幅跳到 640,视频失真。当我将宽度缩放到 640 时,视频垂直显示一半正确。
任何人都可以帮助我理解步幅是如何计算的吗?以及 stride 计算错误的原因是什么?
我在这里发现了一个同样的问题:
OP 提到视频适用于 640、1280、1920。
似乎因为我的设备是 arm64-v8a,步幅总是对齐到 64。为了克服这个问题,我在锁定 window 并使用 ANative_WindowBuffer
后得到步幅。然后我用这个 windowbuffer.stride
来计算 dst_slice for sws_scale
.
AVFrame dummy;
if ((ret = ANativeWindow_lock(window, &windowBuffer, nullptr)) < 0) {
log_error("cannot lock window: %d", ret);
} else {
dummy.data[0] = (uint8_t *) windowBuffer.bits;
dummy.linesize[0] = windowBuffer.stride * 2 // For RGB565;
}
然后:
sws_scale(renderer->sws_ctx,
(const uint8_t* const *) frame->data,
frame->linesize,
0,
codecpar->height,
dummy.data,
dummy.linesize)
这会直接将缩放后的帧数据渲染到window缓冲区。
我正在使用 ffmpeg 为 android 编写简单的视频播放器。以下是我遵循的步骤
- 从文件中读取 AVFrame
- 使用
sws_scale
将AVFrame转换为RGB565格式
- 使用
av_image_copy_to_buffer
获取缓冲区
- 通过将缓冲区复制到
ANativeWindow_Buffer
,将此缓冲区显示到
SurfaceView
大多数视频都可以正常播放,但分辨率低于 window 的视频存在问题。例如,当我在我的 OnePlus 7T (2206x1080) 上播放 656x480 视频时,视频看起来失真了。同一视频在模拟器上播放良好 (2160x1080)。
当我调试整个管道时,我发现在OP7T上,锁定ANativeWindow
后,ANativeWindow_Buffer.stride
设置为704而不是656。对于所有正常播放的视频,步幅与宽度相同缓冲区。 Android 模拟器的情况不同。
我做了一些试验,尝试将宽度缩放到 600,然后步幅跳到 640,视频失真。当我将宽度缩放到 640 时,视频垂直显示一半正确。
任何人都可以帮助我理解步幅是如何计算的吗?以及 stride 计算错误的原因是什么?
我在这里发现了一个同样的问题:
似乎因为我的设备是 arm64-v8a,步幅总是对齐到 64。为了克服这个问题,我在锁定 window 并使用 ANative_WindowBuffer
后得到步幅。然后我用这个 windowbuffer.stride
来计算 dst_slice for sws_scale
.
AVFrame dummy;
if ((ret = ANativeWindow_lock(window, &windowBuffer, nullptr)) < 0) {
log_error("cannot lock window: %d", ret);
} else {
dummy.data[0] = (uint8_t *) windowBuffer.bits;
dummy.linesize[0] = windowBuffer.stride * 2 // For RGB565;
}
然后:
sws_scale(renderer->sws_ctx,
(const uint8_t* const *) frame->data,
frame->linesize,
0,
codecpar->height,
dummy.data,
dummy.linesize)
这会直接将缩放后的帧数据渲染到window缓冲区。