MythTV  0.26-pre
pullup.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) MPlayer Project license GPL v2
00003 */
00004 
00005 
00006 #include <stdio.h>
00007 #include <stdlib.h>
00008 #include <string.h>
00009 #include "pullup.h"
00010 #include "config.h"
00011 #include "../mm_arch.h"
00012 
00013 
00014 
00015 #if HAVE_MMX
00016 static int diff_y_mmx(unsigned char *a, unsigned char *b, int s)
00017 {
00018         int ret;
00019         __asm__ volatile (
00020                 "movl $4, %%ecx \n\t"
00021                 "pxor %%mm4, %%mm4 \n\t"
00022                 "pxor %%mm7, %%mm7 \n\t"
00023                 
00024                 ASMALIGN(4)
00025                 "1: \n\t"
00026                 
00027                 "movq (%%"REG_S"), %%mm0 \n\t"
00028                 "movq (%%"REG_S"), %%mm2 \n\t"
00029                 "add  %%"REG_a", %%"REG_S" \n\t"
00030                 "movq (%%"REG_D"), %%mm1 \n\t"
00031                 "add  %%"REG_a", %%"REG_D" \n\t"
00032                 "psubusb %%mm1, %%mm2 \n\t"
00033                 "psubusb %%mm0, %%mm1 \n\t"
00034                 "movq %%mm2, %%mm0 \n\t"
00035                 "movq %%mm1, %%mm3 \n\t"
00036                 "punpcklbw %%mm7, %%mm0 \n\t"
00037                 "punpcklbw %%mm7, %%mm1 \n\t"
00038                 "punpckhbw %%mm7, %%mm2 \n\t"
00039                 "punpckhbw %%mm7, %%mm3 \n\t"
00040                 "paddw %%mm0, %%mm4 \n\t"
00041                 "paddw %%mm1, %%mm4 \n\t"
00042                 "paddw %%mm2, %%mm4 \n\t"
00043                 "paddw %%mm3, %%mm4 \n\t"
00044                 
00045                 "decl %%ecx \n\t"
00046                 "jnz 1b \n\t"
00047 
00048                 "movq %%mm4, %%mm3 \n\t"
00049                 "punpcklwd %%mm7, %%mm4 \n\t"
00050                 "punpckhwd %%mm7, %%mm3 \n\t"
00051                 "paddd %%mm4, %%mm3 \n\t"
00052                 "movd %%mm3, %%eax \n\t"
00053                 "psrlq $32, %%mm3 \n\t"
00054                 "movd %%mm3, %%edx \n\t"
00055                 "addl %%edx, %%eax \n\t"
00056                 "emms \n\t"
00057                 : "=a" (ret)
00058                 : "S" (a), "D" (b), "a" (s)
00059                 : "%ecx", "%edx"
00060                 );
00061         return ret;
00062 }
00063 
00064 static int licomb_y_mmx(unsigned char *a, unsigned char *b, int s)
00065 {
00066         int ret;
00067         __asm__ volatile (
00068                 "movl $4, %%ecx \n\t"
00069                 "pxor %%mm6, %%mm6 \n\t"
00070                 "pxor %%mm7, %%mm7 \n\t"
00071                 "sub  %%"REG_a", %%"REG_D" \n\t"
00072                 
00073                 ASMALIGN(4)
00074                 "2: \n\t"
00075 
00076                 "movq (%%"REG_D"), %%mm0 \n\t"
00077                 "movq (%%"REG_D"), %%mm1 \n\t"
00078                 "punpcklbw %%mm7, %%mm0 \n\t"
00079                 "movq (%%"REG_D",%%"REG_a"), %%mm2 \n\t"
00080                 "punpcklbw %%mm7, %%mm1 \n\t"
00081                 "punpcklbw %%mm7, %%mm2 \n\t"
00082                 "paddw %%mm0, %%mm0 \n\t"
00083                 "paddw %%mm2, %%mm1 \n\t"
00084                 "movq %%mm0, %%mm2 \n\t"
00085                 "psubusw %%mm1, %%mm0 \n\t"
00086                 "psubusw %%mm2, %%mm1 \n\t"
00087                 "paddw %%mm0, %%mm6 \n\t"
00088                 "paddw %%mm1, %%mm6 \n\t"
00089 
00090                 "movq (%%"REG_S"), %%mm0 \n\t"
00091                 "movq (%%"REG_D"), %%mm1 \n\t"
00092                 "punpckhbw %%mm7, %%mm0 \n\t"
00093                 "movq (%%"REG_D",%%"REG_a"), %%mm2 \n\t"
00094                 "punpckhbw %%mm7, %%mm1 \n\t"
00095                 "punpckhbw %%mm7, %%mm2 \n\t"
00096                 "paddw %%mm0, %%mm0 \n\t"
00097                 "paddw %%mm2, %%mm1 \n\t"
00098                 "movq %%mm0, %%mm2 \n\t"
00099                 "psubusw %%mm1, %%mm0 \n\t"
00100                 "psubusw %%mm2, %%mm1 \n\t"
00101                 "paddw %%mm0, %%mm6 \n\t"
00102                 "paddw %%mm1, %%mm6 \n\t"
00103                 
00104                 "movq (%%"REG_D",%%"REG_a"), %%mm0 \n\t"
00105                 "movq (%%"REG_S"), %%mm1 \n\t"
00106                 "punpcklbw %%mm7, %%mm0 \n\t"
00107                 "movq (%%"REG_S",%%"REG_a"), %%mm2 \n\t"
00108                 "punpcklbw %%mm7, %%mm1 \n\t"
00109                 "punpcklbw %%mm7, %%mm2 \n\t"
00110                 "paddw %%mm0, %%mm0 \n\t"
00111                 "paddw %%mm2, %%mm1 \n\t"
00112                 "movq %%mm0, %%mm2 \n\t"
00113                 "psubusw %%mm1, %%mm0 \n\t"
00114                 "psubusw %%mm2, %%mm1 \n\t"
00115                 "paddw %%mm0, %%mm6 \n\t"
00116                 "paddw %%mm1, %%mm6 \n\t"
00117                 
00118                 "movq (%%"REG_D",%%"REG_a"), %%mm0 \n\t"
00119                 "movq (%%"REG_S"), %%mm1 \n\t"
00120                 "punpckhbw %%mm7, %%mm0 \n\t"
00121                 "movq (%%"REG_S",%%"REG_a"), %%mm2 \n\t"
00122                 "punpckhbw %%mm7, %%mm1 \n\t"
00123                 "punpckhbw %%mm7, %%mm2 \n\t"
00124                 "paddw %%mm0, %%mm0 \n\t"
00125                 "paddw %%mm2, %%mm1 \n\t"
00126                 "movq %%mm0, %%mm2 \n\t"
00127                 "psubusw %%mm1, %%mm0 \n\t"
00128                 "psubusw %%mm2, %%mm1 \n\t"
00129                 "paddw %%mm0, %%mm6 \n\t"
00130                 "paddw %%mm1, %%mm6 \n\t"
00131 
00132                 "add  %%"REG_a", %%"REG_S" \n\t"
00133                 "add  %%"REG_a", %%"REG_D" \n\t"
00134                 "decl %%ecx \n\t"
00135                 "jnz 2b \n\t"
00136                 
00137                 "movq %%mm6, %%mm5 \n\t"
00138                 "punpcklwd %%mm7, %%mm6 \n\t"
00139                 "punpckhwd %%mm7, %%mm5 \n\t"
00140                 "paddd %%mm6, %%mm5 \n\t"
00141                 "movd %%mm5, %%eax \n\t"
00142                 "psrlq $32, %%mm5 \n\t"
00143                 "movd %%mm5, %%edx \n\t"
00144                 "addl %%edx, %%eax \n\t"
00145                 
00146                 "emms \n\t"
00147                 : "=a" (ret)
00148                 : "S" (a), "D" (b), "a" (s)
00149                 : "%ecx", "%edx"
00150                 );
00151         return ret;
00152 }
00153 
00154 static int var_y_mmx(unsigned char *a, unsigned char *b, int s)
00155 {
00156     (void) b;
00157         int ret;
00158         __asm__ volatile (
00159                 "movl $3, %%ecx \n\t"
00160                 "pxor %%mm4, %%mm4 \n\t"
00161                 "pxor %%mm7, %%mm7 \n\t"
00162                 
00163                 ASMALIGN(4)
00164                 "1: \n\t"
00165                 
00166                 "movq (%%"REG_S"), %%mm0 \n\t"
00167                 "movq (%%"REG_S"), %%mm2 \n\t"
00168                 "movq (%%"REG_S",%%"REG_a"), %%mm1 \n\t"
00169                 "add  %%"REG_a", %%"REG_S" \n\t"
00170                 "psubusb %%mm1, %%mm2 \n\t"
00171                 "psubusb %%mm0, %%mm1 \n\t"
00172                 "movq %%mm2, %%mm0 \n\t"
00173                 "movq %%mm1, %%mm3 \n\t"
00174                 "punpcklbw %%mm7, %%mm0 \n\t"
00175                 "punpcklbw %%mm7, %%mm1 \n\t"
00176                 "punpckhbw %%mm7, %%mm2 \n\t"
00177                 "punpckhbw %%mm7, %%mm3 \n\t"
00178                 "paddw %%mm0, %%mm4 \n\t"
00179                 "paddw %%mm1, %%mm4 \n\t"
00180                 "paddw %%mm2, %%mm4 \n\t"
00181                 "paddw %%mm3, %%mm4 \n\t"
00182                 
00183                 "decl %%ecx \n\t"
00184                 "jnz 1b \n\t"
00185 
00186                 "movq %%mm4, %%mm3 \n\t"
00187                 "punpcklwd %%mm7, %%mm4 \n\t"
00188                 "punpckhwd %%mm7, %%mm3 \n\t"
00189                 "paddd %%mm4, %%mm3 \n\t"
00190                 "movd %%mm3, %%eax \n\t"
00191                 "psrlq $32, %%mm3 \n\t"
00192                 "movd %%mm3, %%edx \n\t"
00193                 "addl %%edx, %%eax \n\t"
00194                 "emms \n\t"
00195                 : "=a" (ret)
00196                 : "S" (a), "a" (s)
00197                 : "%ecx", "%edx"
00198                 );
00199         return 4*ret;
00200 }
00201 #endif
00202 
00203 #define ABS(a) (((a)^((a)>>31))-((a)>>31))
00204 
00205 static int diff_y(unsigned char *a, unsigned char *b, int s)
00206 {
00207         int i, j, diff=0;
00208         for (i=4; i; i--) {
00209                 for (j=0; j<8; j++) diff += ABS(a[j]-b[j]);
00210                 a+=s; b+=s;
00211         }
00212         return diff;
00213 }
00214 
00215 static int licomb_y(unsigned char *a, unsigned char *b, int s)
00216 {
00217         int i, j, diff=0;
00218         for (i=4; i; i--) {
00219                 for (j=0; j<8; j++)
00220                         diff += ABS((a[j]<<1) - b[j-s] - b[j])
00221                                 + ABS((b[j]<<1) - a[j] - a[j+s]);
00222                 a+=s; b+=s;
00223         }
00224         return diff;
00225 }
00226 
00227 static int qpcomb_y(unsigned char *a, unsigned char *b, int s)
00228     __attribute__ ((unused)); /* <- to suppress compiler warning */
00229 
00230 static int qpcomb_y(unsigned char *a, unsigned char *b, int s)
00231 {
00232         int i, j, diff=0;
00233         for (i=4; i; i--) {
00234                 for (j=0; j<8; j++)
00235                         diff += ABS(a[j] - 3*b[j-s] + 3*a[j+s] - b[j]);
00236                 a+=s; b+=s;
00237         }
00238         return diff;
00239 }
00240 
00241 #if 0
00242 static int licomb_y_test(unsigned char *a, unsigned char *b, int s)
00243 {
00244         int c = licomb_y(a,b,s);
00245         int m = licomb_y_mmx(a,b,s);
00246         if (c != m) printf("%d != %d\n", c, m);
00247         return m;
00248 }
00249 #endif
00250 
00251 static int var_y(unsigned char *a, unsigned char *b, int s)
00252 {
00253         int i, j, var=0;
00254         for (i=3; i; i--) {
00255                 for (j=0; j<8; j++) {
00256                         var += ABS(a[j]-a[j+s]);
00257                 }
00258                 a+=s; b+=s;
00259         }
00260         return 4*var; /* match comb scaling */
00261 }
00262 
00263 
00264 
00265 
00266 
00267 
00268 
00269 
00270 
00271 static void alloc_buffer(struct pullup_context *c, struct pullup_buffer *b)
00272 {
00273         int i;
00274         if (b->planes) return;
00275         b->planes = calloc(c->nplanes, sizeof(unsigned char *));
00276         for (i = 0; i < c->nplanes; i++) {
00277                 b->planes[i] = malloc(c->h[i]*c->stride[i]);
00278                 /* Deal with idiotic 128=0 for chroma: */
00279                 memset(b->planes[i], c->background[i], c->h[i]*c->stride[i]);
00280         }
00281 }
00282 
00283 struct pullup_buffer *pullup_lock_buffer(struct pullup_buffer *b, int parity)
00284 {
00285         if (!b) return 0;
00286         if ((parity+1) & 1) b->lock[0]++;
00287         if ((parity+1) & 2) b->lock[1]++;
00288         return b;
00289 }
00290 
00291 void pullup_release_buffer(struct pullup_buffer *b, int parity)
00292 {
00293         if (!b) return;
00294         if ((parity+1) & 1) b->lock[0]--;
00295         if ((parity+1) & 2) b->lock[1]--;
00296 }
00297 
00298 struct pullup_buffer *pullup_get_buffer(struct pullup_context *c, int parity)
00299 {
00300         int i;
00301 
00302         /* Try first to get the sister buffer for the previous field */
00303         if (parity < 2 && c->last && parity != c->last->parity
00304             && !c->last->buffer->lock[parity]) {
00305                 alloc_buffer(c, c->last->buffer);
00306                 return pullup_lock_buffer(c->last->buffer, parity);
00307         }
00308         
00309         /* Prefer a buffer with both fields open */
00310         for (i = 0; i < c->nbuffers; i++) {
00311                 if (c->buffers[i].lock[0]) continue;
00312                 if (c->buffers[i].lock[1]) continue;
00313                 alloc_buffer(c, &c->buffers[i]);
00314                 return pullup_lock_buffer(&c->buffers[i], parity);
00315         }
00316 
00317         if (parity == 2) return 0;
00318         
00319         /* Search for any half-free buffer */
00320         for (i = 0; i < c->nbuffers; i++) {
00321                 if (((parity+1) & 1) && c->buffers[i].lock[0]) continue;
00322                 if (((parity+1) & 2) && c->buffers[i].lock[1]) continue;
00323                 alloc_buffer(c, &c->buffers[i]);
00324                 return pullup_lock_buffer(&c->buffers[i], parity);
00325         }
00326         
00327         return 0;
00328 }
00329 
00330 
00331 
00332 
00333 
00334 
00335 static void compute_metric(struct pullup_context *c,
00336         struct pullup_field *fa, int pa,
00337         struct pullup_field *fb, int pb,
00338         int (*func)(unsigned char *, unsigned char *, int), int *dest)
00339 {
00340         unsigned char *a, *b;
00341         int x, y;
00342         int mp = c->metric_plane;
00343         int xstep = c->bpp[mp];
00344         int ystep = c->stride[mp]<<3;
00345         int s = c->stride[mp]<<1; /* field stride */
00346         int w = c->metric_w*xstep;
00347 
00348         if (!fa->buffer || !fb->buffer) return;
00349 
00350         /* Shortcut for duplicate fields (e.g. from RFF flag) */
00351         if (fa->buffer == fb->buffer && pa == pb) {
00352                 memset(dest, 0, c->metric_len * sizeof(int));
00353                 return;
00354         }
00355 
00356         a = fa->buffer->planes[mp] + pa * c->stride[mp] + c->metric_offset;
00357         b = fb->buffer->planes[mp] + pb * c->stride[mp] + c->metric_offset;
00358 
00359         for (y = c->metric_h; y; y--) {
00360                 for (x = 0; x < w; x += xstep) {
00361                         *dest++ = func(a + x, b + x, s);
00362                 }
00363                 a += ystep; b += ystep;
00364         }
00365 }
00366 
00367 
00368 
00369 
00370 
00371 static void alloc_metrics(struct pullup_context *c, struct pullup_field *f)
00372 {
00373         f->diffs = calloc(c->metric_len, sizeof(int));
00374         f->comb = calloc(c->metric_len, sizeof(int));
00375         f->var = calloc(c->metric_len, sizeof(int));
00376         /* add more metrics here as needed */
00377 }
00378 
00379 static struct pullup_field *make_field_queue(struct pullup_context *c, int len)
00380 {
00381         struct pullup_field *head, *f;
00382         f = head = calloc(1, sizeof(struct pullup_field));
00383         alloc_metrics(c, f);
00384         for (; len > 0; len--) {
00385                 f->next = calloc(1, sizeof(struct pullup_field));
00386                 f->next->prev = f;
00387                 f = f->next;
00388                 alloc_metrics(c, f);
00389         }
00390         f->next = head;
00391         head->prev = f;
00392         return head;
00393 }
00394 
00395 static void check_field_queue(struct pullup_context *c)
00396 {
00397         if (c->head->next == c->first) {
00398                 struct pullup_field *f = calloc(1, sizeof(struct pullup_field));
00399                 alloc_metrics(c, f);
00400                 f->prev = c->head;
00401                 f->next = c->first;
00402                 c->head->next = f;
00403                 c->first->prev = f;
00404         }
00405 }
00406 
00407 void pullup_submit_field(struct pullup_context *c, struct pullup_buffer *b, int parity)
00408 {
00409         struct pullup_field *f;
00410         
00411         /* Grow the circular list if needed */
00412         check_field_queue(c);
00413         
00414         /* Cannot have two fields of same parity in a row; drop the new one */
00415         if (c->last && c->last->parity == parity) return;
00416 
00417         f = c->head;
00418         f->parity = parity;
00419         f->buffer = pullup_lock_buffer(b, parity);
00420         f->flags = 0;
00421         f->breaks = 0;
00422         f->affinity = 0;
00423 
00424         compute_metric(c, f, parity, f->prev->prev, parity, c->diff, f->diffs);
00425         compute_metric(c, parity?f->prev:f, 0, parity?f:f->prev, 1, c->comb, f->comb);
00426         compute_metric(c, f, parity, f, -1, c->var, f->var);
00427 
00428         /* Advance the circular list */
00429         if (!c->first) c->first = c->head;
00430         c->last = c->head;
00431         c->head = c->head->next;
00432 }
00433 
00434 void pullup_flush_fields(struct pullup_context *c)
00435 {
00436         struct pullup_field *f;
00437         
00438         for (f = c->first; f && f != c->head; f = f->next) {
00439                 pullup_release_buffer(f->buffer, f->parity);
00440                 f->buffer = 0;
00441         }
00442         c->first = c->last = 0;
00443 }
00444 
00445 
00446 
00447 
00448 
00449 
00450 
00451 
00452 #define F_HAVE_BREAKS 1
00453 #define F_HAVE_AFFINITY 2
00454 
00455 
00456 #define BREAK_LEFT 1
00457 #define BREAK_RIGHT 2
00458 
00459 
00460 
00461 
00462 static int queue_length(struct pullup_field *begin, struct pullup_field *end)
00463 {
00464         int count = 1;
00465         struct pullup_field *f;
00466         
00467         if (!begin || !end) return 0;
00468         for (f = begin; f != end; f = f->next) count++;
00469         return count;
00470 }
00471 
00472 static int find_first_break(struct pullup_field *f, int max)
00473 {
00474         int i;
00475         for (i = 0; i < max; i++) {
00476                 if (f->breaks & BREAK_RIGHT || f->next->breaks & BREAK_LEFT)
00477                         return i+1;
00478                 f = f->next;
00479         }
00480         return 0;
00481 }
00482 
00483 static void compute_breaks(struct pullup_context *c, struct pullup_field *f0)
00484 {
00485         int i;
00486         struct pullup_field *f1 = f0->next;
00487         struct pullup_field *f2 = f1->next;
00488         struct pullup_field *f3 = f2->next;
00489         int l, max_l=0, max_r=0;
00490         //struct pullup_field *ff;
00491         //for (i=0, ff=c->first; ff != f0; i++, ff=ff->next);
00492 
00493         if (f0->flags & F_HAVE_BREAKS) return;
00494         //printf("\n%d: ", i);
00495         f0->flags |= F_HAVE_BREAKS;
00496 
00497         /* Special case when fields are 100% identical */
00498         if (f0->buffer == f2->buffer && f1->buffer != f3->buffer) {
00499                 f2->breaks |= BREAK_RIGHT;
00500                 return;
00501         }
00502         if (f0->buffer != f2->buffer && f1->buffer == f3->buffer) {
00503                 f1->breaks |= BREAK_LEFT;
00504                 return;
00505         }
00506 
00507         for (i = 0; i < c->metric_len; i++) {
00508                 l = f2->diffs[i] - f3->diffs[i];
00509                 if (l > max_l) max_l = l;
00510                 if (-l > max_r) max_r = -l;
00511         }
00512         /* Don't get tripped up when differences are mostly quant error */
00513         //printf("%d %d\n", max_l, max_r);
00514         if (max_l + max_r < 128) return;
00515         if (max_l > 4*max_r) f1->breaks |= BREAK_LEFT;
00516         if (max_r > 4*max_l) f2->breaks |= BREAK_RIGHT;
00517 }
00518 
00519 static void compute_affinity(struct pullup_context *c, struct pullup_field *f)
00520 {
00521         int i;
00522         int max_l=0, max_r=0, l;
00523         if (f->flags & F_HAVE_AFFINITY) return;
00524         f->flags |= F_HAVE_AFFINITY;
00525         if (f->buffer == f->next->next->buffer) {
00526                 f->affinity = 1;
00527                 f->next->affinity = 0;
00528                 f->next->next->affinity = -1;
00529                 f->next->flags |= F_HAVE_AFFINITY;
00530                 f->next->next->flags |= F_HAVE_AFFINITY;
00531                 return;
00532         }
00533         if (1) {
00534                 for (i = 0; i < c->metric_len; i++) {
00535                         int lv = f->prev->var[i];
00536                         int rv = f->next->var[i];
00537                         int v = f->var[i];
00538                         int lc = f->comb[i] - (v+lv) + ABS(v-lv);
00539                         int rc = f->next->comb[i] - (v+rv) + ABS(v-rv);
00540                         lc = lc>0 ? lc : 0;
00541                         rc = rc>0 ? rc : 0;
00542                         l = lc - rc;
00543                         if (l > max_l) max_l = l;
00544                         if (-l > max_r) max_r = -l;
00545                 }
00546                 if (max_l + max_r < 64) return;
00547                 if (max_r > 6*max_l) f->affinity = -1;
00548                 else if (max_l > 6*max_r) f->affinity = 1;
00549         } else {
00550                 for (i = 0; i < c->metric_len; i++) {
00551                         l = f->comb[i] - f->next->comb[i];
00552                         if (l > max_l) max_l = l;
00553                         if (-l > max_r) max_r = -l;
00554                 }
00555                 if (max_l + max_r < 64) return;
00556                 if (max_r > 2*max_l) f->affinity = -1;
00557                 else if (max_l > 2*max_r) f->affinity = 1;
00558         }
00559 }
00560 
00561 static void foo(struct pullup_context *c)
00562 {
00563         struct pullup_field *f = c->first;
00564         int i, n = queue_length(f, c->last);
00565         for (i = 0; i < n-1; i++) {
00566                 if (i < n-3) compute_breaks(c, f);
00567                 compute_affinity(c, f);
00568                 f = f->next;
00569         }
00570 }
00571 
00572 static int decide_frame_length(struct pullup_context *c)
00573 {
00574         struct pullup_field *f0 = c->first;
00575         struct pullup_field *f1 = f0->next;
00576         struct pullup_field *f2 = f1->next;
00577         /*struct pullup_field *f3 = f2->next;*/
00578         int l;
00579         
00580         if (queue_length(c->first, c->last) < 4) return 0;
00581         foo(c);
00582 
00583         if (f0->affinity == -1) return 1;
00584 
00585         l = find_first_break(f0, 3);
00586         if (l == 1 && c->strict_breaks < 0) l = 0;
00587         
00588         switch (l) {
00589         case 1:
00590                 if (c->strict_breaks < 1 && f0->affinity == 1 && f1->affinity == -1)
00591                         return 2;
00592                 else return 1;
00593         case 2:
00594                 /* FIXME: strictly speaking, f0->prev is no longer valid... :) */
00595                 if (c->strict_pairs
00596                         && (f0->prev->breaks & BREAK_RIGHT) && (f2->breaks & BREAK_LEFT)
00597                         && (f0->affinity != 1 || f1->affinity != -1) )
00598                         return 1;
00599                 if (f1->affinity == 1) return 1;
00600                 else return 2;
00601         case 3:
00602                 if (f2->affinity == 1) return 2;
00603                 else return 3;
00604         default:
00605                 /* 9 possibilities covered before switch */
00606                 if (f1->affinity == 1) return 1; /* covers 6 */
00607                 else if (f1->affinity == -1) return 2; /* covers 6 */
00608                 else if (f2->affinity == -1) { /* covers 2 */
00609                         if (f0->affinity == 1) return 3;
00610                         else return 1;
00611                 }
00612                 else return 2; /* the remaining 6 */
00613         }
00614 }
00615 
00616 
00617 static void print_aff_and_breaks(struct pullup_context *c, struct pullup_field *f)
00618 {
00619         int i;
00620         struct pullup_field *f0 = f;
00621         const char aff_l[] = "+..", aff_r[] = "..+";
00622 
00623         (void) c;
00624 
00625         printf("\naffinity: ");
00626         for (i = 0; i < 4; i++) {
00627                 printf("%c%d%c", aff_l[1+f->affinity], i, aff_r[1+f->affinity]);
00628                 f = f->next;
00629         }
00630         f = f0;
00631         printf("\nbreaks:   ");
00632         for (i=0; i<4; i++) {
00633                 printf("%c%d%c", f->breaks & BREAK_LEFT ? '|' : '.', i, f->breaks & BREAK_RIGHT ? '|' : '.');
00634                 f = f->next;
00635         }
00636         printf("\n");
00637 }
00638 
00639 
00640 
00641 
00642 
00643 struct pullup_frame *pullup_get_frame(struct pullup_context *c)
00644 {
00645         int i;
00646         struct pullup_frame *fr = c->frame;
00647         int n = decide_frame_length(c);
00648         int aff = c->first->next->affinity;
00649 
00650         if (!n) return 0;
00651         if (fr->lock) return 0;
00652 
00653         if (c->verbose) {
00654                 print_aff_and_breaks(c, c->first);
00655                 printf("duration: %d    \n", n);
00656         }
00657 
00658         fr->lock++;
00659         fr->length = n;
00660         fr->parity = c->first->parity;
00661         fr->buffer = 0;
00662         for (i = 0; i < n; i++) {
00663                 /* We cheat and steal the buffer without release+relock */
00664                 fr->ifields[i] = c->first->buffer;
00665                 c->first->buffer = 0;
00666                 c->first = c->first->next;
00667         }
00668         
00669         if (n == 1) {
00670                 fr->ofields[fr->parity] = fr->ifields[0];
00671                 fr->ofields[fr->parity^1] = 0;
00672         } else if (n == 2) {
00673                 fr->ofields[fr->parity] = fr->ifields[0];
00674                 fr->ofields[fr->parity^1] = fr->ifields[1];
00675         } else if (n == 3) {
00676                 if (aff == 0)
00677                         aff = (fr->ifields[0] == fr->ifields[1]) ? -1 : 1;
00678                 /* else if (c->verbose) printf("forced aff: %d    \n", aff); */
00679                 fr->ofields[fr->parity] = fr->ifields[1+aff];
00680                 fr->ofields[fr->parity^1] = fr->ifields[1];
00681         }
00682         pullup_lock_buffer(fr->ofields[0], 0);
00683         pullup_lock_buffer(fr->ofields[1], 1);
00684         
00685         if (fr->ofields[0] == fr->ofields[1]) {
00686                 fr->buffer = fr->ofields[0];
00687                 pullup_lock_buffer(fr->buffer, 2);
00688                 return fr;
00689         }
00690         return fr;
00691 }
00692 
00693 static void copy_field(struct pullup_context *c, struct pullup_buffer *dest,
00694         struct pullup_buffer *src, int parity)
00695 {
00696         int i, j;
00697         unsigned char *d, *s;
00698         for (i = 0; i < c->nplanes; i++) {
00699                 s = src->planes[i] + parity*c->stride[i];
00700                 d = dest->planes[i] + parity*c->stride[i];
00701                 for (j = c->h[i]>>1; j; j--) {
00702                         memcpy(d, s, c->stride[i]);
00703                         s += c->stride[i]<<1;
00704                         d += c->stride[i]<<1;
00705                 }
00706         }
00707 }
00708 
00709 void pullup_pack_frame(struct pullup_context *c, struct pullup_frame *fr)
00710 {
00711         int i;
00712         /*int par = fr->parity;*/
00713         if (fr->buffer) return;
00714         if (fr->length < 2) return; /* FIXME: deal with this */
00715         for (i = 0; i < 2; i++)
00716         {
00717                 if (fr->ofields[i]->lock[i^1]) continue;
00718                 fr->buffer = fr->ofields[i];
00719                 pullup_lock_buffer(fr->buffer, 2);
00720                 copy_field(c, fr->buffer, fr->ofields[i^1], i^1);
00721                 return;
00722         }
00723         fr->buffer = pullup_get_buffer(c, 2);
00724         if (!fr->buffer) return;
00725         copy_field(c, fr->buffer, fr->ofields[0], 0);
00726         copy_field(c, fr->buffer, fr->ofields[1], 1);
00727 }
00728 
00729 void pullup_release_frame(struct pullup_frame *fr)
00730 {
00731         int i;
00732         for (i = 0; i < fr->length; i++)
00733                 pullup_release_buffer(fr->ifields[i], fr->parity ^ (i&1));
00734         pullup_release_buffer(fr->ofields[0], 0);
00735         pullup_release_buffer(fr->ofields[1], 1);
00736         if (fr->buffer) pullup_release_buffer(fr->buffer, 2);
00737         fr->lock--;
00738 }
00739 
00740 
00741 
00742 
00743 
00744 
00745 struct pullup_context *pullup_alloc_context(void)
00746 {
00747         struct pullup_context *c;
00748 
00749         c = calloc(1, sizeof(struct pullup_context));
00750 
00751         return c;
00752 }
00753 
00754 void pullup_preinit_context(struct pullup_context *c)
00755 {
00756         c->bpp = calloc(c->nplanes, sizeof(int));
00757         c->w = calloc(c->nplanes, sizeof(int));
00758         c->h = calloc(c->nplanes, sizeof(int));
00759         c->stride = calloc(c->nplanes, sizeof(int));
00760         c->background = calloc(c->nplanes, sizeof(int));
00761 }
00762 
00763 void pullup_init_context(struct pullup_context *c)
00764 {
00765         int mp = c->metric_plane;
00766         if (c->nbuffers < 10) c->nbuffers = 10;
00767         c->buffers = calloc(c->nbuffers, sizeof (struct pullup_buffer));
00768 
00769         c->metric_w = (c->w[mp] - ((c->junk_left + c->junk_right) << 3)) >> 3;
00770         c->metric_h = (c->h[mp] - ((c->junk_top + c->junk_bottom) << 1)) >> 3;
00771         c->metric_offset = c->junk_left*c->bpp[mp] + (c->junk_top<<1)*c->stride[mp];
00772         c->metric_len = c->metric_w * c->metric_h;
00773         
00774         c->head = make_field_queue(c, 8);
00775 
00776         c->frame = calloc(1, sizeof (struct pullup_frame));
00777         c->frame->ifields = calloc(3, sizeof (struct pullup_buffer *));
00778 
00779         switch(c->format) {
00780         case PULLUP_FMT_Y:
00781                 c->diff = diff_y;
00782                 c->comb = licomb_y;
00783                 c->var = var_y;
00784 #if HAVE_MMX
00785                 if (c->cpu & PULLUP_CPU_MMX) {
00786                         c->diff = diff_y_mmx;
00787                         c->comb = licomb_y_mmx;
00788                         c->var = var_y_mmx;
00789                 }
00790 #endif
00791                 /* c->comb = qpcomb_y; */
00792                 break;
00793 #if 0
00794         case PULLUP_FMT_YUY2:
00795                 c->diff = diff_yuy2;
00796                 break;
00797         case PULLUP_FMT_RGB32:
00798                 c->diff = diff_rgb32;
00799                 break;
00800 #endif
00801         }
00802 }
00803 
00804 void pullup_free_context(struct pullup_context *c)
00805 {
00806         struct pullup_field *f;
00807         free(c->buffers);
00808         f = c->head;
00809         do {
00810                 free(f->diffs);
00811                 free(f->comb);
00812         free(f->var);
00813                 f = f->next;
00814                 free(f->prev);
00815         } while (f != c->head);
00816     free(c->frame->ifields);
00817         free(c->frame);
00818     free(c->stride);
00819     free(c->bpp);
00820     free(c->w);
00821     free(c->h);
00822     free(c->background);
00823         free(c);
00824 }
00825 
00826 
00827 
00828 
00829 
00830 
00831 
00832 
00833 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends