diff --git a/src/utils/video_pattern_generator.cpp b/src/utils/video_pattern_generator.cpp index 6b54f6b52..fb94f6d7a 100644 --- a/src/utils/video_pattern_generator.cpp +++ b/src/utils/video_pattern_generator.cpp @@ -484,11 +484,48 @@ struct still_image_video_pattern_generator : public video_pattern_generator { } }; +struct gray_video_pattern_generator : public video_pattern_generator { + gray_video_pattern_generator(int w, int h, codec_t c) + : width(w), height(h), color_spec(c) + { + } + char *get_next() override { + int pixels = get_pf_block_pixels(color_spec); + unsigned char rgba[pixels * 4]; + for (int i = 0; i < pixels * 4; ++i) { + rgba[i] = (i + 1) % 4 != 0 ? col : 0xFFU; // handle alpha + } + int dst_bs = get_pf_block_bytes(color_spec); + unsigned char dst[dst_bs]; + testcard_convert_buffer(RGBA, color_spec, dst, rgba, pixels, 1); + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width / pixels; x += 1) { + memcpy(data.data() + y * vc_get_linesize(width, color_spec) + x * dst_bs, dst, dst_bs); + } + } + + if ((col += step) > 0xFF) { // update color + col = 0; + } + + return (char *) data.data(); + } +private: + constexpr static int step = 16; + int width; + int height; + codec_t color_spec; + int col = 0; + long data_len = vc_get_datalen(width, height, color_spec); + vector data = vector(data_len); +}; + video_pattern_generator_t video_pattern_generator_create(std::string const & config, int width, int height, codec_t color_spec, int offset) { if (config == "help") { - cout << "Pattern to use, one of: " << BOLD("bars, blank, ebu_bars, gradient[=0x], gradient2, noise, raw=0xXX[YYZZ..], smpte_bars, 0x\n"); + cout << "Pattern to use, one of: " << BOLD("bars, blank, ebu_bars, gradient[=0x], gradient2, gray, noise, raw=0xXX[YYZZ..], smpte_bars, 0x\n"); cout << "\t\t- patterns 'gradient2' and 'noise' generate full bit-depth patterns with"; for (codec_t c = VIDEO_CODEC_FIRST; c != VIDEO_CODEC_COUNT; c = static_cast(static_cast(c) + 1)) { if (get_decoder_from_to(RG48, c) != NULL) { @@ -502,6 +539,9 @@ video_pattern_generator_create(std::string const & config, int width, int height } assert(width > 0 && height > 0); try { + if (config == "gray") { + return new gray_video_pattern_generator{width, height, color_spec}; + } return new still_image_video_pattern_generator{config, width, height, color_spec, offset}; } catch (...) { return nullptr; diff --git a/src/video_capture/testcard_common.c b/src/video_capture/testcard_common.c index d5bbab186..ed1970e2c 100644 --- a/src/video_capture/testcard_common.c +++ b/src/video_capture/testcard_common.c @@ -116,10 +116,10 @@ void testcard_convert_buffer(codec_t in_c, codec_t out_c, unsigned char *out, un if (out_c == I420 || out_c == YUYV || (in_c == RGBA && out_c == v210)) { decoder_t decoder = get_decoder_from_to(in_c, UYVY); tmp_buffer = malloc(2L * ((width + 1U) ^ 1U) * height); - long in_linesize = vc_get_linesize(width, in_c); - long out_linesize = vc_get_linesize(width, UYVY); + long in_linesize = vc_get_size(width, in_c); + long out_linesize = vc_get_size(width, UYVY); for (int i = 0; i < height; ++i) { - decoder(tmp_buffer + i * out_linesize, in + i * in_linesize, out_linesize, DEFAULT_R_SHIFT, DEFAULT_G_SHIFT, DEFAULT_B_SHIFT); + decoder(tmp_buffer + i * out_linesize, in + i * in_linesize, vc_get_size(width, UYVY), DEFAULT_R_SHIFT, DEFAULT_G_SHIFT, DEFAULT_B_SHIFT); } in = tmp_buffer; in_c = UYVY; @@ -134,7 +134,7 @@ void testcard_convert_buffer(codec_t in_c, codec_t out_c, unsigned char *out, un long out_linesize = vc_get_linesize(width, out_c); long in_linesize = vc_get_linesize(width, in_c); for (int i = 0; i < height; ++i) { - decoder(out + i * out_linesize, in + i * in_linesize, vc_get_linesize(width, out_c), DEFAULT_R_SHIFT, DEFAULT_G_SHIFT, DEFAULT_B_SHIFT); + decoder(out + i * out_linesize, in + i * in_linesize, vc_get_size(width, out_c), DEFAULT_R_SHIFT, DEFAULT_G_SHIFT, DEFAULT_B_SHIFT); } free(tmp_buffer); } diff --git a/src/video_codec.c b/src/video_codec.c index ebe81a3fb..ac01dd84c 100644 --- a/src/video_codec.c +++ b/src/video_codec.c @@ -497,6 +497,21 @@ int vc_get_linesize(unsigned int width, codec_t codec) return (width + pixs - 1) / pixs * codec_info[codec].block_size_bytes; } +/** + * Returns size of "width" pixels in codec _excluding_ padding. + * This is most likely only distinctive for vc_get_linesize for v210, + * eg. for width=1 that function returns 128, while this function 16. + */ +int vc_get_size(unsigned int width, codec_t codec) +{ + if (codec >= sizeof codec_info / sizeof(struct codec_info_t)) { + return 0; + } + + int pixs = codec_info[codec].block_size_pixels; + return (width + pixs - 1) / pixs * codec_info[codec].block_size_bytes; +} + /** * Returns storage requirements for given parameters */ diff --git a/src/video_codec.h b/src/video_codec.h index 12dbf5ce4..0c9302547 100644 --- a/src/video_codec.h +++ b/src/video_codec.h @@ -111,6 +111,7 @@ decoder_t get_fastest_decoder_from(codec_t in, const codec_t *out_candida int get_pf_block_bytes(codec_t codec) ATTRIBUTE(const); int get_pf_block_pixels(codec_t codec) ATTRIBUTE(const); int vc_get_linesize(unsigned int width, codec_t codec) ATTRIBUTE(const); +int vc_get_size(unsigned int width, codec_t codec) ATTRIBUTE(const); size_t vc_get_datalen(unsigned int width, unsigned int height, codec_t codec) ATTRIBUTE(const); void codec_get_planes_subsampling(codec_t pix_fmt, int *sub); bool codec_is_420(codec_t pix_fmt);