gl/mem: allocate the memory per plane

This patch provides the basic infrastructure required for this.
Upload and Download has been ported to this.

Has the nice effect of allowing GstGLMemory to be our
refcounted texture object for any texture type (not just RGBA).

Should not lose any features/video formats.
This commit is contained in:
Matthew Waters 2014-04-02 17:43:52 +11:00 committed by Tim-Philipp Müller
parent ea2d4cb446
commit 30c6efc432
14 changed files with 1010 additions and 830 deletions

View file

@ -178,10 +178,9 @@ static GstStaticPadTemplate gst_glimage_sink_template =
GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, "RGBA") "; "
#endif
GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS) "; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
GST_GL_COLOR_CONVERT_FORMATS))
"RGBA") "; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
);
enum
@ -438,8 +437,7 @@ _ensure_gl_setup (GstGLImageSink * gl_sink)
if (!gl_sink->upload) {
gl_sink->upload = gst_gl_upload_new (gl_sink->context);
if (!gst_gl_upload_init_format (gl_sink->upload, &gl_sink->info,
&gl_sink->info))
if (!gst_gl_upload_init_format (gl_sink->upload, &gl_sink->info))
goto upload_error;
}

View file

@ -50,6 +50,7 @@ struct _GstGLBufferPoolPrivate
GstCaps *caps;
gint im_format;
GstVideoInfo info;
GstGLUpload *upload;
gboolean add_videometa;
#if GST_GL_HAVE_PLATFORM_EGL
gboolean want_eglimage;
@ -129,6 +130,12 @@ gst_gl_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
&& g_strcmp0 (priv->allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0);
#endif
if (priv->upload)
gst_object_unref (priv->upload);
priv->upload = gst_gl_upload_new (glpool->context);
gst_gl_upload_init_format (priv->upload, &priv->info);
return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
/* ERRORS */
@ -169,7 +176,6 @@ gst_gl_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
GstGLBufferPoolPrivate *priv = glpool->priv;
GstVideoInfo *info;
GstBuffer *buf;
GstMemory *gl_mem;
info = &priv->info;
@ -189,20 +195,10 @@ gst_gl_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
}
#endif
if (!(gl_mem = gst_gl_memory_alloc (glpool->context, info)))
if (!gst_gl_memory_setup_buffer (glpool->context, info, buf))
goto mem_create_failed;
gst_buffer_append_memory (buf, gl_mem);
if (priv->add_videometa) {
GST_DEBUG_OBJECT (pool, "adding GstVideoMeta");
/* these are just the defaults for now */
gst_buffer_add_video_meta (buf, 0,
GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
GST_VIDEO_INFO_HEIGHT (info));
gst_gl_upload_add_video_gl_texture_upload_meta (((GstGLMemory *)
gl_mem)->upload, buf);
}
gst_gl_upload_add_video_gl_texture_upload_meta (glpool->priv->upload, buf);
*buffer = buf;
@ -349,6 +345,9 @@ gst_gl_buffer_pool_finalize (GObject * object)
if (priv->caps)
gst_caps_unref (priv->caps);
if (priv->upload)
gst_object_unref (priv->upload);
G_OBJECT_CLASS (gst_gl_buffer_pool_parent_class)->finalize (object);
/* only release the context once all our memory have been deleted */

View file

@ -52,8 +52,8 @@ static void _init_convert (GstGLContext * context, GstGLColorConvert * convert);
static gboolean _init_convert_fbo (GstGLContext * context,
GstGLColorConvert * convert);
static gboolean _gst_gl_color_convert_perform_unlocked (GstGLColorConvert *
convert, guint in_tex[GST_VIDEO_MAX_PLANES],
guint out_tex[GST_VIDEO_MAX_PLANES]);
convert, GstGLMemory * in_tex[GST_VIDEO_MAX_PLANES],
GstGLMemory * out_tex[GST_VIDEO_MAX_PLANES]);
static gboolean _do_convert_draw (GstGLContext * context,
GstGLColorConvert * convert);
@ -363,8 +363,8 @@ struct _GstGLColorConvertPrivate
struct ConvertInfo convert_info;
guint tex_id;
gboolean mapped;
GstGLMemory *scratch;
GstGLMemory *out_temp[GST_VIDEO_MAX_PLANES];
};
GST_DEBUG_CATEGORY_STATIC (gst_gl_color_convert_debug);
@ -436,6 +436,11 @@ gst_gl_color_convert_finalize (GObject * object)
convert->shader = NULL;
}
if (convert->priv->scratch) {
gst_memory_unref ((GstMemory *) convert->priv->scratch);
convert->priv->scratch = NULL;
}
if (convert->context) {
gst_object_unref (convert->context);
convert->context = NULL;
@ -457,7 +462,7 @@ _gst_gl_color_convert_init_format_unlocked (GstGLColorConvert * convert,
GST_VIDEO_FORMAT_ENCODED, FALSE);
if (convert->initted) {
return FALSE;
return TRUE;
} else {
convert->initted = TRUE;
}
@ -508,7 +513,8 @@ gst_gl_color_convert_init_format (GstGLColorConvert * convert,
*/
gboolean
gst_gl_color_convert_perform (GstGLColorConvert * convert,
guint in_tex[GST_VIDEO_MAX_PLANES], guint out_tex[GST_VIDEO_MAX_PLANES])
GstGLMemory * in_tex[GST_VIDEO_MAX_PLANES],
GstGLMemory * out_tex[GST_VIDEO_MAX_PLANES])
{
gboolean ret;
@ -547,7 +553,8 @@ gst_gl_color_convert_set_texture_scaling (GstGLColorConvert * convert,
static gboolean
_gst_gl_color_convert_perform_unlocked (GstGLColorConvert * convert,
guint in_tex[GST_VIDEO_MAX_PLANES], guint out_tex[GST_VIDEO_MAX_PLANES])
GstGLMemory * in_tex[GST_VIDEO_MAX_PLANES],
GstGLMemory * out_tex[GST_VIDEO_MAX_PLANES])
{
g_return_val_if_fail (convert != NULL, FALSE);
g_return_val_if_fail (in_tex, FALSE);
@ -562,7 +569,7 @@ _gst_gl_color_convert_perform_unlocked (GstGLColorConvert * convert,
convert->out_tex[2] = out_tex[2];
convert->out_tex[3] = out_tex[3];
GST_LOG ("Converting %s from %u,%u,%u,%u into %s using %u,%u,%u,%u",
GST_LOG ("Converting %s from %p,%p,%p,%p into %s using %p,%p,%p,%p",
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)),
in_tex[0], in_tex[1], in_tex[2], in_tex[3],
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->out_info)),
@ -725,7 +732,6 @@ _YUV_to_RGB (GstGLContext * context, GstGLColorConvert * convert)
info->shader_tex_names[0] = "tex";
break;
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_Y41B:
@ -736,12 +742,25 @@ _YUV_to_RGB (GstGLContext * context, GstGLColorConvert * convert)
info->shader_tex_names[1] = "Utex";
info->shader_tex_names[2] = "Vtex";
break;
case GST_VIDEO_FORMAT_YV12:
info->frag_prog = g_strdup_printf (frag_PLANAR_YUV_to_RGB, pixel_order[0],
pixel_order[1], pixel_order[2], pixel_order[3]);
info->in_n_textures = 3;
info->shader_tex_names[0] = "Ytex";
info->shader_tex_names[1] = "Vtex";
info->shader_tex_names[2] = "Utex";
break;
case GST_VIDEO_FORMAT_YUY2:
info->frag_prog = g_strdup_printf (frag_YUY2_UYVY_to_RGB, 'r', 'g', 'a',
pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
info->in_n_textures = 2;
info->shader_tex_names[0] = "Ytex";
info->shader_tex_names[1] = "UVtex";
info->in_n_textures = 1;
info->shader_tex_names[1] = "Ytex";
info->shader_tex_names[0] = "UVtex";
convert->priv->scratch = (GstGLMemory *) gst_gl_memory_alloc (context,
GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA,
GST_VIDEO_INFO_WIDTH (&convert->in_info),
GST_VIDEO_INFO_HEIGHT (&convert->in_info),
GST_VIDEO_INFO_WIDTH (&convert->in_info));
break;
case GST_VIDEO_FORMAT_NV12:
info->frag_prog = g_strdup_printf (frag_NV12_NV21_to_RGB, 'r', 'a',
@ -760,9 +779,14 @@ _YUV_to_RGB (GstGLContext * context, GstGLColorConvert * convert)
case GST_VIDEO_FORMAT_UYVY:
info->frag_prog = g_strdup_printf (frag_YUY2_UYVY_to_RGB, 'a', 'r', 'b',
pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
info->in_n_textures = 2;
info->shader_tex_names[0] = "Ytex";
info->shader_tex_names[1] = "UVtex";
info->in_n_textures = 1;
info->shader_tex_names[1] = "Ytex";
info->shader_tex_names[0] = "UVtex";
convert->priv->scratch = (GstGLMemory *) gst_gl_memory_alloc (context,
GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA,
GST_VIDEO_INFO_WIDTH (&convert->in_info),
GST_VIDEO_INFO_HEIGHT (&convert->in_info),
GST_VIDEO_INFO_WIDTH (&convert->in_info));
break;
default:
break;
@ -1007,13 +1031,15 @@ _init_convert (GstGLContext * context, GstGLColorConvert * convert)
info->cms_coeff3);
}
for (i = info->in_n_textures - 1; i >= 0; i--) {
for (i = info->in_n_textures; i >= 0; i--) {
gchar *scale_name = g_strdup_printf ("tex_scale%u", i);
gst_gl_shader_set_uniform_1i (convert->shader, info->shader_tex_names[i],
i);
gst_gl_shader_set_uniform_2fv (convert->shader, scale_name, 1,
info->shader_scaling[i]);
if (info->shader_tex_names[i])
gst_gl_shader_set_uniform_1i (convert->shader, info->shader_tex_names[i],
i);
if (info->shader_scaling[i])
gst_gl_shader_set_uniform_2fv (convert->shader, scale_name, 1,
info->shader_scaling[i]);
g_free (scale_name);
}
@ -1135,29 +1161,43 @@ void
_do_convert (GstGLContext * context, GstGLColorConvert * convert)
{
guint in_width, in_height, out_width, out_height;
struct ConvertInfo *c_info = &convert->priv->convert_info;
GstMapInfo in_infos[GST_VIDEO_MAX_PLANES], out_infos[GST_VIDEO_MAX_PLANES];
gboolean res = TRUE;
gint i = 0;
out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
in_width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
in_height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);
GST_TRACE ("converting to textures:%u,%u,%u,%u dimensions:%ux%u, "
"from textures:%u,%u,%u,%u dimensions:%ux%u", convert->out_tex[0],
GST_TRACE ("converting to textures:%p,%p,%p,%p dimensions:%ux%u, "
"from textures:%p,%p,%p,%p dimensions:%ux%u", convert->out_tex[0],
convert->out_tex[1], convert->out_tex[2], convert->out_tex[3],
out_width, out_height, convert->in_tex[0], convert->in_tex[1],
convert->in_tex[2], convert->in_tex[3], in_width, in_height);
if (!convert->priv->draw (context, convert))
goto error;
convert->priv->result = TRUE;
return;
error:
{
convert->priv->result = FALSE;
return;
for (i = 0; i < c_info->in_n_textures; i++) {
gst_memory_map ((GstMemory *) convert->in_tex[i], &in_infos[i],
GST_MAP_READ | GST_MAP_GL);
}
for (i = 0; i < c_info->out_n_textures; i++) {
gst_memory_map ((GstMemory *) convert->out_tex[i], &out_infos[i],
GST_MAP_WRITE | GST_MAP_GL);
}
if (!convert->priv->draw (context, convert))
res = FALSE;
for (i = 0; i < c_info->in_n_textures; i++) {
gst_memory_unmap ((GstMemory *) convert->in_tex[i], &in_infos[i]);
}
for (i = 0; i < c_info->out_n_textures; i++) {
gst_memory_unmap ((GstMemory *) convert->out_tex[i], &out_infos[i]);
}
convert->priv->result = res;
return;
}
static gboolean
@ -1191,15 +1231,35 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
/* two sources of the same data */
if (convert->priv->scratch) {
gst_gl_memory_copy_into_texture (convert->in_tex[0],
convert->priv->scratch->tex_id, convert->priv->scratch->tex_type,
convert->priv->scratch->width, convert->priv->scratch->height, TRUE);
}
gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo);
/* attach the texture to the FBO to renderer to */
for (i = 0; i < c_info->out_n_textures; i++) {
/* needed? */
gl->BindTexture (GL_TEXTURE_2D, convert->out_tex[i]);
gl->BindTexture (GL_TEXTURE_2D, convert->out_tex[i]->tex_id);
if (convert->out_tex[i]->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
|| convert->out_tex[i]->tex_type ==
GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA
|| out_width != convert->out_tex[i]->width
|| out_height != convert->out_tex[i]->height) {
/* Luminance formats are not color renderable */
/* renderering to a framebuffer only renders the intersection of all
* the attachments i.e. the smallest attachment size */
convert->priv->out_temp[i] = convert->out_tex[i];
convert->out_tex[i] = (GstGLMemory *) gst_gl_memory_alloc (context,
GST_VIDEO_GL_TEXTURE_TYPE_RGBA, out_width, out_height, out_width);
}
gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
GL_TEXTURE_2D, convert->out_tex[i], 0);
GL_TEXTURE_2D, convert->out_tex[i]->tex_id, 0);
}
if (gl->DrawBuffers)
@ -1222,9 +1282,14 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
gl->EnableVertexAttribArray (convert->shader_attr_position_loc);
gl->EnableVertexAttribArray (convert->shader_attr_texture_loc);
if (convert->priv->scratch) {
gl->ActiveTexture (GL_TEXTURE0 + c_info->in_n_textures);
gl->BindTexture (GL_TEXTURE_2D, convert->priv->scratch->tex_id);
}
for (i = c_info->in_n_textures - 1; i >= 0; i--) {
gl->ActiveTexture (GL_TEXTURE0 + i);
gl->BindTexture (GL_TEXTURE_2D, convert->in_tex[i]);
gl->BindTexture (GL_TEXTURE_2D, convert->in_tex[i]->tex_id);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -1243,6 +1308,18 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
/* we are done with the shader */
gst_gl_context_clear_shader (context);
for (i = 0; i < c_info->out_n_textures; i++) {
if (convert->priv->out_temp[i]) {
GstGLMemory *gl_mem = convert->priv->out_temp[i];
gst_gl_memory_copy_into_texture (convert->out_tex[i], gl_mem->tex_id,
gl_mem->tex_type, gl_mem->width, gl_mem->height, FALSE);
gst_memory_unref ((GstMemory *) convert->out_tex[i]);
convert->out_tex[i] = gl_mem;
}
}
gst_gl_context_check_framebuffer_status (context);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);

View file

@ -56,8 +56,8 @@ struct _GstGLColorConvert
gboolean initted;
guint in_tex[GST_VIDEO_MAX_PLANES];
guint out_tex[GST_VIDEO_MAX_PLANES];
GstGLMemory * in_tex[GST_VIDEO_MAX_PLANES];
GstGLMemory * out_tex[GST_VIDEO_MAX_PLANES];
/* used for the conversion */
GLuint fbo;
@ -109,8 +109,8 @@ void gst_gl_color_convert_set_texture_scaling (GstGLColorConvert * convert,
gfloat scaling[GST_VIDEO_MAX_PLANES][2]);
gboolean gst_gl_color_convert_perform (GstGLColorConvert * convert,
guint in_tex[GST_VIDEO_MAX_PLANES],
guint out_tex[GST_VIDEO_MAX_PLANES]);
GstGLMemory * in_tex[GST_VIDEO_MAX_PLANES],
GstGLMemory * out_tex[GST_VIDEO_MAX_PLANES]);
G_END_DECLS

View file

@ -122,8 +122,8 @@ gst_gl_download_finalize (GObject * object)
for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
if (download->out_texture[i]) {
gst_gl_context_del_texture (download->context, &download->out_texture[i]);
download->out_texture[i] = 0;
gst_memory_unref ((GstMemory *) download->out_texture[i]);
download->out_texture[i] = NULL;
}
}
@ -266,6 +266,8 @@ static gboolean
_gst_gl_download_perform_with_data_unlocked (GstGLDownload * download,
GLuint texture_id, gpointer data[GST_VIDEO_MAX_PLANES])
{
gboolean realloc = FALSE;
gpointer temp_data;
guint i;
g_return_val_if_fail (download != NULL, FALSE);
@ -281,7 +283,26 @@ _gst_gl_download_perform_with_data_unlocked (GstGLDownload * download,
download->in_texture = texture_id;
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&download->info); i++) {
download->data[i] = data[i];
if (download->data[i] != data[i])
realloc = TRUE;
}
if (realloc) {
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&download->info); i++) {
if (download->out_texture[i])
gst_memory_unref ((GstMemory *) download->out_texture[i]);
download->data[i] = data[i];
}
if (GST_VIDEO_INFO_FORMAT (&download->info) == GST_VIDEO_FORMAT_YV12) {
/* YV12 same as I420 except planes 1+2 swapped */
temp_data = download->data[1];
download->data[1] = download->data[2];
download->data[2] = temp_data;
}
gst_gl_memory_setup_wrapped (download->context, &download->info,
download->data, download->out_texture);
}
gst_gl_context_thread_add (download->context,
@ -293,12 +314,10 @@ _gst_gl_download_perform_with_data_unlocked (GstGLDownload * download,
static void
_init_download (GstGLContext * context, GstGLDownload * download)
{
const GstGLFuncs *gl;
GstVideoFormat v_format;
guint out_width, out_height;
GstVideoInfo in_info;
gl = context->gl_vtable;
v_format = GST_VIDEO_INFO_FORMAT (&download->info);
out_width = GST_VIDEO_INFO_WIDTH (&download->info);
out_height = GST_VIDEO_INFO_HEIGHT (&download->info);
@ -306,6 +325,16 @@ _init_download (GstGLContext * context, GstGLDownload * download)
GST_TRACE ("initializing texture download for format %s",
gst_video_format_to_string (v_format));
if (USING_GLES2 (context) && !USING_GLES3 (context)) {
/* GL_RGBA is the only officially supported texture format in GLES2 */
if (v_format == GST_VIDEO_FORMAT_RGB || v_format == GST_VIDEO_FORMAT_BGR) {
gst_gl_context_set_error (context, "Cannot download RGB textures in "
"GLES2");
download->priv->result = FALSE;
return;
}
}
gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, out_width,
out_height);
@ -315,139 +344,37 @@ _init_download (GstGLContext * context, GstGLDownload * download)
if (!download->priv->result)
return;
if (USING_GLES2 (context) && !USING_GLES3 (context)) {
/* GL_RGBA is the only officially supported texture format in GLES2 */
if (v_format == GST_VIDEO_FORMAT_RGB || v_format == GST_VIDEO_FORMAT_BGR) {
download->priv->result = FALSE;
return;
}
}
gl->GenTextures (1, &download->out_texture[0]);
gl->BindTexture (GL_TEXTURE_2D, download->out_texture[0]);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
out_width, out_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (v_format == GST_VIDEO_FORMAT_I420 || v_format == GST_VIDEO_FORMAT_YV12) {
/* setup a second texture to render to */
gl->GenTextures (1, &download->out_texture[1]);
gl->BindTexture (GL_TEXTURE_2D, download->out_texture[1]);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
out_width, out_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
/* setup a third texture to render to */
gl->GenTextures (1, &download->out_texture[2]);
gl->BindTexture (GL_TEXTURE_2D, download->out_texture[2]);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
out_width, out_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
download->priv->result = TRUE;
}
static void
_do_download (GstGLContext * context, GstGLDownload * download)
{
GstGLFuncs *gl;
GstVideoFormat v_format;
guint out_width, out_height;
guint in_tex[] = { download->in_texture, 0, 0, 0 };
gl = context->gl_vtable;
GstMapInfo map_info;
GstGLMemory *in_tex[GST_VIDEO_MAX_PLANES] = { 0, };
gint i;
out_width = GST_VIDEO_INFO_WIDTH (&download->info);
out_height = GST_VIDEO_INFO_HEIGHT (&download->info);
v_format = GST_VIDEO_INFO_FORMAT (&download->info);
GST_TRACE ("doing YUV download of texture:%u (%ux%u)",
download->in_texture, out_width, out_height);
in_tex[0] = gst_gl_memory_wrapped_texture (context, download->in_texture,
GST_VIDEO_GL_TEXTURE_TYPE_RGBA, out_width, out_height, NULL, NULL);
download->priv->result =
gst_gl_color_convert_perform (download->convert, in_tex,
download->out_texture);
if (!download->priv->result)
return;
gl->BindFramebuffer (GL_FRAMEBUFFER, download->convert->fbo);
gl->ReadBuffer (GL_COLOR_ATTACHMENT0);
switch (v_format) {
case GST_VIDEO_FORMAT_AYUV:
gl->ReadPixels (0, 0, out_width, out_height, GL_RGBA,
GL_UNSIGNED_BYTE, download->data[0]);
break;
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2, out_height, GL_RGBA,
GL_UNSIGNED_BYTE, download->data[0]);
break;
case GST_VIDEO_FORMAT_I420:
{
gl->ReadPixels (0, 0, out_width, out_height, GL_LUMINANCE,
GL_UNSIGNED_BYTE, download->data[0]);
gl->ReadBuffer (GL_COLOR_ATTACHMENT1);
gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
download->data[1]);
gl->ReadBuffer (GL_COLOR_ATTACHMENT2);
gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
download->data[2]);
}
break;
case GST_VIDEO_FORMAT_YV12:
{
gl->ReadPixels (0, 0, out_width, out_height, GL_LUMINANCE,
GL_UNSIGNED_BYTE, download->data[0]);
gl->ReadBuffer (GL_COLOR_ATTACHMENT1);
gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
download->data[2]);
gl->ReadBuffer (GL_COLOR_ATTACHMENT2);
gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
download->data[1]);
}
break;
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_RGBx:
case GST_VIDEO_FORMAT_xRGB:
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_xBGR:
case GST_VIDEO_FORMAT_ABGR:
gl->ReadPixels (0, 0, out_width, out_height, GL_RGBA, GL_UNSIGNED_BYTE,
download->data[0]);
break;
case GST_VIDEO_FORMAT_RGB:
case GST_VIDEO_FORMAT_BGR:
gl->ReadPixels (0, 0, out_width, out_height, GL_RGB, GL_UNSIGNED_BYTE,
download->data[0]);
break;
default:
break;
gst_gl_context_set_error (context,
"Download video format inconsistensy %d", v_format);
g_assert_not_reached ();
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&download->info); i++) {
gst_memory_map ((GstMemory *) download->out_texture[i], &map_info,
GST_MAP_READ);
gst_memory_unmap ((GstMemory *) download->out_texture[i], &map_info);
}
gst_gl_context_check_framebuffer_status (context);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
gst_memory_unref ((GstMemory *) in_tex[0]);
}

View file

@ -59,7 +59,7 @@ struct _GstGLDownload
/* used for the conversion */
GLuint in_texture;
GLuint out_texture[GST_VIDEO_MAX_PLANES];
GstGLMemory * out_texture[GST_VIDEO_MAX_PLANES];
GstGLDownloadPrivate *priv;

View file

@ -43,10 +43,9 @@ static GstStaticPadTemplate gst_gl_filter_src_pad_template =
GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE,
"RGBA") "; "
#endif
GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS) "; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
"RGBA"))
"RGBA") "; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
);
static GstStaticPadTemplate gst_gl_filter_sink_pad_template =
@ -58,10 +57,9 @@ static GstStaticPadTemplate gst_gl_filter_sink_pad_template =
GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE,
"RGBA") "; "
#endif
GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS) "; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
"RGBA"))
(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "RGBA") "; "
GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
);
/* Properties */
@ -964,8 +962,7 @@ gst_gl_filter_decide_allocation (GstBaseTransform * trans, GstQuery * query)
if (!filter->upload) {
filter->upload = gst_gl_upload_new (filter->context);
gst_gl_upload_init_format (filter->upload, &filter->in_info,
&filter->out_info);
gst_gl_upload_init_format (filter->upload, &filter->in_info);
}
//blocking call, generate a FBO
if (!gst_gl_context_gen_fbo (filter->context, out_width, out_height,
@ -1288,6 +1285,9 @@ gst_gl_filter_draw_texture (GstGLFilter * filter, GLuint texture,
gl->EnableVertexAttribArray (filter->draw_attr_texture_loc);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
gl->DisableVertexAttribArray (filter->draw_attr_position_loc);
gl->DisableVertexAttribArray (filter->draw_attr_texture_loc);
}
#endif
}

View file

@ -55,59 +55,454 @@ static GstAllocator *_gl_allocator;
typedef struct
{
/* in */
GstGLMemory *src;
GLuint tex_id;
GstVideoGLTextureType out_format;
guint out_width, out_height;
gboolean respecify;
/* inout */
guint tex_id;
/* out */
gboolean result;
} GstGLMemoryCopyParams;
static inline guint
_gl_format_n_components (guint format)
{
switch (format) {
case GST_VIDEO_GL_TEXTURE_TYPE_RGBA:
case GL_RGBA:
return 4;
case GST_VIDEO_GL_TEXTURE_TYPE_RGB:
case GST_VIDEO_GL_TEXTURE_TYPE_RGB16:
case GL_RGB:
return 3;
case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA:
case GST_VIDEO_GL_TEXTURE_TYPE_RG:
case GL_LUMINANCE_ALPHA:
case GL_RG:
return 2;
case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE:
case GST_VIDEO_GL_TEXTURE_TYPE_R:
case GL_LUMINANCE:
case GL_RED:
return 1;
default:
return 0;
}
}
static inline guint
_gl_type_n_components (guint type)
{
switch (type) {
case GL_UNSIGNED_BYTE:
return 1;
case GL_UNSIGNED_SHORT_5_6_5:
return 3;
default:
g_assert_not_reached ();
return 0;
}
}
static inline guint
_gl_type_n_bytes (guint type)
{
switch (type) {
case GL_UNSIGNED_BYTE:
return 1;
case GL_UNSIGNED_SHORT_5_6_5:
return 2;
default:
g_assert_not_reached ();
return 0;
}
}
static inline guint
_gl_format_type_n_bytes (guint format, guint type)
{
return _gl_format_n_components (format) / _gl_type_n_components (type) *
_gl_type_n_bytes (type);
}
static inline GLenum
_gst_gl_format_from_gl_texture_type (GstVideoGLTextureType tex_format)
{
switch (tex_format) {
case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA:
return GL_LUMINANCE_ALPHA;
case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE:
return GL_LUMINANCE;
case GST_VIDEO_GL_TEXTURE_TYPE_RGBA:
return GL_RGBA;
case GST_VIDEO_GL_TEXTURE_TYPE_RGB:
case GST_VIDEO_GL_TEXTURE_TYPE_RGB16:
return GL_RGB;
case GST_VIDEO_GL_TEXTURE_TYPE_RG:
return GL_RG;
case GST_VIDEO_GL_TEXTURE_TYPE_R:
return GL_RED;
default:
return GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
}
}
static inline guint
_gl_texture_type_n_bytes (GstVideoGLTextureType tex_format)
{
guint format, type;
format = _gst_gl_format_from_gl_texture_type (tex_format);
type = GL_UNSIGNED_BYTE;
if (tex_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
type = GL_UNSIGNED_SHORT_5_6_5;
return _gl_format_type_n_bytes (format, type);
}
GstVideoGLTextureType
gst_gl_texture_type_from_format (GstVideoFormat v_format, guint plane)
{
switch (v_format) {
case GST_VIDEO_FORMAT_RGBx:
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_xRGB:
case GST_VIDEO_FORMAT_xBGR:
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_AYUV:
return GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
break;
case GST_VIDEO_FORMAT_RGB:
case GST_VIDEO_FORMAT_BGR:
return GST_VIDEO_GL_TEXTURE_TYPE_RGB;
break;
case GST_VIDEO_FORMAT_GRAY8:
return GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
break;
case GST_VIDEO_FORMAT_GRAY16_BE:
case GST_VIDEO_FORMAT_GRAY16_LE:
return GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA;
break;
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
return GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
break;
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_NV21:
if (plane == 0)
return GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
return GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA;
break;
case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_Y41B:
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
return GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
break;
default:
g_assert_not_reached ();
break;
}
return GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
}
static inline guint
_get_plane_width (GstVideoInfo * info, guint plane)
{
if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_YUY2
|| GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_UYVY) {
return GST_VIDEO_INFO_COMP_WIDTH (info, 1);
}
if (GST_VIDEO_INFO_IS_YUV (info))
/* For now component width and plane width are the same and the
* plane-component mapping matches
*/
return GST_VIDEO_INFO_COMP_WIDTH (info, plane);
else /* RGB, GRAY */
return GST_VIDEO_INFO_WIDTH (info);
}
static inline guint
_get_plane_height (GstVideoInfo * info, guint plane)
{
if (GST_VIDEO_INFO_IS_YUV (info))
/* For now component width and plane width are the same and the
* plane-component mapping matches
*/
return GST_VIDEO_INFO_COMP_HEIGHT (info, plane);
else /* RGB, GRAY */
return GST_VIDEO_INFO_HEIGHT (info);
}
typedef struct _GenTexture
{
guint width, height;
GLenum gl_format;
GLenum gl_type;
guint result;
} GenTexture;
static void
_generate_texture (GstGLContext * context, GenTexture * data)
{
const GstGLFuncs *gl = context->gl_vtable;
GST_CAT_TRACE (GST_CAT_GL_MEMORY,
"Generating texture format:%u type:%u dimensions:%ux%u", data->gl_format,
data->gl_type, data->width, data->height);
gl->GenTextures (1, &data->result);
gl->BindTexture (GL_TEXTURE_2D, data->result);
gl->TexImage2D (GL_TEXTURE_2D, 0, data->gl_format, data->width,
data->height, 0, data->gl_format, data->gl_type, NULL);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GST_CAT_LOG (GST_CAT_GL_MEMORY, "generated texture id:%d", data->result);
}
static void
_upload_memory (GstGLContext * context, GstGLMemory * gl_mem)
{
const GstGLFuncs *gl;
guint unpack_length, n_gl_bytes;
GLenum gl_format, gl_type;
if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD)) {
return;
}
gl = context->gl_vtable;
gl_type = GL_UNSIGNED_BYTE;
if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
gl_type = GL_UNSIGNED_SHORT_5_6_5;
gl_format = _gst_gl_format_from_gl_texture_type (gl_mem->tex_type);
n_gl_bytes = _gl_texture_type_n_bytes (gl_mem->tex_type);
gl_mem->tex_scaling[0] = 1.0f;
gl_mem->tex_scaling[1] = 1.0f;
unpack_length = 1;
#if GST_GL_HAVE_OPENGL || GST_GL_HAVE_GLES3
if (USING_OPENGL (context) || USING_GLES3 (context)) {
unpack_length = gl_mem->stride / n_gl_bytes;
}
#endif
#if GST_GL_HAVE_GLES2
if (USING_GLES2 (context)) {
guint j = 8;
while (j >= n_gl_bytes) {
/* GST_ROUND_UP_j(gl_mem->width * n_gl_bytes) */
guint round_up_j = ((gl_mem->width * n_gl_bytes) + j - 1) & ~(j - 1);
if (round_up_j == gl_mem->stride) {
GST_CAT_LOG (GST_CAT_GL_MEMORY, "Found alignment of %u based on width "
"(with plane width:%u, plane stride:%u and pixel stride:%u. "
"RU%u(%u*%u) = %u)", j, gl_mem->width, gl_mem->stride, n_gl_bytes,
j, gl_mem->width, n_gl_bytes, round_up_j);
unpack_length = j;
break;
}
j >>= 1;
}
if (j < n_gl_bytes) {
/* Failed to find a suitable alignment, try based on plane_stride and
* scale in the shader. Useful for alignments that are greater than 8.
*/
j = 8;
while (j >= n_gl_bytes) {
/* GST_ROUND_UP_j(gl_mem->stride) */
guint round_up_j = ((gl_mem->stride) + j - 1) & ~(j - 1);
if (round_up_j == gl_mem->stride) {
GST_CAT_LOG (GST_CAT_GL_MEMORY, "Found alignment of %u based on "
"stride (with plane stride:%u and pixel stride:%u. "
"RU%u(%u) = %u)", j, gl_mem->stride, n_gl_bytes, j,
gl_mem->stride, round_up_j);
unpack_length = j;
gl_mem->tex_scaling[0] =
(gfloat) (gl_mem->width * n_gl_bytes) / (gfloat) gl_mem->stride;
break;
}
j >>= 1;
}
if (j < n_gl_bytes) {
GST_CAT_ERROR
(GST_CAT_GL_MEMORY, "Failed to find matching alignment. Image may "
"look corrupted. plane width:%u, plane stride:%u and pixel "
"stride:%u", gl_mem->width, gl_mem->stride, n_gl_bytes);
}
}
}
#endif
#if GST_GL_HAVE_OPENGL || GST_GL_HAVE_GLES3
if (USING_OPENGL (context) || USING_GLES3 (context)) {
gl->PixelStorei (GL_UNPACK_ROW_LENGTH, unpack_length);
}
#endif
#if GST_GL_HAVE_GLES2
if (USING_GLES2 (context)) {
gl->PixelStorei (GL_UNPACK_ALIGNMENT, unpack_length);
}
#endif
GST_CAT_LOG (GST_CAT_GL_MEMORY, "upload for texture id:%u, %ux%u",
gl_mem->tex_id, gl_mem->width, gl_mem->height);
gl->BindTexture (GL_TEXTURE_2D, gl_mem->tex_id);
gl->TexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, gl_mem->width, gl_mem->height,
gl_format, gl_type, gl_mem->data);
/* Reset to default values */
#if GST_GL_HAVE_OPENGL || GST_GL_HAVE_GLES3
if (USING_OPENGL (context) || USING_GLES3 (context)) {
gl->PixelStorei (GL_UNPACK_ROW_LENGTH, 0);
}
#endif
#if GST_GL_HAVE_GLES2
if (USING_GLES2 (context)) {
gl->PixelStorei (GL_UNPACK_ALIGNMENT, 4);
}
#endif
gl->BindTexture (GL_TEXTURE_2D, 0);
GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
}
static void
_download_memory (GstGLContext * context, GstGLMemory * gl_mem)
{
const GstGLFuncs *gl;
guint format, type;
GLuint fboId;
gl = context->gl_vtable;
format = _gst_gl_format_from_gl_texture_type (gl_mem->tex_type);
type = GL_UNSIGNED_BYTE;
if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
type = GL_UNSIGNED_SHORT_5_6_5;
if (!gl->GenFramebuffers) {
gst_gl_context_set_error (context, "Cannot download GL texture "
"without support for Framebuffers");
goto error;
}
if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2
&& (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
|| gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA)) {
gst_gl_context_set_error (context, "Cannot download GL luminance/"
"luminance alpha textures");
goto error;
}
GST_CAT_LOG (GST_CAT_GL_MEMORY, "downloading memory %p, tex %u into %p",
gl_mem, gl_mem->tex_id, gl_mem->data);
if (gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
|| gl_mem->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA) {
gl->BindTexture (GL_TEXTURE_2D, gl_mem->tex_id);
gl->GetTexImage (GL_TEXTURE_2D, 0, format, type, gl_mem->data);
gl->BindTexture (GL_TEXTURE_2D, 0);
} else {
/* FIXME: try and avoid creating and destroying fbo's every download... */
/* create a framebuffer object */
gl->GenFramebuffers (1, &fboId);
gl->BindFramebuffer (GL_FRAMEBUFFER, fboId);
gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, gl_mem->tex_id, 0);
if (!gst_gl_context_check_framebuffer_status (context))
goto fbo_error;
gl->ReadPixels (0, 0, gl_mem->width, gl_mem->height, format, type,
gl_mem->data);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
fbo_error:
gl->DeleteFramebuffers (1, &fboId);
}
error:
return;
}
static void
_gl_mem_init (GstGLMemory * mem, GstAllocator * allocator, GstMemory * parent,
GstGLContext * context, GstVideoInfo * v_info, gpointer user_data,
GDestroyNotify notify)
GstGLContext * context, GstVideoGLTextureType tex_type, gint width,
gint height, gint stride, gpointer user_data, GDestroyNotify notify)
{
gsize maxsize;
maxsize = v_info->size;
maxsize = _gl_texture_type_n_bytes (tex_type) * stride * height;
gst_memory_init (GST_MEMORY_CAST (mem), GST_MEMORY_FLAG_NO_SHARE,
allocator, parent, maxsize, 0, 0, maxsize);
mem->context = gst_object_ref (context);
mem->gl_format = GL_RGBA;
mem->v_info = *v_info;
mem->tex_type = tex_type;
mem->width = width;
mem->height = height;
mem->stride = stride;
mem->notify = notify;
mem->user_data = user_data;
mem->wrapped = FALSE;
mem->upload = gst_gl_upload_new (context);
mem->download = gst_gl_download_new (context);
mem->data_wrapped = FALSE;
mem->texture_wrapped = FALSE;
GST_CAT_DEBUG (GST_CAT_GL_MEMORY, "new GL texture memory:%p format:%u "
"dimensions:%ux%u", mem, GST_VIDEO_INFO_FORMAT (v_info),
GST_VIDEO_INFO_WIDTH (v_info), GST_VIDEO_INFO_HEIGHT (v_info));
"dimensions:%ux%u", mem, tex_type, width, height);
}
static GstGLMemory *
_gl_mem_new (GstAllocator * allocator, GstMemory * parent,
GstGLContext * context, GstVideoInfo * v_info, gpointer user_data,
GDestroyNotify notify)
GstGLContext * context, GstVideoGLTextureType tex_type, gint width,
gint height, gint stride, gpointer user_data, GDestroyNotify notify)
{
GstGLMemory *mem;
GLuint tex_id;
GenTexture data = { 0, };
gst_gl_context_gen_texture (context, &tex_id,
GST_VIDEO_INFO_FORMAT (v_info), GST_VIDEO_INFO_WIDTH (v_info),
GST_VIDEO_INFO_HEIGHT (v_info));
if (!tex_id) {
data.width = width;
data.height = height;
data.gl_format = _gst_gl_format_from_gl_texture_type (tex_type);
data.gl_type = GL_UNSIGNED_BYTE;
if (tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
data.gl_type = GL_UNSIGNED_SHORT_5_6_5;
gst_gl_context_thread_add (context,
(GstGLContextThreadFunc) _generate_texture, &data);
if (!data.result) {
GST_CAT_WARNING (GST_CAT_GL_MEMORY,
"Could not create GL texture with context:%p", context);
}
GST_CAT_TRACE (GST_CAT_GL_MEMORY, "created texture %u", tex_id);
GST_CAT_TRACE (GST_CAT_GL_MEMORY, "created texture %u", data.result);
mem = g_slice_alloc (sizeof (GstGLMemory));
_gl_mem_init (mem, allocator, parent, context, v_info, user_data, notify);
_gl_mem_init (mem, allocator, parent, context, tex_type, width, height,
stride, user_data, notify);
mem->tex_id = tex_id;
mem->tex_id = data.result;
return mem;
}
@ -124,18 +519,9 @@ _gl_mem_map (GstGLMemory * gl_mem, gsize maxsize, GstMapFlags flags)
GST_CAT_TRACE (GST_CAT_GL_MEMORY, "mapping GL texture:%u for reading",
gl_mem->tex_id);
if (GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD)) {
if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem,
GST_GL_MEMORY_FLAG_UPLOAD_INITTED)) {
if (!gst_gl_upload_init_format (gl_mem->upload, &gl_mem->v_info,
&gl_mem->v_info)) {
goto error;
}
GST_GL_MEMORY_FLAG_SET (gl_mem, GST_GL_MEMORY_FLAG_UPLOAD_INITTED);
}
if (!gst_gl_upload_perform_with_memory (gl_mem->upload, gl_mem)) {
goto error;
}
gst_gl_context_thread_add (gl_mem->context,
(GstGLContextThreadFunc) _upload_memory, gl_mem);
GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
}
} else {
GST_CAT_TRACE (GST_CAT_GL_MEMORY, "mapping GL texture:%u for writing",
@ -149,20 +535,9 @@ _gl_mem_map (GstGLMemory * gl_mem, gsize maxsize, GstMapFlags flags)
"mapping GL texture:%u for reading from system memory",
gl_mem->tex_id);
if (GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_NEED_DOWNLOAD)) {
if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem,
GST_GL_MEMORY_FLAG_DOWNLOAD_INITTED)) {
if (!gst_gl_download_init_format (gl_mem->download,
GST_VIDEO_INFO_FORMAT (&gl_mem->v_info),
GST_VIDEO_INFO_WIDTH (&gl_mem->v_info),
GST_VIDEO_INFO_HEIGHT (&gl_mem->v_info))) {
goto error;
}
GST_GL_MEMORY_FLAG_SET (gl_mem, GST_GL_MEMORY_FLAG_DOWNLOAD_INITTED);
}
if (!gst_gl_download_perform_with_memory (gl_mem->download, gl_mem)) {
goto error;
}
gst_gl_context_thread_add (gl_mem->context,
(GstGLContextThreadFunc) _download_memory, gl_mem);
GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_DOWNLOAD);
}
} else {
GST_CAT_TRACE (GST_CAT_GL_MEMORY,
@ -175,11 +550,6 @@ _gl_mem_map (GstGLMemory * gl_mem, gsize maxsize, GstMapFlags flags)
gl_mem->map_flags = flags;
return data;
error:
{
return NULL;
}
}
static void
@ -199,24 +569,31 @@ _gl_mem_unmap (GstGLMemory * gl_mem)
static void
_gl_mem_copy_thread (GstGLContext * context, gpointer data)
{
const GstGLFuncs *gl;
GstGLMemoryCopyParams *copy_params;
GstGLMemory *src;
GLuint tex_id;
GLuint rboId, fboId;
gsize width, height;
GLuint gl_format;
GstVideoFormat v_format;
GstGLFuncs *gl;
guint tex_id;
GLuint fboId;
gsize out_width, out_height;
GLuint out_gl_format, out_gl_type;
GLuint in_gl_format, in_gl_type;
gsize in_size, out_size;
copy_params = (GstGLMemoryCopyParams *) data;
src = copy_params->src;
tex_id = copy_params->tex_id;
width = GST_VIDEO_INFO_WIDTH (&src->v_info);
height = GST_VIDEO_INFO_HEIGHT (&src->v_info);
v_format = GST_VIDEO_INFO_FORMAT (&src->v_info);
gl_format = src->gl_format;
out_width = copy_params->out_width;
out_height = copy_params->out_height;
gl = src->context->gl_vtable;
out_gl_format = _gst_gl_format_from_gl_texture_type (copy_params->out_format);
out_gl_type = GL_UNSIGNED_BYTE;
if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
out_gl_type = GL_UNSIGNED_SHORT_5_6_5;
in_gl_format = _gst_gl_format_from_gl_texture_type (src->tex_type);
in_gl_type = GL_UNSIGNED_BYTE;
if (src->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
in_gl_type = GL_UNSIGNED_SHORT_5_6_5;
if (!gl->GenFramebuffers) {
gst_gl_context_set_error (src->context,
@ -224,8 +601,32 @@ _gl_mem_copy_thread (GstGLContext * context, gpointer data)
goto error;
}
if (!tex_id)
gst_gl_context_gen_texture (src->context, &tex_id, v_format, width, height);
in_size = _gl_format_type_n_bytes (in_gl_format, in_gl_type) * src->width *
src->height;
out_size = _gl_format_type_n_bytes (out_gl_format, out_gl_type) * out_width *
out_height;
if (copy_params->respecify) {
if (in_size != out_size) {
GST_ERROR ("Cannot copy between textures with backing data of different"
"sizes. input %" G_GSIZE_FORMAT " output %" G_GSIZE_FORMAT, in_size,
out_size);
goto error;
}
}
if (!tex_id) {
GenTexture data = { 0, };
data.width = copy_params->out_width;
data.height = copy_params->out_height;
data.gl_format = out_gl_format;
data.gl_type = GL_UNSIGNED_BYTE;
if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16)
data.gl_type = GL_UNSIGNED_SHORT_5_6_5;
_generate_texture (context, &data);
tex_id = data.result;
}
if (!tex_id) {
GST_CAT_WARNING (GST_CAT_GL_MEMORY,
@ -240,44 +641,47 @@ _gl_mem_copy_thread (GstGLContext * context, gpointer data)
gl->GenFramebuffers (1, &fboId);
gl->BindFramebuffer (GL_FRAMEBUFFER, fboId);
/* create a renderbuffer object */
gl->GenRenderbuffers (1, &rboId);
gl->BindRenderbuffer (GL_RENDERBUFFER, rboId);
if (USING_OPENGL (src->context)) {
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width,
height);
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
width, height);
}
if (USING_GLES2 (src->context)) {
gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
width, height);
}
/* attach the renderbuffer to depth attachment point */
gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, rboId);
if (USING_OPENGL (src->context)) {
gl->FramebufferRenderbuffer (GL_FRAMEBUFFER,
GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rboId);
}
gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, src->tex_id, 0);
/* check FBO status */
if (!gst_gl_context_check_framebuffer_status (src->context))
goto fbo_error;
/* copy tex */
gl->BindTexture (GL_TEXTURE_2D, tex_id);
gl->CopyTexImage2D (GL_TEXTURE_2D, 0, gl_format, 0, 0, width, height, 0);
gl->BindTexture (GL_TEXTURE_2D, 0);
if (copy_params->respecify) {
if (!gl->GenBuffers) {
gst_gl_context_set_error (context, "Cannot reinterpret texture contents "
"without buffer objects");
gl->BindTexture (GL_TEXTURE_2D, 0);
goto fbo_error;
}
if (!src->pbo)
gl->GenBuffers (1, &src->pbo);
GST_TRACE ("copying texture data with size of %u*%u*%u",
_gl_format_type_n_bytes (in_gl_format, in_gl_type), src->width,
src->height);
/* copy tex */
gl->BindBuffer (GL_PIXEL_PACK_BUFFER, src->pbo);
gl->BufferData (GL_PIXEL_PACK_BUFFER, in_size, NULL, GL_STREAM_COPY);
gl->ReadPixels (0, 0, src->width, src->height, in_gl_format, in_gl_type, 0);
gl->BindBuffer (GL_PIXEL_PACK_BUFFER, 0);
gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, src->pbo);
gl->TexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, out_width, out_height,
out_gl_format, out_gl_type, 0);
gl->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
} else { /* different sizes */
gl->CopyTexImage2D (GL_TEXTURE_2D, 0, out_gl_format, 0, 0, out_width,
out_height, 0);
}
gl->BindTexture (GL_TEXTURE_2D, 0);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
gl->DeleteRenderbuffers (1, &rboId);
gl->DeleteFramebuffers (1, &fboId);
copy_params->tex_id = tex_id;
@ -288,7 +692,6 @@ _gl_mem_copy_thread (GstGLContext * context, gpointer data)
/* ERRORS */
fbo_error:
{
gl->DeleteRenderbuffers (1, &rboId);
gl->DeleteFramebuffers (1, &fboId);
copy_params->tex_id = 0;
@ -307,23 +710,28 @@ static GstMemory *
_gl_mem_copy (GstGLMemory * src, gssize offset, gssize size)
{
GstGLMemory *dest;
GstGLMemoryCopyParams copy_params;
if (GST_GL_MEMORY_FLAG_IS_SET (src, GST_GL_MEMORY_FLAG_NEED_UPLOAD)) {
dest = _gl_mem_new (src->mem.allocator, NULL, src->context, &src->v_info,
NULL, NULL);
dest = _gl_mem_new (src->mem.allocator, NULL, src->context, src->tex_type,
src->width, src->height, src->stride, NULL, NULL);
dest->data = g_malloc (src->mem.maxsize);
memcpy (dest->data, src->data, src->mem.maxsize);
GST_GL_MEMORY_FLAG_SET (dest, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
} else {
copy_params = (GstGLMemoryCopyParams) {
src, 0,};
GstGLMemoryCopyParams copy_params;
copy_params.src = src;
copy_params.tex_id = 0;
copy_params.out_format = src->tex_type;
copy_params.out_width = src->width;
copy_params.out_height = src->height;
copy_params.respecify = FALSE;
gst_gl_context_thread_add (src->context, _gl_mem_copy_thread, &copy_params);
dest = g_slice_alloc (sizeof (GstGLMemory));
_gl_mem_init (dest, src->mem.allocator, NULL, src->context, &src->v_info,
NULL, NULL);
_gl_mem_init (dest, src->mem.allocator, NULL, src->context, src->tex_type,
src->width, src->height, src->stride, NULL, NULL);
if (!copy_params.result) {
GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory");
@ -366,26 +774,35 @@ _gl_mem_alloc (GstAllocator * allocator, gsize size,
return NULL;
}
static void
_destroy_gl_objects (GstGLContext * context, GstGLMemory * gl_mem)
{
const GstGLFuncs *gl = context->gl_vtable;
if (gl_mem->tex_id && !gl_mem->texture_wrapped)
gl->DeleteTextures (1, &gl_mem->tex_id);
if (gl_mem->pbo)
gl->DeleteBuffers (1, &gl_mem->pbo);
}
static void
_gl_mem_free (GstAllocator * allocator, GstMemory * mem)
{
GstGLMemory *gl_mem = (GstGLMemory *) mem;
if (gl_mem->tex_id)
gst_gl_context_del_texture (gl_mem->context, &gl_mem->tex_id);
gst_object_unref (gl_mem->upload);
gst_object_unref (gl_mem->download);
gst_object_unref (gl_mem->context);
gst_gl_context_thread_add (gl_mem->context,
(GstGLContextThreadFunc) _destroy_gl_objects, gl_mem);
if (gl_mem->notify)
gl_mem->notify (gl_mem->user_data);
if (gl_mem->data && !gl_mem->wrapped) {
if (gl_mem->data && !gl_mem->data_wrapped) {
g_free (gl_mem->data);
gl_mem->data = NULL;
}
gst_object_unref (gl_mem->context);
g_slice_free (GstGLMemory, gl_mem);
}
@ -393,19 +810,39 @@ _gl_mem_free (GstAllocator * allocator, GstMemory * mem)
* gst_gl_memory_copy_into_texture:
* @gl_mem:a #GstGLMemory
* @tex_id:OpenGL texture id
* @tex_type: a #GstVIdeoGLTextureType
* @width: width of @tex_id
* @height: height of @tex_id
* @respecify: whether to copy the data or copy per texel
*
* Copies @gl_mem into the texture specfified by @tex_id. This assumes that
* @tex_id has the same dimensions as @gl_mem.
* Copies @gl_mem into the texture specfified by @tex_id. The format of @tex_id
* is specified by @tex_type, @width and @height.
*
* If @respecify is %TRUE, then the copy is performed in terms of the texture
* data. This is useful for splitting RGBA textures into RG or R textures or
* vice versa. The requirement for this to succeed is that the backing texture
* data must be the same size, i.e. say a RGBA8 texture is converted into a RG8
* texture, then the RG texture must have twice as many pixels available for
* output as the RGBA texture.
*
* Otherwise, if @respecify is %FALSE, then the copy is performed per texel
* using glCopyTexImage. See the OpenGL specification for details on the
* mappings between texture formats.
*
* Returns: Whether the copy suceeded
*/
gboolean
gst_gl_memory_copy_into_texture (GstGLMemory * gl_mem, guint tex_id)
gst_gl_memory_copy_into_texture (GstGLMemory * gl_mem, guint tex_id,
GstVideoGLTextureType tex_type, gint width, gint height, gboolean respecify)
{
GstGLMemoryCopyParams copy_params;
copy_params.src = gl_mem;
copy_params.tex_id = tex_id;
copy_params.out_format = tex_type;
copy_params.out_width = width;
copy_params.out_height = height;
copy_params.respecify = respecify;
gst_gl_context_thread_add (gl_mem->context, _gl_mem_copy_thread,
&copy_params);
@ -413,6 +850,31 @@ gst_gl_memory_copy_into_texture (GstGLMemory * gl_mem, guint tex_id)
return copy_params.result;
}
GstGLMemory *
gst_gl_memory_wrapped_texture (GstGLContext * context, guint texture_id,
GstVideoGLTextureType tex_type, gint width, gint height, gpointer user_data,
GDestroyNotify notify)
{
GstGLMemory *mem;
guint n_gl_bytes = _gl_texture_type_n_bytes (tex_type);
mem = g_slice_alloc (sizeof (GstGLMemory));
_gl_mem_init (mem, _gl_allocator, NULL, context, tex_type, width, height,
width * n_gl_bytes, NULL, NULL);
mem->tex_id = texture_id;
mem->texture_wrapped = TRUE;
mem->data = g_malloc (mem->mem.maxsize);
if (mem->data == NULL) {
gst_memory_unref ((GstMemory *) mem);
return NULL;
}
GST_GL_MEMORY_FLAG_SET (mem, GST_GL_MEMORY_FLAG_NEED_DOWNLOAD);
return mem;
}
/**
* gst_gl_memory_alloc:
* @context:a #GstGLContext
@ -422,11 +884,13 @@ gst_gl_memory_copy_into_texture (GstGLMemory * gl_mem, guint tex_id)
* from @context
*/
GstMemory *
gst_gl_memory_alloc (GstGLContext * context, GstVideoInfo * v_info)
gst_gl_memory_alloc (GstGLContext * context, GstVideoGLTextureType tex_type,
gint width, gint height, gint stride)
{
GstGLMemory *mem;
mem = _gl_mem_new (_gl_allocator, NULL, context, v_info, NULL, NULL);
mem = _gl_mem_new (_gl_allocator, NULL, context, tex_type, width, height,
stride, NULL, NULL);
mem->data = g_malloc (mem->mem.maxsize);
if (mem->data == NULL) {
@ -449,15 +913,17 @@ gst_gl_memory_alloc (GstGLContext * context, GstVideoInfo * v_info)
* from @context and contents specified by @data
*/
GstGLMemory *
gst_gl_memory_wrapped (GstGLContext * context, GstVideoInfo * v_info,
gpointer data, gpointer user_data, GDestroyNotify notify)
gst_gl_memory_wrapped (GstGLContext * context, GstVideoGLTextureType tex_type,
gint width, gint height, gint stride, gpointer data, gpointer user_data,
GDestroyNotify notify)
{
GstGLMemory *mem;
mem = _gl_mem_new (_gl_allocator, NULL, context, v_info, user_data, notify);
mem = _gl_mem_new (_gl_allocator, NULL, context, tex_type, width, height,
stride, user_data, notify);
mem->data = data;
mem->wrapped = TRUE;
mem->data_wrapped = TRUE;
GST_GL_MEMORY_FLAG_SET (mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
@ -523,3 +989,74 @@ gst_is_gl_memory (GstMemory * mem)
{
return mem != NULL && mem->allocator == _gl_allocator;
}
/**
* gst_gl_memory_setup_buffer:
* @context: a #GstGLContext
* @info: a #GstVideoInfo
* @buffer: a #GstBuffer
*
* Adds the required #GstGLMemory<!-- -->s with the correct configuration to
* @buffer based on @info.
*
* Returns: whether the memory's were sucessfully added.
*/
gboolean
gst_gl_memory_setup_buffer (GstGLContext * context, GstVideoInfo * info,
GstBuffer * buffer)
{
GstGLMemory *gl_mem[GST_VIDEO_MAX_PLANES] = { NULL, };
GstVideoGLTextureType tex_type;
guint n_mem, i;
n_mem = GST_VIDEO_INFO_N_PLANES (info);
for (i = 0; i < n_mem; i++) {
tex_type =
gst_gl_texture_type_from_format (GST_VIDEO_INFO_FORMAT (info), i);
gl_mem[i] =
(GstGLMemory *) gst_gl_memory_alloc (context, tex_type,
_get_plane_width (info, i), _get_plane_height (info, i),
GST_VIDEO_INFO_PLANE_STRIDE (info, i));
gst_buffer_append_memory (buffer, (GstMemory *) gl_mem[i]);
}
gst_buffer_add_video_meta_full (buffer, 0,
GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
GST_VIDEO_INFO_HEIGHT (info), n_mem, info->offset, info->stride);
return TRUE;
}
/**
* gst_gl_memory_setup_wrapped:
* @context: a #GstGLContext
* @info: a #GstVideoInfo
* @data: a list of per plane data pointers
* @textures: (transfer out): a list of #GstGLMemory
*
* Wraps per plane data pointer in @data into the corresponding entry in
* @textures based on @info.
*
* Returns: whether the memory's were sucessfully created.
*/
gboolean
gst_gl_memory_setup_wrapped (GstGLContext * context, GstVideoInfo * info,
gpointer data[GST_VIDEO_MAX_PLANES],
GstGLMemory * textures[GST_VIDEO_MAX_PLANES])
{
GstVideoGLTextureType tex_type;
gint i;
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
tex_type =
gst_gl_texture_type_from_format (GST_VIDEO_INFO_FORMAT (info), i);
textures[i] = (GstGLMemory *) gst_gl_memory_wrapped (context, tex_type,
_get_plane_width (info, i), _get_plane_height (info, i),
GST_VIDEO_INFO_PLANE_STRIDE (info, i), data[i], NULL, NULL);
}
return TRUE;
}

View file

@ -80,23 +80,25 @@ typedef enum
*/
struct _GstGLMemory
{
GstMemory mem;
GstMemory mem;
GstGLContext *context;
GLuint tex_id;
GstVideoInfo v_info;
GLenum gl_format;
GstGLDownload *download;
GstGLUpload *upload;
GstGLContext *context;
guint tex_id;
GstVideoGLTextureType tex_type;
gint width;
gint height;
gint stride;
gfloat tex_scaling[2];
/* <private> */
GstMapFlags map_flags;
gpointer data;
GstMapFlags map_flags;
gpointer data;
gboolean wrapped;
GDestroyNotify notify;
gpointer user_data;
gboolean data_wrapped;
gboolean texture_wrapped;
GDestroyNotify notify;
gpointer user_data;
guint pbo;
};
/**
@ -141,15 +143,31 @@ struct _GstGLMemory
*/
#define GST_GL_MEMORY_FLAG_UNSET(mem,flag) GST_MEMORY_FLAG_UNSET(mem,flag)
void gst_gl_memory_init (void);
void gst_gl_memory_init (void);
gboolean gst_is_gl_memory (GstMemory * mem);
GstMemory * gst_gl_memory_alloc (GstGLContext * context, GstVideoInfo * info);
GstMemory * gst_gl_memory_alloc (GstGLContext * context, GstVideoGLTextureType tex_type,
gint width, gint height, gint stride);
GstGLMemory * gst_gl_memory_wrapped (GstGLContext * context, GstVideoGLTextureType tex_type,
gint width, gint height, gint stride,
gpointer data, gpointer user_data,
GDestroyNotify notify);
GstGLMemory * gst_gl_memory_wrapped_texture (GstGLContext * context, guint texture_id,
GstVideoGLTextureType tex_type,
gint width, gint height,
gpointer user_data, GDestroyNotify notify);
GstGLMemory * gst_gl_memory_wrapped (GstGLContext * context, GstVideoInfo * info, gpointer data,
gpointer user_data, GDestroyNotify notify);
gboolean gst_gl_memory_copy_into_texture (GstGLMemory *gl_mem, guint tex_id,
GstVideoGLTextureType tex_type,
gint width, gint height, gboolean respecify);
gboolean gst_is_gl_memory (GstMemory * mem);
gboolean gst_gl_memory_copy_into_texture (GstGLMemory *gl_mem, guint tex_id);
gboolean gst_gl_memory_setup_buffer (GstGLContext * context, GstVideoInfo * info,
GstBuffer * buffer);
gboolean gst_gl_memory_setup_wrapped (GstGLContext * context, GstVideoInfo * info,
gpointer data[GST_VIDEO_MAX_PLANES],
GstGLMemory *textures[GST_VIDEO_MAX_PLANES]);
GstVideoGLTextureType gst_gl_texture_type_from_format (GstVideoFormat v_format, guint plane);
/**
* GstGLAllocator

View file

@ -1681,8 +1681,7 @@ gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf)
if (!pad->upload) {
pad->upload = gst_gl_upload_new (mix->context);
if (!gst_gl_upload_init_format (pad->upload, &pad->in_info,
&mix->out_info)) {
if (!gst_gl_upload_init_format (pad->upload, &pad->in_info)) {
GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s",
"Failed to init upload format"), (NULL));
res = FALSE;

View file

@ -43,9 +43,9 @@
#define USING_GLES2(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
#define USING_GLES3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES3)
static void _do_upload (GstGLContext * context, GstGLUpload * upload);
static gboolean _do_upload_fill (GstGLContext * context, GstGLUpload * upload);
static gboolean _do_upload_make (GstGLContext * context, GstGLUpload * upload);
static gboolean _upload_memory (GstGLUpload * upload);
//static gboolean _do_upload_fill (GstGLContext * context, GstGLUpload * upload);
//static gboolean _do_upload_make (GstGLContext * context, GstGLUpload * upload);
static void _init_upload (GstGLContext * context, GstGLUpload * upload);
//static gboolean _init_upload_fbo (GstGLContext * context, GstGLUpload * upload);
static gboolean _gst_gl_upload_perform_with_data_unlocked (GstGLUpload * upload,
@ -70,7 +70,6 @@ struct TexData
struct _GstGLUploadPrivate
{
int n_textures;
gboolean result;
struct TexData texture_info[GST_VIDEO_MAX_PLANES];
@ -142,6 +141,11 @@ gst_gl_upload_finalize (GObject * object)
gst_object_unref (upload->convert);
}
if (upload->out_tex) {
gst_memory_unref ((GstMemory *) upload->out_tex);
upload->out_tex = NULL;
}
if (upload->context) {
gst_object_unref (upload->context);
upload->context = NULL;
@ -163,7 +167,7 @@ _gst_gl_upload_init_format_unlocked (GstGLUpload * upload,
GST_VIDEO_FORMAT_ENCODED, FALSE);
if (upload->initted) {
return FALSE;
return TRUE;
}
upload->in_info = *in_info;
@ -171,7 +175,9 @@ _gst_gl_upload_init_format_unlocked (GstGLUpload * upload,
gst_gl_context_thread_add (upload->context,
(GstGLContextThreadFunc) _init_upload, upload);
return upload->priv->result;
upload->initted = upload->priv->result;
return upload->initted;
}
@ -185,8 +191,7 @@ _gst_gl_upload_init_format_unlocked (GstGLUpload * upload,
* Returns: whether the initialization was successful
*/
gboolean
gst_gl_upload_init_format (GstGLUpload * upload, GstVideoInfo * in_info,
GstVideoInfo * out_info)
gst_gl_upload_init_format (GstGLUpload * upload, GstVideoInfo * in_info)
{
gboolean ret;
@ -217,6 +222,7 @@ gst_gl_upload_perform_with_buffer (GstGLUpload * upload, GstBuffer * buffer,
GstMemory *mem;
GstVideoGLTextureUploadMeta *gl_tex_upload_meta;
guint texture_ids[] = { 0, 0, 0, 0 };
gint i;
g_return_val_if_fail (upload != NULL, FALSE);
g_return_val_if_fail (buffer != NULL, FALSE);
@ -227,24 +233,26 @@ gst_gl_upload_perform_with_buffer (GstGLUpload * upload, GstBuffer * buffer,
mem = gst_buffer_peek_memory (buffer, 0);
if (gst_is_gl_memory (mem)) {
if (!upload->out_tex)
upload->out_tex = (GstGLMemory *) gst_gl_memory_alloc (upload->context,
GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_INFO_WIDTH (&upload->in_info),
GST_VIDEO_INFO_HEIGHT (&upload->in_info),
GST_VIDEO_INFO_WIDTH (&upload->in_info));
GST_LOG_OBJECT (upload, "Attempting upload with GstGLMemory");
/* Assuming only one memory */
if (!gst_video_frame_map (&upload->priv->frame, &upload->in_info, buffer,
GST_MAP_READ | GST_MAP_GL)) {
GST_ERROR_OBJECT (upload, "Failed to map memory");
return FALSE;
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->in_info); i++) {
upload->in_tex[i] = (GstGLMemory *) gst_buffer_peek_memory (buffer, i);
}
*tex_id = *(guint *) upload->priv->frame.data[0];
_upload_memory (upload);
upload->priv->mapped = TRUE;
*tex_id = upload->out_tex->tex_id;
return TRUE;
}
if (!upload->priv->tex_id)
gst_gl_context_gen_texture (upload->context, &upload->priv->tex_id,
GST_VIDEO_INFO_FORMAT (&upload->in_info),
GST_VIDEO_INFO_WIDTH (&upload->in_info),
GST_VIDEO_FORMAT_RGBA, GST_VIDEO_INFO_WIDTH (&upload->in_info),
GST_VIDEO_INFO_HEIGHT (&upload->in_info));
/* GstVideoGLTextureUploadMeta */
@ -292,59 +300,6 @@ gst_gl_upload_release_buffer (GstGLUpload * upload)
gst_video_frame_unmap (&upload->priv->frame);
}
static gboolean
_upload_memory_unlocked (GstGLUpload * upload, GstGLMemory * gl_mem,
guint tex_id)
{
gpointer data[GST_VIDEO_MAX_PLANES];
guint i;
gboolean ret;
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->in_info); i++) {
data[i] = (guint8 *) gl_mem->data +
GST_VIDEO_INFO_PLANE_OFFSET (&upload->in_info, i);
}
ret = _gst_gl_upload_perform_with_data_unlocked (upload, tex_id, data);
if (ret && tex_id == gl_mem->tex_id)
GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
return ret;
}
/**
* gst_gl_upload_perform_with_memory:
* @upload: a #GstGLUpload
* @gl_mem: a #GstGLMemory
*
* Uploads the texture in @gl_mem
*
* Returns: whether the upload was successful
*/
gboolean
gst_gl_upload_perform_with_memory (GstGLUpload * upload, GstGLMemory * gl_mem)
{
gboolean ret;
g_return_val_if_fail (upload != NULL, FALSE);
if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_UPLOAD_INITTED)) {
gst_gl_upload_init_format (upload, &gl_mem->v_info, &gl_mem->v_info);
}
if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD))
return FALSE;
g_mutex_lock (&upload->lock);
ret = _upload_memory_unlocked (upload, gl_mem, gl_mem->tex_id);
g_mutex_unlock (&upload->lock);
return ret;
}
/*
* Uploads as a result of a call to gst_video_gl_texture_upload_meta_upload().
* i.e. provider of GstVideoGLTextureUploadMeta
@ -384,15 +339,13 @@ _do_upload_for_meta (GstGLUpload * upload, GstVideoGLTextureUploadMeta * meta)
mem = gst_buffer_peek_memory (upload->priv->buffer, 0);
if (gst_is_gl_memory (mem)) {
if (GST_GL_MEMORY_FLAG_IS_SET (mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD)) {
ret = _upload_memory_unlocked (upload, (GstGLMemory *) mem,
upload->out_texture);
} else {
ret = gst_gl_memory_copy_into_texture ((GstGLMemory *) mem,
upload->out_texture);
}
GstGLMemory *gl_mem = (GstGLMemory *) mem;
if (ret)
upload->in_tex[0] = gl_mem;
_upload_memory (upload);
upload->in_tex[0] = NULL;
if (upload->priv->result)
return TRUE;
}
@ -408,14 +361,11 @@ _do_upload_for_meta (GstGLUpload * upload, GstVideoGLTextureUploadMeta * meta)
return FALSE;
}
ret = _gst_gl_upload_perform_with_data_unlocked (upload, upload->out_texture,
frame.data);
ret = _gst_gl_upload_perform_with_data_unlocked (upload,
upload->out_tex->tex_id, frame.data);
gst_video_frame_unmap (&frame);
if (ret)
return TRUE;
return ret;
}
@ -470,7 +420,10 @@ gst_gl_upload_perform_with_gl_texture_upload_meta (GstGLUpload * upload,
g_mutex_lock (&upload->lock);
upload->priv->meta = meta;
upload->priv->tex_id = texture_id[0];
if (!upload->priv->tex_id)
gst_gl_context_gen_texture (upload->context, &upload->priv->tex_id,
GST_VIDEO_FORMAT_RGBA, GST_VIDEO_INFO_WIDTH (&upload->in_info),
GST_VIDEO_INFO_HEIGHT (&upload->in_info));
GST_LOG ("Uploading with GLTextureUploadMeta with textures %i,%i,%i,%i",
texture_id[0], texture_id[1], texture_id[2], texture_id[3]);
@ -499,13 +452,19 @@ _gst_gl_upload_perform_for_gl_texture_upload_meta (GstVideoGLTextureUploadMeta *
g_mutex_lock (&upload->lock);
upload->out_texture = texture_id[0];
upload->out_tex = gst_gl_memory_wrapped_texture (upload->context,
texture_id[0], GST_VIDEO_GL_TEXTURE_TYPE_RGBA,
GST_VIDEO_INFO_WIDTH (&upload->in_info),
GST_VIDEO_INFO_HEIGHT (&upload->in_info), NULL, NULL);;
GST_LOG ("Uploading for meta with textures %i,%i,%i,%i", texture_id[0],
texture_id[1], texture_id[2], texture_id[3]);
ret = _do_upload_for_meta (upload, meta);
gst_memory_unref ((GstMemory *) upload->out_tex);
upload->out_tex = NULL;
g_mutex_unlock (&upload->lock);
return ret;
@ -524,15 +483,21 @@ gboolean
gst_gl_upload_add_video_gl_texture_upload_meta (GstGLUpload * upload,
GstBuffer * buffer)
{
GstVideoGLTextureType texture_types[] =
{ GST_VIDEO_GL_TEXTURE_TYPE_RGBA, 0, 0, 0 };
GstVideoGLTextureType texture_types[GST_VIDEO_MAX_PLANES];
GstVideoMeta *v_meta;
gint i;
g_return_val_if_fail (upload != NULL, FALSE);
g_return_val_if_fail (buffer != NULL, FALSE);
g_return_val_if_fail (gst_buffer_n_memory (buffer) == 1, FALSE);
v_meta = gst_buffer_get_video_meta (buffer);
g_return_val_if_fail (v_meta != NULL, FALSE);
upload->priv->buffer = buffer;
for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
texture_types[i] = gst_gl_texture_type_from_format (v_meta->format, i);
}
gst_buffer_add_video_gl_texture_upload_meta (buffer,
GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL, 1, texture_types,
_gst_gl_upload_perform_for_gl_texture_upload_meta,
@ -562,8 +527,15 @@ gst_gl_upload_perform_with_data (GstGLUpload * upload, GLuint texture_id,
g_mutex_lock (&upload->lock);
upload->out_tex = gst_gl_memory_wrapped_texture (upload->context, texture_id,
GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_INFO_WIDTH (&upload->in_info),
GST_VIDEO_INFO_HEIGHT (&upload->in_info), NULL, NULL);
ret = _gst_gl_upload_perform_with_data_unlocked (upload, texture_id, data);
gst_memory_unref ((GstMemory *) upload->out_tex);
upload->out_tex = NULL;
g_mutex_unlock (&upload->lock);
return ret;
@ -578,17 +550,19 @@ _gst_gl_upload_perform_with_data_unlocked (GstGLUpload * upload,
g_return_val_if_fail (upload != NULL, FALSE);
g_return_val_if_fail (texture_id > 0, FALSE);
upload->out_texture = texture_id;
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->in_info); i++) {
upload->data[i] = data[i];
}
gst_gl_memory_setup_wrapped (upload->context, &upload->in_info, data,
upload->in_tex);
GST_LOG ("Uploading data into texture %u", texture_id);
gst_gl_context_thread_add (upload->context,
(GstGLContextThreadFunc) _do_upload, upload);
_upload_memory (upload);
return TRUE;
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->in_info); i++) {
gst_memory_unref ((GstMemory *) upload->in_tex[i]);
upload->in_tex[i] = NULL;
}
return upload->priv->result;
}
/* Called in the gl thread */
@ -612,48 +586,12 @@ _init_upload (GstGLContext * context, GstGLUpload * upload)
goto error;
}
gst_video_info_set_format (&out_info, GST_VIDEO_FORMAT_RGBA, GST_VIDEO_INFO_WIDTH (&upload->in_info), GST_VIDEO_INFO_HEIGHT (&upload->in_info));
gst_video_info_set_format (&out_info, GST_VIDEO_FORMAT_RGBA,
GST_VIDEO_INFO_WIDTH (&upload->in_info),
GST_VIDEO_INFO_HEIGHT (&upload->in_info));
if (!gst_gl_color_convert_init_format (upload->convert, upload->in_info, out_info))
goto error;
switch (v_format) {
case GST_VIDEO_FORMAT_RGB:
case GST_VIDEO_FORMAT_BGR:
case GST_VIDEO_FORMAT_RGB16:
case GST_VIDEO_FORMAT_RGBx:
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_xRGB:
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_xBGR:
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_GRAY8:
case GST_VIDEO_FORMAT_GRAY16_BE:
case GST_VIDEO_FORMAT_GRAY16_LE:
case GST_VIDEO_FORMAT_AYUV:
upload->priv->n_textures = 1;
break;
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_NV21:
upload->priv->n_textures = 2;
break;
case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_Y41B:
upload->priv->n_textures = 3;
break;
default:
g_assert_not_reached ();
break;
}
if (!_do_upload_make (context, upload))
if (!gst_gl_color_convert_init_format (upload->convert, upload->in_info,
out_info))
goto error;
upload->priv->result = TRUE;
@ -663,309 +601,40 @@ error:
upload->priv->result = FALSE;
}
/* Called by the idle function in the gl thread */
void
_do_upload (GstGLContext * context, GstGLUpload * upload)
static gboolean
_upload_memory (GstGLUpload * upload)
{
guint in_width, in_height;
guint out_texture[] = {upload->out_texture, 0, 0, 0};
guint in_texture[GST_VIDEO_MAX_PLANES];
GstGLMemory *out_texture[GST_VIDEO_MAX_PLANES] = {upload->out_tex, 0, 0, 0};
GstMapInfo map_infos[GST_VIDEO_MAX_PLANES];
gboolean res = TRUE;
gint i;
in_width = GST_VIDEO_INFO_WIDTH (&upload->in_info);
in_height = GST_VIDEO_INFO_HEIGHT (&upload->in_info);
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->in_info); i++) {
if (!gst_memory_map ((GstMemory *) upload->in_tex[i], &map_infos[i],
GST_MAP_READ | GST_MAP_GL)) {
gst_gl_context_set_error (upload->context, "Failed to map GL memory %u", i);
res = FALSE;
goto out;
}
in_texture[i] = upload->in_tex[i]->tex_id;
}
GST_TRACE ("uploading to texture:%u with textures:%u,%u,%u dimensions:%ux%u",
upload->out_texture, upload->in_texture[0], upload->in_texture[1],
upload->in_texture[2], in_width, in_height);
out_texture[0]->tex_id, in_texture[0], in_texture[1], in_texture[2],
in_width, in_height);
if (!_do_upload_fill (context, upload))
goto error;
gst_gl_color_convert_perform (upload->convert, upload->in_tex, out_texture);
gst_gl_color_convert_perform (upload->convert, upload->in_texture, out_texture);
upload->priv->result = TRUE;
return;
error:
{
upload->priv->result = FALSE;
return;
out:
for (i--; i >= 0; i--) {
gst_memory_unmap ((GstMemory *) upload->in_tex[i], &map_infos[i]);
}
}
static inline guint
_gl_format_n_components (GLenum format)
{
switch (format) {
case GL_RGBA:
return 4;
case GL_RGB:
return 3;
case GL_LUMINANCE_ALPHA:
return 2;
case GL_LUMINANCE:
return 1;
default:
return 1;
}
}
/* called by gst_gl_context_thread_do_upload (in the gl thread) */
gboolean
_do_upload_make (GstGLContext * context, GstGLUpload * upload)
{
GstGLFuncs *gl;
GstVideoFormat v_format;
guint in_height;
struct TexData *tex = upload->priv->texture_info;
gfloat tex_scaling[GST_VIDEO_MAX_PLANES][2];
guint i;
gl = context->gl_vtable;
in_height = GST_VIDEO_INFO_HEIGHT (&upload->in_info);
v_format = GST_VIDEO_INFO_FORMAT (&upload->in_info);
switch (v_format) {
case GST_VIDEO_FORMAT_RGBx:
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_xRGB:
case GST_VIDEO_FORMAT_xBGR:
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_AYUV:
tex[0].format = GL_RGBA;
tex[0].type = GL_UNSIGNED_BYTE;
tex[0].height = in_height;
break;
case GST_VIDEO_FORMAT_RGB:
case GST_VIDEO_FORMAT_BGR:
tex[0].format = GL_RGB;
tex[0].type = GL_UNSIGNED_BYTE;
tex[0].height = in_height;
break;
case GST_VIDEO_FORMAT_GRAY8:
tex[0].format = GL_LUMINANCE;
tex[0].type = GL_UNSIGNED_BYTE;
tex[0].height = in_height;
break;
case GST_VIDEO_FORMAT_GRAY16_BE:
case GST_VIDEO_FORMAT_GRAY16_LE:
tex[0].format = GL_LUMINANCE_ALPHA;
tex[0].type = GL_UNSIGNED_BYTE;
tex[0].height = in_height;
break;
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
tex[0].format = GL_LUMINANCE_ALPHA;
tex[0].type = GL_UNSIGNED_BYTE;
tex[0].height = in_height;
tex[1].format = GL_RGBA;
tex[1].type = GL_UNSIGNED_BYTE;
tex[1].height = in_height;
break;
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_NV21:
tex[0].format = GL_LUMINANCE;
tex[0].type = GL_UNSIGNED_BYTE;
tex[0].height = in_height;
tex[1].format = GL_LUMINANCE_ALPHA;
tex[1].type = GL_UNSIGNED_BYTE;
tex[1].height = GST_ROUND_UP_2 (in_height) / 2;
break;
case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_Y41B:
tex[0].format = GL_LUMINANCE;
tex[0].type = GL_UNSIGNED_BYTE;
tex[0].height = in_height;
tex[1].format = GL_LUMINANCE;
tex[1].type = GL_UNSIGNED_BYTE;
tex[1].height = in_height;
tex[2].format = GL_LUMINANCE;
tex[2].type = GL_UNSIGNED_BYTE;
tex[2].height = in_height;
break;
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
tex[0].format = GL_LUMINANCE;
tex[0].type = GL_UNSIGNED_BYTE;
tex[0].height = in_height;
tex[1].format = GL_LUMINANCE;
tex[1].type = GL_UNSIGNED_BYTE;
tex[1].height = GST_ROUND_UP_2 (in_height) / 2;
tex[2].format = GL_LUMINANCE;
tex[2].type = GL_UNSIGNED_BYTE;
tex[2].height = GST_ROUND_UP_2 (in_height) / 2;
break;
default:
gst_gl_context_set_error (context, "Unsupported upload video format %d",
v_format);
g_assert_not_reached ();
break;
}
for (i = 0; i < upload->priv->n_textures; i++) {
guint plane_stride, plane_width;
if (GST_VIDEO_INFO_IS_YUV (&upload->in_info))
/* For now component width and plane width are the same and the
* plane-component mapping matches
*/
plane_width = GST_VIDEO_INFO_COMP_WIDTH (&upload->in_info, i);
else /* RGB, GRAY */
plane_width = GST_VIDEO_INFO_WIDTH (&upload->in_info);
plane_stride = GST_VIDEO_INFO_PLANE_STRIDE (&upload->in_info, i);
/* YUV interleaved packed formats require special attention as we upload
* multiple textures from the same plane.
*/
if (v_format == GST_VIDEO_FORMAT_YUY2 || v_format == GST_VIDEO_FORMAT_UYVY) {
if (i == 1)
plane_stride = GST_VIDEO_INFO_COMP_STRIDE (&upload->in_info, 1);
}
tex[i].width = plane_width;
tex_scaling[i][0] = 1.0f;
tex_scaling[i][1] = 1.0f;
#if GST_GL_HAVE_OPENGL || GST_GL_HAVE_GLES3
if (USING_OPENGL (context) || USING_GLES3 (context)) {
guint n_gl_comps = _gl_format_n_components (tex[i].format);
tex[i].unpack_length = plane_stride / n_gl_comps;
}
#endif
#if GST_GL_HAVE_GLES2
if (USING_GLES2 (context)) {
guint pstride, n_planes;
guint j = 8;
pstride = GST_VIDEO_INFO_COMP_PSTRIDE (&upload->in_info, i);
n_planes = GST_VIDEO_INFO_N_PLANES (&upload->in_info);
while (j >= pstride) {
/* GST_ROUND_UP_j(plane_width * pstride) */
guint round_up_j = ((plane_width * pstride) + j - 1) & ~(j - 1);
if (round_up_j == plane_stride) {
GST_LOG ("Found alignment of %u for plane %u based on width (with "
"plane width:%u, plane stride:%u and pixel stride:%u. "
"RU%u(%u*%u) = %u)", j, i, plane_width, plane_stride, pstride,
j, plane_width, pstride, round_up_j);
tex[i].unpack_length = j;
break;
}
j >>= 1;
}
if (j < pstride) {
/* Failed to find a suitable alignment, try based on plane_stride and
* scale in the shader. Useful for alignments that are greater than 8.
*/
j = 8;
while (j >= n_planes) {
/* GST_ROUND_UP_j(plane_stride) */
guint round_up_j = ((plane_stride) + j - 1) & ~(j - 1);
if (round_up_j == plane_stride) {
GST_LOG ("Found alignment of %u for plane %u based on stride "
"(with plane stride:%u and pixel stride:%u. RU%u(%u) = %u)",
j, i, plane_stride, pstride, j, plane_stride, round_up_j);
tex[i].unpack_length = j;
tex_scaling[i][0] =
(gfloat) (plane_width * pstride) / (gfloat) plane_stride;
break;
}
j >>= 1;
}
if (j < n_planes) {
GST_ERROR
("Failed to find matching alignment for plane %u, Image may "
"look corrupted. plane width:%u, plane stride:%u and pixel "
"stride:%u", i, plane_width, plane_stride, pstride);
}
}
}
#endif
gl->GenTextures (1, &upload->in_texture[i]);
gl->BindTexture (GL_TEXTURE_2D, upload->in_texture[i]);
gl->TexImage2D (GL_TEXTURE_2D, 0, tex[i].format,
tex[i].width, tex[i].height, 0, tex[i].format, tex[i].type, NULL);
}
gst_gl_color_convert_set_texture_scaling (upload->convert, tex_scaling);
return TRUE;
}
/* called by gst_gl_context_thread_do_upload (in the gl thread) */
gboolean
_do_upload_fill (GstGLContext * context, GstGLUpload * upload)
{
guint i;
GstVideoFormat v_format;
struct TexData *tex = upload->priv->texture_info;
const GstGLFuncs *gl = context->gl_vtable;
v_format = GST_VIDEO_INFO_FORMAT (&upload->in_info);
for (i = 0; i < upload->priv->n_textures; i++) {
guint data_i = i;
/* upload from the same plane */
if (v_format == GST_VIDEO_FORMAT_YUY2 || v_format == GST_VIDEO_FORMAT_UYVY)
data_i = 0;
/* YV12 is the same as I420 except that planes 1+2 are swapped */
if (v_format == GST_VIDEO_FORMAT_YV12) {
if (i == 1)
data_i = 2;
else if (i == 2)
data_i = 1;
}
#if GST_GL_HAVE_OPENGL || GST_GL_HAVE_GLES3
if (USING_OPENGL (context) || USING_GLES3 (context)) {
gl->PixelStorei (GL_UNPACK_ROW_LENGTH, tex[i].unpack_length);
}
#endif
#if GST_GL_HAVE_GLES2
if (USING_GLES2 (context)) {
gl->PixelStorei (GL_UNPACK_ALIGNMENT, tex[i].unpack_length);
}
#endif
GST_LOG ("data transfer for texture no %u, id:%u, %ux%u %u", i,
upload->in_texture[i], tex[i].width, tex[i].height, data_i);
gl->BindTexture (GL_TEXTURE_2D, upload->in_texture[i]);
gl->TexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, tex[i].width, tex[i].height,
tex[i].format, tex[i].type, upload->data[data_i]);
}
/* Reset to default values */
#if GST_GL_HAVE_OPENGL || GST_GL_HAVE_GLES3
if (USING_OPENGL (context) || USING_GLES3 (context)) {
gl->PixelStorei (GL_UNPACK_ROW_LENGTH, 0);
}
#endif
#if GST_GL_HAVE_GLES2
if (USING_GLES2 (context)) {
gl->PixelStorei (GL_UNPACK_ALIGNMENT, 4);
}
#endif
/* make sure no texture is in use in our opengl context
* in case we want to use the upload texture in an other opengl context
*/
gl->BindTexture (GL_TEXTURE_2D, 0);
return TRUE;
return res;
}

View file

@ -54,11 +54,10 @@ struct _GstGLUpload
/* input data */
GstVideoInfo in_info;
gpointer data[GST_VIDEO_MAX_PLANES];
gboolean initted;
GLuint in_texture[GST_VIDEO_MAX_PLANES];
GLuint out_texture;
GstGLMemory *in_tex[GST_VIDEO_MAX_PLANES];
GstGLMemory *out_tex;
/* <private> */
GstGLUploadPrivate *priv;
@ -78,13 +77,12 @@ struct _GstGLUploadClass
GstGLUpload * gst_gl_upload_new (GstGLContext * context);
gboolean gst_gl_upload_init_format (GstGLUpload * upload, GstVideoInfo * in_info, GstVideoInfo * out_info);
gboolean gst_gl_upload_init_format (GstGLUpload * upload, GstVideoInfo * in_info);
gboolean gst_gl_upload_add_video_gl_texture_upload_meta (GstGLUpload * upload, GstBuffer * buffer);
gboolean gst_gl_upload_perform_with_buffer (GstGLUpload * upload, GstBuffer * buffer, guint * tex_id);
void gst_gl_upload_release_buffer (GstGLUpload * upload);
gboolean gst_gl_upload_perform_with_memory (GstGLUpload * upload, GstGLMemory * gl_mem);
gboolean gst_gl_upload_perform_with_data (GstGLUpload * upload, GLuint texture_id,
gpointer data[GST_VIDEO_MAX_PLANES]);

View file

@ -54,33 +54,29 @@ GST_START_TEST (test_basic)
GstMemory *mem, *mem2;
GstGLMemory *gl_mem, *gl_mem2;
GstAllocator *gl_allocator;
GstVideoInfo vinfo;
gint i;
static GstVideoFormat formats[15] = {
GST_VIDEO_FORMAT_RGBx, GST_VIDEO_FORMAT_BGRx, GST_VIDEO_FORMAT_xRGB,
GST_VIDEO_FORMAT_xBGR, GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FORMAT_BGRA,
GST_VIDEO_FORMAT_ARGB, GST_VIDEO_FORMAT_ABGR, GST_VIDEO_FORMAT_RGB,
GST_VIDEO_FORMAT_BGR, GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_UYVY,
GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_AYUV,
static GstVideoGLTextureType formats[] = {
GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA,
GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
};
for (i = 0; i < G_N_ELEMENTS (formats); i++) {
gsize width = 320, height = 240;
gsize width = 320, height = 240, stride = 324;
gst_video_info_set_format (&vinfo, formats[i], width, height);
gl_allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR);
fail_if (gl_allocator == NULL);
/* test allocator creation */
ASSERT_WARNING (mem = gst_allocator_alloc (gl_allocator, 0, NULL););
mem = gst_gl_memory_alloc (context, &vinfo);
mem = gst_gl_memory_alloc (context, formats[i], width, height, stride);
fail_if (mem == NULL);
gl_mem = (GstGLMemory *) mem;
/* test init params */
fail_if (GST_VIDEO_INFO_WIDTH (&gl_mem->v_info) != width);
fail_if (GST_VIDEO_INFO_HEIGHT (&gl_mem->v_info) != height);
fail_if (GST_VIDEO_INFO_FORMAT (&gl_mem->v_info) != formats[i]);
fail_if (gl_mem->width != width);
fail_if (gl_mem->height != height);
fail_if (gl_mem->stride != stride);
fail_if (gl_mem->context != context);
fail_if (gl_mem->tex_id == 0);
@ -91,15 +87,10 @@ GST_START_TEST (test_basic)
/* test params */
fail_if (gl_mem->tex_id == gl_mem2->tex_id);
fail_if (GST_VIDEO_INFO_FORMAT (&gl_mem->v_info) !=
GST_VIDEO_INFO_FORMAT (&gl_mem2->v_info));
fail_if (GST_VIDEO_INFO_WIDTH (&gl_mem->v_info) !=
GST_VIDEO_INFO_WIDTH (&gl_mem2->v_info));
fail_if (GST_VIDEO_INFO_HEIGHT (&gl_mem->v_info) !=
GST_VIDEO_INFO_HEIGHT (&gl_mem2->v_info));
fail_if (gl_mem->gl_format != gl_mem->gl_format);
fail_if (gl_mem->context != gl_mem->context);
fail_if (gl_mem->tex_id == 0);
fail_if (gl_mem->tex_type != gl_mem2->tex_type);
fail_if (gl_mem->width != gl_mem2->width);
fail_if (gl_mem->stride != gl_mem2->stride);
fail_if (gl_mem->context != gl_mem2->context);
if (gst_gl_context_get_error ())
printf ("%s\n", gst_gl_context_get_error ());

View file

@ -65,7 +65,7 @@ static GLint shader_attr_texture_loc;
#endif
#define FORMAT GST_VIDEO_FORMAT_RGBA
#define FORMAT GST_VIDEO_GL_TEXTURE_TYPE_RGBA
#define WIDTH 10
#define HEIGHT 10
#define RED 0xff, 0x00, 0x00, 0xff
@ -161,7 +161,7 @@ draw_render (gpointer data)
1.0f, 1.0f
};
gl->Viewport (0, 0, 320, 240);
gl->Viewport (0, 0, 10, 10);
gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -241,7 +241,7 @@ GST_START_TEST (test_shader_compile)
gst_video_info_set_format (&info, v_format, 320, 240);
res = gst_gl_upload_init_format (upload, &info, &info);
res = gst_gl_upload_init_format (upload, &info);
fail_if (res == FALSE, "Failed to init upload for video format %s\n",
formats[i]);
@ -256,16 +256,15 @@ GST_START_TEST (test_upload_data)
{
gpointer data[GST_VIDEO_MAX_PLANES] = { rgba_data, NULL, NULL, NULL };
GstVideoInfo in_info;
GstVideoInfo out_info;
gboolean res;
gint i = 0;
gst_video_info_set_format (&in_info, FORMAT, WIDTH, HEIGHT);
gst_video_info_set_format (&out_info, FORMAT, WIDTH, HEIGHT);
gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, WIDTH, HEIGHT);
gst_gl_context_gen_texture (context, &tex_id, FORMAT, WIDTH, HEIGHT);
gst_gl_context_gen_texture (context, &tex_id, GST_VIDEO_FORMAT_RGBA, WIDTH,
HEIGHT);
gst_gl_upload_init_format (upload, &in_info, &out_info);
gst_gl_upload_init_format (upload, &in_info);
res = gst_gl_upload_perform_with_data (upload, tex_id, data);
fail_if (res == FALSE, "Failed to upload buffer: %s\n",
@ -286,57 +285,23 @@ GST_START_TEST (test_upload_data)
GST_END_TEST;
GST_START_TEST (test_upload_memory)
{
GstGLMemory *gl_mem;
GstVideoInfo in_info;
GstVideoInfo out_info;
gboolean res;
gint i = 0;
gst_video_info_set_format (&in_info, FORMAT, WIDTH, HEIGHT);
gst_video_info_set_format (&out_info, FORMAT, WIDTH, HEIGHT);
gl_mem = gst_gl_memory_wrapped (context, &in_info, rgba_data, NULL, NULL);
gst_gl_upload_init_format (upload, &in_info, &out_info);
res = gst_gl_upload_perform_with_memory (upload, gl_mem);
fail_if (res == FALSE, "Failed to upload GstGLMemory: %s\n",
gst_gl_context_get_error ());
tex_id = gl_mem->tex_id;
gst_gl_window_draw (window, WIDTH, HEIGHT);
gst_gl_window_send_message (window, GST_GL_WINDOW_CB (init), context);
while (i < 2) {
gst_gl_window_send_message (window, GST_GL_WINDOW_CB (draw_render),
context);
i++;
}
}
GST_END_TEST;
GST_START_TEST (test_upload_buffer)
{
GstBuffer *buffer;
GstGLMemory *gl_mem;
GstVideoInfo in_info;
GstVideoInfo out_info;
gint i = 0;
gboolean res;
gst_video_info_set_format (&in_info, FORMAT, WIDTH, HEIGHT);
gst_video_info_set_format (&out_info, FORMAT, WIDTH, HEIGHT);
gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, WIDTH, HEIGHT);
/* create GL buffer */
buffer = gst_buffer_new ();
gl_mem = gst_gl_memory_wrapped (context, &in_info, rgba_data, NULL, NULL);
gl_mem = gst_gl_memory_wrapped (context, FORMAT, WIDTH, HEIGHT, WIDTH * 4,
rgba_data, NULL, NULL);
gst_buffer_append_memory (buffer, (GstMemory *) gl_mem);
gst_gl_upload_init_format (upload, &in_info, &out_info);
gst_gl_upload_init_format (upload, &in_info);
res = gst_gl_upload_perform_with_buffer (upload, buffer, &tex_id);
fail_if (res == FALSE, "Failed to upload buffer: %s\n",
@ -352,6 +317,7 @@ GST_START_TEST (test_upload_buffer)
}
gst_gl_upload_release_buffer (upload);
gst_buffer_unref (buffer);
}
GST_END_TEST;
@ -361,23 +327,25 @@ GST_START_TEST (test_upload_meta_producer)
GstBuffer *buffer;
GstGLMemory *gl_mem;
GstVideoInfo in_info;
GstVideoInfo out_info;
GstVideoGLTextureUploadMeta *gl_upload_meta;
guint tex_ids[] = { 0, 0, 0, 0 };
gboolean res;
gint i = 0;
gst_video_info_set_format (&in_info, FORMAT, WIDTH, HEIGHT);
gst_video_info_set_format (&out_info, FORMAT, WIDTH, HEIGHT);
gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, WIDTH, HEIGHT);
/* create GL buffer */
buffer = gst_buffer_new ();
gl_mem = gst_gl_memory_wrapped (context, &in_info, rgba_data, NULL, NULL);
gl_mem = gst_gl_memory_wrapped (context, FORMAT, WIDTH, HEIGHT, WIDTH * 4,
rgba_data, NULL, NULL);
gst_buffer_append_memory (buffer, (GstMemory *) gl_mem);
gst_gl_context_gen_texture (context, &tex_ids[0], FORMAT, WIDTH, HEIGHT);
gst_gl_context_gen_texture (context, &tex_ids[0], GST_VIDEO_FORMAT_RGBA,
WIDTH, HEIGHT);
gst_gl_upload_init_format (upload, &in_info, &out_info);
gst_gl_upload_init_format (upload, &in_info);
gst_buffer_add_video_meta_full (buffer, 0, GST_VIDEO_FORMAT_RGBA, WIDTH,
HEIGHT, 1, in_info.offset, in_info.stride);
gst_gl_upload_add_video_gl_texture_upload_meta (upload, buffer);
gl_upload_meta = gst_buffer_get_video_gl_texture_upload_meta (buffer);
@ -413,7 +381,6 @@ gst_gl_upload_suite (void)
tcase_add_checked_fixture (tc_chain, setup, teardown);
tcase_add_test (tc_chain, test_shader_compile);
tcase_add_test (tc_chain, test_upload_data);
tcase_add_test (tc_chain, test_upload_memory);
tcase_add_test (tc_chain, test_upload_buffer);
tcase_add_test (tc_chain, test_upload_meta_producer);