aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark2009-11-27 15:05:56 -0600
committerNikhil Devshatwar2013-05-15 05:35:27 -0500
commit0410c0375f215efc7833a1577b20ced48a9f8c12 (patch)
tree327526c7027d64a3ed64ad66ad985679c474ffa0
parentd37666d665ddfe7771e6ac30eea36e02ae6e545d (diff)
downloadgst-plugins-base0-10-0410c0375f215efc7833a1577b20ced48a9f8c12.tar.gz
gst-plugins-base0-10-0410c0375f215efc7833a1577b20ced48a9f8c12.tar.xz
gst-plugins-base0-10-0410c0375f215efc7833a1577b20ced48a9f8c12.zip
refactor stridetransform to make it easier to add new transforms (stride and/or colorspace)
-rw-r--r--gst/stride/Makefile.am1
-rw-r--r--gst/stride/convert.c267
-rw-r--r--gst/stride/gststridetransform.c295
-rw-r--r--gst/stride/gststridetransform.h18
4 files changed, 340 insertions, 241 deletions
diff --git a/gst/stride/Makefile.am b/gst/stride/Makefile.am
index 1adc197ef..0b61d5577 100644
--- a/gst/stride/Makefile.am
+++ b/gst/stride/Makefile.am
@@ -2,6 +2,7 @@ plugin_LTLIBRARIES = libgststridetransform.la
2 2
3libgststridetransform_la_SOURCES = \ 3libgststridetransform_la_SOURCES = \
4 gststridetransform.c \ 4 gststridetransform.c \
5 convert.c \
5 plugin.c 6 plugin.c
6 7
7libgststridetransform_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) 8libgststridetransform_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
diff --git a/gst/stride/convert.c b/gst/stride/convert.c
new file mode 100644
index 000000000..860f16cfe
--- /dev/null
+++ b/gst/stride/convert.c
@@ -0,0 +1,267 @@
1/* GStreamer
2 *
3 * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/
4 *
5 * Description: stride transform conversion utilities
6 * Created on: Nov 27, 2009
7 * Author: Rob Clark <rob@ti.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
23 */
24
25
26#ifdef HAVE_CONFIG_H
27#include <config.h>
28#endif
29
30#include <string.h>
31#include <gst/video/video.h>
32
33#include "gststridetransform.h"
34
35
36GST_DEBUG_CATEGORY_EXTERN (stridetransform_debug);
37#define GST_CAT_DEFAULT stridetransform_debug
38
39
40/*
41 * Conversion utilities:
42 */
43
44static void
45memmove_demux (guchar *new_buf, guchar *orig_buf, gint sz, gint pxstride)
46{
47 if (new_buf > orig_buf) {
48 /* copy backwards */
49 new_buf += ((sz - 1) * pxstride);
50 orig_buf += sz - 1;
51 while(sz--) {
52 *new_buf = *orig_buf;
53 new_buf -= pxstride;
54 orig_buf--;
55 }
56 } else {
57 while(sz--) {
58 *new_buf = *orig_buf;
59 new_buf += pxstride;
60 orig_buf++;
61 }
62 }
63}
64
65static void
66stridemove_demux (guchar *new_buf, guchar *orig_buf, gint new_width, gint orig_width, gint height, gint pxstride)
67{
68 int row;
69
70 GST_DEBUG ("new_buf=%p, orig_buf=%p, new_width=%d, orig_width=%d, height=%d",
71 new_buf, orig_buf, new_width, orig_width, height);
72
73 /* if increasing the stride, work from bottom-up to avoid overwriting data
74 * that has not been moved yet.. otherwise, work in the opposite order,
75 * for the same reason.
76 */
77 if (new_width > orig_width) {
78 for (row=height-1; row>=0; row--) {
79 memmove_demux (new_buf+(new_width*row), orig_buf+(orig_width*row), orig_width, pxstride);
80 }
81 } else {
82 for (row=0; row<height; row++) {
83 memmove_demux (new_buf+(new_width*row), orig_buf+(orig_width*row), new_width, pxstride);
84 }
85 }
86}
87
88/**
89 * Convert from one stride to another... like memmove, but can convert stride in
90 * the process. This function is not aware of pixels, only of bytes. So widths
91 * are given in bytes, not pixels. The new_buf and orig_buf can point to the
92 * same buffers to do an in-place conversion, but the buffer should be large
93 * enough.
94 */
95static void
96stridemove (guchar *new_buf, guchar *orig_buf, gint new_width, gint orig_width, gint height)
97{
98 int row;
99
100 GST_DEBUG ("new_buf=%p, orig_buf=%p, new_width=%d, orig_width=%d, height=%d",
101 new_buf, orig_buf, new_width, orig_width, height);
102
103 /* if increasing the stride, work from bottom-up to avoid overwriting data
104 * that has not been moved yet.. otherwise, work in the opposite order,
105 * for the same reason.
106 */
107 if (new_width > orig_width) {
108 for (row=height-1; row>=0; row--) {
109 memmove (new_buf+(new_width*row), orig_buf+(orig_width*row), orig_width);
110 }
111 } else {
112 for (row=0; row<height; row++) {
113 memmove (new_buf+(new_width*row), orig_buf+(orig_width*row), new_width);
114 }
115 }
116}
117
118/*
119 * Conversion Functions:
120 */
121
122/** convert 4:2:0 semiplanar to same 4:2:0 semiplanar */
123static GstFlowReturn
124unstridify_420sp_420sp (GstStrideTransform *self, guchar *unstrided, guchar *strided)
125{
126 gint width = self->width;
127 gint height = self->height;
128 gint stride = self->in_rowstride;
129
130 g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
131
132 stridemove (unstrided, strided, width, stride,
133 (GST_ROUND_UP_2 (height) * 3) / 2);
134
135 return GST_FLOW_OK;
136}
137static GstFlowReturn
138stridify_420sp_420sp (GstStrideTransform *self, guchar *strided, guchar *unstrided)
139{
140 gint width = self->width;
141 gint height = self->height;
142 gint stride = self->out_rowstride;
143
144 g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
145
146 g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
147 stridemove (strided, unstrided, stride, width,
148 (GST_ROUND_UP_2 (height) * 3) / 2);
149
150 return GST_FLOW_OK;
151}
152
153/** convert 4:2:0 planar to same 4:2:0 planar */
154static GstFlowReturn
155unstridify_420p_420p (GstStrideTransform *self, guchar *unstrided, guchar *strided)
156{
157 gint width = self->width;
158 gint height = self->height;
159 gint stride = self->in_rowstride;
160
161 g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
162
163 stridemove (unstrided, strided, width, stride, height); /* move Y */
164 stridemove (
165 unstrided + (height*width),
166 strided + (height*stride),
167 width/2, stride, height); /* move V/U */
168 /* XXX odd widths/heights/strides: */
169 stridemove (
170 unstrided + (int)(height*width*1.5),
171 strided + (int)(height*stride*1.5),
172 width/2, stride, height); /* move U/V */
173
174 return GST_FLOW_OK;
175}
176static GstFlowReturn
177stridify_420p_420p (GstStrideTransform *self, guchar *strided, guchar *unstrided)
178{
179 gint width = self->width;
180 gint height = self->height;
181 gint stride = self->out_rowstride;
182
183 g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
184
185 /* XXX odd widths/heights/strides: */
186 stridemove (
187 strided + (int)(height*stride*1.5),
188 unstrided + (int)(height*width*1.5),
189 stride, width/2, height); /* move U/V */
190 stridemove (
191 strided + (height*stride),
192 unstrided + (height*width),
193 stride, width/2, height); /* move V/U */
194 stridemove (strided, unstrided, stride, width, height); /* move Y */
195
196 return GST_FLOW_OK;
197}
198
199/** convert 4:2:2 packed to same 4:2:2 packed */
200static GstFlowReturn
201unstridify_422i_422i (GstStrideTransform *self, guchar *unstrided, guchar *strided)
202{
203 gint width = self->width;
204 gint height = self->height;
205 gint stride = self->in_rowstride;
206
207 g_return_val_if_fail (stride >= (width*2), GST_FLOW_ERROR);
208
209 stridemove (unstrided, strided, width*2, stride, height);
210
211 return GST_FLOW_OK;
212}
213static GstFlowReturn
214stridify_422i_422i (GstStrideTransform *self, guchar *strided, guchar *unstrided)
215{
216 gint width = self->width;
217 gint height = self->height;
218 gint stride = self->out_rowstride;
219
220 g_return_val_if_fail (stride >= (width*2), GST_FLOW_ERROR);
221
222 stridemove (strided, unstrided, stride, width*2, height);
223
224 return GST_FLOW_OK;
225}
226
227/** convert I420 unstrided to NV12 strided */
228static GstFlowReturn
229stridify_i420_nv12 (GstStrideTransform *self, guchar *strided, guchar *unstrided)
230{
231 gint width = self->width;
232 gint height = self->height;
233 gint stride = self->out_rowstride;
234
235 g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
236
237 /* note: if not an in-place conversion, then doing the U&V in one pass
238 * would be more efficient... but if it is an in-place conversion, I'd
239 * need to think about whether it is potential for the new UV plane to
240 * corrupt the V plane before it is done copying..
241 */
242 stridemove_demux (
243 strided + (height*stride) + 1,
244 unstrided + (int)(height*width*1.25),
245 stride, width/2, height/2, 2); /* move V */
246 stridemove_demux (
247 strided + (height*stride),
248 unstrided + (height*width),
249 stride, width/2, height/2, 2); /* move U */
250 stridemove (strided, unstrided, stride, width, height); /* move Y */
251
252 return GST_FLOW_OK;
253}
254
255/* last entry has GST_VIDEO_FORMAT_UNKNOWN for in/out formats */
256Conversion stride_conversions[] = {
257 { { GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV12 }, stridify_420sp_420sp, unstridify_420sp_420sp },
258 { { GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_I420 }, stridify_420p_420p, unstridify_420p_420p },
259 { { GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YV12 }, stridify_420p_420p, unstridify_420p_420p },
260 { { GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YUY2 }, stridify_422i_422i, unstridify_422i_422i },
261 { { GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_UYVY }, stridify_422i_422i, unstridify_422i_422i },
262 { { GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_NV12 }, stridify_i420_nv12, NULL },
263 /* add new entries before here */
264 { { GST_VIDEO_FORMAT_UNKNOWN } }
265};
266
267
diff --git a/gst/stride/gststridetransform.c b/gst/stride/gststridetransform.c
index 143a9f796..6ab047962 100644
--- a/gst/stride/gststridetransform.c
+++ b/gst/stride/gststridetransform.c
@@ -47,12 +47,17 @@
47#endif 47#endif
48 48
49#include <string.h> 49#include <string.h>
50
50#include <gst/video/video.h> 51#include <gst/video/video.h>
51 52
52#include "gst/gst-i18n-plugin.h" 53#include "gst/gst-i18n-plugin.h"
53#include "gststridetransform.h" 54#include "gststridetransform.h"
54 55
55 56
57/* last entry has GST_VIDEO_FORMAT_UNKNOWN for in/out formats */
58extern const Conversion stride_conversions[];
59
60
56static const GstElementDetails stridetransform_details = 61static const GstElementDetails stridetransform_details =
57GST_ELEMENT_DETAILS ("Stride transform", 62GST_ELEMENT_DETAILS ("Stride transform",
58 "Filter/Converter/Video", 63 "Filter/Converter/Video",
@@ -70,14 +75,14 @@ GST_STATIC_PAD_TEMPLATE ("src",
70 GST_PAD_SRC, 75 GST_PAD_SRC,
71 GST_PAD_ALWAYS, 76 GST_PAD_ALWAYS,
72 GST_STATIC_CAPS (SUPPORTED_CAPS) 77 GST_STATIC_CAPS (SUPPORTED_CAPS)
73 ); 78);
74 79
75static GstStaticPadTemplate sink_template = 80static GstStaticPadTemplate sink_template =
76GST_STATIC_PAD_TEMPLATE ("sink", 81GST_STATIC_PAD_TEMPLATE ("sink",
77 GST_PAD_SINK, 82 GST_PAD_SINK,
78 GST_PAD_ALWAYS, 83 GST_PAD_ALWAYS,
79 GST_STATIC_CAPS (SUPPORTED_CAPS) 84 GST_STATIC_CAPS (SUPPORTED_CAPS)
80 ); 85);
81 86
82 87
83GST_DEBUG_CATEGORY (stridetransform_debug); 88GST_DEBUG_CATEGORY (stridetransform_debug);
@@ -99,8 +104,6 @@ static gboolean gst_stride_transform_set_caps (GstBaseTransform *base,
99 GstCaps *incaps, GstCaps *outcaps); 104 GstCaps *incaps, GstCaps *outcaps);
100static GstFlowReturn gst_stride_transform_transform (GstBaseTransform *base, 105static GstFlowReturn gst_stride_transform_transform (GstBaseTransform *base,
101 GstBuffer *inbuf, GstBuffer *outbuf); 106 GstBuffer *inbuf, GstBuffer *outbuf);
102static GstFlowReturn gst_stride_transform_transform_ip (GstBaseTransform *base,
103 GstBuffer *buf);
104 107
105GST_BOILERPLATE (GstStrideTransform, gst_stride_transform, GstVideoFilter, GST_TYPE_VIDEO_FILTER); 108GST_BOILERPLATE (GstStrideTransform, gst_stride_transform, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
106 109
@@ -136,8 +139,6 @@ gst_stride_transform_class_init (GstStrideTransformClass *klass)
136 GST_DEBUG_FUNCPTR (gst_stride_transform_transform_caps); 139 GST_DEBUG_FUNCPTR (gst_stride_transform_transform_caps);
137 basetransform_class->set_caps = 140 basetransform_class->set_caps =
138 GST_DEBUG_FUNCPTR (gst_stride_transform_set_caps); 141 GST_DEBUG_FUNCPTR (gst_stride_transform_set_caps);
139 basetransform_class->transform_ip =
140 GST_DEBUG_FUNCPTR (gst_stride_transform_transform_ip);
141 basetransform_class->transform = 142 basetransform_class->transform =
142 GST_DEBUG_FUNCPTR (gst_stride_transform_transform); 143 GST_DEBUG_FUNCPTR (gst_stride_transform_transform);
143 144
@@ -219,7 +220,7 @@ gst_stride_transform_transform_size (GstBaseTransform *base,
219 * helper to add all fields, other than rowstride to @caps, copied from @s. 220 * helper to add all fields, other than rowstride to @caps, copied from @s.
220 */ 221 */
221static void 222static void
222add_all_fields (GstCaps *caps, const gchar *name, GstStructure *s, gboolean rowstride) 223add_all_fields (GstCaps *caps, const gchar *name, GstStructure *s, gboolean rowstride, GstPadDirection direction)
223{ 224{
224 gint idx; 225 gint idx;
225 GstStructure *new_s = gst_structure_new (name, NULL); 226 GstStructure *new_s = gst_structure_new (name, NULL);
@@ -232,38 +233,39 @@ add_all_fields (GstCaps *caps, const gchar *name, GstStructure *s, gboolean rows
232 while (idx >= 0) { 233 while (idx >= 0) {
233 const gchar *name = gst_structure_nth_field_name (s, idx); 234 const gchar *name = gst_structure_nth_field_name (s, idx);
234 idx--; 235 idx--;
236
237 /* for format field, check the stride_conversions table to see what
238 * we can support:
239 */
235 if (!strcmp ("format", name)) { 240 if (!strcmp ("format", name)) {
236 // we can do simple color format translations, such as converting from one
237 // YUV420 format to another:
238 GValue formats = {0};
239 GValue fourccval = {0};
240 guint fourcc; 241 guint fourcc;
241 if (gst_structure_get_fourcc (s, name, &fourcc)) { 242
242 switch (gst_video_format_from_fourcc (fourcc)) { 243 /* XXX double check this: */
243 case GST_VIDEO_FORMAT_NV12: 244 gint to_format = (direction == GST_PAD_SINK) ? 1 : 0;
244 case GST_VIDEO_FORMAT_I420: 245 gint from_format = (direction == GST_PAD_SRC) ? 1 : 0;
245GST_DEBUG ("Hmm, let's say I can convert I420<-->NV12.."); 246
246 g_value_init (&formats, GST_TYPE_LIST); 247 if (gst_structure_get_fourcc (s, "format", &fourcc)) {
247 g_value_init (&fourccval, GST_TYPE_FOURCC); 248 GValue formats = {0};
248 gst_value_set_fourcc (&fourccval, 249 GValue fourccval = {0};
249 GST_MAKE_FOURCC ('I', '4', '2', '0')); 250 gint i;
250 gst_value_list_append_value (&formats, &fourccval); 251 GstVideoFormat format = gst_video_format_from_fourcc (fourcc);
251 gst_value_set_fourcc (&fourccval, 252
252 GST_MAKE_FOURCC ('N', 'V', '1', '2')); 253 g_value_init (&formats, GST_TYPE_LIST);
254 g_value_init (&fourccval, GST_TYPE_FOURCC);
255
256 for (i=0; stride_conversions[i].format[0]!=GST_VIDEO_FORMAT_UNKNOWN; i++) {
257 if (stride_conversions[i].format[from_format] == format) {
258 gst_value_set_fourcc (&fourccval, gst_video_format_to_fourcc
259 (stride_conversions[i].format[to_format]));
253 gst_value_list_append_value (&formats, &fourccval); 260 gst_value_list_append_value (&formats, &fourccval);
254 gst_structure_set_value (new_s, "format", &formats); 261 }
255 continue;
256/* maybe handle other cases later..
257 case GST_VIDEO_FORMAT_YV12:
258 case GST_VIDEO_FORMAT_YUY2:
259 case GST_VIDEO_FORMAT_UYVY:
260*/
261 default:
262 break;
263 } 262 }
263
264 continue;
264 } 265 }
265 } 266 }
266 267
268 /* copy over all other non-rowstride fields: */
267 if (strcmp ("rowstride", name)) { 269 if (strcmp ("rowstride", name)) {
268 const GValue *val = gst_structure_get_value (s, name); 270 const GValue *val = gst_structure_get_value (s, name);
269 gst_structure_set_value (new_s, name, val); 271 gst_structure_set_value (new_s, name, val);
@@ -297,14 +299,14 @@ gst_stride_transform_transform_caps (GstBaseTransform *base,
297 if (gst_structure_has_name (s, "video/x-raw-yuv") || 299 if (gst_structure_has_name (s, "video/x-raw-yuv") ||
298 gst_structure_has_name (s, "video/x-raw-yuv-strided")) { 300 gst_structure_has_name (s, "video/x-raw-yuv-strided")) {
299 301
300 add_all_fields (ret, "video/x-raw-yuv", s, FALSE); 302 add_all_fields (ret, "video/x-raw-yuv", s, FALSE, direction);
301 add_all_fields (ret, "video/x-raw-yuv-strided", s, TRUE); 303 add_all_fields (ret, "video/x-raw-yuv-strided", s, TRUE, direction);
302 304
303 } else if (gst_structure_has_name (s, "video/x-raw-rgb") || 305 } else if (gst_structure_has_name (s, "video/x-raw-rgb") ||
304 gst_structure_has_name (s, "video/x-raw-rgb-strided")) { 306 gst_structure_has_name (s, "video/x-raw-rgb-strided")) {
305 307
306 add_all_fields (ret, "video/x-raw-rgb", s, FALSE); 308 add_all_fields (ret, "video/x-raw-rgb", s, FALSE, direction);
307 add_all_fields (ret, "video/x-raw-rgb-strided", s, TRUE); 309 add_all_fields (ret, "video/x-raw-rgb-strided", s, TRUE, direction);
308 310
309 } 311 }
310 312
@@ -324,211 +326,37 @@ gst_stride_transform_set_caps (GstBaseTransform *base,
324{ 326{
325 GstStrideTransform *self = GST_STRIDE_TRANSFORM (base); 327 GstStrideTransform *self = GST_STRIDE_TRANSFORM (base);
326 gint width, height; 328 gint width, height;
329 GstVideoFormat in_format, out_format;
330 gint i;
327 331
328 LOG_CAPS (self, incaps); 332 LOG_CAPS (self, incaps);
329 LOG_CAPS (self, outcaps); 333 LOG_CAPS (self, outcaps);
330 334
331 g_return_val_if_fail (gst_video_format_parse_caps_strided (incaps, 335 g_return_val_if_fail (gst_video_format_parse_caps_strided (incaps,
332 &self->in_format, &self->width, &self->height, &self->in_rowstride), FALSE); 336 &in_format, &self->width, &self->height, &self->in_rowstride), FALSE);
333 g_return_val_if_fail (gst_video_format_parse_caps_strided (outcaps, 337 g_return_val_if_fail (gst_video_format_parse_caps_strided (outcaps,
334 &self->out_format, &width, &height, &self->out_rowstride), FALSE); 338 &out_format, &width, &height, &self->out_rowstride), FALSE);
335
336 g_return_val_if_fail (self->width == width, FALSE);
337 g_return_val_if_fail (self->height == height, FALSE);
338
339 return TRUE;
340}
341
342/* ************************************************************************* */
343
344static void
345memmove_demux (guchar *new_buf, guchar *orig_buf, gint sz, gint pxstride)
346{
347 if (new_buf > orig_buf) {
348 /* copy backwards */
349 new_buf += (sz * pxstride);
350 orig_buf += sz;
351 while(sz--) {
352 *new_buf = *orig_buf;
353 new_buf -= pxstride;
354 orig_buf--;
355 }
356 } else {
357 while(sz--) {
358 *new_buf = *orig_buf;
359 new_buf += pxstride;
360 orig_buf++;
361 }
362 }
363}
364
365static void
366stridemove_demux (guchar *new_buf, guchar *orig_buf, gint new_width, gint orig_width, gint height, gint pxstride)
367{
368 int row;
369
370 GST_DEBUG ("new_buf=%p, orig_buf=%p, new_width=%d, orig_width=%d, height=%d",
371 new_buf, orig_buf, new_width, orig_width, height);
372 /* if increasing the stride, work from bottom-up to avoid overwriting data
373 * that has not been moved yet.. otherwise, work in the opposite order,
374 * for the same reason.
375 */
376 if (new_width > orig_width) {
377 for (row=height-1; row>=0; row--) {
378 memmove_demux (new_buf+(new_width*row), orig_buf+(orig_width*row), orig_width, pxstride);
379 }
380 } else {
381 for (row=0; row<height; row++) {
382 memmove_demux (new_buf+(new_width*row), orig_buf+(orig_width*row), new_width, pxstride);
383 }
384 }
385}
386 339
387/** 340 self->conversion = NULL;
388 * Convert from one stride to another... like memmove, but can convert stride in
389 * the process. This function is not aware of pixels, only of bytes. So widths
390 * are given in bytes, not pixels. The new_buf and orig_buf can point to the
391 * same buffers to do an in-place conversion, but the buffer should be large
392 * enough.
393 */
394static void
395stridemove (guchar *new_buf, guchar *orig_buf, gint new_width, gint orig_width, gint height)
396{
397 int row;
398
399 GST_DEBUG ("new_buf=%p, orig_buf=%p, new_width=%d, orig_width=%d, height=%d",
400 new_buf, orig_buf, new_width, orig_width, height);
401 /* if increasing the stride, work from bottom-up to avoid overwriting data
402 * that has not been moved yet.. otherwise, work in the opposite order,
403 * for the same reason.
404 */
405 if (new_width > orig_width) {
406 for (row=height-1; row>=0; row--) {
407 memmove (new_buf+(new_width*row), orig_buf+(orig_width*row), orig_width);
408 }
409 } else {
410 for (row=0; row<height; row++) {
411 memmove (new_buf+(new_width*row), orig_buf+(orig_width*row), new_width);
412 }
413 }
414}
415 341
416 342 for (i=0; stride_conversions[i].format[0]!=GST_VIDEO_FORMAT_UNKNOWN; i++) {
417/** 343 if ((stride_conversions[i].format[0] == in_format) &&
418 * Convert from a non-strided buffer to strided. The two buffer pointers could 344 (stride_conversions[i].format[1] == out_format)) {
419 * be pointing to the same memory block for in-place transform.. assuming that 345 GST_DEBUG_OBJECT (self, "found stride_conversion: %d", i);
420 * the buffer is large enough 346 self->conversion = &stride_conversions[i];
421 * 347 break;
422 * @strided: the pointer to the resulting strided buffer
423 * @unstrided: the pointer to the initial unstrided buffer
424 * @fourcc: the color format
425 * @stride: the stride, in bytes
426 * @width: the width in pixels
427 * @height: the height in pixels
428 */
429static GstFlowReturn
430stridify (GstStrideTransform *self, guchar *strided, guchar *unstrided)
431{
432 gint width = self->width;
433 gint height = self->height;
434 gint stride = self->out_rowstride;
435
436 if (self->out_format != self->in_format) {
437
438 if ((self->in_format == GST_VIDEO_FORMAT_I420) &&
439 (self->out_format == GST_VIDEO_FORMAT_NV12)) {
440 /* note: if not an in-place conversion, then doing the U&V in one pass
441 * would be more efficient... but if it is an in-place conversion, I'd
442 * need to think about whether it is potential for the new UV plane to
443 * corrupt the V plane before it is done copying..
444 */
445 stridemove_demux (
446 strided + (height*stride) + 1,
447 unstrided + (int)(height*width*1.25),
448 stride, width/2, height/2, 2); /* move V */
449 stridemove_demux (
450 strided + (height*stride),
451 unstrided + (height*width),
452 stride, width/2, height/2, 2); /* move U */
453 stridemove (strided, unstrided, stride, width, height); /* move Y */
454 return GST_FLOW_OK;
455 } 348 }
456 } 349 }
457 350
458 switch (self->out_format) { 351 g_return_val_if_fail (self->conversion, FALSE);
459 case GST_VIDEO_FORMAT_NV12: 352 g_return_val_if_fail (self->conversion->unstridify || !self->in_rowstride, FALSE);
460 g_return_val_if_fail (stride >= width, GST_FLOW_ERROR); 353 g_return_val_if_fail (self->conversion->stridify || !self->out_rowstride, FALSE);
461 stridemove (strided, unstrided, stride, width, (GST_ROUND_UP_2 (height) * 3) / 2); 354 g_return_val_if_fail (self->width == width, FALSE);
462 return GST_FLOW_OK; 355 g_return_val_if_fail (self->height == height, FALSE);
463 case GST_VIDEO_FORMAT_I420:
464 case GST_VIDEO_FORMAT_YV12:
465 g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
466 stridemove (
467 strided + (int)(height*stride*1.5),
468 unstrided + (int)(height*width*1.5),
469 stride, width/2, height); /* move U/V */
470 stridemove (
471 strided + (height*stride),
472 unstrided + (height*width),
473 stride, width/2, height); /* move V/U */
474 stridemove (strided, unstrided, stride, width, height); /* move Y */
475 return GST_FLOW_OK;
476 case GST_VIDEO_FORMAT_YUY2:
477 case GST_VIDEO_FORMAT_UYVY:
478 g_return_val_if_fail (stride >= (width*2), GST_FLOW_ERROR);
479 stridemove (strided, unstrided, stride, width*2, height);
480 return GST_FLOW_OK;
481 default:
482 GST_WARNING ("unknown color format!\n");
483 return GST_FLOW_ERROR;
484 }
485}
486
487 356
488/** 357 return TRUE;
489 * Convert from a strided buffer to non-strided. The two buffer pointers could
490 * be pointing to the same memory block for in-place transform..
491 *
492 * @unstrided: the pointer to the resulting unstrided buffer
493 * @strided: the pointer to the initial strided buffer
494 */
495static GstFlowReturn
496unstridify (GstStrideTransform *self, guchar *unstrided, guchar *strided)
497{
498 gint width = self->width;
499 gint height = self->height;
500 gint stride = self->in_rowstride;
501
502 switch (self->out_format) {
503 case GST_VIDEO_FORMAT_NV12:
504 g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
505 stridemove (unstrided, strided, width, stride, (GST_ROUND_UP_2 (height) * 3) / 2);
506 return GST_FLOW_OK;
507 case GST_VIDEO_FORMAT_I420:
508 case GST_VIDEO_FORMAT_YV12:
509 g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
510 stridemove (unstrided, strided, width, stride, height); /* move Y */
511 stridemove (
512 unstrided + (height*width),
513 strided + (height*stride),
514 width/2, stride, height); /* move V/U */
515 stridemove (
516 unstrided + (int)(height*width*1.5),
517 strided + (int)(height*stride*1.5),
518 width/2, stride, height); /* move U/V */
519 return GST_FLOW_OK;
520 case GST_VIDEO_FORMAT_YUY2:
521 case GST_VIDEO_FORMAT_UYVY:
522 g_return_val_if_fail (stride >= (width*2), GST_FLOW_ERROR);
523 stridemove (unstrided, strided, width*2, stride, height);
524 return GST_FLOW_OK;
525 default:
526 GST_WARNING ("unknown color format!\n");
527 return GST_FLOW_ERROR;
528 }
529} 358}
530 359
531
532static GstFlowReturn 360static GstFlowReturn
533gst_stride_transform_transform (GstBaseTransform *base, 361gst_stride_transform_transform (GstBaseTransform *base,
534 GstBuffer *inbuf, GstBuffer *outbuf) 362 GstBuffer *inbuf, GstBuffer *outbuf)
@@ -543,10 +371,10 @@ gst_stride_transform_transform (GstBaseTransform *base,
543 GST_DEBUG_OBJECT (self, "not implemented"); // TODO 371 GST_DEBUG_OBJECT (self, "not implemented"); // TODO
544 return GST_FLOW_ERROR; 372 return GST_FLOW_ERROR;
545 } else if (self->in_rowstride) { 373 } else if (self->in_rowstride) {
546 return unstridify (self, 374 return self->conversion->unstridify (self,
547 GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (inbuf)); 375 GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (inbuf));
548 } else if (self->out_rowstride) { 376 } else if (self->out_rowstride) {
549 return stridify (self, 377 return self->conversion->stridify (self,
550 GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (inbuf)); 378 GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (inbuf));
551 } 379 }
552 380
@@ -555,12 +383,3 @@ gst_stride_transform_transform (GstBaseTransform *base,
555 383
556 return GST_FLOW_ERROR; 384 return GST_FLOW_ERROR;
557} 385}
558
559static GstFlowReturn
560gst_stride_transform_transform_ip (GstBaseTransform *base,
561 GstBuffer *buf)
562{
563 /* transform function is safe to call with same buffer ptr:
564 */
565 return gst_stride_transform_transform (base, buf, buf);
566}
diff --git a/gst/stride/gststridetransform.h b/gst/stride/gststridetransform.h
index 01415713f..bce252676 100644
--- a/gst/stride/gststridetransform.h
+++ b/gst/stride/gststridetransform.h
@@ -2,7 +2,7 @@
2 * 2 *
3 * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/ 3 * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/
4 * 4 *
5 * Description: V4L2 sink element 5 * Description: stride transform element
6 * Created on: Jul 2, 2009 6 * Created on: Jul 2, 2009
7 * Author: Rob Clark <rob@ti.com> 7 * Author: Rob Clark <rob@ti.com>
8 * 8 *
@@ -29,7 +29,6 @@
29#include <gst/video/gstvideofilter.h> 29#include <gst/video/gstvideofilter.h>
30#include <gst/video/video.h> 30#include <gst/video/video.h>
31 31
32
33G_BEGIN_DECLS 32G_BEGIN_DECLS
34 33
35#define GST_TYPE_STRIDE_TRANSFORM \ 34#define GST_TYPE_STRIDE_TRANSFORM \
@@ -47,6 +46,19 @@ typedef struct _GstStrideTransform GstStrideTransform;
47typedef struct _GstStrideTransformClass GstStrideTransformClass; 46typedef struct _GstStrideTransformClass GstStrideTransformClass;
48 47
49/** 48/**
49 * stride/colorspace conversion table (used internally)
50 */
51typedef struct {
52
53 GstVideoFormat format[2]; /* in_format, out_format */
54
55 GstFlowReturn (*stridify) (GstStrideTransform *self, guchar *strided, guchar *unstrided);
56 GstFlowReturn (*unstridify) (GstStrideTransform *self, guchar *unstrided, guchar *strided);
57
58} Conversion;
59
60
61/**
50 * GstStrideTransform: 62 * GstStrideTransform:
51 * 63 *
52 * Opaque datastructure. 64 * Opaque datastructure.
@@ -55,10 +67,10 @@ struct _GstStrideTransform {
55 GstVideoFilter videofilter; 67 GstVideoFilter videofilter;
56 68
57 /*< private >*/ 69 /*< private >*/
58 GstVideoFormat in_format, out_format;
59 gint width, height; 70 gint width, height;
60 gint in_rowstride; 71 gint in_rowstride;
61 gint out_rowstride; 72 gint out_rowstride;
73 const Conversion *conversion;
62 74
63 /* for caching the tranform_size() results.. */ 75 /* for caching the tranform_size() results.. */
64 GstCaps *cached_caps[2]; 76 GstCaps *cached_caps[2];