video_codec: planar<->packed YUV use unsigned char

This requires less conversions from/to (char *).

\+ vcap/testcard: handle unsuppoted subsampling
This commit is contained in:
Martin Pulec
2024-01-24 11:47:26 +01:00
parent 44c03391ed
commit f4dedb0ffc
4 changed files with 69 additions and 44 deletions

View File

@@ -357,16 +357,26 @@ static size_t testcard_load_from_file_y4m(const char *filename, struct video_des
desc->height = info.height;
desc->color_spec = info.bitdepth == 8 ? UYVY : Y416;
size_t data_len = vc_get_datalen(desc->width, desc->height, desc->color_spec);
*in_file_contents = (char *) malloc(data_len);
unsigned char *converted = malloc(data_len);
if (info.bitdepth == 8) {
if (info.subsampling == Y4M_SUBS_422) {
i422_8_to_uyvy(desc->width, desc->height, (char *) data, *in_file_contents);
} else {
i444_8_to_uyvy(desc->width, desc->height, (char *) data, *in_file_contents);
switch (info.subsampling) {
case Y4M_SUBS_422:
i422_8_to_uyvy(desc->width, desc->height, data,
converted);
break;
case Y4M_SUBS_444:
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(desc->width, desc->height, (char *) data, *in_file_contents, info.bitdepth);
i444_16_to_y416(desc->width, desc->height, data, converted, info.bitdepth);
}
*in_file_contents = (char *) converted;
free(data);
return data_len;
}

View File

@@ -936,43 +936,49 @@ bool codec_is_420(codec_t pix_fmt)
pixfmt_plane_info[pix_fmt].plane_info[5] == 2;
}
void uyvy_to_i422(int width, int height, const char *in, char *out)
void
uyvy_to_i422(int width, int height, const unsigned char *in, unsigned char *out)
{
char *out_y = out;
char *out_cb = out + width * height;
char *out_cr = out + width * height + ((width + 1) / 2) * height;
unsigned char *out_y = out;
unsigned char *out_cb = out + width * height;
unsigned char *out_cr =
out + width * height + ((width + 1) / 2) * height;
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width / 2; ++x) {
*out_cb++ = *in++;
*out_y++ = *in++;
*out_y++ = *in++;
*out_cr++ = *in++;
*out_y++ = *in++;
*out_y++ = *in++;
}
if (width % 2 == 1) {
*out_cb++ = *in++;
*out_y++ = *in++;
*out_y++ = *in++;
*out_cr++ = *in++;
}
}
}
void y416_to_i444(int width, int height, const char *in, char *out, int depth)
void
y416_to_i444(int width, int height, const unsigned char *in, unsigned char *out,
int depth)
{
const uint16_t *inp = (const uint16_t *)(const void *) in;
uint16_t *out_y = (uint16_t *)(void *) out;
uint16_t *out_cb = (uint16_t *)(void *) out + width * height;
uint16_t *out_cr = (uint16_t *)(void *) out + 2 * width * height;
const uint16_t *inp = (const uint16_t *) (const void *) in;
uint16_t *out_y = (uint16_t *) (void *) out;
uint16_t *out_cb = (uint16_t *) (void *) out + width * height;
uint16_t *out_cr = (uint16_t *) (void *) out + 2 * width * height;
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
*out_cb++ = *inp++ >> (16 - depth);
*out_y++ = *inp++ >> (16 - depth);
*out_y++ = *inp++ >> (16 - depth);
*out_cr++ = *inp++ >> (16 - depth);
inp++; // alpha
}
}
}
void i444_16_to_y416(int width, int height, const char *in, char *out, int in_depth)
void
i444_16_to_y416(int width, int height, const unsigned char *in,
unsigned char *out, int in_depth)
{
const uint16_t *in_y = (const uint16_t *)(const void *) in;
const uint16_t *in_cb = (const uint16_t *)(const void *) in + width * height;
@@ -988,12 +994,14 @@ void i444_16_to_y416(int width, int height, const char *in, char *out, int in_de
}
}
void i422_8_to_uyvy(int width, int height, const char *in, char *out)
void
i422_8_to_uyvy(int width, int height, const unsigned char *in,
unsigned char *out)
{
const char *in_y = in;
const char *in_cb = in + width * height;
const char *in_cr = in_cb + (((width + 1) / 2) * height);
char *outp = out;
const unsigned char *in_y = in;
const unsigned char *in_cb = in + width * height;
const unsigned char *in_cr = in_cb + (((width + 1) / 2) * height);
unsigned char *outp = out;
for (int y = 0; y < height; ++y) {
for (int x = 0; x < (width + 1) / 2; ++x) {
*outp++ = *in_cb++;
@@ -1004,12 +1012,14 @@ void i422_8_to_uyvy(int width, int height, const char *in, char *out)
}
}
void i444_8_to_uyvy(int width, int height, const char *in, char *out)
void
i444_8_to_uyvy(int width, int height, const unsigned char *in,
unsigned char *out)
{
const char *in_y = in;
const char *in_cb = in + width * height;
const char *in_cr = in_cb + width * height;
char *outp = out;
const unsigned char *in_y = in;
const unsigned char *in_cb = in + width * height;
const unsigned char *in_cr = in_cb + width * height;
unsigned char *outp = out;
for (int y = 0; y < height; ++y) {
for (int x = 0; x < (width + 1) / 2; ++x) {
*outp++ = *in_cb;

View File

@@ -106,11 +106,16 @@ bool vc_deinterlace_ex(codec_t codec, unsigned char *src, size_t src_linesize, u
bool clear_video_buffer(unsigned char *data, size_t linesize, size_t pitch, size_t height, codec_t color_spec);
// conversions from/to planar formats
void uyvy_to_i422(int width, int height, const char *in, char *out);
void y416_to_i444(int width, int height, const char *in, char *out, int depth);
void i444_16_to_y416(int width, int height, const char *in, char *out, int in_depth);
void i422_8_to_uyvy(int width, int height, const char *in, char *out);
void i444_8_to_uyvy(int width, int height, const char *in, char *out);
void uyvy_to_i422(int width, int height, const unsigned char *in,
unsigned char *out);
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_8_to_uyvy(int width, int height, const unsigned char *in,
unsigned char *out);
void i444_8_to_uyvy(int width, int height, const unsigned char *in,
unsigned char *out);
#ifdef __cplusplus
}

View File

@@ -492,32 +492,32 @@ static bool save_video_frame_as_y4m(struct video_frame *frame, const char *name)
{
struct tile *tile = &frame->tiles[0];
if (get_bits_per_component(frame->color_spec) <= 8 && (frame->color_spec == UYVY || get_decoder_from_to(frame->color_spec, UYVY))) {
char *uyvy = tile->data;
char *tmp_data_uyvy = NULL;
unsigned char *uyvy = (unsigned char *) tile->data;
unsigned char *tmp_data_uyvy = NULL;
if (frame->color_spec != UYVY) {
decoder_t dec = get_decoder_from_to(frame->color_spec, UYVY);
int len = vc_get_datalen(tile->width, tile->height, UYVY);
uyvy = tmp_data_uyvy = malloc(len);
dec ((unsigned char *) uyvy, (const unsigned char *) tile->data, len, 0, 0, 0);
dec (uyvy, (const unsigned char *) tile->data, len, 0, 0, 0);
}
char *i422 = malloc(tile->width * tile->height + 2 * ((tile->width + 1) / 2) * tile->height);
unsigned char *i422 = malloc(tile->width * tile->height + 2 * ((tile->width + 1) / 2) * tile->height);
uyvy_to_i422(tile->width, tile->height, uyvy, i422);
struct y4m_metadata info = { .width = tile->width, .height = tile->height, .bitdepth = 8, .subsampling = Y4M_SUBS_422, .limited = true };
bool ret = y4m_write(name, &info, (unsigned char *) i422);
bool ret = y4m_write(name, &info, i422);
free(tmp_data_uyvy);
free(i422);
return ret;
} else if (get_decoder_from_to(frame->color_spec, Y416)) {
char *y416 = tile->data;
char *tmp_data_y416 = NULL;
unsigned char *y416 = (unsigned char *) tile->data;
unsigned char *tmp_data_y416 = NULL;
if (frame->color_spec != Y416) {
decoder_t dec = get_decoder_from_to(frame->color_spec, Y416);
int len = vc_get_datalen(tile->width, tile->height, Y416);
y416 = tmp_data_y416 = malloc(len);
dec ((unsigned char *) y416, (const unsigned char *) tile->data, len, 0, 0, 0);
dec (y416, (const unsigned char *) tile->data, len, 0, 0, 0);
}
char *i444 = malloc(tile->width * tile->height * 6);
unsigned char *i444 = malloc(tile->width * tile->height * 6);
int depth = get_bits_per_component(frame->color_spec);
y416_to_i444(tile->width, tile->height, y416, i444, depth);