mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-21 17:40:23 +00:00
SW mix: support for arbitrary pixel format
This commit is contained in:
@@ -56,6 +56,7 @@ extern "C" {
|
||||
* @note May include features not compatible with GPUJPEG.
|
||||
*/
|
||||
typedef enum {
|
||||
VIDEO_CODEC_NONE = 0, ///< dummy color spec
|
||||
RGBA, ///< RGBA 8-bit
|
||||
UYVY, ///< YCbCr 422 8-bit - Cb Y0 Cr Y1
|
||||
YUYV, ///< YCbCr 422 8-bit - Y0 Cb Y1 Cr
|
||||
|
||||
@@ -285,10 +285,13 @@ struct slave_data {
|
||||
struct video_desc saved_desc;
|
||||
float posX[4];
|
||||
float posY[4];
|
||||
GLuint texture[2]; // original, RGB(A)
|
||||
GLuint texture[2]; // RGB(A), (UYVY)
|
||||
GLuint fbo; // RGB(A)
|
||||
double x, y, width, height; // in 1x1 unit space
|
||||
double fb_aspect;
|
||||
|
||||
decoder_t decoder;
|
||||
codec_t decoder_from, decoder_to;
|
||||
};
|
||||
|
||||
static struct slave_data *init_slave_data(vidcap_swmix_state *s, FILE *config) {
|
||||
@@ -469,6 +472,137 @@ void main() {
|
||||
gl_Position = ftransform();
|
||||
});
|
||||
|
||||
static void check_for_slave_format_change(struct slave_data *s)
|
||||
{
|
||||
struct video_desc desc = video_desc_from_frame(s->current_frame);
|
||||
|
||||
if(!video_desc_eq(desc, s->saved_desc)) {
|
||||
codec_t in_codec = s->current_frame->color_spec;
|
||||
codec_t out_codec = in_codec;
|
||||
codec_t natively_supported[] = { RGB, BGR, RGBA, UYVY, VIDEO_CODEC_NONE };
|
||||
|
||||
// prepare decoder
|
||||
if (!codec_is_in_set(desc.color_spec, natively_supported)) {
|
||||
int j = 0;
|
||||
while (natively_supported[j] != VIDEO_CODEC_NONE) {
|
||||
if ((s->decoder = get_decoder_from_to(out_codec, natively_supported[j]))) {
|
||||
s->decoder_from = desc.color_spec;
|
||||
desc.color_spec = s->decoder_to = natively_supported[j];
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
reconfigure_slave_rendering(s, desc);
|
||||
desc.color_spec = s->decoder_from;
|
||||
s->saved_desc = desc;
|
||||
}
|
||||
}
|
||||
|
||||
static void load_texture(struct slave_data *s, GLuint from_uyvy)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, s->texture[0]);
|
||||
int width = s->current_frame->tiles[0].width;
|
||||
GLenum format;
|
||||
|
||||
codec_t in_codec = s->current_frame->color_spec;
|
||||
codec_t out_codec = in_codec;
|
||||
codec_t natively_supported[] = { RGB, BGR, RGBA, UYVY, VIDEO_CODEC_NONE };
|
||||
decoder_t decoder = NULL;
|
||||
if (!codec_is_in_set(out_codec, natively_supported)) {
|
||||
if (s->decoder_from == in_codec) {
|
||||
out_codec = s->decoder_to;
|
||||
decoder = s->decoder;
|
||||
}
|
||||
}
|
||||
|
||||
switch (out_codec) {
|
||||
case UYVY:
|
||||
width /= 2;
|
||||
format = GL_RGBA;
|
||||
break;
|
||||
case RGB:
|
||||
format = GL_RGB;
|
||||
break;
|
||||
case BGR:
|
||||
format = GL_BGR;
|
||||
break;
|
||||
case RGBA:
|
||||
format = GL_RGBA;
|
||||
break;
|
||||
default:
|
||||
error_msg("Unexpected color space %s!",
|
||||
get_codec_name(out_codec));
|
||||
abort();
|
||||
}
|
||||
int src_height = s->current_frame->tiles[0].height;
|
||||
int src_width = s->current_frame->tiles[0].width;
|
||||
unsigned char *data = (unsigned char *) s->current_frame->tiles[0].data;
|
||||
unsigned char *tmp = NULL, *in_gl_buffer = data;
|
||||
if (decoder) {
|
||||
tmp = in_gl_buffer = (unsigned char *) malloc(src_height *
|
||||
vc_get_linesize(src_width, out_codec));
|
||||
for (int i = 0; i < src_height; ++i) {
|
||||
decoder(tmp + i * vc_get_linesize(src_width, out_codec),
|
||||
data + i * vc_get_linesize(src_width, in_codec),
|
||||
vc_get_linesize(src_width, out_codec), 0, 8, 16);
|
||||
}
|
||||
}
|
||||
|
||||
if(out_codec == UYVY) {
|
||||
glBindTexture(GL_TEXTURE_2D, s->texture[1]);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, s->texture[0]);
|
||||
}
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
||||
width, src_height, format, GL_UNSIGNED_BYTE, in_gl_buffer);
|
||||
free(tmp);
|
||||
|
||||
if(out_codec == UYVY) {
|
||||
glUseProgram(from_uyvy);
|
||||
glUniform1i(glGetUniformLocation(from_uyvy, "image"), 0);
|
||||
glUniform1f(glGetUniformLocation(from_uyvy, "imageWidth"),
|
||||
(GLfloat) s->current_frame->tiles[0].width);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT,
|
||||
GL_TEXTURE_2D, s->texture[0], 0);
|
||||
|
||||
glViewport(0, 0, s->current_frame->tiles[0].width,
|
||||
s->current_frame->tiles[0].height);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, -1.0);
|
||||
glTexCoord2f(1.0, 0.0); glVertex2f(1.0, -1.0);
|
||||
glTexCoord2f(1.0, 1.0); glVertex2f(1.0, 1.0);
|
||||
glTexCoord2f(0.0, 1.0); glVertex2f(-1.0, 1.0);
|
||||
glEnd();
|
||||
glUseProgram(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void render_slave(struct slave_data *s, interpolation_t interpolation, GLuint bicubic_program)
|
||||
{
|
||||
if(interpolation == BICUBIC) {
|
||||
glUniform1f(glGetUniformLocation(bicubic_program, "fWidth"),
|
||||
(GLfloat) s->current_frame->tiles[0].width);
|
||||
glUniform1f(glGetUniformLocation(bicubic_program, "fHeight"),
|
||||
(GLfloat) s->current_frame->tiles[0].height);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, s->texture[0]);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex2f(s->posX[0],
|
||||
s->posY[0]);
|
||||
glTexCoord2f(1.0, 0.0); glVertex2f(s->posX[1],
|
||||
s->posY[1]);
|
||||
glTexCoord2f(1.0, 1.0); glVertex2f(s->posX[2],
|
||||
s->posY[2]);
|
||||
glTexCoord2f(0.0, 1.0); glVertex2f(s->posX[3],
|
||||
s->posY[3]);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
static void *master_worker(void *arg)
|
||||
{
|
||||
struct vidcap_swmix_state *s = (struct vidcap_swmix_state *) arg;
|
||||
@@ -535,11 +669,7 @@ static void *master_worker(void *arg)
|
||||
// check for mode change
|
||||
for(int i = 0; i < s->devices_cnt; ++i) {
|
||||
if(s->slaves_data[i].current_frame) {
|
||||
struct video_desc desc = video_desc_from_frame(s->slaves_data[i].current_frame);
|
||||
if(!video_desc_eq(desc, s->slaves_data[i].saved_desc)) {
|
||||
reconfigure_slave_rendering(&s->slaves_data[i], desc);
|
||||
s->slaves_data[i].saved_desc = desc;
|
||||
}
|
||||
check_for_slave_format_change(&s->slaves_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,53 +697,9 @@ static void *master_worker(void *arg)
|
||||
s->slaves[i].audio_frame.data_len = 0;
|
||||
}
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, s->slaves_data[i].texture[0]);
|
||||
int width = s->slaves_data[i].current_frame->tiles[0].width;
|
||||
GLenum format;
|
||||
switch(s->slaves_data[i].current_frame->color_spec) {
|
||||
case UYVY:
|
||||
width /= 2;
|
||||
format = GL_RGBA;
|
||||
break;
|
||||
case RGB:
|
||||
format = GL_RGB;
|
||||
break;
|
||||
case BGR:
|
||||
format = GL_BGR;
|
||||
break;
|
||||
case RGBA:
|
||||
format = GL_RGBA;
|
||||
break;
|
||||
default:
|
||||
error_msg("Unexpected color space!");
|
||||
abort();
|
||||
}
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
||||
width,
|
||||
s->slaves_data[i].current_frame->tiles[0].height,
|
||||
format, GL_UNSIGNED_BYTE,
|
||||
s->slaves_data[i].current_frame->tiles[0].data);
|
||||
|
||||
if(s->slaves_data[i].current_frame->color_spec == UYVY) {
|
||||
glUseProgram(from_uyvy);
|
||||
glUniform1i(glGetUniformLocation(from_uyvy, "image"), 0);
|
||||
glUniform1f(glGetUniformLocation(from_uyvy, "imageWidth"),
|
||||
(GLfloat) s->slaves_data[i].current_frame->tiles[0].width);
|
||||
load_texture(&s->slaves_data[i], from_uyvy);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->slaves_data[i].fbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT,
|
||||
GL_TEXTURE_2D, s->slaves_data[i].texture[1], 0);
|
||||
|
||||
glViewport(0, 0, s->slaves_data[i].current_frame->tiles[0].width,
|
||||
s->slaves_data[i].current_frame->tiles[0].height);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, -1.0);
|
||||
glTexCoord2f(1.0, 0.0); glVertex2f(1.0, -1.0);
|
||||
glTexCoord2f(1.0, 1.0); glVertex2f(1.0, 1.0);
|
||||
glTexCoord2f(0.0, 1.0); glVertex2f(-1.0, 1.0);
|
||||
glEnd();
|
||||
glUseProgram(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,28 +719,7 @@ static void *master_worker(void *arg)
|
||||
|
||||
for(int i = 0; i < s->devices_cnt; ++i) {
|
||||
if(s->slaves_data[i].current_frame) {
|
||||
if(s->interpolation == BICUBIC) {
|
||||
glUniform1f(glGetUniformLocation(s->bicubic_program, "fWidth"),
|
||||
(GLfloat) s->slaves_data[i].current_frame->tiles[0].width);
|
||||
glUniform1f(glGetUniformLocation(s->bicubic_program, "fHeight"),
|
||||
(GLfloat) s->slaves_data[i].current_frame->tiles[0].height);
|
||||
}
|
||||
if(s->slaves_data[i].current_frame->color_spec == UYVY) {
|
||||
glBindTexture(GL_TEXTURE_2D, s->slaves_data[i].texture[1]);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, s->slaves_data[i].texture[0]);
|
||||
}
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex2f(s->slaves_data[i].posX[0],
|
||||
s->slaves_data[i].posY[0]);
|
||||
glTexCoord2f(1.0, 0.0); glVertex2f(s->slaves_data[i].posX[1],
|
||||
s->slaves_data[i].posY[1]);
|
||||
glTexCoord2f(1.0, 1.0); glVertex2f(s->slaves_data[i].posX[2],
|
||||
s->slaves_data[i].posY[2]);
|
||||
glTexCoord2f(0.0, 1.0); glVertex2f(s->slaves_data[i].posX[3],
|
||||
s->slaves_data[i].posY[3]);
|
||||
glEnd();
|
||||
render_slave(&s->slaves_data[i], s->interpolation, s->bicubic_program);
|
||||
}
|
||||
}
|
||||
glUseProgram(0);
|
||||
|
||||
@@ -82,6 +82,7 @@ static void vc_copylineToUYVY(unsigned char *dst, const unsigned char *src, int
|
||||
int rshift, int gshift, int bshift, int pix_size);
|
||||
|
||||
const struct codec_info_t codec_info[] = {
|
||||
[VIDEO_CODEC_NONE] = {VIDEO_CODEC_NONE, "(none)", 0, 0, 0.0, 0, FALSE, FALSE, FALSE, NULL},
|
||||
[RGBA] = {RGBA, "RGBA", to_fourcc('R','G','B','A'), 1, 4.0, 4, TRUE, FALSE, FALSE, "rgba"},
|
||||
[UYVY] = {UYVY, "UYVY", to_fourcc('2','v','u','y'), 2, 2, 4, FALSE, FALSE, FALSE, "yuv"},
|
||||
[YUYV] = {YUYV, "YUYV", to_fourcc('Y','U','Y','V'), 2, 2, 4, FALSE, FALSE, FALSE, "yuv"},
|
||||
@@ -1099,7 +1100,7 @@ vc_copylineDPX10toRGB(unsigned char *dst, const unsigned char *src, int dst_len)
|
||||
/**
|
||||
* Returns line decoder for specifiedn input and output codec.
|
||||
*/
|
||||
bool get_decoder_from_to(codec_t in, codec_t out, decoder_t *decoder)
|
||||
decoder_t get_decoder_from_to(codec_t in, codec_t out)
|
||||
{
|
||||
struct item {
|
||||
decoder_t decoder;
|
||||
@@ -1129,12 +1130,11 @@ bool get_decoder_from_to(codec_t in, codec_t out, decoder_t *decoder)
|
||||
|
||||
for (unsigned int i = 0; i < sizeof(decoders)/sizeof(struct item); ++i) {
|
||||
if (decoders[i].in == in && decoders[i].out == out) {
|
||||
*decoder = decoders[i].decoder;
|
||||
return true;
|
||||
return decoders[i].decoder;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** @brief Returns TRUE if specified pixelformat is some form of RGB (not YUV).
|
||||
@@ -1154,3 +1154,18 @@ int codec_is_a_rgb(codec_t codec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find specified codec in set of video codecs.
|
||||
* The set must by ended by VIDEO_CODEC_NONE.
|
||||
*/
|
||||
bool codec_is_in_set(codec_t codec, codec_t *set)
|
||||
{
|
||||
assert (codec != VIDEO_CODEC_NONE);
|
||||
assert (set != NULL);
|
||||
while (*set != VIDEO_CODEC_NONE) {
|
||||
if (*(set++) == codec)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -109,12 +109,14 @@ int is_codec_opaque(codec_t codec) __attribute__((pure));
|
||||
int is_codec_interframe(codec_t codec) __attribute__((pure));
|
||||
codec_t get_codec_from_fcc(uint32_t fourcc) __attribute__((pure));
|
||||
const char *get_codec_file_extension(codec_t codec) __attribute__((pure));
|
||||
decoder_t get_decoder_from_to(codec_t in, codec_t out) __attribute__((pure));
|
||||
|
||||
uint32_t get_fcc_from_codec(codec_t codec) __attribute__((pure));
|
||||
int get_aligned_length(int width, codec_t codec) __attribute__((pure));
|
||||
int get_pf_block_size(codec_t codec) __attribute__((pure));
|
||||
int vc_get_linesize(unsigned int width, codec_t codec) __attribute__((pure));
|
||||
int codec_is_a_rgb(codec_t codec) __attribute__((pure));
|
||||
bool codec_is_in_set(codec_t codec, codec_t *set) __attribute__((pure));
|
||||
|
||||
void vc_deinterlace(unsigned char *src, long src_linesize, int lines);
|
||||
void vc_copylineDVS10(unsigned char *dst, const unsigned char *src, int dst_len);
|
||||
@@ -142,7 +144,6 @@ void vc_copylineDPX10toRGB(unsigned char *dst, const unsigned char *src, int dst
|
||||
void vc_copylineRGB(unsigned char *dst, const unsigned char *src, int dst_len,
|
||||
int rshift, int gshift, int bshift);
|
||||
|
||||
bool get_decoder_from_to(codec_t in, codec_t out, decoder_t *decoder);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -128,9 +128,9 @@ static bool configure_with(struct state_video_compress_cuda_dxt *s, struct video
|
||||
|
||||
if (desc.color_spec == RGB || desc.color_spec == UYVY) {
|
||||
s->in_codec = desc.color_spec;
|
||||
} else if (get_decoder_from_to(desc.color_spec, RGB, &s->decoder)) {
|
||||
} else if ((s->decoder = get_decoder_from_to(desc.color_spec, RGB))) {
|
||||
s->in_codec = RGB;
|
||||
} else if (get_decoder_from_to(desc.color_spec, UYVY, &s->decoder)) {
|
||||
} else if ((s->decoder = get_decoder_from_to(desc.color_spec, UYVY))) {
|
||||
s->in_codec = UYVY;
|
||||
} else {
|
||||
fprintf(stderr, "Unsupported codec: %s\n", get_codec_name(desc.color_spec));
|
||||
|
||||
Reference in New Issue
Block a user