1 /*
2 * Copyright (c) 2017 Gerion Entrup
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 /**
22 * @file
23 * MPEG-7 video signature calculation and lookup filter
24 */
25
28
29 #define HOUGH_MAX_OFFSET 90
30 #define MAX_FRAMERATE 60
31
34 #define DIR_PREV_END 2
35 #define DIR_NEXT_END 3
36
38 #define STATUS_END_REACHED 1
39 #define STATUS_BEGIN_REACHED 2
40
42 {
43 while (*sll) {
48 }
49 }
50
52 {
53 int i, j, tmp_i, tmp_j,count;
54 uint8_t dist;
55
56 for (
i = 0, count = 0;
i < 242;
i++) {
57 for (j =
i + 1; j < 243; j++, count++) {
58 /* ternary distance between i and j */
59 dist = 0;
61 do {
62 dist +=
FFABS((tmp_j % 3) - (tmp_i % 3));
63 tmp_j /= 3;
64 tmp_i /= 3;
65 } while (tmp_i > 0 || tmp_j > 0);
66 lut[count] = dist;
67 }
68 }
69 }
70
72 {
74 for (
i = 0;
i < 28;
i += 4) {
76 (
first[
i+1] & second[
i+1]) << 16 |
77 (
first[
i+2] & second[
i+2]) << 8 |
79 }
81 (
first[29] & second[29]) << 8 |
82 (
first[30] & second[30]) );
84 }
85
87 {
89 for (
i = 0;
i < 28;
i += 4) {
91 (
first[
i+1] | second[
i+1]) << 16 |
92 (
first[
i+2] | second[
i+2]) << 8 |
94 }
96 (
first[29] | second[29]) << 8 |
97 (
first[30] | second[30]) );
99 }
100
102 {
104 unsigned int dist = 0;
106
112 /* little variation of gauss sum formula */
113 dist += sc->
l1distlut[243*242/2 - (243-
s)*(242-
s)/2 +
f -
s - 1];
114 } else {
115 dist += sc->
l1distlut[243*242/2 - (243-
f)*(242-
f)/2 +
s -
f - 1];
116 }
117 }
118 }
119 return dist;
120 }
121
122 /**
123 * calculates the jaccard distance and evaluates a pair of coarse signatures as good
124 * @return 0 if pair is bad, 1 otherwise
125 */
127 {
128 int jaccarddist,
i, composdist = 0, cwthcount = 0;
129 for (
i = 0;
i < 5;
i++) {
132 }
133 jaccarddist = (1 << 16) - jaccarddist;
135 if (++cwthcount > 2) {
136 /* more than half (5/2) of distances are too wide */
137 return 0;
138 }
139 }
140 composdist += jaccarddist;
142 return 0;
143 }
144 }
145 return 1;
146 }
147
148 /**
149 * step through the coarsesignatures as long as a good candidate is found
150 * @return 0 if no candidate is found, 1 otherwise
151 */
153 {
154 /* go one coarsesignature foreword */
155 if (!start) {
156 if ((*second)->next) {
157 *second = (*second)->
next;
158 } else if ((*first)->next) {
159 *second = secondstart;
160 *
first = (*first)->next;
161 } else {
162 return 0;
163 }
164 }
165
166 while (1) {
168 return 1;
169
170 /* next signature */
171 if ((*second)->next) {
172 *second = (*second)->
next;
173 } else if ((*first)->next) {
174 *second = secondstart;
175 *
first = (*first)->next;
176 } else {
177 return 0;
178 }
179 }
180 }
181
182 /**
183 * compares framesignatures and sorts out signatures with a l1 distance above a given threshold.
184 * Then tries to find out offset and differences between framerates with a hough transformation
185 */
187 {
189 size_t i, j, k, l, hmax = 0, score;
191 double m;
193
194 struct {
196 unsigned int dist;
201
202 typedef struct hspace_elem {
203 int dist;
204 size_t score;
207 } hspace_elem;
208
209 /* houghspace */
211 hspace_elem *hspaces;
212
213 if (!hspace)
215 /* initialize houghspace */
217 if (!hspaces)
222 hspace[
i][j].score = 0;
223 hspace[
i][j].dist = 99999;
224 }
225 }
226
227 /* l1 distances */
230 pairs[
i].dist = 99999;
232 for (j = 0,
s = second; j <
COARSE_SIZE &&
s->next; j++,
s =
s->next) {
233 /* l1 distance of finesignature */
235 if (l1dist < sc->thl1) {
236 if (l1dist < pairs[
i].dist) {
238 pairs[
i].dist = l1dist;
239 pairs[
i].b_pos[0] = j;
241 }
else if (l1dist == pairs[
i].dist) {
242 pairs[
i].b[pairs[
i].size] =
s;
243 pairs[
i].b_pos[pairs[
i].size] = j;
245 }
246 }
247 }
248 }
249 /* last incomplete coarsesignature */
250 if (
f->next ==
NULL) {
253 pairs[
i].dist = 99999;
254 }
255 }
256
257 /* hough transformation */
259 for (j = 0; j < pairs[
i].size; j++) {
261 for (l = 0; l < pairs[k].size; l++) {
262 if (pairs[
i].
b[j] != pairs[k].
b[l]) {
263 /* linear regression */
264 m = (pairs[k].b_pos[l]-pairs[
i].b_pos[j]) / (k-
i);
/* good value between 0.0 - 2.0 */
265 framerate = (int) (m*30 + 0.5);
/* round up to 0 - 60 */
267 offset = pairs[
i].b_pos[j] - ((int) (m*
i + 0.5));
/* only second part has to be rounded up */
269 if (pairs[
i].dist < pairs[k].dist) {
274 }
275 } else {
280 }
281 }
282
284 if (score > hmax )
285 hmax = score;
287 }
288 }
289 }
290 }
291 }
292 }
293 }
294
295 if (hmax > 0) {
296 hmax = (int) (0.7*hmax);
299 if (hmax < hspace[
i][j].score) {
305 }
306 c->framerateratio = (
i+1.0) / 30;
307 c->score = hspace[
i][j].score;
309 c->first = hspace[
i][j].a;
310 c->second = hspace[
i][j].b;
312
313 /* not used */
317 }
318 }
319 }
320 }
325 }
326
328 {
330
331 /* between 1 and 2, because frr is between 1 and 2 */
332 step = ((int) 0.5 + fcount * frr)
/* current frame */
333 -((int) 0.5 + (fcount-1) * frr);/* last frame */
334
336 if (frr >= 1.0) {
337 if ((*a)->next) {
339 } else {
341 }
342
344 if ((*b)->next) {
346 (*bcount)++;
347 } else {
349 }
350 } else {
351 if ((*b)->next && (*b)->next->next) {
352 *
b = (*b)->next->next;
353 (*bcount)++;
354 } else {
356 }
357 }
358 } else {
359 if ((*b)->next) {
361 (*bcount)++;
362 } else {
364 }
365
367 if ((*a)->next) {
369 } else {
371 }
372 } else {
373 if ((*a)->next && (*a)->next->next) {
374 *
a = (*a)->next->next;
375 } else {
377 }
378 }
379 }
381 } else {
382 if (frr >= 1.0) {
383 if ((*a)->prev) {
385 } else {
387 }
388
390 if ((*b)->prev) {
392 (*bcount)++;
393 } else {
395 }
396 } else {
397 if ((*b)->prev && (*b)->prev->prev) {
398 *
b = (*b)->prev->prev;
399 (*bcount)++;
400 } else {
402 }
403 }
404 } else {
405 if ((*b)->prev) {
407 (*bcount)++;
408 } else {
410 }
411
413 if ((*a)->prev) {
415 } else {
417 }
418 } else {
419 if ((*a)->prev && (*a)->prev->prev) {
420 *
a = (*a)->prev->prev;
421 } else {
423 }
424 }
425 }
427 }
428 }
429
431 {
432 int dist, distsum = 0, bcount = 1, dir =
DIR_NEXT;
433 int fcount = 0, goodfcount = 0, gooda = 0, goodb = 0;
434 double meandist, minmeandist = bestmatch.
meandist;
435 int tolerancecount = 0;
438
439 for (; infos !=
NULL; infos = infos->
next) {
442 while (1) {
444
445 if (dist > sc->
thl1) {
446 if (
a->confidence >= 1 ||
b->confidence >= 1) {
447 /* bad frame (because high different information) */
448 tolerancecount++;
449 }
450
451 if (tolerancecount > 2) {
453 /* turn around */
457 } else {
460 break;
461 }
462 }
463 } else {
464 /* good frame */
465 distsum += dist;
466 goodfcount++;
467 tolerancecount=0;
468
471
472 if (
a->confidence < 1) gooda++;
473 if (
b->confidence < 1) goodb++;
474 }
475
476 fcount++;
477
484 }
485
488 break;
489 }
490
491 if (sc->
thdi != 0 && bcount >= sc->
thdi) {
492 break; /* enough frames found */
493 }
494 }
495
496 if (bcount < sc->thdi)
497 continue; /* matching sequence is too short */
498 if ((double) goodfcount / (double) fcount < sc->thit)
499 continue;
500 if ((
double) goodfcount*0.5 <=
FFMAX(gooda, goodb))
501 continue;
502
503 meandist = (
double) distsum / (
double) goodfcount;
504
505 if (meandist < minmeandist ||
508 minmeandist = meandist;
509 /* bestcandidate in this iteration */
517 bestmatch.
whole = 0;
/* will be set to true later */
519 }
520
521 /* whole sequence is automatically best match */
524 break;
525 }
526
527 /* first matching sequence is enough, finding the best one is not necessary */
529 break;
530 }
531 }
532 return bestmatch;
533 }
534
536 {
541
542 cs =
first->coarsesiglist;
544
545 /* score of bestmatch is 0, if no match is found */
549
551
552 /* stage 1: coarsesignature matching */
554 return bestmatch; /* no candidate found */
555 do {
557 "indices of first frame: %"PRIu32" and %"PRIu32"\n",
559 /* stage 2: l1-distance and hough-transform */
563 for (
i = infos;
i !=
NULL;
i =
i->next) {
565 "ratio %f, offset %d\n",
i->first->index,
i->second->index,
566 i->framerateratio,
i->offset);
567 }
568 }
569 /* stage 3: evaluation */
571 if (infos) {
574 "ratio %f, offset %d, score %d, %d frames matching\n",
578 }
580 return bestmatch;
581
582 }