gstreamer/gst-libs/gst/video/gstvideometa.c
2012-01-25 12:30:53 +01:00

304 lines
7.9 KiB
C

/* GStreamer
* Copyright (C) <2011> Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gstvideometa.h"
static void
gst_video_meta_copy (GstBuffer * dest, GstMeta * meta,
GstBuffer * buffer, gsize offset, gsize size)
{
GstVideoMeta *dmeta, *smeta;
guint i;
smeta = (GstVideoMeta *) meta;
dmeta =
(GstVideoMeta *) gst_buffer_add_meta (dest, GST_VIDEO_META_INFO, NULL);
dmeta->buffer = dest;
dmeta->flags = smeta->flags;
dmeta->id = smeta->id;
dmeta->format = smeta->format;
dmeta->width = smeta->width;
dmeta->height = smeta->height;
dmeta->n_planes = smeta->n_planes;
for (i = 0; i < dmeta->n_planes; i++) {
dmeta->offset[i] = smeta->offset[i];
dmeta->stride[i] = smeta->stride[i];
}
}
/* video metadata */
const GstMetaInfo *
gst_video_meta_get_info (void)
{
static const GstMetaInfo *video_meta_info = NULL;
if (video_meta_info == NULL) {
video_meta_info = gst_meta_register (GST_VIDEO_META_API, "GstVideoMeta",
sizeof (GstVideoMeta),
(GstMetaInitFunction) NULL,
(GstMetaFreeFunction) NULL,
gst_video_meta_copy, (GstMetaTransformFunction) NULL);
}
return video_meta_info;
}
/**
* gst_buffer_get_video_meta_id:
* @buffer: a #GstBuffer
* @id: a metadata id
*
* Find the #GstVideoMeta on @buffer with the given @id.
*
* Buffers can contain multiple #GstVideoMeta metadata items when dealing with
* multiview buffers.
*
* Returns: the #GstVideoMeta with @id or %NULL when there is no such metadata
* on @buffer.
*/
GstVideoMeta *
gst_buffer_get_video_meta_id (GstBuffer * buffer, gint id)
{
gpointer state = NULL;
GstMeta *meta;
const GstMetaInfo *info = GST_VIDEO_META_INFO;
while ((meta = gst_buffer_iterate_meta (buffer, &state))) {
if (meta->info->api == info->api) {
GstVideoMeta *vmeta = (GstVideoMeta *) meta;
if (vmeta->id == id)
return vmeta;
}
}
return NULL;
}
/**
* gst_buffer_add_video_meta:
* @buffer: a #GstBuffer
* @flags: #GstVideoFlags
* @format: a #GstVideoFormat
* @width: the width
* @height: the height
*
* Attaches GstVideoMeta metadata to @buffer with the given parameters and the
* default offsets and strides for @format and @width x @height.
*
* This function calculates the default offsets and strides and then calls
* gst_buffer_add_video_meta_full() with them.
*
* Returns: the #GstVideoMeta on @buffer.
*/
GstVideoMeta *
gst_buffer_add_video_meta (GstBuffer * buffer, GstVideoFlags flags,
GstVideoFormat format, guint width, guint height)
{
GstVideoMeta *meta;
GstVideoInfo info;
gst_video_info_set_format (&info, format, width, height);
meta = gst_buffer_add_video_meta_full (buffer, flags, format, width, height,
info.finfo->n_planes, info.offset, info.stride);
return meta;
}
/**
* gst_buffer_add_video_meta_full:
* @buffer: a #GstBuffer
* @flags: #GstVideoFlags
* @format: a #GstVideoFormat
* @width: the width
* @height: the height
* @n_planes: number of planes
* @offset: offset of each plane
* @stride: stride of each plane
*
* Attaches GstVideoMeta metadata to @buffer with the given parameters.
*
* Returns: the #GstVideoMeta on @buffer.
*/
GstVideoMeta *
gst_buffer_add_video_meta_full (GstBuffer * buffer, GstVideoFlags flags,
GstVideoFormat format, guint width, guint height,
guint n_planes, gsize offset[GST_VIDEO_MAX_PLANES],
gint stride[GST_VIDEO_MAX_PLANES])
{
GstVideoMeta *meta;
guint i;
meta =
(GstVideoMeta *) gst_buffer_add_meta (buffer, GST_VIDEO_META_INFO, NULL);
meta->flags = flags;
meta->format = format;
meta->id = 0;
meta->width = width;
meta->height = height;
meta->buffer = buffer;
meta->n_planes = n_planes;
for (i = 0; i < n_planes; i++) {
meta->offset[i] = offset[i];
meta->stride[i] = stride[i];
}
return meta;
}
static GstMemory *
find_mem_for_offset (GstBuffer * buffer, guint * offset, GstMapFlags flags)
{
guint n, i;
GstMemory *res = NULL;
n = gst_buffer_n_memory (buffer);
for (i = 0; i < n; i++) {
GstMemory *mem = NULL;
gsize size;
mem = gst_buffer_peek_memory (buffer, i, flags);
size = gst_memory_get_sizes (mem, NULL, NULL);
if (*offset < size) {
res = mem;
break;
}
*offset -= size;
}
return res;
}
/**
* gst_video_meta_map:
* @meta: a #GstVideoMeta
* @plane: a plane
* @info: a #GstMapInfo
* @stride: result stride
* @flags: @GstMapFlags
*
* Map the video plane with index @plane in @meta and return a pointer to the
* first byte of the plane and the stride of the plane.
*
* Returns: a pointer to the first byte of the plane data
*/
gboolean
gst_video_meta_map (GstVideoMeta * meta, guint plane, GstMapInfo * info,
gint * stride, GstMapFlags flags)
{
guint offset;
gboolean write, res;
GstBuffer *buffer;
GstMemory *mem;
g_return_val_if_fail (meta != NULL, FALSE);
g_return_val_if_fail (plane < meta->n_planes, FALSE);
g_return_val_if_fail (info != NULL, FALSE);
g_return_val_if_fail (stride != NULL, FALSE);
buffer = meta->buffer;
g_return_val_if_fail (buffer != NULL, FALSE);
write = (flags & GST_MAP_WRITE) != 0;
g_return_val_if_fail (!write || gst_buffer_is_writable (buffer), FALSE);
offset = meta->offset[plane];
*stride = meta->stride[plane];
/* find the memory block for this plane, this is the memory block containing
* the plane offset */
mem = find_mem_for_offset (buffer, &offset, flags);
res = gst_memory_map (mem, info, flags);
/* move to the right offset inside the block */
info->data += offset;
info->size -= offset;
info->maxsize -= offset;
return res;
}
/**
* gst_video_meta_unmap:
* @meta: a #GstVideoMeta
* @plane: a plane
* @info: a #GstMapInfo
*
* Unmap a previously mapped plane with gst_video_meta_map().
*
* Returns: TRUE if the memory was successfully unmapped.
*/
gboolean
gst_video_meta_unmap (GstVideoMeta * meta, guint plane, GstMapInfo * info)
{
guint offset;
GstBuffer *buffer;
GstMemory *mem;
g_return_val_if_fail (meta != NULL, FALSE);
g_return_val_if_fail (plane < meta->n_planes, FALSE);
g_return_val_if_fail (info != NULL, FALSE);
buffer = meta->buffer;
g_return_val_if_fail (buffer != NULL, FALSE);
offset = meta->offset[plane];
mem = find_mem_for_offset (buffer, &offset, GST_MAP_READ);
/* move to the right offset inside the block */
info->data -= offset;
info->size += offset;
info->maxsize += offset;
gst_memory_unmap (mem, info);
return TRUE;
}
static void
gst_video_crop_meta_copy (GstBuffer * dest, GstMeta * meta,
GstBuffer * buffer, gsize offset, gsize size)
{
GstVideoCropMeta *dmeta, *smeta;
smeta = (GstVideoCropMeta *) meta;
dmeta = gst_buffer_add_video_crop_meta (dest);
dmeta->x = smeta->x;
dmeta->y = smeta->y;
dmeta->width = smeta->width;
dmeta->height = smeta->height;
}
const GstMetaInfo *
gst_video_crop_meta_get_info (void)
{
static const GstMetaInfo *video_crop_meta_info = NULL;
if (video_crop_meta_info == NULL) {
video_crop_meta_info =
gst_meta_register (GST_VIDEO_CROP_META_API, "GstVideoCropMeta",
sizeof (GstVideoCropMeta), (GstMetaInitFunction) NULL,
(GstMetaFreeFunction) NULL, gst_video_crop_meta_copy,
(GstMetaTransformFunction) NULL);
}
return video_crop_meta_info;
}