使用 swscale 进行图像合成
Using swscale for image composing
我有一个输入图像 A 和一个以 YUV420 格式存储的大小为 800x600 的结果图像 B,我需要将图像 A 缩放为 100x100 大小并在某个点将其放入结果图像 B (x=100, y =100)。为了减少内存和 CPU 的使用,我将 swscale 结果直接放入最终的 B 图像中。
这是一个代码片段(非常简单):
//here we a creating sws context for scaling into 100x100
sws_ctx = sws_getCachedContext(sws_ctx, frame.hdr.width, frame.hdr.height, AV_PIX_FMT_YUV420P,
100, 100, AV_PIX_FMT_YUV420P, SWS_BILINEAR, nullptr, nullptr, nullptr);
接下来我们创建相应的切片和步长来描述图像 A
int src_y_plane_sz = frame.hdr.width * frame.hdr.height;
int src_uv_plane_sz = src_y_plane_sz / 2;
std::int32_t src_stride[] = {
frame.hdr.width,
frame.hdr.width / 2,
frame.hdr.width / 2,
0};
const uint8_t* const src_slice[] = {
&frame.raw_frame[0],
&frame.raw_frame[0] + src_y_plane_sz,
&frame.raw_frame[0] + src_y_plane_sz + src_uv_plane_sz,
nullptr};
现在对目标 B 图像执行相同的操作
std::int32_t dst_stride[] = {
current_frame.hdr.width,
current_frame.hdr.width /2,
current_frame.hdr.width /2,
0
};
std::int32_t y_plane_sz = current_frame.hdr.width * current_frame.hdr.height;
std::int32_t uv_plane_sz = y_plane_sz / 2;
//calculate offset in slices for x=100, y=100 position
std::int32_t y_offset = current_frame.hdr.width * 100 + 100;
uint8_t* const dst_slice[] = {
¤t_frame.raw_frame[0] + y_offset,
¤t_frame.raw_frame[0] + y_plane_sz + y_offset / 2,
¤t_frame.raw_frame[0] + y_plane_sz + uv_plane_sz + y_offset / 2,
nullptr};
毕竟 - 调用 swscale
int ret = sws_scale(sws_ctx, src_slice, src_stride, 0, frame.hdr.height,
dst_slice, dst_stride);
使用测试序列后,我得到了一些无效的结果,并存在以下问题:
- Y 组件得到一些填充线
- UV 组件错位 -
它们比原来的 Y 分量低一点。
有没有人对swscale函数有同样的问题?我对这个 FFmpeg 库集合很陌生,所以我愿意接受任何关于如何正确执行此任务的意见。
FFmpeg 版本使用 3.3
YUV420
格式将图像的宽度和高度缩放两倍。即每个色度平面比亮度平面小 4 倍:
int src_uv_plane_sz = src_y_plane_sz / 4;
我也不确定计算的步幅值是否正确。通常 stride != width.
感谢@VTT 指出可能的问题 - 我已将目标切片指针计算固定为以下内容:
int dest_x = 200, dest_y = 70;
//into 100x100 position
std::int32_t y_offset = current_frame.hdr.width * dest_y + dest_x;
std::int32_t u_offset = ( current_frame.hdr.width * dest_y ) / 4 + dest_x /2;
std::int32_t v_offset = u_offset + y_plane_sz / 4;
uint8_t* const dst_slice[] = {
¤t_frame.raw_frame[0] + y_offset,
¤t_frame.raw_frame[0] + y_plane_sz + u_offset,
¤t_frame.raw_frame[0] + y_plane_sz + v_offset,
nullptr};
"line artefact" 的第二个问题通过使用按比例缩放的尺寸大小因子 8 解决。
为目标切片指针的正确位置计算添加了一个新内容——必须根据当前的 Y 平面指向重新调整 y 坐标,因为每两个 Y 步幅只有一个 U 或 V 步幅。例如(参见 adjusted_uv_y 变量):
std::int32_t adjusted_uv_y = dest_y % 2 == 0 ? dest_y : dest_y - 1;
std::int32_t y_offset = current_frame.hdr.width * dest_y + dest_x;
std::int32_t u_offset = ( current_frame.hdr.width * adjusted_uv_y ) / 4 + dest_x /2;
std::int32_t v_offset = u_offset + y_plane_sz / 4;
我有一个输入图像 A 和一个以 YUV420 格式存储的大小为 800x600 的结果图像 B,我需要将图像 A 缩放为 100x100 大小并在某个点将其放入结果图像 B (x=100, y =100)。为了减少内存和 CPU 的使用,我将 swscale 结果直接放入最终的 B 图像中。
这是一个代码片段(非常简单):
//here we a creating sws context for scaling into 100x100
sws_ctx = sws_getCachedContext(sws_ctx, frame.hdr.width, frame.hdr.height, AV_PIX_FMT_YUV420P,
100, 100, AV_PIX_FMT_YUV420P, SWS_BILINEAR, nullptr, nullptr, nullptr);
接下来我们创建相应的切片和步长来描述图像 A
int src_y_plane_sz = frame.hdr.width * frame.hdr.height;
int src_uv_plane_sz = src_y_plane_sz / 2;
std::int32_t src_stride[] = {
frame.hdr.width,
frame.hdr.width / 2,
frame.hdr.width / 2,
0};
const uint8_t* const src_slice[] = {
&frame.raw_frame[0],
&frame.raw_frame[0] + src_y_plane_sz,
&frame.raw_frame[0] + src_y_plane_sz + src_uv_plane_sz,
nullptr};
现在对目标 B 图像执行相同的操作
std::int32_t dst_stride[] = {
current_frame.hdr.width,
current_frame.hdr.width /2,
current_frame.hdr.width /2,
0
};
std::int32_t y_plane_sz = current_frame.hdr.width * current_frame.hdr.height;
std::int32_t uv_plane_sz = y_plane_sz / 2;
//calculate offset in slices for x=100, y=100 position
std::int32_t y_offset = current_frame.hdr.width * 100 + 100;
uint8_t* const dst_slice[] = {
¤t_frame.raw_frame[0] + y_offset,
¤t_frame.raw_frame[0] + y_plane_sz + y_offset / 2,
¤t_frame.raw_frame[0] + y_plane_sz + uv_plane_sz + y_offset / 2,
nullptr};
毕竟 - 调用 swscale
int ret = sws_scale(sws_ctx, src_slice, src_stride, 0, frame.hdr.height,
dst_slice, dst_stride);
使用测试序列后,我得到了一些无效的结果,并存在以下问题:
- Y 组件得到一些填充线
- UV 组件错位 - 它们比原来的 Y 分量低一点。
有没有人对swscale函数有同样的问题?我对这个 FFmpeg 库集合很陌生,所以我愿意接受任何关于如何正确执行此任务的意见。
FFmpeg 版本使用 3.3
YUV420
格式将图像的宽度和高度缩放两倍。即每个色度平面比亮度平面小 4 倍:
int src_uv_plane_sz = src_y_plane_sz / 4;
我也不确定计算的步幅值是否正确。通常 stride != width.
感谢@VTT 指出可能的问题 - 我已将目标切片指针计算固定为以下内容:
int dest_x = 200, dest_y = 70;
//into 100x100 position
std::int32_t y_offset = current_frame.hdr.width * dest_y + dest_x;
std::int32_t u_offset = ( current_frame.hdr.width * dest_y ) / 4 + dest_x /2;
std::int32_t v_offset = u_offset + y_plane_sz / 4;
uint8_t* const dst_slice[] = {
¤t_frame.raw_frame[0] + y_offset,
¤t_frame.raw_frame[0] + y_plane_sz + u_offset,
¤t_frame.raw_frame[0] + y_plane_sz + v_offset,
nullptr};
"line artefact" 的第二个问题通过使用按比例缩放的尺寸大小因子 8 解决。
为目标切片指针的正确位置计算添加了一个新内容——必须根据当前的 Y 平面指向重新调整 y 坐标,因为每两个 Y 步幅只有一个 U 或 V 步幅。例如(参见 adjusted_uv_y 变量):
std::int32_t adjusted_uv_y = dest_y % 2 == 0 ? dest_y : dest_y - 1;
std::int32_t y_offset = current_frame.hdr.width * dest_y + dest_x;
std::int32_t u_offset = ( current_frame.hdr.width * adjusted_uv_y ) / 4 + dest_x /2;
std::int32_t v_offset = u_offset + y_plane_sz / 4;