1 // deinterlace.c
2 // weed plugin
3 // (c) G. Finch (salsaman) 2006 - 2008
4 //
5 // released under the GNU GPL 3 or later
6 // see file COPYING or www.gnu.org for details
7
8 ///////////////////////////////////////////////////////////////////
9
10 static int package_version = 1; // version of this package
11
12 //////////////////////////////////////////////////////////////////
13 #define NEED_PALETTE_UTILS
14
15 #ifndef NEED_LOCAL_WEED_PLUGIN
16 #include <weed/weed-plugin.h>
17 #include <weed/weed-utils.h> // optional
18 #include <weed/weed-plugin-utils.h> // optional
19 #else
20 #include "../../libweed/weed-plugin.h"
21 #include "../../libweed/weed-utils.h" // optional
22 #include "../../libweed/weed-plugin-utils.h" // optional
23 #endif
24
25 #include "weed-plugin-utils.c" // optional
26
27 /////////////////////////////////////////////////////////////
28
29 #include <stdlib.h>
30
31
mix(unsigned char * a,unsigned char * b,int pcpy)32 static inline unsigned char *mix(unsigned char *a, unsigned char *b, int pcpy) {
33 unsigned char *mixed = (unsigned char *)weed_malloc(pcpy);
34 register int i;
35 for (i = 0; i < pcpy; i++) {
36 mixed[i] = (*(a + i) + * (b + i)) >> 1;
37 }
38 return mixed;
39 }
40
41
deinterlace_process(weed_plant_t * inst,weed_timecode_t tc)42 static weed_error_t deinterlace_process(weed_plant_t *inst, weed_timecode_t tc) {
43 weed_plant_t *in_channel = weed_get_in_channel(inst, 0),
44 *out_channel = weed_get_out_channel(inst, 0);
45 unsigned char *src = weed_channel_get_pixel_data(in_channel);
46 unsigned char *dst = weed_channel_get_pixel_data(out_channel);
47
48 unsigned char **src_array = (unsigned char **)weed_channel_get_pixel_data_planar(in_channel, NULL);
49 unsigned char **dst_array = (unsigned char **)weed_channel_get_pixel_data_planar(out_channel, NULL);
50
51 int inplace = (src == dst);
52
53 int width = weed_channel_get_width(in_channel);
54 int height = weed_channel_get_height(in_channel);
55 int palette = weed_channel_get_palette(in_channel);
56 int irowstride = weed_channel_get_stride(in_channel);
57 int orowstride = weed_channel_get_stride(out_channel), orowstride2 = orowstride * 2;
58 int *irowstrides = weed_channel_get_rowstrides(in_channel, NULL);
59 int *orowstrides = weed_channel_get_rowstrides(out_channel, NULL);
60
61 int x;
62
63 unsigned char *val1a, *val2a, *val3a, *val4a;
64 unsigned char *val2b, *val3b, *val4b;
65 unsigned char *val1c, *val2c, *val3c, *val4c;
66 unsigned char *res1, *res2, *res3, *res4, *res5, *res6;
67
68 unsigned char *val2a_u = NULL, *val3a_u = NULL, *val4a_u = NULL;
69 unsigned char *val2b_u = NULL, *val3b_u = NULL, *val4b_u = NULL;
70 unsigned char *val2c_u = NULL, *val3c_u = NULL, *val4c_u = NULL;
71 unsigned char *res1_u = NULL, *res2_u = NULL, *res3_u = NULL, *res4_u = NULL, *res5_u = NULL, *res6_u = NULL;
72
73 unsigned char *val2a_v = NULL, *val3a_v = NULL, *val4a_v = NULL;
74 unsigned char *val2b_v = NULL, *val3b_v = NULL, *val4b_v = NULL;
75 unsigned char *val2c_v = NULL, *val3c_v = NULL, *val4c_v = NULL;
76 unsigned char *res1_v = NULL, *res2_v = NULL, *res3_v = NULL, *res4_v = NULL, *res5_v = NULL, *res6_v = NULL;
77
78 int d1, d2;
79 unsigned char m1, m2, m3, m4;
80
81 int irowstride2 = irowstride * 2;
82 unsigned char *end = src + height * irowstride - irowstride2;
83
84 int psize = 3, psize2, psize3, pcpy;
85 int widthx;
86
87 int green_offs = 0;
88
89 psize = pixel_size(palette);
90
91 if (palette == WEED_PALETTE_RGBA32 || palette == WEED_PALETTE_BGRA32 ||
92 palette == WEED_PALETTE_RGB24 || palette == WEED_PALETTE_BGR24) green_offs = 1;
93 if (palette == WEED_PALETTE_ARGB32) green_offs = 2;
94
95 psize2 = psize * 2;
96 psize3 = psize * 3;
97
98 widthx = width * psize;
99
100 src += irowstride;
101 dst += orowstride;
102
103 if (palette == WEED_PALETTE_YUV444P || palette == WEED_PALETTE_YUVA4444P) {
104 for (int i = 1; i < 3; i++) {
105 dst_array[i] += orowstrides[i];
106 src_array[i] += irowstrides[i];
107 }
108 }
109
110 pcpy = psize;
111
112 if (palette == WEED_PALETTE_ARGB32 || palette == WEED_PALETTE_RGBA32 || palette == WEED_PALETTE_BGRA32 ||
113 palette == WEED_PALETTE_YUVA8888) pcpy = 3;
114
115 for (; src < end ; src += irowstride2) {
116 for (x = 0; x < widthx; x += psize3) {
117
118 if (!inplace && palette == WEED_PALETTE_ARGB32) {
119 // copy alpha packed
120 dst[x] = src[x];
121 dst[x + 4] = src[x + 4];
122 dst[x + 8] = src[x + 8];
123 x++;
124 }
125
126 val1a = (src - irowstride + x);
127 val2a = (src + x);
128 val3a = (src + irowstride + x);
129 val4a = (src + irowstride2 + x);
130
131 val2b = (src + x + psize);
132
133 val1c = (src - irowstride + x + psize2);
134 val2c = (src + x + psize2);
135 val3c = (src + irowstride + x + psize2);
136 val4c = (src + irowstride2 + x + psize2);
137
138 res1 = val2a;
139 res3 = val2b;
140 res5 = val2c;
141
142 if (palette == WEED_PALETTE_YUV444P || palette == WEED_PALETTE_YUVA4444P) {
143 // u and v planes
144 val2a_u = (src_array[1] + x);
145 val3a_u = (src_array[1] + irowstrides[1] + x);
146 val4a_u = (src_array[1] + irowstrides[1] * 2 + x);
147
148 val2b_u = (src_array[1] + x + psize);
149
150 val2c_u = (src_array[1] + x + psize2);
151 val3c_u = (src_array[1] + irowstrides[1] + x + psize2);
152 val4c_u = (src_array[1] + irowstrides[1] * 2 + x + psize2);
153
154 res1_u = val2a_u;
155 res3_u = val2b_u;
156 res5_u = val2c_u;
157
158 val3a_v = (src_array[2] + irowstrides[2] + x);
159 val4a_v = (src_array[2] + irowstrides[2] * 2 + x);
160
161 val2b_v = (src_array[2] + x + psize);
162
163 val2c_v = (src_array[2] + x + psize2);
164 val3c_v = (src_array[2] + irowstrides[2] + x + psize2);
165 val4c_v = (src_array[2] + irowstrides[2] * 2 + x + psize2);
166
167 res1_v = val2a_v;
168 res3_v = val2b_v;
169 res5_v = val2c_v;
170 }
171
172 if (palette == WEED_PALETTE_UYVY8888) {
173 //average 4 y values
174 m1 = (*(val1a + 1) + * (val1a + 3) + * (val1c + 1) + * (val1c + 3)) >> 2;
175 m2 = (*(val3a + 1) + * (val3a + 3) + * (val3c + 1) + * (val3c + 3)) >> 2;
176 m3 = (*(val2a + 1) + * (val2a + 3) + * (val2c + 1) + * (val2c + 3)) >> 2;
177 m4 = (*(val4a + 1) + * (val4a + 3) + * (val4c + 1) + * (val4c + 3)) >> 2;
178 } else if (palette == WEED_PALETTE_YUYV8888) {
179 // average 4 y values
180 m1 = (*(val1a) + * (val1a + 2) + * (val1c) + * (val1c + 2)) >> 2;
181 m2 = (*(val3a) + * (val3a + 2) + * (val3c) + * (val3c + 2)) >> 2;
182 m3 = (*(val2a) + * (val2a + 2) + * (val2c) + * (val2c + 2)) >> 2;
183 m4 = (*(val4a) + * (val4a + 2) + * (val4c) + * (val4c + 2)) >> 2;
184 } else {
185 // average 2 green values
186 m1 = (*(val1a + green_offs) + * (val1c + green_offs)) >> 1; // -1 row
187 m2 = (*(val3a + green_offs) + * (val3c + green_offs)) >> 1; // +1 row
188 m3 = (*(val2a + green_offs) + * (val2c + green_offs)) >> 1; // +0 row
189 m4 = (*(val4a + green_offs) + * (val4c + green_offs)) >> 1; // +2 row
190 }
191
192 d1 = abs(m1 - m2) + abs(m3 - m4); // diff (-1,+1) + diff (0,+2)
193 d2 = abs(m1 - m4) + abs(m3 - m2); // diff (-1,+2) + diff (0,+1)
194
195 if ((d1) < (d2)) {// alternate rows differ more than consecutive rows
196 val4b = (src + irowstride2 + x + psize);
197 val2b = (src + x + psize);
198
199 res2 = mix(val2a, val4a, pcpy);
200 res4 = mix(val2b, val4b, pcpy);
201 res6 = mix(val2c, val4c, pcpy);
202
203 if (palette == WEED_PALETTE_YUV444P || palette == WEED_PALETTE_YUVA4444P) {
204 // apply to u and v planes
205 val4b_u = (src_array[1] + irowstrides[1] * 2 + x + psize);
206 val2b_u = (src_array[1] + x + psize);
207
208 res2_u = mix(val2a_u, val4a_u, pcpy);
209 res4_u = mix(val2b_u, val4b_u, pcpy);
210 res6_u = mix(val2c_u, val4c_u, pcpy);
211
212 val4b_v = (src_array[2] + irowstrides[2] * 2 + x + psize);
213 val2b_v = (src_array[2] + x + psize);
214
215 res2_v = mix(val2a_v, val4a_v, pcpy);
216 res4_v = mix(val2b_v, val4b_v, pcpy);
217 res6_v = mix(val2c_v, val4c_v, pcpy);
218 }
219 } else {
220 val3b = (src + irowstride + x + psize);
221
222 res2 = val3a;
223 res4 = val3b;
224 res6 = val3c;
225
226 if (palette == WEED_PALETTE_YUV444P || palette == WEED_PALETTE_YUVA4444P) {
227 val3b_u = (src_array[1] + irowstrides[1] + x + psize);
228
229 res2_u = val3a_u;
230 res4_u = val3b_u;
231 res6_u = val3c_u;
232
233 val3b_v = (src_array[2] + irowstrides[2] + x + psize);
234
235 res2_v = val3a_v;
236 res4_v = val3b_v;
237 res6_v = val3c_v;
238 }
239 }
240
241 weed_memcpy(dst + x - orowstride, res1, pcpy);
242 weed_memcpy(dst + x, res2, pcpy);
243 weed_memcpy(dst + x + psize - orowstride, res3, pcpy);
244 weed_memcpy(dst + x + psize, res4, pcpy);
245 weed_memcpy(dst + x + psize2 - orowstride, res5, pcpy);
246 weed_memcpy(dst + x + psize2, res6, pcpy);
247
248 if (palette == WEED_PALETTE_YUV444P || palette == WEED_PALETTE_YUVA4444P) {
249 // u and v planes
250
251 weed_memcpy(dst_array[1] + x - orowstrides[1], res1_u, pcpy);
252 weed_memcpy(dst_array[1] + x, res2_u, pcpy);
253 weed_memcpy(dst_array[1] + x + psize - orowstrides[1], res3_u, pcpy);
254 weed_memcpy(dst_array[1] + x + psize, res4_u, pcpy);
255 weed_memcpy(dst_array[1] + x + psize2 - orowstrides[1], res5_u, pcpy);
256 weed_memcpy(dst_array[1] + x + psize2, res6_u, pcpy);
257
258 weed_memcpy(dst_array[2] + x - orowstrides[2], res1_v, pcpy);
259 weed_memcpy(dst_array[2] + x, res2_v, pcpy);
260 weed_memcpy(dst_array[2] + x + psize - orowstrides[2], res3_v, pcpy);
261 weed_memcpy(dst_array[2] + x + psize, res4_v, pcpy);
262 weed_memcpy(dst_array[2] + x + psize2 - orowstrides[2], res5_v, pcpy);
263 weed_memcpy(dst_array[2] + x + psize2, res6_v, pcpy);
264 }
265
266 if (!inplace && (palette == WEED_PALETTE_RGBA32 || palette == WEED_PALETTE_BGRA32
267 || palette == WEED_PALETTE_YUVA8888)) {
268 // copy alpha packed
269 dst[x + 3] = src[x + 3];
270 dst[x + 7] = src[x + 7];
271 dst[x + 11] = src[x + 11];
272 }
273
274 if ((d1) < (d2)) {
275 weed_free(res2);
276 weed_free(res4);
277 weed_free(res6);
278 if (palette == WEED_PALETTE_YUV444P || palette == WEED_PALETTE_YUVA4444P) {
279 weed_free(res2_u);
280 weed_free(res4_u);
281 weed_free(res6_u);
282 weed_free(res2_v);
283 weed_free(res4_v);
284 weed_free(res6_v);
285 }
286 }
287 }
288
289 if (palette == WEED_PALETTE_YUV444P || palette == WEED_PALETTE_YUVA4444P) {
290 dst_array[1] += orowstrides[1] * 2;
291 dst_array[2] += orowstrides[2] * 2;
292 }
293 dst += orowstride2;
294 }
295
296 if (!inplace) {
297 if (palette == WEED_PALETTE_YUV422P || palette == WEED_PALETTE_YUV420P || palette == WEED_PALETTE_YVU420P) {
298 // copy chroma planes
299 weed_memcpy(dst_array[1], src_array[1], orowstrides[1] * height >> (palette == WEED_PALETTE_YUV422P ? 0 : 1));
300 weed_memcpy(dst_array[2], src_array[2], orowstrides[2] * height >> (palette == WEED_PALETTE_YUV422P ? 0 : 1));
301
302 } else if (palette == WEED_PALETTE_YUVA4444P) {
303 // copy alpha plane
304 weed_memcpy(dst_array[3], src_array[3], orowstrides[3] * height);
305 }
306 }
307
308 weed_free(src_array);
309 weed_free(dst_array);
310
311 return WEED_SUCCESS;
312 }
313
314
315 WEED_SETUP_START(200, 200) {
316 int palette_list[] = {WEED_PALETTE_RGB24, WEED_PALETTE_BGR24, WEED_PALETTE_YUV888, WEED_PALETTE_RGBA32, WEED_PALETTE_BGRA32, WEED_PALETTE_ARGB32, WEED_PALETTE_YUVA8888, WEED_PALETTE_UYVY, WEED_PALETTE_YUYV, WEED_PALETTE_YUV444P, WEED_PALETTE_YUVA4444P, WEED_PALETTE_YUV420P, WEED_PALETTE_YVU420P, WEED_PALETTE_YUV422P, WEED_PALETTE_END};
317
318 weed_plant_t *in_chantmpls[] = {weed_channel_template_init("in channel 0", 0), NULL};
319 weed_plant_t *out_chantmpls[] = {weed_channel_template_init("out channel 0", WEED_CHANNEL_CAN_DO_INPLACE), NULL};
320 weed_plant_t *filter_class = weed_filter_class_init("deinterlace", "salsaman", 1, 0, palette_list,
321 NULL, deinterlace_process, NULL, in_chantmpls, out_chantmpls, NULL, NULL);
322
323 weed_plugin_info_add_filter_class(plugin_info, filter_class);
324 weed_set_int_value(plugin_info, WEED_LEAF_VERSION, package_version);
325 }
326 WEED_SETUP_END;
327
328