func: static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
  
  {
  
      AVFilterContext *ctx = inlink->dst;
  
      SignatureContext *sic = ctx->priv;
  
      StreamContext *sc = &(sic->streamcontexts[FF_INLINK_IDX(inlink)]);
  
      FineSignature* fs;
  
  
  
      static const uint8_t pot3[5] = { 3*3*3*3, 3*3*3, 3*3, 3, 1 };
  
      /* indexes of words : 210,217,219,274,334  44,175,233,270,273  57,70,103,237,269  100,285,295,337,354  101,102,111,275,296
  
      s2usw = sorted to unsorted wordvec: 44 is at index 5, 57 at index 10...
  
      */
  
      static const unsigned int wordvec[25] = {44,57,70,100,101,102,103,111,175,210,217,219,233,237,269,270,273,274,275,285,295,296,334,337,354};
  
      static const uint8_t      s2usw[25]   = { 5,10,11, 15, 20, 21, 12, 22,  6,  0,  1,  2,  7, 13, 14,  8,  9,  3, 23, 16, 17, 24,  4, 18, 19};
  
  
  
      uint8_t wordt2b[5] = { 0, 0, 0, 0, 0 }; /* word ternary to binary */
  
      uint64_t intpic[32][32];
  
      uint64_t rowcount;
  
      uint8_t *p = picref->data[0];
  
      int inti, intj;
  
      int *intjlut;
  
  
  
      uint64_t conflist[DIFFELEM_SIZE];
  
      int f = 0, g = 0, w = 0;
  
      int32_t dh1 = 1, dh2 = 1, dw1 = 1, dw2 = 1, a, b;
  
      int64_t denom;
  
      int i, j, k, ternary;
  
      uint64_t blocksum;
  
      int blocksize;
  
      int64_t th; /* threshold */
  
      int64_t sum;
  
  
  
      int64_t precfactor = (sc->divide) ? 65536 : BLOCK_LCM;
  
  
  
      /* initialize fs */
  
      if (sc->curfinesig) {
  
          fs = av_mallocz(sizeof(FineSignature));
  
          if (!fs)
  
              return AVERROR(ENOMEM);
  
          sc->curfinesig->next = fs;
  
          fs->prev = sc->curfinesig;
  
          sc->curfinesig = fs;
  
      } else {
  
          fs = sc->curfinesig = sc->finesiglist;
  
          sc->curcoarsesig1->first = fs;
  
      }
  
  
  
      fs->pts = picref->pts;
  
      fs->index = sc->lastindex++;
  
  
  
      memset(intpic, 0, sizeof(uint64_t)*32*32);
  
      intjlut = av_malloc_array(inlink->w, sizeof(int));
  
      if (!intjlut)
  
          return AVERROR(ENOMEM);
  
      for (i = 0; i < inlink->w; i++) {
  
          intjlut[i] = (i*32)/inlink->w;
  
      }
  
  
  
      for (i = 0; i < inlink->h; i++) {
  
          inti = (i*32)/inlink->h;
  
          for (j = 0; j < inlink->w; j++) {
  
              intj = intjlut[j];
  
              intpic[inti][intj] += p[j];
  
          }
  
          p += picref->linesize[0];
  
      }
  
      av_freep(&intjlut);
  
  
  
      /* The following calculates a summed area table (intpic) and brings the numbers
  
       * in intpic to the same denominator.
  
       * So you only have to handle the numinator in the following sections.
  
       */
  
      dh1 = inlink->h / 32;
  
      if (inlink->h % 32)
  
          dh2 = dh1 + 1;
  
      dw1 = inlink->w / 32;
  
      if (inlink->w % 32)
  
          dw2 = dw1 + 1;
  
      denom = (sc->divide) ? dh1 * dh2 * dw1 * dw2 : 1;
  
  
  
      for (i = 0; i < 32; i++) {
  
          rowcount = 0;
  
          a = 1;
  
          if (dh2 > 1) {
  
              a = ((inlink->h*(i+1))%32 == 0) ? (inlink->h*(i+1))/32 - 1 : (inlink->h*(i+1))/32;
  
              a -= ((inlink->h*i)%32 == 0) ? (inlink->h*i)/32 - 1 : (inlink->h*i)/32;
  
              a = (a == dh1)? dh2 : dh1;
  
          }
  
          for (j = 0; j < 32; j++) {
  
              b = 1;
  
              if (dw2 > 1) {
  
                  b = ((inlink->w*(j+1))%32 == 0) ? (inlink->w*(j+1))/32 - 1 : (inlink->w*(j+1))/32;
  
                  b -= ((inlink->w*j)%32 == 0) ? (inlink->w*j)/32 - 1 : (inlink->w*j)/32;
  
                  b = (b == dw1)? dw2 : dw1;
  
              }
  
              rowcount += intpic[i][j] * a * b * precfactor / denom;
  
              if (i > 0) {
  
                  intpic[i][j] = intpic[i-1][j] + rowcount;
  
              } else {
  
                  intpic[i][j] = rowcount;
  
              }
  
          }
  
      }
  
  
  
      denom = (sc->divide) ? 1 : dh1 * dh2 * dw1 * dw2;
  
  
  
      for (i = 0; i < ELEMENT_COUNT; i++) {
  
          const ElemCat* elemcat = elements[i];
  
          int64_t* elemsignature;
  
          uint64_t* sortsignature;
  
  
  
          elemsignature = av_malloc_array(elemcat->elem_count, sizeof(int64_t));
  
          if (!elemsignature)
  
              return AVERROR(ENOMEM);
  
          sortsignature = av_malloc_array(elemcat->elem_count, sizeof(int64_t));
  
          if (!sortsignature)
  
              return AVERROR(ENOMEM);
  
  
  
          for (j = 0; j < elemcat->elem_count; j++) {
  
              blocksum = 0;
  
              blocksize = 0;
  
              for (k = 0; k < elemcat->left_count; k++) {
  
                  blocksum += get_block_sum(sc, intpic, &elemcat->blocks[j*elemcat->block_count+k]);
  
                  blocksize += get_block_size(&elemcat->blocks[j*elemcat->block_count+k]);
  
              }
  
              sum = blocksum / blocksize;
  
              if (elemcat->av_elem) {
  
                  sum -= 128 * precfactor * denom;
  
              } else {
  
                  blocksum = 0;
  
                  blocksize = 0;
  
                  for (; k < elemcat->block_count; k++) {
  
                      blocksum += get_block_sum(sc, intpic, &elemcat->blocks[j*elemcat->block_count+k]);
  
                      blocksize += get_block_size(&elemcat->blocks[j*elemcat->block_count+k]);
  
                  }
  
                  sum -= blocksum / blocksize;
  
                  conflist[g++] = FFABS(sum * 8 / (precfactor * denom));
  
              }
  
  
  
              elemsignature[j] = sum;
  
              sortsignature[j] = FFABS(sum);
  
          }
  
  
  
          /* get threshold */
  
          qsort(sortsignature, elemcat->elem_count, sizeof(uint64_t), (void*) cmp);
  
          th = sortsignature[(int) (elemcat->elem_count*0.333)];
  
  
  
          /* ternarize */
  
          for (j = 0; j < elemcat->elem_count; j++) {
  
              if (elemsignature[j] < -th) {
  
                  ternary = 0;
  
              } else if (elemsignature[j] <= th) {
  
                  ternary = 1;
  
              } else {
  
                  ternary = 2;
  
              }
  
              fs->framesig[f/5] += ternary * pot3[f%5];
  
  
  
              if (f == wordvec[w]) {
  
                  fs->words[s2usw[w]/5] += ternary * pot3[wordt2b[s2usw[w]/5]++];
  
                  if (w < 24)
  
                      w++;
  
              }
  
              f++;
  
          }
  
          av_freep(&elemsignature);
  
          av_freep(&sortsignature);
  
      }
  
  
  
      /* confidence */
  
      qsort(conflist, DIFFELEM_SIZE, sizeof(uint64_t), (void*) cmp);
  
      fs->confidence = FFMIN(conflist[DIFFELEM_SIZE/2], 255);
  
  
  
      /* coarsesignature */
  
      if (sc->coarsecount == 0) {
  
          if (sc->curcoarsesig2) {
  
              sc->curcoarsesig1 = av_mallocz(sizeof(CoarseSignature));
  
              if (!sc->curcoarsesig1)
  
                  return AVERROR(ENOMEM);
  
              sc->curcoarsesig1->first = fs;
  
              sc->curcoarsesig2->next = sc->curcoarsesig1;
  
              sc->coarseend = sc->curcoarsesig1;
  
          }
  
      }
  
      if (sc->coarsecount == 45) {
  
          sc->midcoarse = 1;
  
          sc->curcoarsesig2 = av_mallocz(sizeof(CoarseSignature));
  
          if (!sc->curcoarsesig2)
  
              return AVERROR(ENOMEM);
  
          sc->curcoarsesig2->first = fs;
  
          sc->curcoarsesig1->next = sc->curcoarsesig2;
  
          sc->coarseend = sc->curcoarsesig2;
  
      }
  
      for (i = 0; i < 5; i++) {
  
          set_bit(sc->curcoarsesig1->data[i], fs->words[i]);
  
      }
  
      /* assuming the actual frame is the last */
  
      sc->curcoarsesig1->last = fs;
  
      if (sc->midcoarse) {
  
          for (i = 0; i < 5; i++) {
  
              set_bit(sc->curcoarsesig2->data[i], fs->words[i]);
  
          }
  
          sc->curcoarsesig2->last = fs;
  
      }
  
  
  
      sc->coarsecount = (sc->coarsecount+1)%90;
  
  
  
      /* debug printing finesignature */
  
      if (av_log_get_level() == AV_LOG_DEBUG) {
  
          av_log(ctx, AV_LOG_DEBUG, "input %d, confidence: %d\n", FF_INLINK_IDX(inlink), fs->confidence);
  
  
  
          av_log(ctx, AV_LOG_DEBUG, "words:");
  
          for (i = 0; i < 5; i++) {
  
              av_log(ctx, AV_LOG_DEBUG, " %d:", fs->words[i] );
  
              av_log(ctx, AV_LOG_DEBUG, " %d", fs->words[i] / pot3[0] );
  
              for (j = 1; j < 5; j++)
  
                  av_log(ctx, AV_LOG_DEBUG, ",%d", fs->words[i] % pot3[j-1] / pot3[j] );
  
              av_log(ctx, AV_LOG_DEBUG, ";");
  
          }
  
          av_log(ctx, AV_LOG_DEBUG, "\n");
  
  
  
          av_log(ctx, AV_LOG_DEBUG, "framesignature:");
  
          for (i = 0; i < SIGELEM_SIZE/5; i++) {
  
              av_log(ctx, AV_LOG_DEBUG, " %d", fs->framesig[i] / pot3[0] );
  
              for (j = 1; j < 5; j++)
  
                  av_log(ctx, AV_LOG_DEBUG, ",%d", fs->framesig[i] % pot3[j-1] / pot3[j] );
  
          }
  
          av_log(ctx, AV_LOG_DEBUG, "\n");
  
      }
  
  
  
      if (FF_INLINK_IDX(inlink) == 0)
  
          return ff_filter_frame(inlink->dst->outputs[0], picref);
  
      return 1;
  
  }
  