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_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, "RGBA") "; " (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, "RGBA") "; "
#endif #endif
GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS) "; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, (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 enum
@ -438,8 +437,7 @@ _ensure_gl_setup (GstGLImageSink * gl_sink)
if (!gl_sink->upload) { if (!gl_sink->upload) {
gl_sink->upload = gst_gl_upload_new (gl_sink->context); gl_sink->upload = gst_gl_upload_new (gl_sink->context);
if (!gst_gl_upload_init_format (gl_sink->upload, &gl_sink->info, if (!gst_gl_upload_init_format (gl_sink->upload, &gl_sink->info))
&gl_sink->info))
goto upload_error; goto upload_error;
} }

View file

@ -50,6 +50,7 @@ struct _GstGLBufferPoolPrivate
GstCaps *caps; GstCaps *caps;
gint im_format; gint im_format;
GstVideoInfo info; GstVideoInfo info;
GstGLUpload *upload;
gboolean add_videometa; gboolean add_videometa;
#if GST_GL_HAVE_PLATFORM_EGL #if GST_GL_HAVE_PLATFORM_EGL
gboolean want_eglimage; 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); && g_strcmp0 (priv->allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0);
#endif #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); return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
/* ERRORS */ /* ERRORS */
@ -169,7 +176,6 @@ gst_gl_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
GstGLBufferPoolPrivate *priv = glpool->priv; GstGLBufferPoolPrivate *priv = glpool->priv;
GstVideoInfo *info; GstVideoInfo *info;
GstBuffer *buf; GstBuffer *buf;
GstMemory *gl_mem;
info = &priv->info; info = &priv->info;
@ -189,20 +195,10 @@ gst_gl_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
} }
#endif #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; goto mem_create_failed;
gst_buffer_append_memory (buf, gl_mem);
if (priv->add_videometa) { gst_gl_upload_add_video_gl_texture_upload_meta (glpool->priv->upload, buf);
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);
}
*buffer = buf; *buffer = buf;
@ -349,6 +345,9 @@ gst_gl_buffer_pool_finalize (GObject * object)
if (priv->caps) if (priv->caps)
gst_caps_unref (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); G_OBJECT_CLASS (gst_gl_buffer_pool_parent_class)->finalize (object);
/* only release the context once all our memory have been deleted */ /* 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, static gboolean _init_convert_fbo (GstGLContext * context,
GstGLColorConvert * convert); GstGLColorConvert * convert);
static gboolean _gst_gl_color_convert_perform_unlocked (GstGLColorConvert * static gboolean _gst_gl_color_convert_perform_unlocked (GstGLColorConvert *
convert, guint in_tex[GST_VIDEO_MAX_PLANES], convert, GstGLMemory * in_tex[GST_VIDEO_MAX_PLANES],
guint out_tex[GST_VIDEO_MAX_PLANES]); GstGLMemory * out_tex[GST_VIDEO_MAX_PLANES]);
static gboolean _do_convert_draw (GstGLContext * context, static gboolean _do_convert_draw (GstGLContext * context,
GstGLColorConvert * convert); GstGLColorConvert * convert);
@ -363,8 +363,8 @@ struct _GstGLColorConvertPrivate
struct ConvertInfo convert_info; struct ConvertInfo convert_info;
guint tex_id; GstGLMemory *scratch;
gboolean mapped; GstGLMemory *out_temp[GST_VIDEO_MAX_PLANES];
}; };
GST_DEBUG_CATEGORY_STATIC (gst_gl_color_convert_debug); GST_DEBUG_CATEGORY_STATIC (gst_gl_color_convert_debug);
@ -436,6 +436,11 @@ gst_gl_color_convert_finalize (GObject * object)
convert->shader = NULL; convert->shader = NULL;
} }
if (convert->priv->scratch) {
gst_memory_unref ((GstMemory *) convert->priv->scratch);
convert->priv->scratch = NULL;
}
if (convert->context) { if (convert->context) {
gst_object_unref (convert->context); gst_object_unref (convert->context);
convert->context = NULL; convert->context = NULL;
@ -457,7 +462,7 @@ _gst_gl_color_convert_init_format_unlocked (GstGLColorConvert * convert,
GST_VIDEO_FORMAT_ENCODED, FALSE); GST_VIDEO_FORMAT_ENCODED, FALSE);
if (convert->initted) { if (convert->initted) {
return FALSE; return TRUE;
} else { } else {
convert->initted = TRUE; convert->initted = TRUE;
} }
@ -508,7 +513,8 @@ gst_gl_color_convert_init_format (GstGLColorConvert * convert,
*/ */
gboolean gboolean
gst_gl_color_convert_perform (GstGLColorConvert * convert, 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; gboolean ret;
@ -547,7 +553,8 @@ gst_gl_color_convert_set_texture_scaling (GstGLColorConvert * convert,
static gboolean static gboolean
_gst_gl_color_convert_perform_unlocked (GstGLColorConvert * convert, _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 (convert != NULL, FALSE);
g_return_val_if_fail (in_tex, 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[2] = out_tex[2];
convert->out_tex[3] = out_tex[3]; 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)), gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)),
in_tex[0], in_tex[1], in_tex[2], in_tex[3], in_tex[0], in_tex[1], in_tex[2], in_tex[3],
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->out_info)), 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"; info->shader_tex_names[0] = "tex";
break; break;
case GST_VIDEO_FORMAT_I420: case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_Y444: case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y42B: case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_Y41B: 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[1] = "Utex";
info->shader_tex_names[2] = "Vtex"; info->shader_tex_names[2] = "Vtex";
break; 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: case GST_VIDEO_FORMAT_YUY2:
info->frag_prog = g_strdup_printf (frag_YUY2_UYVY_to_RGB, 'r', 'g', 'a', 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]); pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
info->in_n_textures = 2; info->in_n_textures = 1;
info->shader_tex_names[0] = "Ytex"; info->shader_tex_names[1] = "Ytex";
info->shader_tex_names[1] = "UVtex"; 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; break;
case GST_VIDEO_FORMAT_NV12: case GST_VIDEO_FORMAT_NV12:
info->frag_prog = g_strdup_printf (frag_NV12_NV21_to_RGB, 'r', 'a', 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: case GST_VIDEO_FORMAT_UYVY:
info->frag_prog = g_strdup_printf (frag_YUY2_UYVY_to_RGB, 'a', 'r', 'b', 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]); pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
info->in_n_textures = 2; info->in_n_textures = 1;
info->shader_tex_names[0] = "Ytex"; info->shader_tex_names[1] = "Ytex";
info->shader_tex_names[1] = "UVtex"; 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; break;
default: default:
break; break;
@ -1007,13 +1031,15 @@ _init_convert (GstGLContext * context, GstGLColorConvert * convert)
info->cms_coeff3); 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); gchar *scale_name = g_strdup_printf ("tex_scale%u", i);
gst_gl_shader_set_uniform_1i (convert->shader, info->shader_tex_names[i], if (info->shader_tex_names[i])
i); gst_gl_shader_set_uniform_1i (convert->shader, info->shader_tex_names[i],
gst_gl_shader_set_uniform_2fv (convert->shader, scale_name, 1, i);
info->shader_scaling[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); g_free (scale_name);
} }
@ -1135,29 +1161,43 @@ void
_do_convert (GstGLContext * context, GstGLColorConvert * convert) _do_convert (GstGLContext * context, GstGLColorConvert * convert)
{ {
guint in_width, in_height, out_width, out_height; 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_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info); out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
in_width = GST_VIDEO_INFO_WIDTH (&convert->in_info); in_width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
in_height = GST_VIDEO_INFO_HEIGHT (&convert->in_info); in_height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);
GST_TRACE ("converting to textures:%u,%u,%u,%u dimensions:%ux%u, " GST_TRACE ("converting to textures:%p,%p,%p,%p dimensions:%ux%u, "
"from textures:%u,%u,%u,%u dimensions:%ux%u", convert->out_tex[0], "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], convert->out_tex[1], convert->out_tex[2], convert->out_tex[3],
out_width, out_height, convert->in_tex[0], convert->in_tex[1], out_width, out_height, convert->in_tex[0], convert->in_tex[1],
convert->in_tex[2], convert->in_tex[3], in_width, in_height); convert->in_tex[2], convert->in_tex[3], in_width, in_height);
if (!convert->priv->draw (context, convert)) for (i = 0; i < c_info->in_n_textures; i++) {
goto error; gst_memory_map ((GstMemory *) convert->in_tex[i], &in_infos[i],
GST_MAP_READ | GST_MAP_GL);
convert->priv->result = TRUE;
return;
error:
{
convert->priv->result = FALSE;
return;
} }
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 static gboolean
@ -1191,15 +1231,35 @@ _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info); out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&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); gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo);
/* attach the texture to the FBO to renderer to */ /* attach the texture to the FBO to renderer to */
for (i = 0; i < c_info->out_n_textures; i++) { for (i = 0; i < c_info->out_n_textures; i++) {
/* needed? */ /* 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->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) 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_position_loc);
gl->EnableVertexAttribArray (convert->shader_attr_texture_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--) { for (i = c_info->in_n_textures - 1; i >= 0; i--) {
gl->ActiveTexture (GL_TEXTURE0 + 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_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_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 */ /* we are done with the shader */
gst_gl_context_clear_shader (context); 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); gst_gl_context_check_framebuffer_status (context);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0); gl->BindFramebuffer (GL_FRAMEBUFFER, 0);

View file

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

View file

@ -122,8 +122,8 @@ gst_gl_download_finalize (GObject * object)
for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) { for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
if (download->out_texture[i]) { if (download->out_texture[i]) {
gst_gl_context_del_texture (download->context, &download->out_texture[i]); gst_memory_unref ((GstMemory *) download->out_texture[i]);
download->out_texture[i] = 0; download->out_texture[i] = NULL;
} }
} }
@ -266,6 +266,8 @@ static gboolean
_gst_gl_download_perform_with_data_unlocked (GstGLDownload * download, _gst_gl_download_perform_with_data_unlocked (GstGLDownload * download,
GLuint texture_id, gpointer data[GST_VIDEO_MAX_PLANES]) GLuint texture_id, gpointer data[GST_VIDEO_MAX_PLANES])
{ {
gboolean realloc = FALSE;
gpointer temp_data;
guint i; guint i;
g_return_val_if_fail (download != NULL, FALSE); 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; download->in_texture = texture_id;
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&download->info); i++) { 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, gst_gl_context_thread_add (download->context,
@ -293,12 +314,10 @@ _gst_gl_download_perform_with_data_unlocked (GstGLDownload * download,
static void static void
_init_download (GstGLContext * context, GstGLDownload * download) _init_download (GstGLContext * context, GstGLDownload * download)
{ {
const GstGLFuncs *gl;
GstVideoFormat v_format; GstVideoFormat v_format;
guint out_width, out_height; guint out_width, out_height;
GstVideoInfo in_info; GstVideoInfo in_info;
gl = context->gl_vtable;
v_format = GST_VIDEO_INFO_FORMAT (&download->info); v_format = GST_VIDEO_INFO_FORMAT (&download->info);
out_width = GST_VIDEO_INFO_WIDTH (&download->info); out_width = GST_VIDEO_INFO_WIDTH (&download->info);
out_height = GST_VIDEO_INFO_HEIGHT (&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_TRACE ("initializing texture download for format %s",
gst_video_format_to_string (v_format)); 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, gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, out_width,
out_height); out_height);
@ -315,139 +344,37 @@ _init_download (GstGLContext * context, GstGLDownload * download)
if (!download->priv->result) if (!download->priv->result)
return; 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; download->priv->result = TRUE;
} }
static void static void
_do_download (GstGLContext * context, GstGLDownload * download) _do_download (GstGLContext * context, GstGLDownload * download)
{ {
GstGLFuncs *gl;
GstVideoFormat v_format;
guint out_width, out_height; guint out_width, out_height;
guint in_tex[] = { download->in_texture, 0, 0, 0 }; GstMapInfo map_info;
GstGLMemory *in_tex[GST_VIDEO_MAX_PLANES] = { 0, };
gl = context->gl_vtable; gint i;
out_width = GST_VIDEO_INFO_WIDTH (&download->info); out_width = GST_VIDEO_INFO_WIDTH (&download->info);
out_height = GST_VIDEO_INFO_HEIGHT (&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)", GST_TRACE ("doing YUV download of texture:%u (%ux%u)",
download->in_texture, out_width, out_height); 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 = download->priv->result =
gst_gl_color_convert_perform (download->convert, in_tex, gst_gl_color_convert_perform (download->convert, in_tex,
download->out_texture); download->out_texture);
if (!download->priv->result) if (!download->priv->result)
return; return;
gl->BindFramebuffer (GL_FRAMEBUFFER, download->convert->fbo); for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&download->info); i++) {
gl->ReadBuffer (GL_COLOR_ATTACHMENT0); gst_memory_map ((GstMemory *) download->out_texture[i], &map_info,
GST_MAP_READ);
switch (v_format) { gst_memory_unmap ((GstMemory *) download->out_texture[i], &map_info);
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 ();
} }
gst_gl_context_check_framebuffer_status (context); gst_memory_unref ((GstMemory *) in_tex[0]);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
} }

View file

@ -59,7 +59,7 @@ struct _GstGLDownload
/* used for the conversion */ /* used for the conversion */
GLuint in_texture; GLuint in_texture;
GLuint out_texture[GST_VIDEO_MAX_PLANES]; GstGLMemory * out_texture[GST_VIDEO_MAX_PLANES];
GstGLDownloadPrivate *priv; 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, GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE,
"RGBA") "; " "RGBA") "; "
#endif #endif
GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS) "; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, (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 = 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, GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE,
"RGBA") "; " "RGBA") "; "
#endif #endif
GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS) "; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "RGBA") "; "
"RGBA")) GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
); );
/* Properties */ /* Properties */
@ -964,8 +962,7 @@ gst_gl_filter_decide_allocation (GstBaseTransform * trans, GstQuery * query)
if (!filter->upload) { if (!filter->upload) {
filter->upload = gst_gl_upload_new (filter->context); filter->upload = gst_gl_upload_new (filter->context);
gst_gl_upload_init_format (filter->upload, &filter->in_info, gst_gl_upload_init_format (filter->upload, &filter->in_info);
&filter->out_info);
} }
//blocking call, generate a FBO //blocking call, generate a FBO
if (!gst_gl_context_gen_fbo (filter->context, out_width, out_height, 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->EnableVertexAttribArray (filter->draw_attr_texture_loc);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
gl->DisableVertexAttribArray (filter->draw_attr_position_loc);
gl->DisableVertexAttribArray (filter->draw_attr_texture_loc);
} }
#endif #endif
} }

View file

@ -55,59 +55,454 @@ static GstAllocator *_gl_allocator;
typedef struct typedef struct
{ {
/* in */
GstGLMemory *src; GstGLMemory *src;
GLuint tex_id; GstVideoGLTextureType out_format;
guint out_width, out_height;
gboolean respecify;
/* inout */
guint tex_id;
/* out */
gboolean result; gboolean result;
} GstGLMemoryCopyParams; } 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 static void
_gl_mem_init (GstGLMemory * mem, GstAllocator * allocator, GstMemory * parent, _gl_mem_init (GstGLMemory * mem, GstAllocator * allocator, GstMemory * parent,
GstGLContext * context, GstVideoInfo * v_info, gpointer user_data, GstGLContext * context, GstVideoGLTextureType tex_type, gint width,
GDestroyNotify notify) gint height, gint stride, gpointer user_data, GDestroyNotify notify)
{ {
gsize maxsize; 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, gst_memory_init (GST_MEMORY_CAST (mem), GST_MEMORY_FLAG_NO_SHARE,
allocator, parent, maxsize, 0, 0, maxsize); allocator, parent, maxsize, 0, 0, maxsize);
mem->context = gst_object_ref (context); mem->context = gst_object_ref (context);
mem->gl_format = GL_RGBA; mem->tex_type = tex_type;
mem->v_info = *v_info; mem->width = width;
mem->height = height;
mem->stride = stride;
mem->notify = notify; mem->notify = notify;
mem->user_data = user_data; mem->user_data = user_data;
mem->wrapped = FALSE; mem->data_wrapped = FALSE;
mem->upload = gst_gl_upload_new (context); mem->texture_wrapped = FALSE;
mem->download = gst_gl_download_new (context);
GST_CAT_DEBUG (GST_CAT_GL_MEMORY, "new GL texture memory:%p format:%u " GST_CAT_DEBUG (GST_CAT_GL_MEMORY, "new GL texture memory:%p format:%u "
"dimensions:%ux%u", mem, GST_VIDEO_INFO_FORMAT (v_info), "dimensions:%ux%u", mem, tex_type, width, height);
GST_VIDEO_INFO_WIDTH (v_info), GST_VIDEO_INFO_HEIGHT (v_info));
} }
static GstGLMemory * static GstGLMemory *
_gl_mem_new (GstAllocator * allocator, GstMemory * parent, _gl_mem_new (GstAllocator * allocator, GstMemory * parent,
GstGLContext * context, GstVideoInfo * v_info, gpointer user_data, GstGLContext * context, GstVideoGLTextureType tex_type, gint width,
GDestroyNotify notify) gint height, gint stride, gpointer user_data, GDestroyNotify notify)
{ {
GstGLMemory *mem; GstGLMemory *mem;
GLuint tex_id; GenTexture data = { 0, };
gst_gl_context_gen_texture (context, &tex_id, data.width = width;
GST_VIDEO_INFO_FORMAT (v_info), GST_VIDEO_INFO_WIDTH (v_info), data.height = height;
GST_VIDEO_INFO_HEIGHT (v_info)); data.gl_format = _gst_gl_format_from_gl_texture_type (tex_type);
if (!tex_id) { 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, GST_CAT_WARNING (GST_CAT_GL_MEMORY,
"Could not create GL texture with context:%p", context); "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)); 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; 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", GST_CAT_TRACE (GST_CAT_GL_MEMORY, "mapping GL texture:%u for reading",
gl_mem->tex_id); 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_NEED_UPLOAD)) {
if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem, gst_gl_context_thread_add (gl_mem->context,
GST_GL_MEMORY_FLAG_UPLOAD_INITTED)) { (GstGLContextThreadFunc) _upload_memory, gl_mem);
if (!gst_gl_upload_init_format (gl_mem->upload, &gl_mem->v_info, GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
&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;
}
} }
} else { } else {
GST_CAT_TRACE (GST_CAT_GL_MEMORY, "mapping GL texture:%u for writing", 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", "mapping GL texture:%u for reading from system memory",
gl_mem->tex_id); 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_NEED_DOWNLOAD)) {
if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem, gst_gl_context_thread_add (gl_mem->context,
GST_GL_MEMORY_FLAG_DOWNLOAD_INITTED)) { (GstGLContextThreadFunc) _download_memory, gl_mem);
if (!gst_gl_download_init_format (gl_mem->download, GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_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;
}
} }
} else { } else {
GST_CAT_TRACE (GST_CAT_GL_MEMORY, 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; gl_mem->map_flags = flags;
return data; return data;
error:
{
return NULL;
}
} }
static void static void
@ -199,24 +569,31 @@ _gl_mem_unmap (GstGLMemory * gl_mem)
static void static void
_gl_mem_copy_thread (GstGLContext * context, gpointer data) _gl_mem_copy_thread (GstGLContext * context, gpointer data)
{ {
const GstGLFuncs *gl;
GstGLMemoryCopyParams *copy_params; GstGLMemoryCopyParams *copy_params;
GstGLMemory *src; GstGLMemory *src;
GLuint tex_id; guint tex_id;
GLuint rboId, fboId; GLuint fboId;
gsize width, height; gsize out_width, out_height;
GLuint gl_format; GLuint out_gl_format, out_gl_type;
GstVideoFormat v_format; GLuint in_gl_format, in_gl_type;
GstGLFuncs *gl; gsize in_size, out_size;
copy_params = (GstGLMemoryCopyParams *) data; copy_params = (GstGLMemoryCopyParams *) data;
src = copy_params->src; src = copy_params->src;
tex_id = copy_params->tex_id; tex_id = copy_params->tex_id;
width = GST_VIDEO_INFO_WIDTH (&src->v_info); out_width = copy_params->out_width;
height = GST_VIDEO_INFO_HEIGHT (&src->v_info); out_height = copy_params->out_height;
v_format = GST_VIDEO_INFO_FORMAT (&src->v_info);
gl_format = src->gl_format;
gl = src->context->gl_vtable; 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) { if (!gl->GenFramebuffers) {
gst_gl_context_set_error (src->context, gst_gl_context_set_error (src->context,
@ -224,8 +601,32 @@ _gl_mem_copy_thread (GstGLContext * context, gpointer data)
goto error; goto error;
} }
if (!tex_id) in_size = _gl_format_type_n_bytes (in_gl_format, in_gl_type) * src->width *
gst_gl_context_gen_texture (src->context, &tex_id, v_format, width, height); 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) { if (!tex_id) {
GST_CAT_WARNING (GST_CAT_GL_MEMORY, GST_CAT_WARNING (GST_CAT_GL_MEMORY,
@ -240,44 +641,47 @@ _gl_mem_copy_thread (GstGLContext * context, gpointer data)
gl->GenFramebuffers (1, &fboId); gl->GenFramebuffers (1, &fboId);
gl->BindFramebuffer (GL_FRAMEBUFFER, 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->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, src->tex_id, 0); GL_TEXTURE_2D, src->tex_id, 0);
/* check FBO status */
if (!gst_gl_context_check_framebuffer_status (src->context)) if (!gst_gl_context_check_framebuffer_status (src->context))
goto fbo_error; goto fbo_error;
/* copy tex */
gl->BindTexture (GL_TEXTURE_2D, tex_id); gl->BindTexture (GL_TEXTURE_2D, tex_id);
gl->CopyTexImage2D (GL_TEXTURE_2D, 0, gl_format, 0, 0, width, height, 0); if (copy_params->respecify) {
gl->BindTexture (GL_TEXTURE_2D, 0); 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->BindFramebuffer (GL_FRAMEBUFFER, 0);
gl->DeleteRenderbuffers (1, &rboId);
gl->DeleteFramebuffers (1, &fboId); gl->DeleteFramebuffers (1, &fboId);
copy_params->tex_id = tex_id; copy_params->tex_id = tex_id;
@ -288,7 +692,6 @@ _gl_mem_copy_thread (GstGLContext * context, gpointer data)
/* ERRORS */ /* ERRORS */
fbo_error: fbo_error:
{ {
gl->DeleteRenderbuffers (1, &rboId);
gl->DeleteFramebuffers (1, &fboId); gl->DeleteFramebuffers (1, &fboId);
copy_params->tex_id = 0; copy_params->tex_id = 0;
@ -307,23 +710,28 @@ static GstMemory *
_gl_mem_copy (GstGLMemory * src, gssize offset, gssize size) _gl_mem_copy (GstGLMemory * src, gssize offset, gssize size)
{ {
GstGLMemory *dest; GstGLMemory *dest;
GstGLMemoryCopyParams copy_params;
if (GST_GL_MEMORY_FLAG_IS_SET (src, GST_GL_MEMORY_FLAG_NEED_UPLOAD)) { 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, dest = _gl_mem_new (src->mem.allocator, NULL, src->context, src->tex_type,
NULL, NULL); src->width, src->height, src->stride, NULL, NULL);
dest->data = g_malloc (src->mem.maxsize); dest->data = g_malloc (src->mem.maxsize);
memcpy (dest->data, src->data, src->mem.maxsize); memcpy (dest->data, src->data, src->mem.maxsize);
GST_GL_MEMORY_FLAG_SET (dest, GST_GL_MEMORY_FLAG_NEED_UPLOAD); GST_GL_MEMORY_FLAG_SET (dest, GST_GL_MEMORY_FLAG_NEED_UPLOAD);
} else { } else {
copy_params = (GstGLMemoryCopyParams) { GstGLMemoryCopyParams copy_params;
src, 0,};
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); gst_gl_context_thread_add (src->context, _gl_mem_copy_thread, &copy_params);
dest = g_slice_alloc (sizeof (GstGLMemory)); dest = g_slice_alloc (sizeof (GstGLMemory));
_gl_mem_init (dest, src->mem.allocator, NULL, src->context, &src->v_info, _gl_mem_init (dest, src->mem.allocator, NULL, src->context, src->tex_type,
NULL, NULL); src->width, src->height, src->stride, NULL, NULL);
if (!copy_params.result) { if (!copy_params.result) {
GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory"); 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; 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 static void
_gl_mem_free (GstAllocator * allocator, GstMemory * mem) _gl_mem_free (GstAllocator * allocator, GstMemory * mem)
{ {
GstGLMemory *gl_mem = (GstGLMemory *) mem; GstGLMemory *gl_mem = (GstGLMemory *) mem;
if (gl_mem->tex_id) gst_gl_context_thread_add (gl_mem->context,
gst_gl_context_del_texture (gl_mem->context, &gl_mem->tex_id); (GstGLContextThreadFunc) _destroy_gl_objects, gl_mem);
gst_object_unref (gl_mem->upload);
gst_object_unref (gl_mem->download);
gst_object_unref (gl_mem->context);
if (gl_mem->notify) if (gl_mem->notify)
gl_mem->notify (gl_mem->user_data); 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); g_free (gl_mem->data);
gl_mem->data = NULL; gl_mem->data = NULL;
} }
gst_object_unref (gl_mem->context);
g_slice_free (GstGLMemory, gl_mem); g_slice_free (GstGLMemory, gl_mem);
} }
@ -393,19 +810,39 @@ _gl_mem_free (GstAllocator * allocator, GstMemory * mem)
* gst_gl_memory_copy_into_texture: * gst_gl_memory_copy_into_texture:
* @gl_mem:a #GstGLMemory * @gl_mem:a #GstGLMemory
* @tex_id:OpenGL texture id * @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 * Copies @gl_mem into the texture specfified by @tex_id. The format of @tex_id
* @tex_id has the same dimensions as @gl_mem. * 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 * Returns: Whether the copy suceeded
*/ */
gboolean 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; GstGLMemoryCopyParams copy_params;
copy_params.src = gl_mem; copy_params.src = gl_mem;
copy_params.tex_id = tex_id; 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, gst_gl_context_thread_add (gl_mem->context, _gl_mem_copy_thread,
&copy_params); &copy_params);
@ -413,6 +850,31 @@ gst_gl_memory_copy_into_texture (GstGLMemory * gl_mem, guint tex_id)
return copy_params.result; 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: * gst_gl_memory_alloc:
* @context:a #GstGLContext * @context:a #GstGLContext
@ -422,11 +884,13 @@ gst_gl_memory_copy_into_texture (GstGLMemory * gl_mem, guint tex_id)
* from @context * from @context
*/ */
GstMemory * 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; 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); mem->data = g_malloc (mem->mem.maxsize);
if (mem->data == NULL) { if (mem->data == NULL) {
@ -449,15 +913,17 @@ gst_gl_memory_alloc (GstGLContext * context, GstVideoInfo * v_info)
* from @context and contents specified by @data * from @context and contents specified by @data
*/ */
GstGLMemory * GstGLMemory *
gst_gl_memory_wrapped (GstGLContext * context, GstVideoInfo * v_info, gst_gl_memory_wrapped (GstGLContext * context, GstVideoGLTextureType tex_type,
gpointer data, gpointer user_data, GDestroyNotify notify) gint width, gint height, gint stride, gpointer data, gpointer user_data,
GDestroyNotify notify)
{ {
GstGLMemory *mem; 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->data = data;
mem->wrapped = TRUE; mem->data_wrapped = TRUE;
GST_GL_MEMORY_FLAG_SET (mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD); 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; 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 struct _GstGLMemory
{ {
GstMemory mem; GstMemory mem;
GstGLContext *context; GstGLContext *context;
GLuint tex_id; guint tex_id;
GstVideoInfo v_info; GstVideoGLTextureType tex_type;
GLenum gl_format; gint width;
gint height;
GstGLDownload *download; gint stride;
GstGLUpload *upload; gfloat tex_scaling[2];
/* <private> */ /* <private> */
GstMapFlags map_flags; GstMapFlags map_flags;
gpointer data; gpointer data;
gboolean wrapped; gboolean data_wrapped;
GDestroyNotify notify; gboolean texture_wrapped;
gpointer user_data; 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) #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, gboolean gst_gl_memory_copy_into_texture (GstGLMemory *gl_mem, guint tex_id,
gpointer user_data, GDestroyNotify notify); GstVideoGLTextureType tex_type,
gint width, gint height, gboolean respecify);
gboolean gst_is_gl_memory (GstMemory * mem); gboolean gst_gl_memory_setup_buffer (GstGLContext * context, GstVideoInfo * info,
gboolean gst_gl_memory_copy_into_texture (GstGLMemory *gl_mem, guint tex_id); 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 * GstGLAllocator

View file

@ -1681,8 +1681,7 @@ gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf)
if (!pad->upload) { if (!pad->upload) {
pad->upload = gst_gl_upload_new (mix->context); pad->upload = gst_gl_upload_new (mix->context);
if (!gst_gl_upload_init_format (pad->upload, &pad->in_info, if (!gst_gl_upload_init_format (pad->upload, &pad->in_info)) {
&mix->out_info)) {
GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s",
"Failed to init upload format"), (NULL)); "Failed to init upload format"), (NULL));
res = FALSE; 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_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) #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 _upload_memory (GstGLUpload * upload);
static gboolean _do_upload_fill (GstGLContext * context, GstGLUpload * upload); //static gboolean _do_upload_fill (GstGLContext * context, GstGLUpload * upload);
static gboolean _do_upload_make (GstGLContext * context, GstGLUpload * upload); //static gboolean _do_upload_make (GstGLContext * context, GstGLUpload * upload);
static void _init_upload (GstGLContext * context, GstGLUpload * upload); static void _init_upload (GstGLContext * context, GstGLUpload * upload);
//static gboolean _init_upload_fbo (GstGLContext * context, GstGLUpload * upload); //static gboolean _init_upload_fbo (GstGLContext * context, GstGLUpload * upload);
static gboolean _gst_gl_upload_perform_with_data_unlocked (GstGLUpload * upload, static gboolean _gst_gl_upload_perform_with_data_unlocked (GstGLUpload * upload,
@ -70,7 +70,6 @@ struct TexData
struct _GstGLUploadPrivate struct _GstGLUploadPrivate
{ {
int n_textures;
gboolean result; gboolean result;
struct TexData texture_info[GST_VIDEO_MAX_PLANES]; struct TexData texture_info[GST_VIDEO_MAX_PLANES];
@ -142,6 +141,11 @@ gst_gl_upload_finalize (GObject * object)
gst_object_unref (upload->convert); gst_object_unref (upload->convert);
} }
if (upload->out_tex) {
gst_memory_unref ((GstMemory *) upload->out_tex);
upload->out_tex = NULL;
}
if (upload->context) { if (upload->context) {
gst_object_unref (upload->context); gst_object_unref (upload->context);
upload->context = NULL; upload->context = NULL;
@ -163,7 +167,7 @@ _gst_gl_upload_init_format_unlocked (GstGLUpload * upload,
GST_VIDEO_FORMAT_ENCODED, FALSE); GST_VIDEO_FORMAT_ENCODED, FALSE);
if (upload->initted) { if (upload->initted) {
return FALSE; return TRUE;
} }
upload->in_info = *in_info; upload->in_info = *in_info;
@ -171,7 +175,9 @@ _gst_gl_upload_init_format_unlocked (GstGLUpload * upload,
gst_gl_context_thread_add (upload->context, gst_gl_context_thread_add (upload->context,
(GstGLContextThreadFunc) _init_upload, upload); (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 * Returns: whether the initialization was successful
*/ */
gboolean gboolean
gst_gl_upload_init_format (GstGLUpload * upload, GstVideoInfo * in_info, gst_gl_upload_init_format (GstGLUpload * upload, GstVideoInfo * in_info)
GstVideoInfo * out_info)
{ {
gboolean ret; gboolean ret;
@ -217,6 +222,7 @@ gst_gl_upload_perform_with_buffer (GstGLUpload * upload, GstBuffer * buffer,
GstMemory *mem; GstMemory *mem;
GstVideoGLTextureUploadMeta *gl_tex_upload_meta; GstVideoGLTextureUploadMeta *gl_tex_upload_meta;
guint texture_ids[] = { 0, 0, 0, 0 }; guint texture_ids[] = { 0, 0, 0, 0 };
gint i;
g_return_val_if_fail (upload != NULL, FALSE); g_return_val_if_fail (upload != NULL, FALSE);
g_return_val_if_fail (buffer != 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); mem = gst_buffer_peek_memory (buffer, 0);
if (gst_is_gl_memory (mem)) { 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"); GST_LOG_OBJECT (upload, "Attempting upload with GstGLMemory");
/* Assuming only one memory */ for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->in_info); i++) {
if (!gst_video_frame_map (&upload->priv->frame, &upload->in_info, buffer, upload->in_tex[i] = (GstGLMemory *) gst_buffer_peek_memory (buffer, i);
GST_MAP_READ | GST_MAP_GL)) {
GST_ERROR_OBJECT (upload, "Failed to map memory");
return FALSE;
} }
*tex_id = *(guint *) upload->priv->frame.data[0]; _upload_memory (upload);
upload->priv->mapped = TRUE; *tex_id = upload->out_tex->tex_id;
return TRUE; return TRUE;
} }
if (!upload->priv->tex_id) if (!upload->priv->tex_id)
gst_gl_context_gen_texture (upload->context, &upload->priv->tex_id, gst_gl_context_gen_texture (upload->context, &upload->priv->tex_id,
GST_VIDEO_INFO_FORMAT (&upload->in_info), GST_VIDEO_FORMAT_RGBA, GST_VIDEO_INFO_WIDTH (&upload->in_info),
GST_VIDEO_INFO_WIDTH (&upload->in_info),
GST_VIDEO_INFO_HEIGHT (&upload->in_info)); GST_VIDEO_INFO_HEIGHT (&upload->in_info));
/* GstVideoGLTextureUploadMeta */ /* GstVideoGLTextureUploadMeta */
@ -292,59 +300,6 @@ gst_gl_upload_release_buffer (GstGLUpload * upload)
gst_video_frame_unmap (&upload->priv->frame); 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(). * Uploads as a result of a call to gst_video_gl_texture_upload_meta_upload().
* i.e. provider of GstVideoGLTextureUploadMeta * 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); mem = gst_buffer_peek_memory (upload->priv->buffer, 0);
if (gst_is_gl_memory (mem)) { if (gst_is_gl_memory (mem)) {
if (GST_GL_MEMORY_FLAG_IS_SET (mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD)) { GstGLMemory *gl_mem = (GstGLMemory *) mem;
ret = _upload_memory_unlocked (upload, (GstGLMemory *) mem,
upload->out_texture);
} else {
ret = gst_gl_memory_copy_into_texture ((GstGLMemory *) mem,
upload->out_texture);
}
if (ret) upload->in_tex[0] = gl_mem;
_upload_memory (upload);
upload->in_tex[0] = NULL;
if (upload->priv->result)
return TRUE; return TRUE;
} }
@ -408,14 +361,11 @@ _do_upload_for_meta (GstGLUpload * upload, GstVideoGLTextureUploadMeta * meta)
return FALSE; return FALSE;
} }
ret = _gst_gl_upload_perform_with_data_unlocked (upload, upload->out_texture, ret = _gst_gl_upload_perform_with_data_unlocked (upload,
frame.data); upload->out_tex->tex_id, frame.data);
gst_video_frame_unmap (&frame); gst_video_frame_unmap (&frame);
if (ret)
return TRUE;
return ret; return ret;
} }
@ -470,7 +420,10 @@ gst_gl_upload_perform_with_gl_texture_upload_meta (GstGLUpload * upload,
g_mutex_lock (&upload->lock); g_mutex_lock (&upload->lock);
upload->priv->meta = meta; 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", GST_LOG ("Uploading with GLTextureUploadMeta with textures %i,%i,%i,%i",
texture_id[0], texture_id[1], texture_id[2], texture_id[3]); 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); 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], GST_LOG ("Uploading for meta with textures %i,%i,%i,%i", texture_id[0],
texture_id[1], texture_id[2], texture_id[3]); texture_id[1], texture_id[2], texture_id[3]);
ret = _do_upload_for_meta (upload, meta); ret = _do_upload_for_meta (upload, meta);
gst_memory_unref ((GstMemory *) upload->out_tex);
upload->out_tex = NULL;
g_mutex_unlock (&upload->lock); g_mutex_unlock (&upload->lock);
return ret; return ret;
@ -524,15 +483,21 @@ gboolean
gst_gl_upload_add_video_gl_texture_upload_meta (GstGLUpload * upload, gst_gl_upload_add_video_gl_texture_upload_meta (GstGLUpload * upload,
GstBuffer * buffer) GstBuffer * buffer)
{ {
GstVideoGLTextureType texture_types[] = GstVideoGLTextureType texture_types[GST_VIDEO_MAX_PLANES];
{ GST_VIDEO_GL_TEXTURE_TYPE_RGBA, 0, 0, 0 }; GstVideoMeta *v_meta;
gint i;
g_return_val_if_fail (upload != NULL, FALSE); g_return_val_if_fail (upload != NULL, FALSE);
g_return_val_if_fail (buffer != 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; 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_buffer_add_video_gl_texture_upload_meta (buffer,
GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL, 1, texture_types, GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL, 1, texture_types,
_gst_gl_upload_perform_for_gl_texture_upload_meta, _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); 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); 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); g_mutex_unlock (&upload->lock);
return ret; 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 (upload != NULL, FALSE);
g_return_val_if_fail (texture_id > 0, FALSE); g_return_val_if_fail (texture_id > 0, FALSE);
upload->out_texture = texture_id; gst_gl_memory_setup_wrapped (upload->context, &upload->in_info, data,
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->in_info); i++) { upload->in_tex);
upload->data[i] = data[i];
}
GST_LOG ("Uploading data into texture %u", texture_id); GST_LOG ("Uploading data into texture %u", texture_id);
gst_gl_context_thread_add (upload->context, _upload_memory (upload);
(GstGLContextThreadFunc) _do_upload, 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 */ /* Called in the gl thread */
@ -612,48 +586,12 @@ _init_upload (GstGLContext * context, GstGLUpload * upload)
goto error; 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)) if (!gst_gl_color_convert_init_format (upload->convert, upload->in_info,
goto error; out_info))
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))
goto error; goto error;
upload->priv->result = TRUE; upload->priv->result = TRUE;
@ -663,309 +601,40 @@ error:
upload->priv->result = FALSE; upload->priv->result = FALSE;
} }
/* Called by the idle function in the gl thread */ static gboolean
void _upload_memory (GstGLUpload * upload)
_do_upload (GstGLContext * context, GstGLUpload * upload)
{ {
guint in_width, in_height; 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_width = GST_VIDEO_INFO_WIDTH (&upload->in_info);
in_height = GST_VIDEO_INFO_HEIGHT (&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", 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], out_texture[0]->tex_id, in_texture[0], in_texture[1], in_texture[2],
upload->in_texture[2], in_width, in_height); in_width, in_height);
if (!_do_upload_fill (context, upload)) gst_gl_color_convert_perform (upload->convert, upload->in_tex, out_texture);
goto error;
gst_gl_color_convert_perform (upload->convert, upload->in_texture, out_texture); out:
for (i--; i >= 0; i--) {
upload->priv->result = TRUE; gst_memory_unmap ((GstMemory *) upload->in_tex[i], &map_infos[i]);
return;
error:
{
upload->priv->result = FALSE;
return;
} }
}
return res;
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;
} }

View file

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

View file

@ -54,33 +54,29 @@ GST_START_TEST (test_basic)
GstMemory *mem, *mem2; GstMemory *mem, *mem2;
GstGLMemory *gl_mem, *gl_mem2; GstGLMemory *gl_mem, *gl_mem2;
GstAllocator *gl_allocator; GstAllocator *gl_allocator;
GstVideoInfo vinfo;
gint i; gint i;
static GstVideoFormat formats[15] = { static GstVideoGLTextureType formats[] = {
GST_VIDEO_FORMAT_RGBx, GST_VIDEO_FORMAT_BGRx, GST_VIDEO_FORMAT_xRGB, GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
GST_VIDEO_FORMAT_xBGR, GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FORMAT_BGRA, GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA,
GST_VIDEO_FORMAT_ARGB, GST_VIDEO_FORMAT_ABGR, GST_VIDEO_FORMAT_RGB, GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
GST_VIDEO_FORMAT_BGR, GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_UYVY,
GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_AYUV,
}; };
for (i = 0; i < G_N_ELEMENTS (formats); i++) { 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); gl_allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR);
fail_if (gl_allocator == NULL); fail_if (gl_allocator == NULL);
/* test allocator creation */ /* test allocator creation */
ASSERT_WARNING (mem = gst_allocator_alloc (gl_allocator, 0, NULL);); 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); fail_if (mem == NULL);
gl_mem = (GstGLMemory *) mem; gl_mem = (GstGLMemory *) mem;
/* test init params */ /* test init params */
fail_if (GST_VIDEO_INFO_WIDTH (&gl_mem->v_info) != width); fail_if (gl_mem->width != width);
fail_if (GST_VIDEO_INFO_HEIGHT (&gl_mem->v_info) != height); fail_if (gl_mem->height != height);
fail_if (GST_VIDEO_INFO_FORMAT (&gl_mem->v_info) != formats[i]); fail_if (gl_mem->stride != stride);
fail_if (gl_mem->context != context); fail_if (gl_mem->context != context);
fail_if (gl_mem->tex_id == 0); fail_if (gl_mem->tex_id == 0);
@ -91,15 +87,10 @@ GST_START_TEST (test_basic)
/* test params */ /* test params */
fail_if (gl_mem->tex_id == gl_mem2->tex_id); fail_if (gl_mem->tex_id == gl_mem2->tex_id);
fail_if (GST_VIDEO_INFO_FORMAT (&gl_mem->v_info) != fail_if (gl_mem->tex_type != gl_mem2->tex_type);
GST_VIDEO_INFO_FORMAT (&gl_mem2->v_info)); fail_if (gl_mem->width != gl_mem2->width);
fail_if (GST_VIDEO_INFO_WIDTH (&gl_mem->v_info) != fail_if (gl_mem->stride != gl_mem2->stride);
GST_VIDEO_INFO_WIDTH (&gl_mem2->v_info)); fail_if (gl_mem->context != gl_mem2->context);
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);
if (gst_gl_context_get_error ()) if (gst_gl_context_get_error ())
printf ("%s\n", 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 #endif
#define FORMAT GST_VIDEO_FORMAT_RGBA #define FORMAT GST_VIDEO_GL_TEXTURE_TYPE_RGBA
#define WIDTH 10 #define WIDTH 10
#define HEIGHT 10 #define HEIGHT 10
#define RED 0xff, 0x00, 0x00, 0xff #define RED 0xff, 0x00, 0x00, 0xff
@ -161,7 +161,7 @@ draw_render (gpointer data)
1.0f, 1.0f 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); 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); 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", fail_if (res == FALSE, "Failed to init upload for video format %s\n",
formats[i]); formats[i]);
@ -256,16 +256,15 @@ GST_START_TEST (test_upload_data)
{ {
gpointer data[GST_VIDEO_MAX_PLANES] = { rgba_data, NULL, NULL, NULL }; gpointer data[GST_VIDEO_MAX_PLANES] = { rgba_data, NULL, NULL, NULL };
GstVideoInfo in_info; GstVideoInfo in_info;
GstVideoInfo out_info;
gboolean res; gboolean res;
gint i = 0; gint i = 0;
gst_video_info_set_format (&in_info, FORMAT, WIDTH, HEIGHT); gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, WIDTH, HEIGHT);
gst_video_info_set_format (&out_info, FORMAT, 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); res = gst_gl_upload_perform_with_data (upload, tex_id, data);
fail_if (res == FALSE, "Failed to upload buffer: %s\n", fail_if (res == FALSE, "Failed to upload buffer: %s\n",
@ -286,57 +285,23 @@ GST_START_TEST (test_upload_data)
GST_END_TEST; 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) GST_START_TEST (test_upload_buffer)
{ {
GstBuffer *buffer; GstBuffer *buffer;
GstGLMemory *gl_mem; GstGLMemory *gl_mem;
GstVideoInfo in_info; GstVideoInfo in_info;
GstVideoInfo out_info;
gint i = 0; gint i = 0;
gboolean res; gboolean res;
gst_video_info_set_format (&in_info, FORMAT, WIDTH, HEIGHT); gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, WIDTH, HEIGHT);
gst_video_info_set_format (&out_info, FORMAT, WIDTH, HEIGHT);
/* create GL buffer */ /* create GL buffer */
buffer = gst_buffer_new (); 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_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); res = gst_gl_upload_perform_with_buffer (upload, buffer, &tex_id);
fail_if (res == FALSE, "Failed to upload buffer: %s\n", 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_gl_upload_release_buffer (upload);
gst_buffer_unref (buffer);
} }
GST_END_TEST; GST_END_TEST;
@ -361,23 +327,25 @@ GST_START_TEST (test_upload_meta_producer)
GstBuffer *buffer; GstBuffer *buffer;
GstGLMemory *gl_mem; GstGLMemory *gl_mem;
GstVideoInfo in_info; GstVideoInfo in_info;
GstVideoInfo out_info;
GstVideoGLTextureUploadMeta *gl_upload_meta; GstVideoGLTextureUploadMeta *gl_upload_meta;
guint tex_ids[] = { 0, 0, 0, 0 }; guint tex_ids[] = { 0, 0, 0, 0 };
gboolean res; gboolean res;
gint i = 0; gint i = 0;
gst_video_info_set_format (&in_info, FORMAT, WIDTH, HEIGHT); gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, WIDTH, HEIGHT);
gst_video_info_set_format (&out_info, FORMAT, WIDTH, HEIGHT);
/* create GL buffer */ /* create GL buffer */
buffer = gst_buffer_new (); 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_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); gst_gl_upload_add_video_gl_texture_upload_meta (upload, buffer);
gl_upload_meta = gst_buffer_get_video_gl_texture_upload_meta (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_checked_fixture (tc_chain, setup, teardown);
tcase_add_test (tc_chain, test_shader_compile); tcase_add_test (tc_chain, test_shader_compile);
tcase_add_test (tc_chain, test_upload_data); 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_buffer);
tcase_add_test (tc_chain, test_upload_meta_producer); tcase_add_test (tc_chain, test_upload_meta_producer);