summaryrefslogtreecommitdiff
blob: b948c02936786f5f1fc75ca40074541ae28bfed4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
From 44d68a183355bce2dd7b6c890f67420ab300e0b4 Mon Sep 17 00:00:00 2001
From: Rob Clark <rob@ti.com>
Date: Fri, 31 Jul 2009 17:39:47 -0500
Subject: [PATCH 04/24] stridetransform: implement transform function

Still needed are a few details, like conversion from one stride to another (instead of just strided->nonstrided or visa versa), and support for RGB and more YUV color formats.
---
 gst/stride/gststridetransform.c |  163 +++++++++++++++++++++++++++++++++++++--
 1 files changed, 157 insertions(+), 6 deletions(-)

diff --git a/gst/stride/gststridetransform.c b/gst/stride/gststridetransform.c
index e31bf11..a911cd0 100644
--- a/gst/stride/gststridetransform.c
+++ b/gst/stride/gststridetransform.c
@@ -187,7 +187,7 @@ add_all_fields (GstCaps *caps, const gchar *name, GstStructure *s, gboolean rows
   GstStructure *new_s = gst_structure_new (name, NULL);
 
   if (rowstride) {
-    gst_structure_set (new_s, "rowstride", GST_TYPE_INT_RANGE, 1, 1000, NULL);  // XXX
+    gst_structure_set (new_s, "rowstride", GST_TYPE_INT_RANGE, 1, 1000, NULL);  // TODO
   }
 
   idx = gst_structure_n_fields (s) - 1;
@@ -253,6 +253,8 @@ gst_stride_transform_set_caps (GstBaseTransform *base,
     GstCaps *incaps, GstCaps *outcaps)
 {
   GstStrideTransform *self = GST_STRIDE_TRANSFORM (base);
+  GstVideoFormat format;
+  gint width, height;
 
   LOG_CAPS (self, incaps);
   LOG_CAPS (self, outcaps);
@@ -260,17 +262,166 @@ gst_stride_transform_set_caps (GstBaseTransform *base,
   g_return_val_if_fail (gst_video_format_parse_caps_strided (incaps,
       &self->format, &self->width, &self->height, &self->in_rowstride), FALSE);
   g_return_val_if_fail (gst_video_format_parse_caps_strided (outcaps,
-      NULL, NULL, NULL, &self->out_rowstride), FALSE);
+      &format, &width, &height, &self->out_rowstride), FALSE);
+
+  g_return_val_if_fail (self->format == format, FALSE);
+  g_return_val_if_fail (self->width  == width,  FALSE);
+  g_return_val_if_fail (self->height == height, FALSE);
 
   return TRUE;
 }
 
+/* ************************************************************************* */
+
+/**
+ * Convert from one stride to another... like memmove, but can convert stride in
+ * the process.  This function is not aware of pixels, only of bytes.  So widths
+ * are given in bytes, not pixels.  The new_buf and orig_buf can point to the
+ * same buffers to do an in-place conversion, but the buffer should be large
+ * enough.
+ */
+static void
+stridemove (guchar *new_buf, guchar *orig_buf, gint new_width, gint orig_width, gint height)
+{
+  int row;
+
+  GST_DEBUG ("new_buf=%p, orig_buf=%p, new_width=%d, orig_width=%d, height=%d",
+      new_buf, orig_buf, new_width, orig_width, height);
+  /* if increasing the stride, work from bottom-up to avoid overwriting data
+   * that has not been moved yet.. otherwise, work in the opposite order,
+   * for the same reason.
+   */
+  if (new_width > orig_width) {
+    for (row=height-1; row>=0; row--) {
+      memmove (new_buf+(new_width*row), orig_buf+(orig_width*row), orig_width);
+    }
+  } else {
+    for (row=0; row<height; row++) {
+      memmove (new_buf+(new_width*row), orig_buf+(orig_width*row), orig_width);
+    }
+  }
+}
+
+
+/**
+ * Convert from a non-strided buffer to strided.  The two buffer pointers could
+ * be pointing to the same memory block for in-place transform.. assuming that
+ * the buffer is large enough
+ *
+ * @strided:    the pointer to the resulting strided buffer
+ * @unstrided:  the pointer to the initial unstrided buffer
+ * @fourcc:     the color format
+ * @stride:     the stride, in bytes
+ * @width:      the width in pixels
+ * @height:     the height in pixels
+ */
+static GstFlowReturn
+stridify (GstStrideTransform *self, guchar *strided, guchar *unstrided)
+{
+  gint width  = self->width;
+  gint height = self->height;
+  gint stride = self->out_rowstride;
+
+  switch (self->format) {
+#if 0 /* TODO */
+    case GST_VIDEO_FORMAT_NV12:
+      g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
+      stridemove (strided, unstrided, stride, width, height * 1.5);
+      return GST_FLOW_OK;
+#endif
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+      g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
+      stridemove (
+          strided + (int)(height*stride*1.5),
+          unstrided + (int)(height*width*1.5),
+          stride, width/2, height);                             /* move U/V */
+      stridemove (
+          strided + (height*stride),
+          unstrided + (height*width),
+          stride, width/2, height);                             /* move V/U */
+      stridemove (strided, unstrided, stride, width, height);   /* move Y */
+      return GST_FLOW_OK;
+    case GST_VIDEO_FORMAT_YUY2:
+    case GST_VIDEO_FORMAT_UYVY:
+      g_return_val_if_fail (stride >= (width*2), GST_FLOW_ERROR);
+      stridemove (strided, unstrided, stride, width*2, height);
+      return GST_FLOW_OK;
+    default:
+      GST_WARNING ("unknown color format!\n");
+      return GST_FLOW_ERROR;
+  }
+}
+
+
+/**
+ * Convert from a strided buffer to non-strided.  The two buffer pointers could
+ * be pointing to the same memory block for in-place transform..
+ *
+ * @unstrided:  the pointer to the resulting unstrided buffer
+ * @strided:    the pointer to the initial strided buffer
+ */
+static GstFlowReturn
+unstridify (GstStrideTransform *self, guchar *unstrided, guchar *strided)
+{
+  gint width  = self->width;
+  gint height = self->height;
+  gint stride = self->in_rowstride;
+
+  switch (self->format) {
+#if 0 /* TODO */
+    case GST_VIDEO_FORMAT_NV12:
+      g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
+      stridemove (unstrided, strided, width, stride, height * 1.5);
+      return GST_FLOW_OK;
+#endif
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+      g_return_val_if_fail (stride >= width, GST_FLOW_ERROR);
+      stridemove (unstrided, strided, width, stride, height);   /* move Y */
+      stridemove (
+          unstrided + (height*width),
+          strided + (height*stride),
+          width/2, stride, height);                             /* move V/U */
+      stridemove (
+          unstrided + (int)(height*width*1.5),
+          strided + (int)(height*stride*1.5),
+          width/2, stride, height);                             /* move U/V */
+      return GST_FLOW_OK;
+    case GST_VIDEO_FORMAT_YUY2:
+    case GST_VIDEO_FORMAT_UYVY:
+      g_return_val_if_fail (stride >= (width*2), GST_FLOW_ERROR);
+      stridemove (unstrided, strided, width*2, stride, height);
+      return GST_FLOW_OK;
+    default:
+      GST_WARNING ("unknown color format!\n");
+      return GST_FLOW_ERROR;
+  }
+}
+
+
 static GstFlowReturn
 gst_stride_transform_transform (GstBaseTransform *base,
     GstBuffer *inbuf, GstBuffer *outbuf)
 {
   GstStrideTransform *self = GST_STRIDE_TRANSFORM (base);
-  GST_DEBUG_OBJECT (self, "not implemented");
+
+  GST_DEBUG_OBJECT (self, "inbuf=%p, outbuf=%p", inbuf, outbuf);
+
+  if (self->in_rowstride && self->out_rowstride) {
+    GST_DEBUG_OBJECT (self, "not implemented");  // TODO
+    return GST_FLOW_ERROR;
+  } else if (self->in_rowstride) {
+    return unstridify (self,
+        GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (inbuf));
+  } else if (self->out_rowstride) {
+    return stridify (self,
+        GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (inbuf));
+  }
+
+  GST_DEBUG_OBJECT (self, "this shouldn't happen!  in_rowstride=%d, out_rowstride=%d",
+      self->in_rowstride, self->out_rowstride);
+
   return GST_FLOW_ERROR;
 }
 
@@ -278,7 +429,7 @@ static GstFlowReturn
 gst_stride_transform_transform_ip (GstBaseTransform *base,
     GstBuffer *buf)
 {
-  GstStrideTransform *self = GST_STRIDE_TRANSFORM (base);
-  GST_DEBUG_OBJECT (self, "not implemented");
-  return GST_FLOW_ERROR;
+  /* transform function is safe to call with same buffer ptr:
+   */
+  return gst_stride_transform_transform (base, buf, buf);
 }
-- 
1.7.1