gl: Add support for GstVideoAlignment

This allow saving a copy with libav video decoders or decoders with
similar padding requirement.

https://bugzilla.gnome.org/show_bug.cgi?id=740900
This commit is contained in:
Nicolas Dufresne 2014-12-19 12:11:08 -05:00 committed by Tim-Philipp Müller
parent 45ac36ca26
commit a1e02726ee
10 changed files with 138 additions and 55 deletions

View file

@ -638,7 +638,7 @@ gst_gl_overlay_load_jpeg (GstGLFilter * filter)
overlay->image_width, overlay->image_height);
overlay->image_memory =
(GstGLMemory *) gst_gl_memory_alloc (filter->context, &v_info, 0);
(GstGLMemory *) gst_gl_memory_alloc (filter->context, &v_info, 0, NULL);
if (!gst_memory_map ((GstMemory *) overlay->image_memory, &map_info,
GST_MAP_WRITE)) {
@ -740,7 +740,7 @@ gst_gl_overlay_load_png (GstGLFilter * filter)
gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_RGBA, width, height);
overlay->image_memory =
(GstGLMemory *) gst_gl_memory_alloc (filter->context, &v_info, 0);
(GstGLMemory *) gst_gl_memory_alloc (filter->context, &v_info, 0, NULL);
if (!gst_memory_map ((GstMemory *) overlay->image_memory, &map_info,
GST_MAP_WRITE)) {

View file

@ -24,6 +24,7 @@
#include "gl.h"
#include "gstglbufferpool.h"
#include "gstglutils.h"
#if GST_GL_HAVE_PLATFORM_EGL
#include <gst/gl/egl/gsteglimagememory.h>
@ -50,6 +51,7 @@ struct _GstGLBufferPoolPrivate
GstCaps *caps;
gint im_format;
GstVideoInfo info;
GstVideoAlignment valign;
gboolean add_videometa;
gboolean add_uploadmeta;
gboolean add_glsyncmeta;
@ -75,7 +77,9 @@ gst_gl_buffer_pool_get_options (GstBufferPool * pool)
{
static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META,
GST_BUFFER_POOL_OPTION_GL_SYNC_META, NULL
GST_BUFFER_POOL_OPTION_GL_SYNC_META,
GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT,
NULL
};
return options;
@ -88,11 +92,13 @@ gst_gl_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
GstGLBufferPoolPrivate *priv = glpool->priv;
GstVideoInfo info;
GstCaps *caps = NULL;
guint min_buffers, max_buffers;
GstAllocator *allocator = NULL;
GstAllocationParams alloc_params;
gboolean reset = TRUE;
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min_buffers,
&max_buffers))
goto wrong_config;
if (caps == NULL)
@ -145,6 +151,29 @@ gst_gl_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
priv->want_eglimage = FALSE;
#endif
if (gst_buffer_pool_config_has_option (config,
GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) {
gint p;
priv->add_videometa = TRUE;
gst_buffer_pool_config_get_video_alignment (config, &priv->valign);
gst_video_info_align (&priv->info, &priv->valign);
/* Recalulate the size as we don't add padding between planes. */
priv->info.size = 0;
for (p = 0; p < GST_VIDEO_INFO_N_PLANES (&priv->info); p++) {
priv->info.size +=
gst_gl_get_plane_data_size (&priv->info, &priv->valign, p);
}
gst_buffer_pool_config_set_video_alignment (config, &priv->valign);
gst_buffer_pool_config_set_params (config, caps, priv->info.size,
min_buffers, max_buffers);
} else {
gst_video_alignment_reset (&priv->valign);
}
if (reset) {
if (glpool->upload)
gst_object_unref (glpool->upload);
@ -152,6 +181,7 @@ gst_gl_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
glpool->upload = gst_gl_upload_meta_new (glpool->context);
}
return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
/* ERRORS */
@ -202,9 +232,11 @@ gst_gl_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
GstGLBufferPool *glpool = GST_GL_BUFFER_POOL_CAST (pool);
GstGLBufferPoolPrivate *priv = glpool->priv;
GstVideoInfo *info;
GstVideoAlignment *valign;
GstBuffer *buf;
info = &priv->info;
valign = &priv->valign;
if (!(buf = gst_buffer_new ())) {
goto no_buffer;
@ -222,7 +254,7 @@ gst_gl_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
}
#endif
if (!gst_gl_memory_setup_buffer (glpool->context, info, buf))
if (!gst_gl_memory_setup_buffer (glpool->context, info, valign, buf))
goto mem_create_failed;
if (priv->add_uploadmeta)

View file

@ -1334,7 +1334,7 @@ _do_convert (GstGLContext * context, GstGLColorConvert * convert)
convert->outbuf = gst_buffer_new ();
if (!gst_gl_memory_setup_buffer (convert->context, &convert->out_info,
convert->outbuf)) {
NULL, convert->outbuf)) {
convert->priv->result = FALSE;
return;
}
@ -1383,7 +1383,7 @@ _do_convert (GstGLContext * context, GstGLColorConvert * convert)
if (!convert->priv->out_tex[j])
convert->priv->out_tex[j] =
(GstGLMemory *) gst_gl_memory_alloc (context, &temp_info, 0);
(GstGLMemory *) gst_gl_memory_alloc (context, &temp_info, 0, NULL);
} else {
convert->priv->out_tex[j] = out_tex;
}

View file

@ -232,7 +232,7 @@ _gst_gl_download_perform_with_data_unlocked (GstGLDownload * download,
download->priv->in_tex[0] =
gst_gl_memory_wrapped_texture (download->context, texture_id,
&temp_info, 0, NULL, NULL);
&temp_info, 0, NULL, NULL, NULL);
}
download->priv->in_tex[0]->tex_id = texture_id;

View file

@ -27,6 +27,7 @@
#include <gst/video/video.h>
#include "gstglmemory.h"
#include "gstglutils.h"
/**
* SECTION:gstglmemory
@ -348,15 +349,6 @@ _get_plane_height (GstVideoInfo * info, guint plane)
return GST_VIDEO_INFO_HEIGHT (info);
}
static inline gsize
_get_plane_data_size (GstVideoInfo * info, guint plane)
{
if (GST_VIDEO_INFO_N_PLANES (info) == plane + 1)
return info->offset[0] + info->size - info->offset[plane];
return info->offset[plane + 1] - info->offset[plane];
}
typedef struct _GenTexture
{
guint width, height;
@ -575,14 +567,14 @@ error:
static void
_gl_mem_init (GstGLMemory * mem, GstAllocator * allocator, GstMemory * parent,
GstGLContext * context, GstVideoInfo * info, guint plane,
gpointer user_data, GDestroyNotify notify)
GstGLContext * context, GstVideoInfo * info, GstVideoAlignment * valign,
guint plane, gpointer user_data, GDestroyNotify notify)
{
gsize maxsize;
g_return_if_fail (plane < GST_VIDEO_INFO_N_PLANES (info));
maxsize = _get_plane_data_size (info, plane);
maxsize = gst_gl_get_plane_data_size (info, valign, plane);
gst_memory_init (GST_MEMORY_CAST (mem), GST_MEMORY_FLAG_NO_SHARE,
allocator, parent, maxsize, 0, 0, maxsize);
@ -598,6 +590,11 @@ _gl_mem_init (GstGLMemory * mem, GstAllocator * allocator, GstMemory * parent,
mem->data_wrapped = FALSE;
mem->texture_wrapped = FALSE;
if (valign)
mem->valign = *valign;
else
gst_video_alignment_reset (&mem->valign);
_calculate_unpack_length (mem);
GST_CAT_DEBUG (GST_CAT_GL_MEMORY, "new GL texture memory:%p format:%u "
@ -607,14 +604,14 @@ _gl_mem_init (GstGLMemory * mem, GstAllocator * allocator, GstMemory * parent,
static GstGLMemory *
_gl_mem_new (GstAllocator * allocator, GstMemory * parent,
GstGLContext * context, GstVideoInfo * info, guint plane,
gpointer user_data, GDestroyNotify notify)
GstGLContext * context, GstVideoInfo * info, GstVideoAlignment * valign,
guint plane, gpointer user_data, GDestroyNotify notify)
{
GstGLMemory *mem;
GenTexture data = { 0, };
mem = g_slice_new0 (GstGLMemory);
_gl_mem_init (mem, allocator, parent, context, info, plane, user_data,
notify);
_gl_mem_init (mem, allocator, parent, context, info, valign, plane,
user_data, notify);
data.width = mem->tex_width;
data.height = GL_MEM_HEIGHT (mem);
@ -849,7 +846,7 @@ _gl_mem_copy (GstGLMemory * src, gssize offset, gssize size)
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->info,
src->plane, NULL, NULL);
&src->valign, src->plane, NULL, NULL);
dest->data = g_try_malloc (src->mem.maxsize);
if (dest->data == NULL) {
GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory");
@ -873,7 +870,7 @@ _gl_mem_copy (GstGLMemory * src, gssize offset, gssize size)
dest = g_slice_new0 (GstGLMemory);
_gl_mem_init (dest, src->mem.allocator, NULL, src->context, &src->info,
src->plane, NULL, NULL);
&src->valign, src->plane, NULL, NULL);
if (!copy_params.result) {
GST_CAT_WARNING (GST_CAT_GL_MEMORY, "Could not copy GL Memory");
@ -997,14 +994,29 @@ gst_gl_memory_copy_into_texture (GstGLMemory * gl_mem, guint tex_id,
return copy_params.result;
}
/**
* gst_gl_memory_wrapped_texture:
* @context: a #GstGLContext
* @texture_id: the GL texture handle
* @info: the #GstVideoInfo of the memory
* @plane: The plane this memory will represent
* @user_data: user data
* @notify: Destroy callback for the user data
*
* Wraps a texture handle into a #GstGLMemory.
*
* Returns: a newly allocated #GstGLMemory
*/
GstGLMemory *
gst_gl_memory_wrapped_texture (GstGLContext * context, guint texture_id,
GstVideoInfo * info, guint plane, gpointer user_data, GDestroyNotify notify)
GstVideoInfo * info, guint plane, GstVideoAlignment * valign,
gpointer user_data, GDestroyNotify notify)
{
GstGLMemory *mem;
mem = g_slice_new0 (GstGLMemory);
_gl_mem_init (mem, _gl_allocator, NULL, context, info, plane, NULL, NULL);
_gl_mem_init (mem, _gl_allocator, NULL, context, info, valign, plane, NULL,
NULL);
mem->tex_id = texture_id;
mem->texture_wrapped = TRUE;
@ -1022,17 +1034,23 @@ gst_gl_memory_wrapped_texture (GstGLContext * context, guint texture_id,
/**
* gst_gl_memory_alloc:
* @context:a #GstGLContext
* @v_info: the #GstVideoInfo of the memory
* @info: the #GstVideoInfo of the memory
* @plane: the plane this memory will represent
* @valign: the #GstVideoAlignment applied to @info
*
* Returns: a #GstMemory object with a GL texture specified by @v_info
* Allocated a new #GstGlMemory.
*
* Returns: a #GstMemory object with a GL texture specified by @vinfo
* from @context
*/
GstMemory *
gst_gl_memory_alloc (GstGLContext * context, GstVideoInfo * info, guint plane)
gst_gl_memory_alloc (GstGLContext * context, GstVideoInfo * info,
guint plane, GstVideoAlignment * valign)
{
GstGLMemory *mem;
mem = _gl_mem_new (_gl_allocator, NULL, context, info, plane, NULL, NULL);
mem = _gl_mem_new (_gl_allocator, NULL, context, info, valign, plane, NULL,
NULL);
mem->data = g_try_malloc (mem->mem.maxsize);
if (mem->data == NULL) {
@ -1044,25 +1062,30 @@ gst_gl_memory_alloc (GstGLContext * context, GstVideoInfo * info, guint plane)
}
/**
* gst_gl_memory_wrapped
* gst_gl_memory_wrapped:
* @context:a #GstGLContext
* @v_info: the #GstVideoInfo of the memory and data
* @info: the #GstVideoInfo of the memory and data
* @plane: the plane this memory will represent
* @valign: the #GstVideoAlignment applied to @info
* @data: the data to wrap
* @user_data: data called with for @notify
* @notify: function called with @user_data when @data needs to be freed
*
* Wrapped @data into a #GstGLMemory. This version will account for padding
* added to the allocation and expressed through @valign.
*
* Returns: a #GstGLMemory object with a GL texture specified by @v_info
* from @context and contents specified by @data
*/
GstGLMemory *
gst_gl_memory_wrapped (GstGLContext * context, GstVideoInfo * info, guint plane,
gpointer data, gpointer user_data, GDestroyNotify notify)
gst_gl_memory_wrapped (GstGLContext * context, GstVideoInfo * info,
guint plane, GstVideoAlignment * valign, gpointer data, gpointer user_data,
GDestroyNotify notify)
{
GstGLMemory *mem;
mem =
_gl_mem_new (_gl_allocator, NULL, context, info, plane, user_data,
notify);
mem = _gl_mem_new (_gl_allocator, NULL, context, info, valign, plane,
user_data, notify);
mem->data = data;
mem->data_wrapped = TRUE;
@ -1152,16 +1175,17 @@ gst_is_gl_memory (GstMemory * mem)
* gst_gl_memory_setup_buffer:
* @context: a #GstGLContext
* @info: a #GstVideoInfo
* @valign: the #GstVideoAlignment applied to @info
* @buffer: a #GstBuffer
*
* Adds the required #GstGLMemory<!-- -->s with the correct configuration to
* @buffer based on @info.
* @buffer based on @info. This version handles padding through @valign.
*
* Returns: whether the memory's were sucessfully added.
*/
gboolean
gst_gl_memory_setup_buffer (GstGLContext * context, GstVideoInfo * info,
GstBuffer * buffer)
GstVideoAlignment * valign, GstBuffer * buffer)
{
GstGLMemory *gl_mem[GST_VIDEO_MAX_PLANES] = { NULL, };
guint n_mem, i;
@ -1169,7 +1193,7 @@ gst_gl_memory_setup_buffer (GstGLContext * context, GstVideoInfo * info,
n_mem = GST_VIDEO_INFO_N_PLANES (info);
for (i = 0; i < n_mem; i++) {
gl_mem[i] = (GstGLMemory *) gst_gl_memory_alloc (context, info, i);
gl_mem[i] = (GstGLMemory *) gst_gl_memory_alloc (context, info, i, valign);
if (gl_mem[i] == NULL)
return FALSE;
@ -1187,24 +1211,25 @@ gst_gl_memory_setup_buffer (GstGLContext * context, GstVideoInfo * info,
* gst_gl_memory_setup_wrapped:
* @context: a #GstGLContext
* @info: a #GstVideoInfo
* @valign: 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.
* @textures based on @info and padding from @valign.
*
* Returns: whether the memory's were sucessfully created.
*/
gboolean
gst_gl_memory_setup_wrapped (GstGLContext * context, GstVideoInfo * info,
gpointer data[GST_VIDEO_MAX_PLANES],
GstVideoAlignment * valign, gpointer data[GST_VIDEO_MAX_PLANES],
GstGLMemory * textures[GST_VIDEO_MAX_PLANES])
{
gint i;
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
textures[i] = (GstGLMemory *) gst_gl_memory_wrapped (context, info, i,
data[i], NULL, NULL);
valign, data[i], NULL, NULL);
}
return TRUE;

View file

@ -86,6 +86,7 @@ struct _GstGLMemory
guint tex_id;
GstVideoGLTextureType tex_type;
GstVideoInfo info;
GstVideoAlignment valign;
guint plane;
gfloat tex_scaling[2];
@ -150,11 +151,13 @@ struct _GstGLMemory
void gst_gl_memory_init (void);
gboolean gst_is_gl_memory (GstMemory * mem);
GstMemory * gst_gl_memory_alloc (GstGLContext * context, GstVideoInfo * info, guint plane);
GstMemory * gst_gl_memory_alloc (GstGLContext * context, GstVideoInfo * info, guint plane,
GstVideoAlignment *valign);
GstGLMemory * gst_gl_memory_wrapped (GstGLContext * context, GstVideoInfo * info, guint plane,
gpointer data, gpointer user_data, GDestroyNotify notify);
GstVideoAlignment *valign, gpointer data,
gpointer user_data, GDestroyNotify notify);
GstGLMemory * gst_gl_memory_wrapped_texture (GstGLContext * context, guint texture_id,
GstVideoInfo * info, guint plane,
GstVideoInfo * info, guint plane, GstVideoAlignment *valign,
gpointer user_data, GDestroyNotify notify);
gboolean gst_gl_memory_copy_into_texture (GstGLMemory *gl_mem, guint tex_id,
@ -162,9 +165,9 @@ gboolean gst_gl_memory_copy_into_texture (GstGLMemory *gl_mem, guint tex_id
gint width, gint height, gint stride,
gboolean respecify);
gboolean gst_gl_memory_setup_buffer (GstGLContext * context, GstVideoInfo * info,
gboolean gst_gl_memory_setup_buffer (GstGLContext * context, GstVideoInfo * info, GstVideoAlignment *valign,
GstBuffer * buffer);
gboolean gst_gl_memory_setup_wrapped (GstGLContext * context, GstVideoInfo * info,
gboolean gst_gl_memory_setup_wrapped (GstGLContext * context, GstVideoInfo * info, GstVideoAlignment *valign,
gpointer data[GST_VIDEO_MAX_PLANES],
GstGLMemory *textures[GST_VIDEO_MAX_PLANES]);

View file

@ -261,7 +261,7 @@ _egl_image_upload_perform (gpointer impl, GstBuffer * buffer,
/* FIXME: buffer pool */
*outbuf = gst_buffer_new ();
gst_gl_memory_setup_buffer (image->upload->context,
&image->upload->priv->out_info, *outbuf);
&image->upload->priv->out_info, NULL, *outbuf);
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&image->upload->priv->in_info); i++) {
GstMemory *mem = gst_buffer_peek_memory (buffer, i);
@ -401,7 +401,7 @@ _upload_meta_upload_perform (gpointer impl, GstBuffer * buffer,
/* FIXME: buffer pool */
*outbuf = gst_buffer_new ();
gst_gl_memory_setup_buffer (upload->upload->context,
&upload->upload->priv->in_info, *outbuf);
&upload->upload->priv->in_info, NULL, *outbuf);
for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
guint tex_id = 0;
@ -509,7 +509,7 @@ _raw_data_upload_perform (gpointer impl, GstBuffer * buffer,
if (!raw->in_tex[0])
gst_gl_memory_setup_wrapped (raw->upload->context,
&raw->upload->priv->in_info, raw->in_frame.data, raw->in_tex);
&raw->upload->priv->in_info, NULL, raw->in_frame.data, raw->in_tex);
for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
if (raw->in_tex[i]) {

View file

@ -223,7 +223,7 @@ _perform_with_gl_memory (GstGLUploadMeta * upload, GstVideoGLTextureUploadMeta *
if (!upload->priv->out_tex[i])
upload->priv->out_tex[i] = gst_gl_memory_wrapped_texture (upload->context,
texture_id[i], &upload->info, i, NULL, NULL);
texture_id[i], &upload->info, i, NULL, NULL, NULL);
out_mem = upload->priv->out_tex[i];
@ -256,7 +256,7 @@ _perform_with_data_unlocked (GstGLUploadMeta * upload,
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->info); i++) {
if (!upload->priv->in_tex[i])
upload->priv->in_tex[i] = gst_gl_memory_wrapped (upload->context,
&upload->info, i, data[i], NULL, NULL);
&upload->info, i, NULL, data[i], NULL, NULL);
upload->priv->in_tex[i]->data = data[i];
}

View file

@ -852,3 +852,23 @@ gst_gl_handle_context_query (GstElement * element, GstQuery * query,
return res;
}
gsize
gst_gl_get_plane_data_size (GstVideoInfo * info, GstVideoAlignment * align,
guint plane)
{
gint padded_height;
gsize plane_size;
padded_height = info->height;
if (align)
padded_height += align->padding_top + align->padding_bottom;
padded_height =
GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, plane, padded_height);
plane_size = GST_VIDEO_INFO_PLANE_STRIDE (info, plane) * padded_height;
return plane_size;
}

View file

@ -99,6 +99,9 @@ gboolean gst_gl_handle_set_context (GstElement * element, GstContext * context,
gboolean gst_gl_handle_context_query (GstElement * element, GstQuery * query,
GstGLDisplay ** display, GstGLContext ** other_context);
gsize gst_gl_get_plane_data_size (GstVideoInfo * info, GstVideoAlignment * align,
guint plane);
G_END_DECLS
#endif /* __GST_GL_UTILS_H__ */