libobs: Round up chroma sizes for odd resolutions
When playing video, OBS can overflow and crash, or render video edges incorrectly if the video resolution does not divide into 2 for trivial chroma subsampling. This is fixed by rounding chroma plane sizes up instead of down, and maintaining that through the video pipeline.
This commit is contained in:
parent
d6c77964c0
commit
8440a53da3
@ -37,34 +37,40 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
|
||||
case VIDEO_FORMAT_NONE:
|
||||
return;
|
||||
|
||||
case VIDEO_FORMAT_I420:
|
||||
case VIDEO_FORMAT_I420: {
|
||||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[0] = size;
|
||||
size += (width / 2) * (height / 2);
|
||||
const uint32_t half_width = (width + 1) / 2;
|
||||
const uint32_t half_height = (height + 1) / 2;
|
||||
const uint32_t quarter_area = half_width * half_height;
|
||||
size += quarter_area;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[1] = size;
|
||||
size += (width / 2) * (height / 2);
|
||||
size += quarter_area;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
|
||||
frame->data[2] = (uint8_t *)frame->data[0] + offsets[1];
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width / 2;
|
||||
frame->linesize[2] = width / 2;
|
||||
frame->linesize[1] = half_width;
|
||||
frame->linesize[2] = half_width;
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_NV12:
|
||||
case VIDEO_FORMAT_NV12: {
|
||||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[0] = size;
|
||||
size += (width / 2) * (height / 2) * 2;
|
||||
const uint32_t cbcr_width = (width + 1) & (UINT32_MAX - 1);
|
||||
size += cbcr_width * ((height + 1) / 2);
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width;
|
||||
frame->linesize[1] = cbcr_width;
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_Y800:
|
||||
size = width * height;
|
||||
@ -75,12 +81,15 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
|
||||
|
||||
case VIDEO_FORMAT_YVYU:
|
||||
case VIDEO_FORMAT_YUY2:
|
||||
case VIDEO_FORMAT_UYVY:
|
||||
size = width * height * 2;
|
||||
case VIDEO_FORMAT_UYVY: {
|
||||
const uint32_t double_width =
|
||||
((width + 1) & (UINT32_MAX - 1)) * 2;
|
||||
size = double_width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->linesize[0] = width * 2;
|
||||
frame->linesize[0] = double_width;
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_RGBA:
|
||||
case VIDEO_FORMAT_BGRA:
|
||||
@ -110,31 +119,37 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
|
||||
frame->linesize[0] = width * 3;
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_I422:
|
||||
case VIDEO_FORMAT_I422: {
|
||||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[0] = size;
|
||||
size += (width / 2) * height;
|
||||
const uint32_t half_width = (width + 1) / 2;
|
||||
const uint32_t half_area = half_width * height;
|
||||
size += half_area;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[1] = size;
|
||||
size += (width / 2) * height;
|
||||
size += half_area;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
frame->data[0] = bmalloc(size);
|
||||
frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
|
||||
frame->data[2] = (uint8_t *)frame->data[0] + offsets[1];
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width / 2;
|
||||
frame->linesize[2] = width / 2;
|
||||
frame->linesize[1] = half_width;
|
||||
frame->linesize[2] = half_width;
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_I40A:
|
||||
case VIDEO_FORMAT_I40A: {
|
||||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[0] = size;
|
||||
size += (width / 2) * (height / 2);
|
||||
const uint32_t half_width = (width + 1) / 2;
|
||||
const uint32_t half_height = (height + 1) / 2;
|
||||
const uint32_t quarter_area = half_width * half_height;
|
||||
size += quarter_area;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[1] = size;
|
||||
size += (width / 2) * (height / 2);
|
||||
size += quarter_area;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[2] = size;
|
||||
size += width * height;
|
||||
@ -144,19 +159,22 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
|
||||
frame->data[2] = (uint8_t *)frame->data[0] + offsets[1];
|
||||
frame->data[3] = (uint8_t *)frame->data[0] + offsets[2];
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width / 2;
|
||||
frame->linesize[2] = width / 2;
|
||||
frame->linesize[1] = half_width;
|
||||
frame->linesize[2] = half_width;
|
||||
frame->linesize[3] = width;
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_I42A:
|
||||
case VIDEO_FORMAT_I42A: {
|
||||
size = width * height;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[0] = size;
|
||||
size += (width / 2) * height;
|
||||
const uint32_t half_width = (width + 1) / 2;
|
||||
const uint32_t half_area = half_width * height;
|
||||
size += half_area;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[1] = size;
|
||||
size += (width / 2) * height;
|
||||
size += half_area;
|
||||
ALIGN_SIZE(size, alignment);
|
||||
offsets[2] = size;
|
||||
size += width * height;
|
||||
@ -166,10 +184,11 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
|
||||
frame->data[2] = (uint8_t *)frame->data[0] + offsets[1];
|
||||
frame->data[3] = (uint8_t *)frame->data[0] + offsets[2];
|
||||
frame->linesize[0] = width;
|
||||
frame->linesize[1] = width / 2;
|
||||
frame->linesize[2] = width / 2;
|
||||
frame->linesize[1] = half_width;
|
||||
frame->linesize[2] = half_width;
|
||||
frame->linesize[3] = width;
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_YUVA:
|
||||
size = width * height;
|
||||
|
@ -1554,8 +1554,11 @@ static inline enum convert_type get_convert_type(enum video_format format,
|
||||
static inline bool set_packed422_sizes(struct obs_source *source,
|
||||
const struct obs_source_frame *frame)
|
||||
{
|
||||
source->async_convert_width[0] = frame->width / 2;
|
||||
source->async_convert_height[0] = frame->height;
|
||||
const uint32_t width = frame->width;
|
||||
const uint32_t height = frame->height;
|
||||
const uint32_t half_width = (width + 1) / 2;
|
||||
source->async_convert_width[0] = half_width;
|
||||
source->async_convert_height[0] = height;
|
||||
source->async_texture_formats[0] = GS_BGRA;
|
||||
source->async_channel_count = 1;
|
||||
return true;
|
||||
@ -1611,12 +1614,16 @@ set_planar444_alpha_sizes(struct obs_source *source,
|
||||
static inline bool set_planar420_sizes(struct obs_source *source,
|
||||
const struct obs_source_frame *frame)
|
||||
{
|
||||
source->async_convert_width[0] = frame->width;
|
||||
source->async_convert_width[1] = frame->width / 2;
|
||||
source->async_convert_width[2] = frame->width / 2;
|
||||
source->async_convert_height[0] = frame->height;
|
||||
source->async_convert_height[1] = frame->height / 2;
|
||||
source->async_convert_height[2] = frame->height / 2;
|
||||
const uint32_t width = frame->width;
|
||||
const uint32_t height = frame->height;
|
||||
const uint32_t half_width = (width + 1) / 2;
|
||||
const uint32_t half_height = (height + 1) / 2;
|
||||
source->async_convert_width[0] = width;
|
||||
source->async_convert_width[1] = half_width;
|
||||
source->async_convert_width[2] = half_width;
|
||||
source->async_convert_height[0] = height;
|
||||
source->async_convert_height[1] = half_height;
|
||||
source->async_convert_height[2] = half_height;
|
||||
source->async_texture_formats[0] = GS_R8;
|
||||
source->async_texture_formats[1] = GS_R8;
|
||||
source->async_texture_formats[2] = GS_R8;
|
||||
@ -1628,14 +1635,18 @@ static inline bool
|
||||
set_planar420_alpha_sizes(struct obs_source *source,
|
||||
const struct obs_source_frame *frame)
|
||||
{
|
||||
source->async_convert_width[0] = frame->width;
|
||||
source->async_convert_width[1] = frame->width / 2;
|
||||
source->async_convert_width[2] = frame->width / 2;
|
||||
source->async_convert_width[3] = frame->width;
|
||||
source->async_convert_height[0] = frame->height;
|
||||
source->async_convert_height[1] = frame->height / 2;
|
||||
source->async_convert_height[2] = frame->height / 2;
|
||||
source->async_convert_height[3] = frame->height;
|
||||
const uint32_t width = frame->width;
|
||||
const uint32_t height = frame->height;
|
||||
const uint32_t half_width = (width + 1) / 2;
|
||||
const uint32_t half_height = (height + 1) / 2;
|
||||
source->async_convert_width[0] = width;
|
||||
source->async_convert_width[1] = half_width;
|
||||
source->async_convert_width[2] = half_width;
|
||||
source->async_convert_width[3] = width;
|
||||
source->async_convert_height[0] = height;
|
||||
source->async_convert_height[1] = half_height;
|
||||
source->async_convert_height[2] = half_height;
|
||||
source->async_convert_height[3] = height;
|
||||
source->async_texture_formats[0] = GS_R8;
|
||||
source->async_texture_formats[1] = GS_R8;
|
||||
source->async_texture_formats[2] = GS_R8;
|
||||
@ -1647,12 +1658,15 @@ set_planar420_alpha_sizes(struct obs_source *source,
|
||||
static inline bool set_planar422_sizes(struct obs_source *source,
|
||||
const struct obs_source_frame *frame)
|
||||
{
|
||||
source->async_convert_width[0] = frame->width;
|
||||
source->async_convert_width[1] = frame->width / 2;
|
||||
source->async_convert_width[2] = frame->width / 2;
|
||||
source->async_convert_height[0] = frame->height;
|
||||
source->async_convert_height[1] = frame->height;
|
||||
source->async_convert_height[2] = frame->height;
|
||||
const uint32_t width = frame->width;
|
||||
const uint32_t height = frame->height;
|
||||
const uint32_t half_width = (width + 1) / 2;
|
||||
source->async_convert_width[0] = width;
|
||||
source->async_convert_width[1] = half_width;
|
||||
source->async_convert_width[2] = half_width;
|
||||
source->async_convert_height[0] = height;
|
||||
source->async_convert_height[1] = height;
|
||||
source->async_convert_height[2] = height;
|
||||
source->async_texture_formats[0] = GS_R8;
|
||||
source->async_texture_formats[1] = GS_R8;
|
||||
source->async_texture_formats[2] = GS_R8;
|
||||
@ -1664,14 +1678,17 @@ static inline bool
|
||||
set_planar422_alpha_sizes(struct obs_source *source,
|
||||
const struct obs_source_frame *frame)
|
||||
{
|
||||
source->async_convert_width[0] = frame->width;
|
||||
source->async_convert_width[1] = frame->width / 2;
|
||||
source->async_convert_width[2] = frame->width / 2;
|
||||
source->async_convert_width[3] = frame->width;
|
||||
source->async_convert_height[0] = frame->height;
|
||||
source->async_convert_height[1] = frame->height;
|
||||
source->async_convert_height[2] = frame->height;
|
||||
source->async_convert_height[3] = frame->height;
|
||||
const uint32_t width = frame->width;
|
||||
const uint32_t height = frame->height;
|
||||
const uint32_t half_width = (width + 1) / 2;
|
||||
source->async_convert_width[0] = width;
|
||||
source->async_convert_width[1] = half_width;
|
||||
source->async_convert_width[2] = half_width;
|
||||
source->async_convert_width[3] = width;
|
||||
source->async_convert_height[0] = height;
|
||||
source->async_convert_height[1] = height;
|
||||
source->async_convert_height[2] = height;
|
||||
source->async_convert_height[3] = height;
|
||||
source->async_texture_formats[0] = GS_R8;
|
||||
source->async_texture_formats[1] = GS_R8;
|
||||
source->async_texture_formats[2] = GS_R8;
|
||||
@ -1683,10 +1700,14 @@ set_planar422_alpha_sizes(struct obs_source *source,
|
||||
static inline bool set_nv12_sizes(struct obs_source *source,
|
||||
const struct obs_source_frame *frame)
|
||||
{
|
||||
source->async_convert_width[0] = frame->width;
|
||||
source->async_convert_width[1] = frame->width / 2;
|
||||
source->async_convert_height[0] = frame->height;
|
||||
source->async_convert_height[1] = frame->height / 2;
|
||||
const uint32_t width = frame->width;
|
||||
const uint32_t height = frame->height;
|
||||
const uint32_t half_width = (width + 1) / 2;
|
||||
const uint32_t half_height = (height + 1) / 2;
|
||||
source->async_convert_width[0] = width;
|
||||
source->async_convert_width[1] = half_width;
|
||||
source->async_convert_height[0] = height;
|
||||
source->async_convert_height[1] = half_height;
|
||||
source->async_texture_formats[0] = GS_R8;
|
||||
source->async_texture_formats[1] = GS_R8G8;
|
||||
source->async_channel_count = 2;
|
||||
@ -2746,16 +2767,22 @@ static void copy_frame_data(struct obs_source_frame *dst,
|
||||
}
|
||||
|
||||
switch (src->format) {
|
||||
case VIDEO_FORMAT_I420:
|
||||
copy_frame_data_plane(dst, src, 0, dst->height);
|
||||
copy_frame_data_plane(dst, src, 1, dst->height / 2);
|
||||
copy_frame_data_plane(dst, src, 2, dst->height / 2);
|
||||
case VIDEO_FORMAT_I420: {
|
||||
const uint32_t height = dst->height;
|
||||
const uint32_t half_height = (height + 1) / 2;
|
||||
copy_frame_data_plane(dst, src, 0, height);
|
||||
copy_frame_data_plane(dst, src, 1, half_height);
|
||||
copy_frame_data_plane(dst, src, 2, half_height);
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_NV12:
|
||||
copy_frame_data_plane(dst, src, 0, dst->height);
|
||||
copy_frame_data_plane(dst, src, 1, dst->height / 2);
|
||||
case VIDEO_FORMAT_NV12: {
|
||||
const uint32_t height = dst->height;
|
||||
const uint32_t half_height = (height + 1) / 2;
|
||||
copy_frame_data_plane(dst, src, 0, height);
|
||||
copy_frame_data_plane(dst, src, 1, half_height);
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_I444:
|
||||
case VIDEO_FORMAT_I422:
|
||||
@ -2777,12 +2804,15 @@ static void copy_frame_data(struct obs_source_frame *dst,
|
||||
copy_frame_data_plane(dst, src, 0, dst->height);
|
||||
break;
|
||||
|
||||
case VIDEO_FORMAT_I40A:
|
||||
copy_frame_data_plane(dst, src, 0, dst->height);
|
||||
copy_frame_data_plane(dst, src, 1, dst->height / 2);
|
||||
copy_frame_data_plane(dst, src, 2, dst->height / 2);
|
||||
copy_frame_data_plane(dst, src, 3, dst->height);
|
||||
case VIDEO_FORMAT_I40A: {
|
||||
const uint32_t height = dst->height;
|
||||
const uint32_t half_height = (height + 1) / 2;
|
||||
copy_frame_data_plane(dst, src, 0, height);
|
||||
copy_frame_data_plane(dst, src, 1, half_height);
|
||||
copy_frame_data_plane(dst, src, 2, half_height);
|
||||
copy_frame_data_plane(dst, src, 3, height);
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDEO_FORMAT_I42A:
|
||||
case VIDEO_FORMAT_YUVA:
|
||||
|
Loading…
x
Reference in New Issue
Block a user