diff options
author | Rob Clark | 2009-11-27 15:05:56 -0600 |
---|---|---|
committer | Nikhil Devshatwar | 2013-05-15 05:35:27 -0500 |
commit | 0410c0375f215efc7833a1577b20ced48a9f8c12 (patch) | |
tree | 327526c7027d64a3ed64ad66ad985679c474ffa0 | |
parent | d37666d665ddfe7771e6ac30eea36e02ae6e545d (diff) | |
download | gst-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.am | 1 | ||||
-rw-r--r-- | gst/stride/convert.c | 267 | ||||
-rw-r--r-- | gst/stride/gststridetransform.c | 295 | ||||
-rw-r--r-- | gst/stride/gststridetransform.h | 18 |
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 | ||
3 | libgststridetransform_la_SOURCES = \ | 3 | libgststridetransform_la_SOURCES = \ |
4 | gststridetransform.c \ | 4 | gststridetransform.c \ |
5 | convert.c \ | ||
5 | plugin.c | 6 | plugin.c |
6 | 7 | ||
7 | libgststridetransform_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) | 8 | libgststridetransform_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 | |||
36 | GST_DEBUG_CATEGORY_EXTERN (stridetransform_debug); | ||
37 | #define GST_CAT_DEFAULT stridetransform_debug | ||
38 | |||
39 | |||
40 | /* | ||
41 | * Conversion utilities: | ||
42 | */ | ||
43 | |||
44 | static void | ||
45 | memmove_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 | |||
65 | static void | ||
66 | stridemove_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 | */ | ||
95 | static void | ||
96 | stridemove (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 */ | ||
123 | static GstFlowReturn | ||
124 | unstridify_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 | } | ||
137 | static GstFlowReturn | ||
138 | stridify_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 */ | ||
154 | static GstFlowReturn | ||
155 | unstridify_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 | } | ||
176 | static GstFlowReturn | ||
177 | stridify_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 */ | ||
200 | static GstFlowReturn | ||
201 | unstridify_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 | } | ||
213 | static GstFlowReturn | ||
214 | stridify_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 */ | ||
228 | static GstFlowReturn | ||
229 | stridify_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 */ | ||
256 | Conversion 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 */ | ||
58 | extern const Conversion stride_conversions[]; | ||
59 | |||
60 | |||
56 | static const GstElementDetails stridetransform_details = | 61 | static const GstElementDetails stridetransform_details = |
57 | GST_ELEMENT_DETAILS ("Stride transform", | 62 | GST_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 | ||
75 | static GstStaticPadTemplate sink_template = | 80 | static GstStaticPadTemplate sink_template = |
76 | GST_STATIC_PAD_TEMPLATE ("sink", | 81 | GST_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 | ||
83 | GST_DEBUG_CATEGORY (stridetransform_debug); | 88 | GST_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); |
100 | static GstFlowReturn gst_stride_transform_transform (GstBaseTransform *base, | 105 | static GstFlowReturn gst_stride_transform_transform (GstBaseTransform *base, |
101 | GstBuffer *inbuf, GstBuffer *outbuf); | 106 | GstBuffer *inbuf, GstBuffer *outbuf); |
102 | static GstFlowReturn gst_stride_transform_transform_ip (GstBaseTransform *base, | ||
103 | GstBuffer *buf); | ||
104 | 107 | ||
105 | GST_BOILERPLATE (GstStrideTransform, gst_stride_transform, GstVideoFilter, GST_TYPE_VIDEO_FILTER); | 108 | GST_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 | */ |
221 | static void | 222 | static void |
222 | add_all_fields (GstCaps *caps, const gchar *name, GstStructure *s, gboolean rowstride) | 223 | add_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; |
245 | GST_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 | |||
344 | static void | ||
345 | memmove_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 | |||
365 | static void | ||
366 | stridemove_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 | */ | ||
394 | static void | ||
395 | stridemove (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 | */ | ||
429 | static GstFlowReturn | ||
430 | stridify (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 | */ | ||
495 | static GstFlowReturn | ||
496 | unstridify (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 | |||
532 | static GstFlowReturn | 360 | static GstFlowReturn |
533 | gst_stride_transform_transform (GstBaseTransform *base, | 361 | gst_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 | |||
559 | static GstFlowReturn | ||
560 | gst_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 | |||
33 | G_BEGIN_DECLS | 32 | G_BEGIN_DECLS |
34 | 33 | ||
35 | #define GST_TYPE_STRIDE_TRANSFORM \ | 34 | #define GST_TYPE_STRIDE_TRANSFORM \ |
@@ -47,6 +46,19 @@ typedef struct _GstStrideTransform GstStrideTransform; | |||
47 | typedef struct _GstStrideTransformClass GstStrideTransformClass; | 46 | typedef struct _GstStrideTransformClass GstStrideTransformClass; |
48 | 47 | ||
49 | /** | 48 | /** |
49 | * stride/colorspace conversion table (used internally) | ||
50 | */ | ||
51 | typedef 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]; |