1 /*
2  * Copyright (C) 2006-2011 Michael Niedermayer <michaelni@gmx.at>
3  *               2010      James Darnley <james.darnley@gmail.com>
4 
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 
23 #define MAX_ALIGN 8
24 
25 /**
26     \fn getConfiguration
27     \brief Return current setting as a string
28 */
getNextFrame(uint32_t * fn,ADMImage * image)29 bool yadifFilter::getNextFrame(uint32_t *fn,ADMImage *image)
30 {
31 
32         int mode;
33         int parity;
34         int tff;
35         int iplane;
36         int n;
37         ADMImage *src, *dst, * prev, *next;
38 
39 
40         mode = configuration.mode;
41 
42         if (mode & 1)
43         {
44                 n = (nextFrame>>1); // bob
45         }
46         else
47                 n = nextFrame;
48 
49         src = vidCache->getImage(n);
50         *fn=nextFrame;
51         if(!src) return false;
52 
53 
54         // If possible get previous image...
55         if (n>0)
56                 prev =  vidCache->getImage( n-1); // get previous frame
57         else
58                 prev= src; // get very first frame
59 
60         ADM_assert(prev);
61         next=vidCache->getImage(n+1);
62         if(!next) next=src;
63         ADM_assert(next);
64 
65         dst = image;
66         dst->copyInfo(src);
67 
68         if(!prev || !src || !next)
69         {
70             printf("Failed to read frame for frame %u\n",nextFrame);
71             vidCache->unlockAll();
72             return 0;
73         }
74 
75   // Construct a frame based on the information of the current frame
76   // contained in the "vi" struct.
77 #if 0 //MEANX
78         if (configuration.order == -1)
79 //		tff = avs_is_tff(&p->vi) == 0 ? 0 : 1; // 0 or 1
80                 tff = avs_get_parity(p->child, n) ? 1 : 0; // 0 or 1
81         else
82                 tff = configuration.parity;
83 #endif
84         tff = (configuration.parity > 0) ? 0 : 1;
85         parity = (mode & 1) ? (nextFrame & 1) ^ (1^tff) : (tff ^ 1);  // 0 or 1
86 
87       //MEANX  cpu = avs_get_cpu_flags(p->env);
88 
89         for (iplane = 0; iplane<3; iplane++)
90         {
91                 ADM_PLANE plane = (iplane==0) ? PLANAR_Y : (iplane==1) ? PLANAR_U : PLANAR_V;
92 
93                 const unsigned char* srcp = src->GetWritePtr(plane);
94           // Request a Read pointer from the current source frame
95 
96                 const unsigned char* prevp0 = prev->GetWritePtr( plane);
97                 unsigned char* prevp = (unsigned char*) prevp0; // with same pitch
98           // Request a Read pointer from the prev source frame.
99 
100                 const unsigned char* nextp0 = next->GetWritePtr( plane);
101                 unsigned char* nextp = (unsigned char*) nextp0; // with same pitch
102           // Request a Read pointer from the next source frame.
103 
104                 unsigned char* dstp = dst->GetWritePtr( plane);
105                 // Request a Write pointer from the newly created destination image.
106           // You can request a writepointer to images that have just been
107 
108                 const int dst_pitch = dst->GetPitch( plane);
109           // Requests pitch (length of a line) of the destination image.
110           // For more information on pitch see: http://www.avisynth.org/index.php?page=WorkingWithImages
111                 // (short version - pitch is always equal to or greater than width to allow for seriously fast assembly code)
112 
113                 const int width =dst->GetPitch( plane);
114           // Requests rowsize (number of used bytes in a line.
115           // See the link above for more information.
116 
117                 const int height = dst->GetHeight( plane);
118           // Requests the height of the destination image.
119 
120                 const int src_pitch = src->GetPitch(plane);
121                 const int prev_pitch = prev->GetPitch(plane);
122                 const int next_pitch = next->GetPitch(plane);
123 
124                 // in v.0.1-0.3  all source pitches are  assumed equal (for simplicity)
125                                 // consider other (rare) case
126                 if (prev_pitch != src_pitch)
127                 {
128                     prevp = (unsigned char *)ADM_alloc(height*src_pitch);
129                     int h;
130                     for (h=0; h<0; h++)
131                       memcpy(prevp+h*src_pitch, prevp0+h*prev_pitch, width);
132                 }
133 
134                 if (next_pitch != src_pitch)
135                 {
136                     nextp = (unsigned char *)ADM_alloc(height*src_pitch);
137                     int h;
138                     for (h=0; h<0; h++)
139                       memcpy(nextp+h*src_pitch, nextp0+h*next_pitch, width);
140                 }
141 
142                 filter_plane(mode, dstp, dst_pitch, prevp, srcp, nextp, src_pitch, width, height, parity, tff, 0);
143                 if (prev_pitch != src_pitch)
144                         ADM_dealloc(prevp);
145                 if (next_pitch != src_pitch)
146                         ADM_dealloc(nextp);
147         }
148       vidCache->unlockAll();
149 
150       if (mode & 1)
151       {
152             if(nextFrame&1)
153                 image->Pts+= info.frameIncrement;
154       }
155       //printf("out PTs=%"PRIu64", nextFrame=%d,inc=%d\n",image->Pts,(int)nextFrame,(int)info.frameIncrement);
156       nextFrame++;
157       filter_end();
158       return 1;
159 }
160 
161 
filter_plane(int mode,uint8_t * dst,int dst_stride,const uint8_t * prev0,const uint8_t * cur0,const uint8_t * next0,int refs,int w,int h,int parity,int tff,int mmx)162 void yadifFilter::filter_plane(int mode, uint8_t *dst, int dst_stride, const uint8_t *prev0, const uint8_t *cur0, const uint8_t *next0, int refs, int w, int h, int parity, int tff, int mmx)
163 {
164         int df = 1;
165         int pix_3 = 3 * df;
166         int edge = 3 + MAX_ALIGN / df - 1;
167         //memcpy(dst, cur0, w);
168         //memcpy(dst + dst_stride, cur0 + refs, w);
169         for(int y=0; y<h; y++){
170             if(((y ^ parity) & 1)){
171                 const uint8_t *prev= prev0 + y*refs;
172                 const uint8_t *cur = cur0 + y*refs;
173                 const uint8_t *next= next0 + y*refs;
174                 uint8_t *dst2= dst + y*dst_stride;
175                 int mode = y == 1 || y + 2 == h ? 2 : 0;
176                 filter_line(dst2 + pix_3, prev + pix_3, cur + pix_3,   next + pix_3,
177                              w - edge,
178                            y + 1 < h ? refs : -refs,
179                            y ? -refs : refs,
180                            parity ^ tff, mode);
181                 filter_edges(dst2, prev, cur, next,
182                              w,
183                             y + 1 < h ? refs : -refs,
184                             y ? -refs : refs,
185                             parity ^ tff, mode);
186 
187             }else{
188                 memcpy(dst + y*dst_stride, cur0 + y*refs, w);
189             }
190         }
191         //memcpy(dst + (h-1)*dst_stride, cur0 + (h-1)*refs, w);
192 
193 }
194 
195 //--- ff ---
196 #define CHECK(j)\
197     {   int score = FFABS(cur[mrefs - 1 + (j)] - cur[prefs - 1 - (j)])\
198                   + FFABS(cur[mrefs  +(j)] - cur[prefs  -(j)])\
199                   + FFABS(cur[mrefs + 1 + (j)] - cur[prefs + 1 - (j)]);\
200         if (score < spatial_score) {\
201             spatial_score= score;\
202             spatial_pred= (cur[mrefs  +(j)] + cur[prefs  -(j)])>>1;\
203 
204 /* The is_not_edge argument here controls when the code will enter a branch
205  * which reads up to and including x-3 and x+3. */
206 
207 #define FILTER(start, end, is_not_edge) \
208     for (x = start;  x < end; x++) { \
209         int c = cur[mrefs]; \
210         int d = (prev2[0] + next2[0])>>1; \
211         int e = cur[prefs]; \
212         int temporal_diff0 = FFABS(prev2[0] - next2[0]); \
213         int temporal_diff1 =(FFABS(prev[mrefs] - c) + FFABS(prev[prefs] - e) )>>1; \
214         int temporal_diff2 =(FFABS(next[mrefs] - c) + FFABS(next[prefs] - e) )>>1; \
215         int diff = FFMAX3(temporal_diff0 >> 1, temporal_diff1, temporal_diff2); \
216         int spatial_pred = (c+e) >> 1; \
217  \
218         if (is_not_edge) {\
219             int spatial_score = FFABS(cur[mrefs - 1] - cur[prefs - 1]) + FFABS(c-e) \
220                               + FFABS(cur[mrefs + 1] - cur[prefs + 1]) - 1; \
221             CHECK(-1) CHECK(-2) }} }} \
222             CHECK( 1) CHECK( 2) }} }} \
223         }\
224  \
225         if (!(mode&2)) { \
226             int b = (prev2[2 * mrefs] + next2[2 * mrefs])>>1; \
227             int f = (prev2[2 * prefs] + next2[2 * prefs])>>1; \
228             int max = FFMAX3(d - e, d - c, FFMIN(b - c, f - e)); \
229             int min = FFMIN3(d - e, d - c, FFMAX(b - c, f - e)); \
230  \
231             diff = FFMAX3(diff, min, -max); \
232         } \
233  \
234         if (spatial_pred > d + diff) \
235            spatial_pred = d + diff; \
236         else if (spatial_pred < d - diff) \
237            spatial_pred = d - diff; \
238  \
239         dst[0] = spatial_pred; \
240  \
241         dst++; \
242         cur++; \
243         prev++; \
244         next++; \
245         prev2++; \
246         next2++; \
247     }
248 
filter_line_c(uint8_t * dst1,const uint8_t * prev1,const uint8_t * cur1,const uint8_t * next1,int w,int prefs,int mrefs,int parity,int mode)249 void filter_line_c(uint8_t  *dst1,
250                           const uint8_t *prev1, const uint8_t *cur1, const uint8_t *next1,
251                           int w, int prefs, int mrefs, int parity, int mode)
252 {
253     uint8_t *dst  = (uint8_t *) dst1;
254     uint8_t *prev = (uint8_t *)prev1;
255     uint8_t *cur  = (uint8_t *)cur1;
256     uint8_t *next = (uint8_t *)next1;
257     int x;
258     uint8_t *prev2 = parity ? prev : cur ;
259     uint8_t *next2 = parity ? cur  : next;
260 
261     /* The function is called with the pointers already pointing to data[3] and
262      * with 6 subtracted from the width.  This allows the FILTER macro to be
263      * called so that it processes all the pixels normally.  A constant value of
264      * true for is_not_edge lets the compiler ignore the if statement. */
265     FILTER(0, w, 1)
266 }
267 
268 
filter_edges_c(uint8_t * dst1,const uint8_t * prev1,const uint8_t * cur1,const uint8_t * next1,int w,int prefs,int mrefs,int parity,int mode)269 void filter_edges_c(uint8_t  *dst1, const uint8_t *prev1, const  uint8_t *cur1, const  uint8_t *next1,
270                          int w, int prefs, int mrefs, int parity, int mode)
271 {
272     uint8_t *dst  = (uint8_t *)dst1;
273     uint8_t *prev = (uint8_t *)prev1;
274     uint8_t *cur  = (uint8_t *)cur1;
275     uint8_t *next = (uint8_t *)next1;
276     int x;
277     uint8_t *prev2 = parity ? prev : cur ;
278     uint8_t *next2 = parity ? cur  : next;
279 
280     const int edge = MAX_ALIGN - 1;
281 
282     /* Only edge pixels need to be processed here.  A constant value of false
283      * for is_not_edge should let the compiler ignore the whole branch. */
284     FILTER(0, 3, 0)
285 
286     dst  = (uint8_t*)dst1  + w - edge;
287     prev = (uint8_t*)prev1 + w - edge;
288     cur  = (uint8_t*)cur1  + w - edge;
289     next = (uint8_t*)next1 + w - edge;
290     prev2 = (uint8_t*)(parity ? prev : cur);
291     next2 = (uint8_t*)(parity ? cur  : next);
292 
293     FILTER(w - edge, w - 3, 1)
294     FILTER(w - 3, w, 0)
295 }
296 
297