diff --git a/libobs/media-io/video-frame.c b/libobs/media-io/video-frame.c index 746d53f21..a85d562a0 100644 --- a/libobs/media-io/video-frame.c +++ b/libobs/media-io/video-frame.c @@ -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; diff --git a/libobs/obs-source.c b/libobs/obs-source.c index 93cd1aa29..2b8dc11ab 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -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: