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