MythTV  0.26-pre
filter_yadif.c
Go to the documentation of this file.
00001 /*
00002  * Yadif
00003  *
00004  * Original taken from mplayer (vf_yadif.c)
00005     Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00020  *
00021  * converted for myth by Markus Schulz <msc@antzsystem.de>
00022  * */
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <unistd.h>
00026 #include "config.h"
00027 #if HAVE_STDINT_H
00028 #include <stdint.h>
00029 #endif
00030 #include <inttypes.h>
00031 
00032 #include <string.h>
00033 #include <math.h>
00034 #include <pthread.h>
00035 
00036 #include "filter.h"
00037 #include "frame.h"
00038 
00039 #define MIN(a,b) ((a) > (b) ? (b) : (a))
00040 #define MAX(a,b) ((a) < (b) ? (b) : (a))
00041 #define ABS(a) ((a) > 0 ? (a) : (-(a)))
00042 
00043 #define MIN3(a,b,c) MIN(MIN(a,b),c)
00044 #define MAX3(a,b,c) MAX(MAX(a,b),c)
00045 
00046 #include "../mm_arch.h"
00047 #if HAVE_MMX
00048 #include "ffmpeg-mmx.h"
00049 #endif
00050 
00051 #include "aclib.h"
00052 
00053 static void* (*fast_memcpy)(void * to, const void * from, size_t len);
00054 
00055 struct DeintThread
00056 {
00057     int       ready;
00058     pthread_t id;
00059     int       exists;
00060 };
00061 
00062 typedef struct ThisFilter
00063 {
00064     VideoFilter vf;
00065 
00066     struct DeintThread *threads;
00067     VideoFrame *frame;
00068     int         field;
00069     int         ready;
00070     int         kill_threads;
00071     int         actual_threads;
00072     int         requested_threads;
00073     pthread_mutex_t mutex;
00074 
00075     long long last_framenr;
00076 
00077     uint8_t *ref[4][3];
00078     int stride[3];
00079     int8_t got_frames[4];
00080 
00081     void (*filter_line)(struct ThisFilter *p, uint8_t *dst,
00082                         uint8_t *prev, uint8_t *cur, uint8_t *next,
00083                         int w, int refs, int parity);
00084     int mode;
00085     int width;
00086     int height;
00087 
00088     int mm_flags;
00089     TF_STRUCT;
00090 } ThisFilter;
00091 
00092 static void AllocFilter(ThisFilter* filter, int width, int height)
00093 {
00094     int i,j;
00095     if ((width != filter->width) || height != filter->height)
00096     {
00097         printf("YadifDeint: size changed from %d x %d -> %d x %d\n",
00098                 filter->width, filter->height, width, height);
00099         for (i=0; i<3*3; i++)
00100         {
00101             uint8_t **p= &filter->ref[i%3][i/3];
00102             if (*p) free(*p - 3*filter->stride[i/3]);
00103             *p= NULL;
00104         }
00105         for (i=0; i<3; i++)
00106         {
00107             int is_chroma= !!i;
00108             int w= ((width   + 31) & (~31))>>is_chroma;
00109             int h= ((height+6+ 31) & (~31))>>is_chroma;
00110 
00111             filter->stride[i]= w;
00112             for (j=0; j<3; j++)
00113                 filter->ref[j][i]= (uint8_t*)calloc(w*h*sizeof(uint8_t),1)+3*w;
00114         }
00115         filter->width = width;
00116         filter->height = height;
00117         memset(filter->got_frames, 0, sizeof(filter->got_frames));
00118     }
00119 }
00120 
00121 static inline void * memcpy_pic2(void * dst, const void * src,
00122                                  int bytesPerLine, int height,
00123                                  int dstStride, int srcStride, int limit2width)
00124 {
00125     int i;
00126     void *retval=dst;
00127 
00128     if (!limit2width && dstStride == srcStride)
00129     {
00130         if (srcStride < 0)
00131         {
00132             src = (const uint8_t*)src + (height-1)*srcStride;
00133             dst = (uint8_t*)dst + (height-1)*dstStride;
00134             srcStride = -srcStride;
00135         }
00136         fast_memcpy(dst, src, srcStride*height);
00137     }
00138     else
00139     {
00140         for (i=0; i<height; i++)
00141         {
00142             fast_memcpy(dst, src, bytesPerLine);
00143             src = (const uint8_t*)src + srcStride;
00144             dst = (uint8_t*)dst + dstStride;
00145         }
00146     }
00147 
00148     return retval;
00149 }
00150 #define memcpy_pic(d, s, b, h, ds, ss) memcpy_pic2(d, s, b, h, ds, ss, 0)
00151 
00152 static void store_ref(struct ThisFilter *p, uint8_t *src, int src_offsets[3],
00153                       int src_stride[3], int width, int height)
00154 {
00155     int i;
00156 
00157     memcpy (p->ref[3], p->ref[0], sizeof(uint8_t *)*3);
00158     memmove(p->ref[0], p->ref[1], sizeof(uint8_t *)*3*3);
00159 
00160     memcpy (&p->got_frames[3], &p->got_frames[0], sizeof(uint8_t));
00161     memmove(&p->got_frames[0], &p->got_frames[1], sizeof(uint8_t) * 3);
00162 
00163     for (i=0; i<3; i++)
00164     {
00165         int is_chroma= !!i;
00166         memcpy_pic(p->ref[2][i], src + src_offsets[i], width>>is_chroma,
00167                    height>>is_chroma, p->stride[i], src_stride[i]);
00168     }
00169     p->got_frames[2] = 1;
00170 }
00171 
00172 
00173 #if HAVE_MMX
00174 
00175 #define LOAD4(mem,dst) \
00176             "movd      "mem", "#dst" \n\t"\
00177             "punpcklbw %%mm7, "#dst" \n\t"
00178 
00179 #define PABS(tmp,dst) \
00180             "pxor     "#tmp", "#tmp" \n\t"\
00181             "psubw    "#dst", "#tmp" \n\t"\
00182             "pmaxsw   "#tmp", "#dst" \n\t"
00183 
00184 #define CHECK(pj,mj) \
00185             "movq "#pj"(%[cur],%[mrefs]), %%mm2 \n\t" /* cur[x-refs-1+j] */\
00186             "movq "#mj"(%[cur],%[prefs]), %%mm3 \n\t" /* cur[x+refs-1-j] */\
00187             "movq      %%mm2, %%mm4 \n\t"\
00188             "movq      %%mm2, %%mm5 \n\t"\
00189             "pxor      %%mm3, %%mm4 \n\t"\
00190             "pavgb     %%mm3, %%mm5 \n\t"\
00191             "pand     %[pb1], %%mm4 \n\t"\
00192             "psubusb   %%mm4, %%mm5 \n\t"\
00193             "psrlq     $8,    %%mm5 \n\t"\
00194             "punpcklbw %%mm7, %%mm5 \n\t" /* (cur[x-refs+j] + cur[x+refs-j])>>1 */\
00195             "movq      %%mm2, %%mm4 \n\t"\
00196             "psubusb   %%mm3, %%mm2 \n\t"\
00197             "psubusb   %%mm4, %%mm3 \n\t"\
00198             "pmaxub    %%mm3, %%mm2 \n\t"\
00199             "movq      %%mm2, %%mm3 \n\t"\
00200             "movq      %%mm2, %%mm4 \n\t" /* ABS(cur[x-refs-1+j] - cur[x+refs-1-j]) */\
00201             "psrlq      $8,   %%mm3 \n\t" /* ABS(cur[x-refs  +j] - cur[x+refs  -j]) */\
00202             "psrlq     $16,   %%mm4 \n\t" /* ABS(cur[x-refs+1+j] - cur[x+refs+1-j]) */\
00203             "punpcklbw %%mm7, %%mm2 \n\t"\
00204             "punpcklbw %%mm7, %%mm3 \n\t"\
00205             "punpcklbw %%mm7, %%mm4 \n\t"\
00206             "paddw     %%mm3, %%mm2 \n\t"\
00207             "paddw     %%mm4, %%mm2 \n\t" /* score */
00208 
00209 #define CHECK1 \
00210             "movq      %%mm0, %%mm3 \n\t"\
00211             "pcmpgtw   %%mm2, %%mm3 \n\t" /* if (score < spatial_score) */\
00212             "pminsw    %%mm2, %%mm0 \n\t" /* spatial_score= score; */\
00213             "movq      %%mm3, %%mm6 \n\t"\
00214             "pand      %%mm3, %%mm5 \n\t"\
00215             "pandn     %%mm1, %%mm3 \n\t"\
00216             "por       %%mm5, %%mm3 \n\t"\
00217             "movq      %%mm3, %%mm1 \n\t" /* spatial_pred= (cur[x-refs+j] + cur[x+refs-j])>>1; */
00218 
00219 #define CHECK2 /* pretend not to have checked dir=2 if dir=1 was bad.\
00220                   hurts both quality and speed, but matches the C version. */\
00221             "paddw    %[pw1], %%mm6 \n\t"\
00222             "psllw     $14,   %%mm6 \n\t"\
00223             "paddsw    %%mm6, %%mm2 \n\t"\
00224             "movq      %%mm0, %%mm3 \n\t"\
00225             "pcmpgtw   %%mm2, %%mm3 \n\t"\
00226             "pminsw    %%mm2, %%mm0 \n\t"\
00227             "pand      %%mm3, %%mm5 \n\t"\
00228             "pandn     %%mm1, %%mm3 \n\t"\
00229             "por       %%mm5, %%mm3 \n\t"\
00230             "movq      %%mm3, %%mm1 \n\t"
00231 
00232 static void filter_line_mmx2(struct ThisFilter *p, uint8_t *dst,
00233                              uint8_t *prev, uint8_t *cur, uint8_t *next,
00234                              int w, int refs, int parity)
00235 {
00236     static const uint64_t pw_1 = 0x0001000100010001ULL;
00237     static const uint64_t pb_1 = 0x0101010101010101ULL;
00238     const int mode = p->mode;
00239     uint64_t tmp0, tmp1, tmp2, tmp3;
00240     int x;
00241 
00242 #define FILTER\
00243     for (x=0; x<w; x+=4){\
00244         __asm__ volatile(\
00245             "pxor      %%mm7, %%mm7 \n\t"\
00246             LOAD4("(%[cur],%[mrefs])", %%mm0) /* c = cur[x-refs] */\
00247             LOAD4("(%[cur],%[prefs])", %%mm1) /* e = cur[x+refs] */\
00248             LOAD4("(%["prev2"])", %%mm2) /* prev2[x] */\
00249             LOAD4("(%["next2"])", %%mm3) /* next2[x] */\
00250             "movq      %%mm3, %%mm4 \n\t"\
00251             "paddw     %%mm2, %%mm3 \n\t"\
00252             "psraw     $1,    %%mm3 \n\t" /* d = (prev2[x] + next2[x])>>1 */\
00253             "movq      %%mm0, %[tmp0] \n\t" /* c */\
00254             "movq      %%mm3, %[tmp1] \n\t" /* d */\
00255             "movq      %%mm1, %[tmp2] \n\t" /* e */\
00256             "psubw     %%mm4, %%mm2 \n\t"\
00257             PABS(      %%mm4, %%mm2) /* temporal_diff0 */\
00258             LOAD4("(%[prev],%[mrefs])", %%mm3) /* prev[x-refs] */\
00259             LOAD4("(%[prev],%[prefs])", %%mm4) /* prev[x+refs] */\
00260             "psubw     %%mm0, %%mm3 \n\t"\
00261             "psubw     %%mm1, %%mm4 \n\t"\
00262             PABS(      %%mm5, %%mm3)\
00263             PABS(      %%mm5, %%mm4)\
00264             "paddw     %%mm4, %%mm3 \n\t" /* temporal_diff1 */\
00265             "psrlw     $1,    %%mm2 \n\t"\
00266             "psrlw     $1,    %%mm3 \n\t"\
00267             "pmaxsw    %%mm3, %%mm2 \n\t"\
00268             LOAD4("(%[next],%[mrefs])", %%mm3) /* next[x-refs] */\
00269             LOAD4("(%[next],%[prefs])", %%mm4) /* next[x+refs] */\
00270             "psubw     %%mm0, %%mm3 \n\t"\
00271             "psubw     %%mm1, %%mm4 \n\t"\
00272             PABS(      %%mm5, %%mm3)\
00273             PABS(      %%mm5, %%mm4)\
00274             "paddw     %%mm4, %%mm3 \n\t" /* temporal_diff2 */\
00275             "psrlw     $1,    %%mm3 \n\t"\
00276             "pmaxsw    %%mm3, %%mm2 \n\t"\
00277             "movq      %%mm2, %[tmp3] \n\t" /* diff */\
00278 \
00279             "paddw     %%mm0, %%mm1 \n\t"\
00280             "paddw     %%mm0, %%mm0 \n\t"\
00281             "psubw     %%mm1, %%mm0 \n\t"\
00282             "psrlw     $1,    %%mm1 \n\t" /* spatial_pred */\
00283             PABS(      %%mm2, %%mm0)      /* ABS(c-e) */\
00284 \
00285             "movq -1(%[cur],%[mrefs]), %%mm2 \n\t" /* cur[x-refs-1] */\
00286             "movq -1(%[cur],%[prefs]), %%mm3 \n\t" /* cur[x+refs-1] */\
00287             "movq      %%mm2, %%mm4 \n\t"\
00288             "psubusb   %%mm3, %%mm2 \n\t"\
00289             "psubusb   %%mm4, %%mm3 \n\t"\
00290             "pmaxub    %%mm3, %%mm2 \n\t"\
00291             "pshufw $9,%%mm2, %%mm3 \n\t"\
00292             "punpcklbw %%mm7, %%mm2 \n\t" /* ABS(cur[x-refs-1] - cur[x+refs-1]) */\
00293             "punpcklbw %%mm7, %%mm3 \n\t" /* ABS(cur[x-refs+1] - cur[x+refs+1]) */\
00294             "paddw     %%mm2, %%mm0 \n\t"\
00295             "paddw     %%mm3, %%mm0 \n\t"\
00296             "psubw    %[pw1], %%mm0 \n\t" /* spatial_score */\
00297 \
00298             CHECK(-2,0)\
00299             CHECK1\
00300             CHECK(-3,1)\
00301             CHECK2\
00302             CHECK(0,-2)\
00303             CHECK1\
00304             CHECK(1,-3)\
00305             CHECK2\
00306 \
00307             /* if (p->mode<2) ... */\
00308             "movq    %[tmp3], %%mm6 \n\t" /* diff */\
00309             "cmpl      $2, %[mode] \n\t"\
00310             "jge       1f \n\t"\
00311             LOAD4("(%["prev2"],%[mrefs],2)", %%mm2) /* prev2[x-2*refs] */\
00312             LOAD4("(%["next2"],%[mrefs],2)", %%mm4) /* next2[x-2*refs] */\
00313             LOAD4("(%["prev2"],%[prefs],2)", %%mm3) /* prev2[x+2*refs] */\
00314             LOAD4("(%["next2"],%[prefs],2)", %%mm5) /* next2[x+2*refs] */\
00315             "paddw     %%mm4, %%mm2 \n\t"\
00316             "paddw     %%mm5, %%mm3 \n\t"\
00317             "psrlw     $1,    %%mm2 \n\t" /* b */\
00318             "psrlw     $1,    %%mm3 \n\t" /* f */\
00319             "movq    %[tmp0], %%mm4 \n\t" /* c */\
00320             "movq    %[tmp1], %%mm5 \n\t" /* d */\
00321             "movq    %[tmp2], %%mm7 \n\t" /* e */\
00322             "psubw     %%mm4, %%mm2 \n\t" /* b-c */\
00323             "psubw     %%mm7, %%mm3 \n\t" /* f-e */\
00324             "movq      %%mm5, %%mm0 \n\t"\
00325             "psubw     %%mm4, %%mm5 \n\t" /* d-c */\
00326             "psubw     %%mm7, %%mm0 \n\t" /* d-e */\
00327             "movq      %%mm2, %%mm4 \n\t"\
00328             "pminsw    %%mm3, %%mm2 \n\t"\
00329             "pmaxsw    %%mm4, %%mm3 \n\t"\
00330             "pmaxsw    %%mm5, %%mm2 \n\t"\
00331             "pminsw    %%mm5, %%mm3 \n\t"\
00332             "pmaxsw    %%mm0, %%mm2 \n\t" /* max */\
00333             "pminsw    %%mm0, %%mm3 \n\t" /* min */\
00334             "pxor      %%mm4, %%mm4 \n\t"\
00335             "pmaxsw    %%mm3, %%mm6 \n\t"\
00336             "psubw     %%mm2, %%mm4 \n\t" /* -max */\
00337             "pmaxsw    %%mm4, %%mm6 \n\t" /* diff= MAX3(diff, min, -max); */\
00338             "1: \n\t"\
00339 \
00340             "movq    %[tmp1], %%mm2 \n\t" /* d */\
00341             "movq      %%mm2, %%mm3 \n\t"\
00342             "psubw     %%mm6, %%mm2 \n\t" /* d-diff */\
00343             "paddw     %%mm6, %%mm3 \n\t" /* d+diff */\
00344             "pmaxsw    %%mm2, %%mm1 \n\t"\
00345             "pminsw    %%mm3, %%mm1 \n\t" /* d = clip(spatial_pred, d-diff, d+diff); */\
00346             "packuswb  %%mm1, %%mm1 \n\t"\
00347 \
00348             :[tmp0]"=m"(tmp0),\
00349              [tmp1]"=m"(tmp1),\
00350              [tmp2]"=m"(tmp2),\
00351              [tmp3]"=m"(tmp3)\
00352             :[prev] "r"(prev),\
00353              [cur]  "r"(cur),\
00354              [next] "r"(next),\
00355              [prefs]"r"((long)refs),\
00356              [mrefs]"r"((long)-refs),\
00357              [pw1]  "m"(pw_1),\
00358              [pb1]  "m"(pb_1),\
00359              [mode] "g"(mode)\
00360         );\
00361         __asm__ volatile("movd %%mm1, %0" :"=m"(*dst));\
00362         dst += 4;\
00363         prev+= 4;\
00364         cur += 4;\
00365         next+= 4;\
00366     }
00367 
00368     if (parity)
00369     {
00370 #define prev2 "prev"
00371 #define next2 "cur"
00372         FILTER
00373 #undef prev2
00374 #undef next2
00375     }
00376     else
00377     {
00378 #define prev2 "cur"
00379 #define next2 "next"
00380         FILTER
00381 #undef prev2
00382 #undef next2
00383     }
00384 }
00385 #undef LOAD4
00386 #undef PABS
00387 #undef CHECK
00388 #undef CHECK1
00389 #undef CHECK2
00390 #undef FILTER
00391 
00392 #endif /* HAVE_MMX && defined(NAMED_ASM_ARGS) */
00393 
00394 static void filter_line_c(struct ThisFilter *p, uint8_t *dst,
00395                           uint8_t *prev, uint8_t *cur, uint8_t *next,
00396                           int w, int refs, int parity)
00397 {
00398     int x;
00399     uint8_t *prev2= parity ? prev : cur ;
00400     uint8_t *next2= parity ? cur  : next;
00401     for (x=0; x<w; x++)
00402     {
00403         int c= cur[-refs];
00404         int d= (prev2[0] + next2[0])>>1;
00405         int e= cur[+refs];
00406         int temporal_diff0= ABS(prev2[0] - next2[0]);
00407         int temporal_diff1=( ABS(prev[-refs] - c) + ABS(prev[+refs] - e) )>>1;
00408         int temporal_diff2=( ABS(next[-refs] - c) + ABS(next[+refs] - e) )>>1;
00409         int diff= MAX3(temporal_diff0>>1, temporal_diff1, temporal_diff2);
00410         int spatial_pred= (c+e)>>1;
00411         int spatial_score= ABS(cur[-refs-1] - cur[+refs-1]) + ABS(c-e)
00412                          + ABS(cur[-refs+1] - cur[+refs+1]) - 1;
00413 
00414 #define CHECK(j)\
00415     {   int score= ABS(cur[-refs-1+j] - cur[+refs-1-j])\
00416                  + ABS(cur[-refs  +j] - cur[+refs  -j])\
00417                  + ABS(cur[-refs+1+j] - cur[+refs+1-j]);\
00418         if (score < spatial_score){\
00419             spatial_score= score;\
00420             spatial_pred= (cur[-refs  +j] + cur[+refs  -j])>>1;\
00421 
00422         CHECK(-1) CHECK(-2) }} }}
00423         CHECK( 1) CHECK( 2) }} }}
00424 
00425         int b= (prev2[-2*refs] + next2[-2*refs])>>1;
00426         int f= (prev2[+2*refs] + next2[+2*refs])>>1;
00427         int max= MAX3(d-e, d-c, MIN(b-c, f-e));
00428         int min= MIN3(d-e, d-c, MAX(b-c, f-e));
00429         diff= MAX3(diff, min, -max);
00430 
00431         if (spatial_pred > d + diff)
00432            spatial_pred = d + diff;
00433         else if (spatial_pred < d - diff)
00434            spatial_pred = d - diff;
00435 
00436         dst[0] = spatial_pred;
00437 
00438         dst++;
00439         cur++;
00440         prev++;
00441         next++;
00442         prev2++;
00443         next2++;
00444     }
00445 }
00446 
00447 static void filter_func(struct ThisFilter *p, uint8_t *dst, int dst_offsets[3],
00448                         int dst_stride[3], int width, int height, int parity,
00449                         int tff, int this_slice, int total_slices)
00450 {
00451     if (total_slices < 1)
00452         return;
00453 
00454     int y, i;
00455     uint8_t nr_p, nr_c;
00456     nr_c = p->got_frames[1] ? 1: 2;
00457     nr_p = p->got_frames[0] ? 0: nr_c;
00458     int slice_height = height / total_slices;
00459     slice_height     = (slice_height >> 1) << 1;
00460     int starth       = slice_height * this_slice;
00461     int endh         = starth + slice_height;
00462     if ((this_slice + 1) >= total_slices)
00463         endh = height;
00464 
00465     for (i = 0; i < 3; i++)
00466     {
00467         int is_chroma= !!i;
00468         int w     = width  >> is_chroma;
00469         int start = starth >> is_chroma;
00470         int end   = endh   >> is_chroma;
00471         int refs  = p->stride[i];
00472 
00473         for (y = start; y < end; y++)
00474         {
00475             uint8_t *dst2= dst + dst_offsets[i] + y*dst_stride[i];
00476             int field = parity ^ tff;
00477             if ((y ^ (1 - field)) & 1)
00478             {
00479                 uint8_t *prev= &p->ref[nr_p][i][y*refs];
00480                 uint8_t *cur = &p->ref[nr_c][i][y*refs];
00481                 uint8_t *next= &p->ref[2][i][y*refs];
00482                 uint8_t *dst2= dst + dst_offsets[i] + y*dst_stride[i];
00483                 p->filter_line(p, dst2, prev, cur, next, w, refs, field);
00484             }
00485             else
00486             {
00487                 fast_memcpy(dst2, &p->ref[nr_c][i][y*refs], w);
00488             }
00489         }
00490     }
00491 #if HAVE_MMX
00492     emms();
00493 #endif
00494 }
00495 
00496 static int YadifDeint (VideoFilter * f, VideoFrame * frame, int field)
00497 {
00498     ThisFilter *filter = (ThisFilter *) f;
00499     TF_VARS;
00500 
00501     AllocFilter(filter, frame->width, frame->height);
00502 
00503     if (filter->last_framenr != frame->frameNumber)
00504     {
00505         if (filter->last_framenr != (frame->frameNumber - 1))
00506             memset(filter->got_frames, 0, sizeof(filter->got_frames));
00507         store_ref(filter, frame->buf,  frame->offsets,
00508                   frame->pitches, frame->width, frame->height);
00509     }
00510 
00511     if (filter->actual_threads < 1)
00512     {
00513         filter_func(
00514             filter, frame->buf, frame->offsets, frame->pitches,
00515             frame->width, frame->height, field, frame->top_field_first,
00516             0, 1);
00517     }
00518     else
00519     {
00520         int i;
00521         for (i = 0; i < filter->actual_threads; i++)
00522             filter->threads[i].ready = 1;
00523         filter->field = field;
00524         filter->frame = frame;
00525         filter->ready = filter->actual_threads;
00526         i = 0;
00527         while (filter->ready > 0 && i < 1000)
00528         {
00529             usleep(1000);
00530             i++;
00531         }
00532     }
00533 
00534     filter->last_framenr = frame->frameNumber;
00535 
00536     return 0;
00537 }
00538 
00539 
00540 static void CleanupYadifDeintFilter (VideoFilter * filter)
00541 {
00542     int i;
00543     ThisFilter* f = (ThisFilter*)filter;
00544 
00545     if (f->threads != NULL)
00546     {
00547         f->kill_threads = 1;
00548         for (i = 0; i < f->requested_threads; i++)
00549             if (f->threads[i].exists)
00550                 pthread_join(f->threads[i].id, NULL);
00551         free(f->threads);
00552     }
00553 
00554     for (i = 0; i < 3*3; i++)
00555     {
00556         uint8_t **p= &f->ref[i%3][i/3];
00557         if (*p) free(*p - 3*f->stride[i/3]);
00558         *p= NULL;
00559     }
00560 }
00561 
00562 static void *YadifThread(void *args)
00563 {
00564     ThisFilter *filter = (ThisFilter*)args;
00565 
00566     pthread_mutex_lock(&(filter->mutex));
00567     int num = filter->actual_threads;
00568     filter->actual_threads = num + 1;
00569     pthread_mutex_unlock(&(filter->mutex));
00570 
00571     while (!filter->kill_threads)
00572     {
00573         usleep(1000);
00574         if (filter->ready &&
00575             filter->frame != NULL &&
00576             filter->threads[num].ready)
00577         {
00578             filter_func(
00579                 filter, filter->frame->buf, filter->frame->offsets,
00580                 filter->frame->pitches, filter->frame->width,
00581                 filter->frame->height, filter->field,
00582                 filter->frame->top_field_first, num, filter->actual_threads);
00583 
00584             pthread_mutex_lock(&(filter->mutex));
00585             filter->ready = filter->ready - 1;
00586             filter->threads[num].ready = 0;
00587             pthread_mutex_unlock(&(filter->mutex));
00588         }
00589     }
00590     pthread_exit(NULL);
00591     return NULL;
00592 }
00593 
00594 static VideoFilter * YadifDeintFilter(VideoFrameType inpixfmt,
00595                                       VideoFrameType outpixfmt,
00596                                       int *width, int *height, char *options,
00597                                       int threads)
00598 {
00599     ThisFilter *filter;
00600     (void) height;
00601     (void) options;
00602 
00603     fprintf(stderr, "YadifDeint: In-Pixformat = %d Out-Pixformat=%d\n",
00604             inpixfmt, outpixfmt);
00605     filter = (ThisFilter *) malloc (sizeof(ThisFilter));
00606     if (filter == NULL)
00607     {
00608         fprintf (stderr, "YadifDeint: failed to allocate memory.\n");
00609         return NULL;
00610     }
00611 
00612     filter->width = 0;
00613     filter->height = 0;
00614     filter->mode = 1;
00615     memset(filter->ref, 0, sizeof(filter->ref));
00616 
00617     AllocFilter(filter, *width, *height);
00618 
00619 #if HAVE_MMX
00620     filter->mm_flags = av_get_cpu_flags();
00621     TF_INIT(filter);
00622 #else
00623     filter->mm_flags = 0;
00624 #endif
00625 
00626     filter->filter_line = filter_line_c;
00627 #if HAVE_MMX
00628     if (filter->mm_flags & AV_CPU_FLAG_MMX)
00629     {
00630         filter->filter_line = filter_line_mmx2;
00631     }
00632 
00633     if (filter->mm_flags & AV_CPU_FLAG_SSE2)
00634         fast_memcpy=fast_memcpy_SSE;
00635     else if (filter->mm_flags & AV_CPU_FLAG_MMX2)
00636         fast_memcpy=fast_memcpy_MMX2;
00637     else if (filter->mm_flags & AV_CPU_FLAG_3DNOW)
00638         fast_memcpy=fast_memcpy_3DNow;
00639     else if (filter->mm_flags & AV_CPU_FLAG_MMX)
00640         fast_memcpy=fast_memcpy_MMX;
00641     else
00642 #endif
00643         fast_memcpy=memcpy;
00644 
00645     filter->vf.filter = &YadifDeint;
00646     filter->vf.cleanup = &CleanupYadifDeintFilter;
00647 
00648     filter->frame = NULL;
00649     filter->field = 0;
00650     filter->ready = 0;
00651     filter->kill_threads = 0;
00652     filter->actual_threads  = 0;
00653     filter->requested_threads  = threads;
00654     filter->threads = NULL;
00655 
00656     if (filter->requested_threads > 1)
00657     {
00658         filter->threads = (struct DeintThread *) calloc(threads,
00659                           sizeof(struct DeintThread));
00660         if (filter->threads == NULL)
00661         {
00662             printf("YadifDeint: failed to allocate memory for threads - "
00663                    "falling back to existing, single thread.\n");
00664             filter->requested_threads = 1;
00665         }
00666     }
00667 
00668     if (filter->requested_threads > 1)
00669     {
00670         pthread_mutex_init(&(filter->mutex), NULL);
00671         int success = 0;
00672         for (int i = 0; i < filter->requested_threads; i++)
00673         {
00674             if (pthread_create(&(filter->threads[i].id), NULL,
00675                                YadifThread, (void*)filter) != 0)
00676                 filter->threads[i].exists = 0;
00677             else
00678             {
00679                 success++;
00680                 filter->threads[i].exists = 1;
00681             }
00682         }
00683 
00684         if (success < filter->requested_threads)
00685         {
00686             printf("YadifDeint: only created %d of %d threads - "
00687                    "falling back to existing, single thread.\n"
00688                    , success, filter->requested_threads);
00689         }
00690         else
00691         {
00692             int timeout = 0;
00693             while (filter->actual_threads != filter->requested_threads)
00694             {
00695                 timeout++;
00696                 if (timeout > 5000)
00697                 {
00698                     printf("YadifDeint: waited too long for threads to start."
00699                            "- continuing.\n");
00700                     break;
00701                 }
00702                 usleep(1000);
00703             }
00704             printf("yadifdeint: Created %d threads (%d requested)\n",
00705                    filter->actual_threads, filter->requested_threads);
00706         }
00707     }
00708 
00709     if (filter->actual_threads < 1 )
00710     {
00711         printf("YadifDeint: Using existing thread.\n");
00712     }
00713 
00714     return (VideoFilter *) filter;
00715 }
00716 
00717 static FmtConv FmtList[] =
00718 {
00719     { FMT_YV12, FMT_YV12 } ,
00720     FMT_NULL
00721 };
00722 
00723 ConstFilterInfo filter_table[] =
00724 {
00725     {
00726             filter_init: &YadifDeintFilter,
00727             name:       "yadifdeint",
00728             descript:   "combines data from several fields to deinterlace with less motion blur",
00729             formats:    FmtList,
00730             libname:    NULL
00731     },
00732     {
00733             filter_init: &YadifDeintFilter,
00734             name:       "yadifdoubleprocessdeint",
00735             descript:   "combines data from several fields to deinterlace with less motion blur",
00736             formats:    FmtList,
00737             libname:    NULL
00738     },FILT_NULL
00739 };
00740 
00741 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends