2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Library <2002> Ronald Bultje <rbultje@ronald.bitfreak.net>
4 * Copyright (C) 2007 David A. Schleef <ds@schleef.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
29 #include <gst/video/video.h>
30 #include "video-frame.h"
31 #include "video-tile.h"
32 #include "gstvideometa.h"
34 #define CAT_PERFORMANCE video_frame_get_perf_category()
36 static inline GstDebugCategory *
37 video_frame_get_perf_category (void)
39 static GstDebugCategory *cat = NULL;
41 if (g_once_init_enter (&cat)) {
44 GST_DEBUG_CATEGORY_GET (c, "GST_PERFORMANCE");
45 g_once_init_leave (&cat, c);
51 * gst_video_frame_map_id:
52 * @frame: (out caller-allocates): pointer to #GstVideoFrame
53 * @info: a #GstVideoInfo
54 * @buffer: the buffer to map
55 * @id: the frame id to map
56 * @flags: #GstMapFlags
58 * Use @info and @buffer to fill in the values of @frame with the video frame
59 * information of frame @id.
61 * When @id is -1, the default frame is mapped. When @id != -1, this function
62 * will return %FALSE when there is no GstVideoMeta with that id.
64 * All video planes of @buffer will be mapped and the pointers will be set in
67 * Returns: %TRUE on success.
70 gst_video_frame_map_id (GstVideoFrame * frame, const GstVideoInfo * info,
71 GstBuffer * buffer, gint id, GstMapFlags flags)
76 g_return_val_if_fail (frame != NULL, FALSE);
77 g_return_val_if_fail (info != NULL, FALSE);
78 g_return_val_if_fail (info->finfo != NULL, FALSE);
79 g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
82 meta = gst_buffer_get_video_meta (buffer);
84 meta = gst_buffer_get_video_meta_id (buffer, id);
90 /* All these values must be consistent */
91 g_return_val_if_fail (info->finfo->format == meta->format, FALSE);
92 g_return_val_if_fail (info->width <= meta->width, FALSE);
93 g_return_val_if_fail (info->height <= meta->height, FALSE);
94 g_return_val_if_fail (info->finfo->n_planes == meta->n_planes, FALSE);
96 frame->info.finfo = gst_video_format_get_info (meta->format);
97 frame->info.width = meta->width;
98 frame->info.height = meta->height;
100 frame->flags = meta->flags;
102 for (i = 0; i < meta->n_planes; i++) {
103 frame->info.offset[i] = meta->offset[i];
104 if (!gst_video_meta_map (meta, i, &frame->map[i], &frame->data[i],
105 &frame->info.stride[i], flags))
106 goto frame_map_failed;
109 /* no metadata, we really need to have the metadata when the id is
117 if (!gst_buffer_map (buffer, &frame->map[0], flags))
120 /* do some sanity checks */
121 if (frame->map[0].size < info->size)
124 /* set up pointers */
125 for (i = 0; i < info->finfo->n_planes; i++) {
126 frame->data[i] = frame->map[0].data + info->offset[i];
129 frame->buffer = buffer;
130 if ((flags & GST_VIDEO_FRAME_MAP_FLAG_NO_REF) == 0)
131 gst_buffer_ref (frame->buffer);
135 /* buffer flags enhance the frame flags */
136 if (GST_VIDEO_INFO_IS_INTERLACED (info)) {
137 if (GST_VIDEO_INFO_INTERLACE_MODE (info) == GST_VIDEO_INTERLACE_MODE_MIXED) {
138 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED)) {
139 frame->flags |= GST_VIDEO_FRAME_FLAG_INTERLACED;
142 frame->flags |= GST_VIDEO_FRAME_FLAG_INTERLACED;
145 if (GST_VIDEO_INFO_FIELD_ORDER (info) ==
146 GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST) {
147 frame->flags |= GST_VIDEO_FRAME_FLAG_TFF;
149 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_TFF))
150 frame->flags |= GST_VIDEO_FRAME_FLAG_TFF;
151 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_RFF))
152 frame->flags |= GST_VIDEO_FRAME_FLAG_RFF;
153 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_ONEFIELD))
154 frame->flags |= GST_VIDEO_FRAME_FLAG_ONEFIELD;
162 GST_ERROR ("no GstVideoMeta for id %d", id);
163 memset (frame, 0, sizeof (GstVideoFrame));
168 GST_ERROR ("failed to map video frame plane %d", i);
170 gst_video_meta_unmap (meta, i, &frame->map[i]);
171 memset (frame, 0, sizeof (GstVideoFrame));
176 GST_ERROR ("failed to map buffer");
181 GST_ERROR ("invalid buffer size %" G_GSIZE_FORMAT " < %" G_GSIZE_FORMAT,
182 frame->map[0].size, info->size);
183 gst_buffer_unmap (buffer, &frame->map[0]);
184 memset (frame, 0, sizeof (GstVideoFrame));
190 * gst_video_frame_map:
191 * @frame: (out caller-allocates): pointer to #GstVideoFrame
192 * @info: a #GstVideoInfo
193 * @buffer: the buffer to map
194 * @flags: #GstMapFlags
196 * Use @info and @buffer to fill in the values of @frame. @frame is usually
197 * allocated on the stack, and you will pass the address to the #GstVideoFrame
198 * structure allocated on the stack; gst_video_frame_map() will then fill in
199 * the structures with the various video-specific information you need to access
200 * the pixels of the video buffer. You can then use accessor macros such as
201 * GST_VIDEO_FRAME_COMP_DATA(), GST_VIDEO_FRAME_PLANE_DATA(),
202 * GST_VIDEO_FRAME_COMP_STRIDE(), GST_VIDEO_FRAME_PLANE_STRIDE() etc.
203 * to get to the pixels.
205 * |[<!-- language="C" -->
206 * GstVideoFrame vframe;
208 * // set RGB pixels to black one at a time
209 * if (gst_video_frame_map (&vframe, video_info, video_buffer, GST_MAP_WRITE)) {
210 * guint8 *pixels = GST_VIDEO_FRAME_PLANE_DATA (vframe, 0);
211 * guint stride = GST_VIDEO_FRAME_PLANE_STRIDE (vframe, 0);
212 * guint pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (vframe, 0);
214 * for (h = 0; h < height; ++h) {
215 * for (w = 0; w < width; ++w) {
216 * guint8 *pixel = pixels + h * stride + w * pixel_stride;
218 * memset (pixel, 0, pixel_stride);
222 * gst_video_frame_unmap (&vframe);
227 * All video planes of @buffer will be mapped and the pointers will be set in
230 * The purpose of this function is to make it easy for you to get to the video
231 * pixels in a generic way, without you having to worry too much about details
232 * such as whether the video data is allocated in one contiguous memory chunk
233 * or multiple memory chunks (e.g. one for each plane); or if custom strides
234 * and custom plane offsets are used or not (as signalled by GstVideoMeta on
235 * each buffer). This function will just fill the #GstVideoFrame structure
236 * with the right values and if you use the accessor macros everything will
237 * just work and you can access the data easily. It also maps the underlying
238 * memory chunks for you.
240 * Returns: %TRUE on success.
243 gst_video_frame_map (GstVideoFrame * frame, const GstVideoInfo * info,
244 GstBuffer * buffer, GstMapFlags flags)
246 return gst_video_frame_map_id (frame, info, buffer, -1, flags);
250 * gst_video_frame_unmap:
251 * @frame: a #GstVideoFrame
253 * Unmap the memory previously mapped with gst_video_frame_map.
256 gst_video_frame_unmap (GstVideoFrame * frame)
263 g_return_if_fail (frame != NULL);
265 buffer = frame->buffer;
267 flags = frame->map[0].flags;
270 for (i = 0; i < frame->info.finfo->n_planes; i++) {
271 gst_video_meta_unmap (meta, i, &frame->map[i]);
274 gst_buffer_unmap (buffer, &frame->map[0]);
277 if ((flags & GST_VIDEO_FRAME_MAP_FLAG_NO_REF) == 0)
278 gst_buffer_unref (frame->buffer);
282 * gst_video_frame_copy_plane:
283 * @dest: a #GstVideoFrame
284 * @src: a #GstVideoFrame
287 * Copy the plane with index @plane from @src to @dest.
289 * Note: Since: 1.18, @dest dimensions are allowed to be
290 * smaller than @src dimensions.
292 * Returns: TRUE if the contents could be copied.
295 gst_video_frame_copy_plane (GstVideoFrame * dest, const GstVideoFrame * src,
298 const GstVideoInfo *sinfo;
300 const GstVideoFormatInfo *finfo;
301 gint comp[GST_VIDEO_MAX_COMPONENTS];
306 g_return_val_if_fail (dest != NULL, FALSE);
307 g_return_val_if_fail (src != NULL, FALSE);
312 g_return_val_if_fail (dinfo->finfo->format == sinfo->finfo->format, FALSE);
314 finfo = dinfo->finfo;
316 g_return_val_if_fail (dinfo->width <= sinfo->width
317 && dinfo->height <= sinfo->height, FALSE);
318 g_return_val_if_fail (finfo->n_planes > plane, FALSE);
320 sp = src->data[plane];
321 dp = dest->data[plane];
323 if (GST_VIDEO_FORMAT_INFO_HAS_PALETTE (finfo) && plane == 1) {
324 /* copy the palette and we're done */
325 memcpy (dp, sp, 256 * 4);
329 gst_video_format_info_component (finfo, plane, comp);
330 w = GST_VIDEO_FRAME_COMP_WIDTH (dest,
331 comp[0]) * GST_VIDEO_FRAME_COMP_PSTRIDE (dest, comp[0]);
332 /* FIXME: workaround for complex formats like v210, UYVP and IYU1 that have
335 w = MIN (GST_VIDEO_INFO_PLANE_STRIDE (dinfo, plane),
336 GST_VIDEO_INFO_PLANE_STRIDE (sinfo, plane));
338 h = GST_VIDEO_FRAME_COMP_HEIGHT (dest, comp[0]);
340 ss = GST_VIDEO_INFO_PLANE_STRIDE (sinfo, plane);
341 ds = GST_VIDEO_INFO_PLANE_STRIDE (dinfo, plane);
343 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo)) {
345 gint sx_tiles, sy_tiles, dx_tiles, dy_tiles;
346 guint i, j, ws, hs, ts;
347 GstVideoTileMode mode;
349 ws = GST_VIDEO_FORMAT_INFO_TILE_WS (finfo);
350 hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
355 mode = GST_VIDEO_FORMAT_INFO_TILE_MODE (finfo);
357 sx_tiles = GST_VIDEO_TILE_X_TILES (ss);
358 sy_tiles = GST_VIDEO_TILE_Y_TILES (ss);
360 dx_tiles = GST_VIDEO_TILE_X_TILES (ds);
361 dy_tiles = GST_VIDEO_TILE_Y_TILES (ds);
363 /* this is the amount of tiles to copy */
364 w = ((w - 1) >> ws) + 1;
365 h = ((h - 1) >> hs) + 1;
367 /* FIXME can possibly do better when no retiling is needed, it depends on
368 * the stride and the tile_size */
369 for (j = 0; j < h; j++) {
370 for (i = 0; i < w; i++) {
373 si = gst_video_tile_get_index (mode, i, j, sx_tiles, sy_tiles);
374 di = gst_video_tile_get_index (mode, i, j, dx_tiles, dy_tiles);
376 memcpy (dp + (di << ts), sp + (si << ts), tile_size);
382 GST_CAT_DEBUG (CAT_PERFORMANCE, "copy plane %d, w:%d h:%d ", plane, w, h);
384 for (j = 0; j < h; j++) {
395 * gst_video_frame_copy:
396 * @dest: a #GstVideoFrame
397 * @src: a #GstVideoFrame
399 * Copy the contents from @src to @dest.
401 * Note: Since: 1.18, @dest dimensions are allowed to be
402 * smaller than @src dimensions.
404 * Returns: TRUE if the contents could be copied.
407 gst_video_frame_copy (GstVideoFrame * dest, const GstVideoFrame * src)
410 const GstVideoInfo *sinfo;
413 g_return_val_if_fail (dest != NULL, FALSE);
414 g_return_val_if_fail (src != NULL, FALSE);
419 g_return_val_if_fail (dinfo->finfo->format == sinfo->finfo->format, FALSE);
420 g_return_val_if_fail (dinfo->width <= sinfo->width
421 && dinfo->height <= sinfo->height, FALSE);
423 n_planes = dinfo->finfo->n_planes;
425 for (i = 0; i < n_planes; i++)
426 gst_video_frame_copy_plane (dest, src, i);