From 614025742b1ac28b25dd73a240770275dd5587ea Mon Sep 17 00:00:00 2001 From: James Park Date: Thu, 30 May 2019 06:05:53 -0700 Subject: [PATCH] libobs: linux-v412: obs-ffmpeg: Add packed BGR3 video support Someone mentioned this format preserves the most quality for a particular capture card using V4L2. --- libobs/data/format_conversion.effect | 43 +++++++++++++++++++++++++ libobs/media-io/video-frame.c | 8 +++++ libobs/media-io/video-io.h | 5 +++ libobs/media-io/video-scaler-ffmpeg.c | 1 + libobs/obs-source.c | 21 ++++++++++++ plugins/linux-v4l2/v4l2-helpers.h | 1 + plugins/obs-ffmpeg/obs-ffmpeg-formats.h | 2 ++ 7 files changed, 81 insertions(+) diff --git a/libobs/data/format_conversion.effect b/libobs/data/format_conversion.effect index b3d274e40..5cdda7a28 100644 --- a/libobs/data/format_conversion.effect +++ b/libobs/data/format_conversion.effect @@ -378,6 +378,31 @@ float4 PSRGB_Limited(VertInOut vert_in) : TARGET return rgba; } +float4 PSBGR3_Limited(VertInOut vert_in) : TARGET +{ + int x = int(vert_in.uv.x * width * 3.0 + PRECISION_OFFSET); + int y = int(vert_in.uv.y * height + PRECISION_OFFSET); + + float b = image.Load(int3(x - 1, y, 0)).x; + float g = image.Load(int3(x, y, 0)).x; + float r = image.Load(int3(x + 1, y, 0)).x; + float3 rgb = float3(r, g, b); + rgb = saturate((rgb - (16.0 / 255.0)) * (255.0 / 219.0)); + return float4(rgb, 1.0); +} + +float4 PSBGR3_Full(VertInOut vert_in) : TARGET +{ + int x = int(vert_in.uv.x * width * 3.0 + PRECISION_OFFSET); + int y = int(vert_in.uv.y * height + PRECISION_OFFSET); + + float b = image.Load(int3(x - 1, y, 0)).x; + float g = image.Load(int3(x, y, 0)).x; + float r = image.Load(int3(x + 1, y, 0)).x; + float3 rgb = float3(r, g, b); + return float4(rgb, 1.0); +} + technique Planar420 { pass @@ -503,3 +528,21 @@ technique RGB_Limited pixel_shader = PSRGB_Limited(vert_in); } } + +technique BGR3_Limited +{ + pass + { + vertex_shader = VSDefault(vert_in); + pixel_shader = PSBGR3_Limited(vert_in); + } +} + +technique BGR3_Full +{ + pass + { + vertex_shader = VSDefault(vert_in); + pixel_shader = PSBGR3_Full(vert_in); + } +} diff --git a/libobs/media-io/video-frame.c b/libobs/media-io/video-frame.c index f29a6f11a..b4d586e41 100644 --- a/libobs/media-io/video-frame.c +++ b/libobs/media-io/video-frame.c @@ -101,6 +101,13 @@ void video_frame_init(struct video_frame *frame, enum video_format format, frame->linesize[1] = width; frame->linesize[2] = width; break; + + case VIDEO_FORMAT_BGR3: + size = width * height * 3; + ALIGN_SIZE(size, alignment); + frame->data[0] = bmalloc(size); + frame->linesize[0] = width*3; + break; } } @@ -129,6 +136,7 @@ void video_frame_copy(struct video_frame *dst, const struct video_frame *src, case VIDEO_FORMAT_RGBA: case VIDEO_FORMAT_BGRA: case VIDEO_FORMAT_BGRX: + case VIDEO_FORMAT_BGR3: memcpy(dst->data[0], src->data[0], src->linesize[0] * cy); break; diff --git a/libobs/media-io/video-io.h b/libobs/media-io/video-io.h index 77acf8f7a..7c322688a 100644 --- a/libobs/media-io/video-io.h +++ b/libobs/media-io/video-io.h @@ -50,6 +50,9 @@ enum video_format { /* planar 4:4:4 */ VIDEO_FORMAT_I444, + + /* more packed uncompressed formats */ + VIDEO_FORMAT_BGR3, }; enum video_colorspace { @@ -99,6 +102,7 @@ static inline bool format_is_yuv(enum video_format format) case VIDEO_FORMAT_BGRA: case VIDEO_FORMAT_BGRX: case VIDEO_FORMAT_Y800: + case VIDEO_FORMAT_BGR3: return false; } @@ -118,6 +122,7 @@ static inline const char *get_video_format_name(enum video_format format) case VIDEO_FORMAT_BGRX: return "BGRX"; case VIDEO_FORMAT_I444: return "I444"; case VIDEO_FORMAT_Y800: return "Y800"; + case VIDEO_FORMAT_BGR3: return "BGR3"; case VIDEO_FORMAT_NONE:; } diff --git a/libobs/media-io/video-scaler-ffmpeg.c b/libobs/media-io/video-scaler-ffmpeg.c index e46aa4e9b..9cd5daa04 100644 --- a/libobs/media-io/video-scaler-ffmpeg.c +++ b/libobs/media-io/video-scaler-ffmpeg.c @@ -40,6 +40,7 @@ static inline enum AVPixelFormat get_ffmpeg_video_format( case VIDEO_FORMAT_BGRX: return AV_PIX_FMT_BGRA; case VIDEO_FORMAT_Y800: return AV_PIX_FMT_GRAY8; case VIDEO_FORMAT_I444: return AV_PIX_FMT_YUV444P; + case VIDEO_FORMAT_BGR3: return AV_PIX_FMT_BGR24; } return AV_PIX_FMT_NONE; diff --git a/libobs/obs-source.c b/libobs/obs-source.c index aa3f26b33..da4181b58 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -1332,6 +1332,7 @@ enum convert_type { CONVERT_444, CONVERT_800, CONVERT_RGB_LIMITED, + CONVERT_BGR3, }; static inline enum convert_type get_convert_type(enum video_format format, @@ -1359,6 +1360,9 @@ static inline enum convert_type get_convert_type(enum video_format format, case VIDEO_FORMAT_BGRA: case VIDEO_FORMAT_BGRX: return full_range ? CONVERT_NONE : CONVERT_RGB_LIMITED; + + case VIDEO_FORMAT_BGR3: + return CONVERT_BGR3; } return CONVERT_NONE; @@ -1429,6 +1433,15 @@ static inline bool set_rgb_limited_sizes(struct obs_source *source, return true; } +static inline bool set_bgr3_sizes(struct obs_source *source, + const struct obs_source_frame *frame) +{ + source->async_convert_width = frame->width * 3; + source->async_convert_height = frame->height; + source->async_texture_format = GS_R8; + return true; +} + static inline bool init_gpu_conversion(struct obs_source *source, const struct obs_source_frame *frame) { @@ -1452,6 +1465,9 @@ static inline bool init_gpu_conversion(struct obs_source *source, case CONVERT_RGB_LIMITED: return set_rgb_limited_sizes(source, frame); + case CONVERT_BGR3: + return set_bgr3_sizes(source, frame); + case CONVERT_NONE: assert(false && "No conversion requested"); break; @@ -1528,6 +1544,7 @@ static void upload_raw_frame(gs_texture_t *tex, case CONVERT_422_Y: case CONVERT_800: case CONVERT_RGB_LIMITED: + case CONVERT_BGR3: gs_texture_set_image(tex, frame->data[0], frame->linesize[0], false); break; @@ -1570,6 +1587,9 @@ static const char *select_conversion_technique(enum video_format format, case VIDEO_FORMAT_Y800: return full_range ? "Y800_Full" : "Y800_Limited"; + case VIDEO_FORMAT_BGR3: + return full_range ? "BGR3_Full" : "BGR3_Limited"; + case VIDEO_FORMAT_BGRA: case VIDEO_FORMAT_BGRX: case VIDEO_FORMAT_RGBA: @@ -2300,6 +2320,7 @@ static void copy_frame_data(struct obs_source_frame *dst, case VIDEO_FORMAT_BGRA: case VIDEO_FORMAT_BGRX: case VIDEO_FORMAT_Y800: + case VIDEO_FORMAT_BGR3: copy_frame_data_plane(dst, src, 0, dst->height); break; } diff --git a/plugins/linux-v4l2/v4l2-helpers.h b/plugins/linux-v4l2/v4l2-helpers.h index e25d0bbbd..993326e76 100644 --- a/plugins/linux-v4l2/v4l2-helpers.h +++ b/plugins/linux-v4l2/v4l2-helpers.h @@ -69,6 +69,7 @@ static inline enum video_format v4l2_to_obs_video_format(uint_fast32_t format) #ifdef V4L2_PIX_FMT_ABGR32 case V4L2_PIX_FMT_ABGR32: return VIDEO_FORMAT_BGRA; #endif + case V4L2_PIX_FMT_BGR24: return VIDEO_FORMAT_BGR3; default: return VIDEO_FORMAT_NONE; } } diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-formats.h b/plugins/obs-ffmpeg/obs-ffmpeg-formats.h index 260f7514c..8fe2849a6 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-formats.h +++ b/plugins/obs-ffmpeg/obs-ffmpeg-formats.h @@ -22,6 +22,7 @@ static inline enum AVPixelFormat obs_to_ffmpeg_video_format( case VIDEO_FORMAT_BGRA: return AV_PIX_FMT_BGRA; case VIDEO_FORMAT_BGRX: return AV_PIX_FMT_BGRA; case VIDEO_FORMAT_Y800: return AV_PIX_FMT_GRAY8; + case VIDEO_FORMAT_BGR3: return AV_PIX_FMT_BGR24; } return AV_PIX_FMT_NONE; @@ -39,6 +40,7 @@ static inline enum video_format ffmpeg_to_obs_video_format( case AV_PIX_FMT_RGBA: return VIDEO_FORMAT_RGBA; case AV_PIX_FMT_BGRA: return VIDEO_FORMAT_BGRA; case AV_PIX_FMT_GRAY8: return VIDEO_FORMAT_Y800; + case AV_PIX_FMT_BGR24: return VIDEO_FORMAT_BGR3; case AV_PIX_FMT_NONE: default: return VIDEO_FORMAT_NONE; }