win-dshow: Add support for YUY2 in virtualcam

master
jp9000 2020-11-03 00:24:53 -08:00
parent 8b30204946
commit 18a73c9a45
4 changed files with 100 additions and 13 deletions

@ -1 +1 @@
Subproject commit 1d9685530922617778ae99f7d45ca427f67d7370
Subproject commit 46c9b12f27f70d19c3eac45069ae0e4b37846676

View File

@ -6,10 +6,10 @@
* it's nearest neighbor so not really a huge deal. at the very least it
* should be sse2 at some point. */
void nv12_scale_init(nv12_scale_t *s, bool convert_to_i420, int dst_cx,
void nv12_scale_init(nv12_scale_t *s, enum target_format format, int dst_cx,
int dst_cy, int src_cx, int src_cy)
{
s->convert_to_i420 = convert_to_i420;
s->format = format;
s->src_cx = src_cx;
s->src_cy = src_cy;
@ -118,16 +118,89 @@ static void nv12_convert_to_i420(nv12_scale_t *s, uint8_t *dst_start,
}
}
static void nv12_scale_nearest_to_yuy2(nv12_scale_t *s, uint8_t *dst_start,
const uint8_t *src)
{
register uint8_t *dst = dst_start;
const int src_cx = s->src_cx;
const int src_cy = s->src_cy;
const int dst_cx = s->dst_cx;
const int dst_cy = s->dst_cy;
const int src_cx_d2 = src_cx / 2;
const int src_cy_d2 = src_cy / 2;
const int dst_cx_d2 = dst_cx / 2;
const int dst_cy_d2 = dst_cy / 2;
const int size = src_cx * src_cy;
const uint8_t *src_uv = src + size;
register int uv_flip = 0;
for (int y = 0; y < dst_cy; y++) {
const int src_line = y * src_cy / dst_cy * s->src_cx;
const int src_line_d2 =
y / 2 * src_cy_d2 / dst_cy_d2 * s->src_cx;
for (int x = 0; x < dst_cx; x++) {
const int src_x = x * src_cx / dst_cx;
const int src_x_d2 = x / 2 * src_cx_d2 / dst_cx_d2;
const int pos = src_line + src_x;
const int pos_uv = src_line_d2 + src_x_d2 * 2 + uv_flip;
*(dst++) = src[pos];
*(dst++) = src_uv[pos_uv];
uv_flip ^= 1;
}
}
}
static void nv12_convert_to_yuy2(nv12_scale_t *s, uint8_t *dst_start,
const uint8_t *src_start)
{
const int size = s->src_cx * s->src_cy;
const int size_dst_line = s->src_cx * 4;
register const uint8_t *src_y = src_start;
register const uint8_t *src_uv = src_y + size;
register uint8_t *dst = dst_start;
register uint8_t *dst_end = dst + size * 2;
while (dst < dst_end) {
register uint8_t *dst_line_end = dst + size_dst_line;
const uint8_t *src_uv_start = src_uv;
while (dst < dst_line_end) {
*(dst++) = *(src_y++);
*(dst++) = *(src_uv++);
*(dst++) = *(src_y++);
*(dst++) = *(src_uv++);
}
dst_line_end = dst + size_dst_line;
src_uv = src_uv_start;
while (dst < dst_line_end) {
*(dst++) = *(src_y++);
*(dst++) = *(src_uv++);
*(dst++) = *(src_y++);
*(dst++) = *(src_uv++);
}
}
}
void nv12_do_scale(nv12_scale_t *s, uint8_t *dst, const uint8_t *src)
{
if (s->src_cx == s->dst_cx && s->src_cy == s->dst_cy) {
if (s->convert_to_i420)
if (s->format == TARGET_FORMAT_I420)
nv12_convert_to_i420(s, dst, src);
else if (s->format == TARGET_FORMAT_YUY2)
nv12_convert_to_yuy2(s, dst, src);
else
memcpy(dst, src, s->src_cx * s->src_cy * 3 / 2);
} else {
if (s->convert_to_i420)
if (s->format == TARGET_FORMAT_I420)
nv12_scale_nearest_to_i420(s, dst, src);
else if (s->format == TARGET_FORMAT_YUY2)
nv12_scale_nearest_to_yuy2(s, dst, src);
else
nv12_scale_nearest(s, dst, src);
}

View File

@ -7,8 +7,14 @@
extern "C" {
#endif
enum target_format {
TARGET_FORMAT_NV12,
TARGET_FORMAT_I420,
TARGET_FORMAT_YUY2,
};
struct nv12_scale {
bool convert_to_i420;
enum target_format format;
int src_cx;
int src_cy;
@ -19,8 +25,8 @@ struct nv12_scale {
typedef struct nv12_scale nv12_scale_t;
extern void nv12_scale_init(nv12_scale_t *s, bool convert_to_i420, int dst_cx,
int dst_cy, int src_cx, int src_cy);
extern void nv12_scale_init(nv12_scale_t *s, enum target_format format,
int dst_cx, int dst_cy, int src_cx, int src_cy);
extern void nv12_do_scale(nv12_scale_t *s, uint8_t *dst, const uint8_t *src);
#ifdef __cplusplus

View File

@ -20,6 +20,8 @@ VCamFilter::VCamFilter()
AddVideoFormat(VideoFormat::I420, DEFAULT_CX, DEFAULT_CY,
DEFAULT_INTERVAL);
AddVideoFormat(VideoFormat::YUY2, DEFAULT_CX, DEFAULT_CY,
DEFAULT_INTERVAL);
/* ---------------------------------------- */
/* load placeholder image */
@ -90,13 +92,14 @@ VCamFilter::VCamFilter()
if (new_cx != cx || new_cy != cy || new_interval != interval) {
AddVideoFormat(VideoFormat::NV12, new_cx, new_cy, new_interval);
AddVideoFormat(VideoFormat::I420, new_cx, new_cy, new_interval);
AddVideoFormat(VideoFormat::YUY2, new_cx, new_cy, new_interval);
SetVideoFormat(VideoFormat::NV12, new_cx, new_cy, new_interval);
cx = new_cx;
cy = new_cy;
interval = new_interval;
}
nv12_scale_init(&scaler, false, cx, cy, cx, cy);
nv12_scale_init(&scaler, TARGET_FORMAT_NV12, cx, cy, cx, cy);
/* ---------------------------------------- */
@ -157,7 +160,7 @@ void VCamFilter::Thread()
cy = GetCY();
interval = GetInterval();
nv12_scale_init(&scaler, false, GetCX(), GetCY(), cx, cy);
nv12_scale_init(&scaler, TARGET_FORMAT_NV12, GetCX(), GetCY(), cx, cy);
while (!stopped()) {
Frame(filter_time);
@ -201,15 +204,20 @@ void VCamFilter::Frame(uint64_t ts)
new_interval);
}
nv12_scale_init(&scaler, false, GetCX(), GetCY(), new_cx,
new_cy);
nv12_scale_init(&scaler, TARGET_FORMAT_NV12, GetCX(), GetCY(),
new_cx, new_cy);
cx = new_cx;
cy = new_cy;
interval = new_interval;
}
scaler.convert_to_i420 = GetVideoFormat() == VideoFormat::I420;
if (GetVideoFormat() == VideoFormat::I420)
scaler.format = TARGET_FORMAT_I420;
else if (GetVideoFormat() == VideoFormat::YUY2)
scaler.format = TARGET_FORMAT_YUY2;
else
scaler.format = TARGET_FORMAT_NV12;
uint8_t *ptr;
if (LockSampleData(&ptr)) {