Merge pull request #1930 from jpark37/ffmpeg-mjpeg

Add planar 4:2:2 video support; Use FFmpeg MJPEG decoder instead of DirectShow
This commit is contained in:
Jim 2019-07-25 23:22:18 -07:00 committed by GitHub
commit 916d89a73b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 89 additions and 17 deletions

View File

@ -363,6 +363,25 @@ float4 PSPlanar420_Reverse(FragTex frag_in) : TARGET
return saturate(mul(float4(yuv, 1.0), color_matrix));
}
float4 PSPlanar422_Reverse(FragTex frag_in) : TARGET
{
int x = int(frag_in.uv.x * width + PRECISION_OFFSET);
int y = int(frag_in.uv.y * height + PRECISION_OFFSET);
int lum_offset = y * int_width + x;
int chroma_offset = y * (int_width / 2) + x / 2;
int chroma1 = int_u_plane_offset + chroma_offset;
int chroma2 = int_v_plane_offset + chroma_offset;
float3 yuv = float3(
GetIntOffsetColor(lum_offset),
GetIntOffsetColor(chroma1),
GetIntOffsetColor(chroma2)
);
yuv = clamp(yuv, color_range_min, color_range_max);
return saturate(mul(float4(yuv, 1.0), color_matrix));
}
float4 PSPlanar444_Reverse(FragTex frag_in) : TARGET
{
int x = int(frag_in.uv.x * width + PRECISION_OFFSET);
@ -535,6 +554,15 @@ technique I420_Reverse
}
}
technique I422_Reverse
{
pass
{
vertex_shader = VSPosTex(id);
pixel_shader = PSPlanar422_Reverse(frag_in);
}
}
technique I444_Reverse
{
pass

View File

@ -108,6 +108,23 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
frame->data[0] = bmalloc(size);
frame->linesize[0] = width * 3;
break;
case VIDEO_FORMAT_I422:
size = width * height;
ALIGN_SIZE(size, alignment);
offsets[0] = size;
size += (width / 2) * height;
ALIGN_SIZE(size, alignment);
offsets[1] = size;
size += (width / 2) * height;
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;
break;
}
}
@ -141,6 +158,7 @@ void video_frame_copy(struct video_frame *dst, const struct video_frame *src,
break;
case VIDEO_FORMAT_I444:
case VIDEO_FORMAT_I422:
memcpy(dst->data[0], src->data[0], src->linesize[0] * cy);
memcpy(dst->data[1], src->data[1], src->linesize[1] * cy);
memcpy(dst->data[2], src->data[2], src->linesize[2] * cy);

View File

@ -53,6 +53,9 @@ enum video_format {
/* more packed uncompressed formats */
VIDEO_FORMAT_BGR3,
/* planar 4:2:2 */
VIDEO_FORMAT_I422,
};
enum video_colorspace {

View File

@ -53,6 +53,8 @@ get_ffmpeg_video_format(enum video_format format)
return AV_PIX_FMT_YUV444P;
case VIDEO_FORMAT_BGR3:
return AV_PIX_FMT_BGR24;
case VIDEO_FORMAT_I422:
return AV_PIX_FMT_YUV422P;
}
return AV_PIX_FMT_NONE;

View File

@ -1334,6 +1334,7 @@ enum convert_type {
CONVERT_NONE,
CONVERT_NV12,
CONVERT_420,
CONVERT_422,
CONVERT_422_U,
CONVERT_422_Y,
CONVERT_444,
@ -1352,6 +1353,8 @@ static inline enum convert_type get_convert_type(enum video_format format,
return CONVERT_NV12;
case VIDEO_FORMAT_I444:
return CONVERT_444;
case VIDEO_FORMAT_I422:
return CONVERT_422;
case VIDEO_FORMAT_YVYU:
case VIDEO_FORMAT_YUY2:
@ -1409,6 +1412,20 @@ static inline bool set_planar420_sizes(struct obs_source *source,
return true;
}
static inline bool set_planar422_sizes(struct obs_source *source,
const struct obs_source_frame *frame)
{
uint32_t size = frame->width * frame->height;
size *= 2;
source->async_convert_width = frame->width;
source->async_convert_height = size / frame->width;
source->async_texture_format = GS_R8;
source->async_plane_offset[0] = (int)(frame->data[1] - frame->data[0]);
source->async_plane_offset[1] = (int)(frame->data[2] - frame->data[0]);
return true;
}
static inline bool set_nv12_sizes(struct obs_source *source,
const struct obs_source_frame *frame)
{
@ -1460,6 +1477,9 @@ static inline bool init_gpu_conversion(struct obs_source *source,
case CONVERT_420:
return set_planar420_sizes(source, frame);
case CONVERT_422:
return set_planar422_sizes(source, frame);
case CONVERT_NV12:
return set_nv12_sizes(source, frame);
@ -1557,6 +1577,7 @@ static void upload_raw_frame(gs_texture_t *tex,
break;
case CONVERT_420:
case CONVERT_422:
case CONVERT_NV12:
case CONVERT_444:
gs_texture_set_image(tex, frame->data[0], frame->width, false);
@ -1596,6 +1617,9 @@ static const char *select_conversion_technique(enum video_format format,
case VIDEO_FORMAT_BGR3:
return full_range ? "BGR3_Full" : "BGR3_Limited";
case VIDEO_FORMAT_I422:
return "I422_Reverse";
case VIDEO_FORMAT_BGRA:
case VIDEO_FORMAT_BGRX:
case VIDEO_FORMAT_RGBA:
@ -2316,6 +2340,7 @@ static void copy_frame_data(struct obs_source_frame *dst,
break;
case VIDEO_FORMAT_I444:
case VIDEO_FORMAT_I422:
copy_frame_data_plane(dst, src, 0, dst->height);
copy_frame_data_plane(dst, src, 1, dst->height);
copy_frame_data_plane(dst, src, 2, dst->height);

View File

@ -35,6 +35,8 @@ obs_to_ffmpeg_video_format(enum video_format format)
return AV_PIX_FMT_GRAY8;
case VIDEO_FORMAT_BGR3:
return AV_PIX_FMT_BGR24;
case VIDEO_FORMAT_I422:
return AV_PIX_FMT_YUV422P;
}
return AV_PIX_FMT_NONE;
@ -62,6 +64,8 @@ ffmpeg_to_obs_video_format(enum AVPixelFormat format)
return VIDEO_FORMAT_Y800;
case AV_PIX_FMT_BGR24:
return VIDEO_FORMAT_BGR3;
case AV_PIX_FMT_YUV422P:
return VIDEO_FORMAT_I422;
case AV_PIX_FMT_NONE:
default:
return VIDEO_FORMAT_NONE;

View File

@ -74,6 +74,9 @@ static inline enum video_format convert_pixel_format(int f)
return VIDEO_FORMAT_YUY2;
case AV_PIX_FMT_UYVY422:
return VIDEO_FORMAT_UYVY;
case AV_PIX_FMT_YUV422P:
case AV_PIX_FMT_YUVJ422P:
return VIDEO_FORMAT_I422;
case AV_PIX_FMT_RGBA:
return VIDEO_FORMAT_RGBA;
case AV_PIX_FMT_BGRA:

View File

@ -418,8 +418,6 @@ static inline video_format ConvertVideoFormat(VideoFormat format)
return VIDEO_FORMAT_UYVY;
case VideoFormat::HDYC:
return VIDEO_FORMAT_UYVY;
case VideoFormat::MJPEG:
return VIDEO_FORMAT_YUY2;
default:
return VIDEO_FORMAT_NONE;
}
@ -502,6 +500,11 @@ void DShowInput::OnVideoData(const VideoConfig &config, unsigned char *data,
return;
}
if (videoConfig.format == VideoFormat::MJPEG) {
OnEncodedVideoData(AV_CODEC_ID_MJPEG, data, size, startTime);
return;
}
const int cx = config.cx;
const int cy = config.cy;
@ -905,8 +908,7 @@ bool DShowInput::UpdateVideoConfig(obs_data_t *settings)
placeholders::_3, placeholders::_4,
placeholders::_5);
if (videoConfig.internalFormat != VideoFormat::MJPEG)
videoConfig.format = videoConfig.internalFormat;
videoConfig.format = videoConfig.internalFormat;
if (!device.SetVideoConfig(&videoConfig)) {
blog(LOG_WARNING, "%s: device.SetVideoConfig failed",
@ -914,19 +916,6 @@ bool DShowInput::UpdateVideoConfig(obs_data_t *settings)
return false;
}
if (videoConfig.internalFormat == VideoFormat::MJPEG) {
videoConfig.format = VideoFormat::XRGB;
videoConfig.useDefaultConfig = false;
if (!device.SetVideoConfig(&videoConfig)) {
blog(LOG_WARNING,
"%s: device.SetVideoConfig (XRGB) "
"failed",
obs_source_get_name(source));
return false;
}
}
DStr formatName = GetVideoFormatName(videoConfig.internalFormat);
double fps = 0.0;