Skip to content

Commit

Permalink
testcard y4m: support for >8 bit non-444 y4m
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinPulec committed Feb 29, 2024
1 parent 2516767 commit 4b4a949
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 22 deletions.
52 changes: 30 additions & 22 deletions src/video_capture/testcard.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*/
/*
* Copyright (c) 2005-2006 University of Glasgow
* Copyright (c) 2005-2023 CESNET z.s.p.o.
* Copyright (c) 2005-2024 CESNET z.s.p.o.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
Expand Down Expand Up @@ -349,42 +349,50 @@ static size_t testcard_load_from_file_y4m(const char *filename, struct video_des
return 0;
}
if (info.bitdepth < DEPTH8 ||
((info.subsampling < Y4M_SUBS_420 ||
info.subsampling > Y4M_SUBS_444) &&
info.bitdepth == DEPTH8) ||
(info.bitdepth > DEPTH8 && info.subsampling != Y4M_SUBS_444)) {
MSG(ERROR, "Only 3-channel 8-bit Y4M or >8 bit 4:4:4 "
"subsampled are supported.\n");
(info.subsampling < Y4M_SUBS_420 ||
info.subsampling > Y4M_SUBS_444)) {
MSG(ERROR, "Only 3-channel 8+ bit Y4M is supported.\n");
log_msg(LOG_LEVEL_INFO, MOD_NAME "Provided Y4M picture has subsampling %d and bit depth %d bits.\n", info.subsampling, info.bitdepth);
return 0;
}
desc->width = info.width;
desc->height = info.height;
desc->color_spec = info.bitdepth == 8 ? UYVY : Y416;
desc->color_spec = info.bitdepth == DEPTH8 ? UYVY : Y416;
size_t data_len = vc_get_datalen(desc->width, desc->height, desc->color_spec);
unsigned char *converted = malloc(data_len);

if (info.bitdepth == 8) {
switch (info.subsampling) {
case Y4M_SUBS_420:
switch (info.subsampling) {
case Y4M_SUBS_420:
if (info.bitdepth == DEPTH8) {
i420_8_to_uyvy(desc->width, desc->height, data,
converted);
break;
case Y4M_SUBS_422:
} else {
i420_16_to_y416((int) desc->width, (int) desc->height,
data, converted, info.bitdepth);
}
break;
case Y4M_SUBS_422:
if (info.bitdepth == DEPTH8) {
i422_8_to_uyvy(desc->width, desc->height, data,
converted);
break;
case Y4M_SUBS_444:
} else {
i422_16_to_y416((int) desc->width, (int) desc->height,
data, converted, info.bitdepth);
}
break;
case Y4M_SUBS_444:
if (info.bitdepth == DEPTH8) {
i444_8_to_uyvy(desc->width, desc->height, data,
converted);
break;
default:
MSG(ERROR, "Wrong Y4M subsampling: %d", info.subsampling);
free(converted);
return 0;
} else {
i444_16_to_y416((int) desc->width, (int) desc->height,
data, converted, info.bitdepth);
}
} else {
i444_16_to_y416(desc->width, desc->height, data, converted, info.bitdepth);
break;
default:
MSG(ERROR, "Wrong Y4M subsampling: %d", info.subsampling);
free(converted);
return 0;
}
*in_file_contents = (char *) converted;
free(data);
Expand Down
65 changes: 65 additions & 0 deletions src/video_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,71 @@ i444_16_to_y416(int width, int height, const unsigned char *in,
}
}

void
i422_16_to_y416(int width, int height, const unsigned char *in,
unsigned char *out, int in_depth)
{
enum { ALPHA16_OPAQUE = 0xFFFF };
const uint16_t *in_y = (const uint16_t *) (const void *) in;
const uint16_t *in_cb = in_y + (ptrdiff_t) width * height;
const uint16_t *in_cr = in_cb + (ptrdiff_t) ((width + 1) / 2) * height;
uint16_t *outp = (void *) out;
for (int y = 0; y < height; ++y) {
for (int x = 0; x < (width + 1) / 2; ++x) {
*outp++ = *in_cb << (DEPTH16 - in_depth);
*outp++ = *in_y++ << (DEPTH16 - in_depth);
*outp++ = *in_cr << (DEPTH16 - in_depth);
*outp++ = ALPHA16_OPAQUE;
*outp++ = *in_cb++ << (DEPTH16 - in_depth);
*outp++ = *in_y++ << (DEPTH16 - in_depth);
*outp++ = *in_cr++ << (DEPTH16 - in_depth);
*outp++ = ALPHA16_OPAQUE;
}
}
}

void
i420_16_to_y416(int width, int height, const unsigned char *in,
unsigned char *out, int in_depth)
{
enum { ALPHA16_OPAQUE = 0xFFFF };
const uint16_t *in_y1 = (const void *) in;
const uint16_t *in_y2 = in_y1 + width;
const uint16_t *in_cb =
(const uint16_t *) (const void *) in + (ptrdiff_t) width * height;
const uint16_t *in_cr =
in_cb + (ptrdiff_t) ((width + 1) / 2) * ((height + 1) / 2);
const size_t out_line_len = vc_get_linesize(width, Y416) / 2;
uint16_t *outp1 = (void *) out;
uint16_t *outp2 = outp1 + out_line_len;
for (int y = 0; y < (height + 1) / 2; ++y) {
for (int x = 0; x < (width + 1) / 2; ++x) {
*outp1++ = *in_cb << (DEPTH16 - in_depth);
*outp1++ = *in_y1++ << (DEPTH16 - in_depth);
*outp1++ = *in_cr << (DEPTH16 - in_depth);
*outp1++ = ALPHA16_OPAQUE;

*outp2++ = *in_cb << (DEPTH16 - in_depth);
*outp2++ = *in_y2++ << (DEPTH16 - in_depth);
*outp2++ = *in_cr << (DEPTH16 - in_depth);
*outp2++ = ALPHA16_OPAQUE;

*outp1++ = *in_cb << (DEPTH16 - in_depth);
*outp1++ = *in_y1++ << (DEPTH16 - in_depth);
*outp1++ = *in_cr << (DEPTH16 - in_depth);
*outp1++ = ALPHA16_OPAQUE;

*outp2++ = *in_cb++ << (DEPTH16 - in_depth);
*outp2++ = *in_y2++ << (DEPTH16 - in_depth);
*outp2++ = *in_cr++ << (DEPTH16 - in_depth);
*outp2++ = ALPHA16_OPAQUE;
}
outp1 += out_line_len;
outp2 += out_line_len;
in_y1 += width;
in_y2 += width;
}
}
void
i420_8_to_uyvy(int width, int height, const unsigned char *in, unsigned char *out)
{
Expand Down
4 changes: 4 additions & 0 deletions src/video_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ void y416_to_i444(int width, int height, const unsigned char *in,
unsigned char *out, int depth);
void i444_16_to_y416(int width, int height, const unsigned char *in,
unsigned char *out, int in_depth);
void i422_16_to_y416(int width, int height, const unsigned char *in,
unsigned char *out, int in_depth);
void i420_16_to_y416(int width, int height, const unsigned char *in,
unsigned char *out, int in_depth);
void i420_8_to_uyvy(int width, int height, const unsigned char *in,
unsigned char *out);
void i422_8_to_uyvy(int width, int height, const unsigned char *in,
Expand Down

0 comments on commit 4b4a949

Please sign in to comment.