00001
00002 #include <sys/time.h>
00003
00004
00005 #include <cstdlib>
00006 #include <cmath>
00007
00008
00009 #include <algorithm>
00010 using namespace std;
00011
00012
00013 #include <QFile>
00014 #include <QFileInfo>
00015
00016
00017 #include "mythplayer.h"
00018 #include "mythcorecontext.h"
00019 #include "mythlogging.h"
00020
00021
00022 #include "CommDetector2.h"
00023 #include "FrameAnalyzer.h"
00024 #include "pgm.h"
00025 #include "PGMConverter.h"
00026 #include "EdgeDetector.h"
00027 #include "BlankFrameDetector.h"
00028 #include "TemplateFinder.h"
00029 #include "TemplateMatcher.h"
00030
00031 using namespace commDetector2;
00032 using namespace frameAnalyzer;
00033
00034 namespace {
00035
00036 int pgm_set(const AVPicture *pict, int height)
00037 {
00038 const int width = pict->linesize[0];
00039 const int size = height * width;
00040 int score, ii;
00041
00042 score = 0;
00043 for (ii = 0; ii < size; ii++)
00044 if (pict->data[0][ii])
00045 score++;
00046 return score;
00047 }
00048
00049 int pgm_match(const AVPicture *tmpl, const AVPicture *test, int height,
00050 int radius, unsigned short *pscore)
00051 {
00052
00053 const int width = tmpl->linesize[0];
00054 int score, rr, cc;
00055
00056 if (width != test->linesize[0])
00057 {
00058 LOG(VB_COMMFLAG, LOG_ERR,
00059 QString("pgm_match widths don't match: %1 != %2")
00060 .arg(width).arg(test->linesize[0]));
00061 return -1;
00062 }
00063
00064 score = 0;
00065 for (rr = 0; rr < height; rr++)
00066 {
00067 for (cc = 0; cc < width; cc++)
00068 {
00069 int r2min, r2max, r2, c2min, c2max, c2;
00070
00071 if (!tmpl->data[0][rr * width + cc])
00072 continue;
00073
00074 r2min = max(0, rr - radius);
00075 r2max = min(height, rr + radius);
00076
00077 c2min = max(0, cc - radius);
00078 c2max = min(width, cc + radius);
00079
00080 for (r2 = r2min; r2 <= r2max; r2++)
00081 {
00082 for (c2 = c2min; c2 <= c2max; c2++)
00083 {
00084 if (test->data[0][r2 * width + c2])
00085 {
00086 score++;
00087 goto next_pixel;
00088 }
00089 }
00090 }
00091 next_pixel:
00092 ;
00093 }
00094 }
00095
00096 *pscore = score;
00097 return 0;
00098 }
00099
00100 bool readMatches(QString filename, unsigned short *matches, long long nframes)
00101 {
00102 FILE *fp;
00103 long long frameno;
00104
00105 QByteArray fname = filename.toLocal8Bit();
00106 if (!(fp = fopen(fname.constData(), "r")))
00107 return false;
00108
00109 for (frameno = 0; frameno < nframes; frameno++)
00110 {
00111 int nitems = fscanf(fp, "%20hu", &matches[frameno]);
00112 if (nitems != 1)
00113 {
00114 LOG(VB_COMMFLAG, LOG_ERR,
00115 QString("Not enough data in %1: frame %2")
00116 .arg(filename).arg(frameno));
00117 goto error;
00118 }
00119 }
00120
00121 if (fclose(fp))
00122 LOG(VB_COMMFLAG, LOG_ERR, QString("Error closing %1: %2")
00123 .arg(filename).arg(strerror(errno)));
00124 return true;
00125
00126 error:
00127 if (fclose(fp))
00128 LOG(VB_COMMFLAG, LOG_ERR, QString("Error closing %1: %2")
00129 .arg(filename).arg(strerror(errno)));
00130 return false;
00131 }
00132
00133 bool writeMatches(QString filename, unsigned short *matches, long long nframes)
00134 {
00135 FILE *fp;
00136 long long frameno;
00137
00138 QByteArray fname = filename.toLocal8Bit();
00139 if (!(fp = fopen(fname.constData(), "w")))
00140 return false;
00141
00142 for (frameno = 0; frameno < nframes; frameno++)
00143 (void)fprintf(fp, "%hu\n", matches[frameno]);
00144
00145 if (fclose(fp))
00146 LOG(VB_COMMFLAG, LOG_ERR, QString("Error closing %1: %2")
00147 .arg(filename).arg(strerror(errno)));
00148 return true;
00149 }
00150
00151 int finishedDebug(long long nframes, const unsigned short *matches,
00152 const unsigned char *match)
00153 {
00154 unsigned short low, high, score;
00155 long long startframe;
00156
00157 score = matches[0];
00158 low = score;
00159 high = score;
00160 startframe = 0;
00161
00162 for (long long frameno = 1; frameno < nframes; frameno++)
00163 {
00164 score = matches[frameno];
00165 if (match[frameno - 1] == match[frameno])
00166 {
00167 if (score < low)
00168 low = score;
00169 if (score > high)
00170 high = score;
00171 continue;
00172 }
00173
00174 LOG(VB_COMMFLAG, LOG_INFO, QString("Frame %1-%2: %3 L-H: %4-%5 (%6)")
00175 .arg(startframe, 6).arg(frameno - 1, 6)
00176 .arg(match[frameno - 1] ? "logo " : " no-logo")
00177 .arg(low, 4).arg(high, 4).arg(frameno - startframe, 5));
00178
00179 low = score;
00180 high = score;
00181 startframe = frameno;
00182 }
00183
00184 return 0;
00185 }
00186
00187 int sort_ascending(const void *aa, const void *bb)
00188 {
00189 return *(unsigned short*)aa - *(unsigned short*)bb;
00190 }
00191
00192 long long matchspn(long long nframes, unsigned char *match, long long frameno,
00193 unsigned char acceptval)
00194 {
00195
00196
00197
00198
00199 while (frameno < nframes && match[frameno] == acceptval)
00200 frameno++;
00201 return frameno;
00202 }
00203
00204 unsigned int range_area(const unsigned short *freq, unsigned short start,
00205 unsigned short end)
00206 {
00207
00208 const unsigned short width = end - start;
00209 unsigned short matchcnt;
00210 unsigned int sum, nsamples;
00211
00212 sum = 0;
00213 nsamples = 0;
00214 for (matchcnt = start; matchcnt < end; matchcnt++)
00215 {
00216 if (freq[matchcnt])
00217 {
00218 sum += freq[matchcnt];
00219 nsamples++;
00220 }
00221 }
00222 if (!nsamples)
00223 return 0;
00224 return width * sum / nsamples;
00225 }
00226
00227 unsigned short pick_mintmpledges(const unsigned short *matches,
00228 long long nframes)
00229 {
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 static const float LEFTWIDTH = 0.04;
00251 static const float MIDDLEWIDTH = 0.04;
00252 static const float RIGHTWIDTH = 0.04;
00253
00254 static const float MATCHSTART = 0.20;
00255 static const float MATCHEND = 0.80;
00256
00257 unsigned short matchrange, matchstart, matchend;
00258 unsigned short leftwidth, middlewidth, rightwidth;
00259 unsigned short *sorted, minmatch, maxmatch, *freq;
00260 int nfreq, matchcnt, local_minimum;
00261 unsigned int maxdelta;
00262
00263 sorted = new unsigned short[nframes];
00264 memcpy(sorted, matches, nframes * sizeof(*matches));
00265 qsort(sorted, nframes, sizeof(*sorted), sort_ascending);
00266 minmatch = sorted[0];
00267 maxmatch = sorted[nframes - 1];
00268 matchrange = maxmatch - minmatch;
00269
00270
00271 leftwidth = (unsigned short)(LEFTWIDTH * matchrange);
00272 middlewidth = (unsigned short)(MIDDLEWIDTH * matchrange);
00273 rightwidth = (unsigned short)(RIGHTWIDTH * matchrange);
00274
00275 nfreq = maxmatch + 1;
00276 freq = new unsigned short[nfreq];
00277 memset(freq, 0, nfreq * sizeof(*freq));
00278 for (long long frameno = 0; frameno < nframes; frameno++)
00279 freq[matches[frameno]]++;
00280
00281 matchstart = minmatch + (unsigned short)(MATCHSTART * matchrange);
00282 matchend = minmatch + (unsigned short)(MATCHEND * matchrange);
00283
00284 local_minimum = matchstart;
00285 maxdelta = 0;
00286 for (matchcnt = matchstart + leftwidth + middlewidth / 2;
00287 matchcnt < matchend - rightwidth - middlewidth / 2;
00288 matchcnt++)
00289 {
00290 unsigned short p0, p1, p2, p3;
00291 unsigned int leftscore, middlescore, rightscore;
00292
00293 p0 = matchcnt - leftwidth - middlewidth / 2;
00294 p1 = p0 + leftwidth;
00295 p2 = p1 + middlewidth;
00296 p3 = p2 + rightwidth;
00297
00298 leftscore = range_area(freq, p0, p1);
00299 middlescore = range_area(freq, p1, p2);
00300 rightscore = range_area(freq, p2, p3);
00301 if (middlescore < leftscore && middlescore < rightscore)
00302 {
00303 unsigned int delta = (leftscore - middlescore) +
00304 (rightscore - middlescore);
00305 if (delta > maxdelta)
00306 {
00307 local_minimum = matchcnt;
00308 maxdelta = delta;
00309 }
00310 }
00311 }
00312
00313 LOG(VB_COMMFLAG, LOG_INFO,
00314 QString("pick_mintmpledges minmatch=%1 maxmatch=%2"
00315 " matchstart=%3 matchend=%4 widths=%5,%6,%7 local_minimum=%8")
00316 .arg(minmatch).arg(maxmatch).arg(matchstart).arg(matchend)
00317 .arg(leftwidth).arg(middlewidth).arg(rightwidth)
00318 .arg(local_minimum));
00319
00320 delete []freq;
00321 delete []sorted;
00322 return local_minimum;
00323 }
00324
00325 };
00326
00327 TemplateMatcher::TemplateMatcher(PGMConverter *pgmc, EdgeDetector *ed,
00328 TemplateFinder *tf, QString debugdir) :
00329 FrameAnalyzer(), pgmConverter(pgmc),
00330 edgeDetector(ed), templateFinder(tf),
00331 tmpl(0),
00332 tmplrow(-1), tmplcol(-1),
00333 tmplwidth(-1), tmplheight(-1),
00334 matches(NULL), match(NULL),
00335 fps(0.0f),
00336 debugLevel(0), debugdir(debugdir),
00337 #ifdef PGM_CONVERT_GREYSCALE
00338 debugdata(debugdir + "/TemplateMatcher-pgm.txt"),
00339 #else
00340 debugdata(debugdir + "/TemplateMatcher-yuv.txt"),
00341 #endif
00342 player(NULL),
00343 debug_matches(false), debug_removerunts(false),
00344 matches_done(false)
00345 {
00346 memset(&cropped, 0, sizeof(cropped));
00347 memset(&analyze_time, 0, sizeof(analyze_time));
00348
00349
00350
00351
00352
00353
00354
00355 debugLevel = gCoreContext->GetNumSetting("TemplateMatcherDebugLevel", 0);
00356
00357 if (debugLevel >= 1)
00358 {
00359 createDebugDirectory(debugdir,
00360 QString("TemplateMatcher debugLevel %1").arg(debugLevel));
00361 debug_matches = true;
00362 if (debugLevel >= 2)
00363 debug_removerunts = true;
00364 }
00365 }
00366
00367 TemplateMatcher::~TemplateMatcher(void)
00368 {
00369 if (matches)
00370 delete []matches;
00371 if (match)
00372 delete []match;
00373 avpicture_free(&cropped);
00374 }
00375
00376 enum FrameAnalyzer::analyzeFrameResult
00377 TemplateMatcher::MythPlayerInited(MythPlayer *_player,
00378 long long nframes)
00379 {
00380 player = _player;
00381 fps = player->GetFrameRate();
00382
00383 if (!(tmpl = templateFinder->getTemplate(&tmplrow, &tmplcol,
00384 &tmplwidth, &tmplheight)))
00385 {
00386 LOG(VB_COMMFLAG, LOG_ERR,
00387 QString("TemplateMatcher::MythPlayerInited: no template"));
00388 return ANALYZE_FATAL;
00389 }
00390
00391 if (avpicture_alloc(&cropped, PIX_FMT_GRAY8, tmplwidth, tmplheight))
00392 {
00393 LOG(VB_COMMFLAG, LOG_ERR,
00394 QString("TemplateMatcher::MythPlayerInited "
00395 "avpicture_alloc cropped (%1x%2) failed")
00396 .arg(tmplwidth).arg(tmplheight));
00397 return ANALYZE_FATAL;
00398 }
00399
00400 if (pgmConverter->MythPlayerInited(player))
00401 goto free_cropped;
00402
00403 matches = new unsigned short[nframes];
00404 memset(matches, 0, nframes * sizeof(*matches));
00405
00406 match = new unsigned char[nframes];
00407
00408 if (debug_matches)
00409 {
00410 if (readMatches(debugdata, matches, nframes))
00411 {
00412 LOG(VB_COMMFLAG, LOG_INFO,
00413 QString("TemplateMatcher::MythPlayerInited read %1")
00414 .arg(debugdata));
00415 matches_done = true;
00416 }
00417 }
00418
00419 if (matches_done)
00420 return ANALYZE_FINISHED;
00421
00422 return ANALYZE_OK;
00423
00424 free_cropped:
00425 avpicture_free(&cropped);
00426 return ANALYZE_FATAL;
00427 }
00428
00429 enum FrameAnalyzer::analyzeFrameResult
00430 TemplateMatcher::analyzeFrame(const VideoFrame *frame, long long frameno,
00431 long long *pNextFrame)
00432 {
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 const int FRAMESGMPCTILE = 70;
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 const int JITTER_RADIUS = 0;
00467
00468 const AVPicture *pgm;
00469 const AVPicture *edges;
00470 int pgmwidth, pgmheight;
00471 struct timeval start, end, elapsed;
00472
00473 *pNextFrame = NEXTFRAME;
00474
00475 if (!(pgm = pgmConverter->getImage(frame, frameno, &pgmwidth, &pgmheight)))
00476 goto error;
00477
00478 (void)gettimeofday(&start, NULL);
00479
00480 if (pgm_crop(&cropped, pgm, pgmheight, tmplrow, tmplcol,
00481 tmplwidth, tmplheight))
00482 goto error;
00483
00484 if (!(edges = edgeDetector->detectEdges(&cropped, tmplheight,
00485 FRAMESGMPCTILE)))
00486 goto error;
00487
00488 if (pgm_match(tmpl, edges, tmplheight, JITTER_RADIUS, &matches[frameno]))
00489 goto error;
00490
00491 (void)gettimeofday(&end, NULL);
00492 timersub(&end, &start, &elapsed);
00493 timeradd(&analyze_time, &elapsed, &analyze_time);
00494
00495 return ANALYZE_OK;
00496
00497 error:
00498 LOG(VB_COMMFLAG, LOG_ERR,
00499 QString("TemplateMatcher::analyzeFrame error at frame %1 of %2")
00500 .arg(frameno));
00501 return ANALYZE_ERROR;
00502 }
00503
00504 int
00505 TemplateMatcher::finished(long long nframes, bool final)
00506 {
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 const int MINBREAKLEN = (int)roundf(45 * fps);
00517 const int MINSEGLEN = (int)roundf(105 * fps);
00518
00519 int tmpledges, mintmpledges;
00520 int minbreaklen, minseglen;
00521 long long brkb;
00522 FrameAnalyzer::FrameMap::Iterator bb;
00523
00524 if (!matches_done && debug_matches)
00525 {
00526 if (final && writeMatches(debugdata, matches, nframes))
00527 {
00528 LOG(VB_COMMFLAG, LOG_INFO,
00529 QString("TemplateMatcher::finished wrote %1") .arg(debugdata));
00530 matches_done = true;
00531 }
00532 }
00533
00534 tmpledges = pgm_set(tmpl, tmplheight);
00535 mintmpledges = pick_mintmpledges(matches, nframes);
00536
00537 LOG(VB_COMMFLAG, LOG_INFO,
00538 QString("TemplateMatcher::finished %1x%2@(%3,%4),"
00539 " %5 edge pixels, want %6")
00540 .arg(tmplwidth).arg(tmplheight).arg(tmplcol).arg(tmplrow)
00541 .arg(tmpledges).arg(mintmpledges));
00542
00543 for (long long ii = 0; ii < nframes; ii++)
00544 match[ii] = matches[ii] >= mintmpledges ? 1 : 0;
00545
00546 if (debugLevel >= 2)
00547 {
00548 if (final && finishedDebug(nframes, matches, match))
00549 goto error;
00550 }
00551
00552
00553
00554
00555 breakMap.clear();
00556 brkb = match[0] ? matchspn(nframes, match, 0, match[0]) : 0;
00557 while (brkb < nframes)
00558 {
00559
00560 long long brke = matchspn(nframes, match, brkb, match[brkb]);
00561 long long brklen = brke - brkb;
00562 breakMap.insert(brkb, brklen);
00563
00564
00565 brkb = matchspn(nframes, match, brke, match[brke]);
00566 }
00567
00568
00569 minbreaklen = 1;
00570 minseglen = 1;
00571 for (;;)
00572 {
00573 bool f1 = false;
00574 bool f2 = false;
00575 if (minbreaklen <= MINBREAKLEN)
00576 {
00577 f1 = removeShortBreaks(&breakMap, fps, minbreaklen,
00578 debug_removerunts);
00579 minbreaklen++;
00580 }
00581 if (minseglen <= MINSEGLEN)
00582 {
00583 f2 = removeShortSegments(&breakMap, nframes, fps, minseglen,
00584 debug_removerunts);
00585 minseglen++;
00586 }
00587 if (minbreaklen > MINBREAKLEN && minseglen > MINSEGLEN)
00588 break;
00589 if (debug_removerunts && (f1 || f2))
00590 frameAnalyzerReportMap(&breakMap, fps, "** TM Break");
00591 }
00592
00593
00594
00595
00596 frameAnalyzerReportMap(&breakMap, fps, "TM Break");
00597
00598 return 0;
00599
00600 error:
00601 return -1;
00602 }
00603
00604 int
00605 TemplateMatcher::reportTime(void) const
00606 {
00607 if (pgmConverter->reportTime())
00608 return -1;
00609
00610 LOG(VB_COMMFLAG, LOG_INFO, QString("TM Time: analyze=%1s")
00611 .arg(strftimeval(&analyze_time)));
00612 return 0;
00613 }
00614
00615 int
00616 TemplateMatcher::templateCoverage(long long nframes, bool final) const
00617 {
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629 const int MINBREAKS = nframes * 20 / 100;
00630 const int MAXBREAKS = nframes * 45 / 100;
00631
00632 const long long brklen = frameAnalyzerMapSum(&breakMap);
00633 const bool good = brklen >= MINBREAKS && brklen <= MAXBREAKS;
00634
00635 if (debugLevel >= 1)
00636 {
00637 if (!tmpl)
00638 {
00639 LOG(VB_COMMFLAG, LOG_ERR,
00640 QString("TemplateMatcher: no template (wanted %2-%3%)")
00641 .arg(100 * MINBREAKS / nframes)
00642 .arg(100 * MAXBREAKS / nframes));
00643 }
00644 else if (!final)
00645 {
00646 LOG(VB_COMMFLAG, LOG_ERR,
00647 QString("TemplateMatcher has %1% breaks (real-time flagging)")
00648 .arg(100 * brklen / nframes));
00649 }
00650 else if (good)
00651 {
00652 LOG(VB_COMMFLAG, LOG_INFO, QString("TemplateMatcher has %1% breaks")
00653 .arg(100 * brklen / nframes));
00654 }
00655 else
00656 {
00657 LOG(VB_COMMFLAG, LOG_INFO,
00658 QString("TemplateMatcher has %1% breaks (wanted %2-%3%)")
00659 .arg(100 * brklen / nframes)
00660 .arg(100 * MINBREAKS / nframes)
00661 .arg(100 * MAXBREAKS / nframes));
00662 }
00663 }
00664
00665 if (!final)
00666 return 0;
00667
00668 return brklen < MINBREAKS ? 1 : brklen <= MAXBREAKS ? 0 : -1;
00669 }
00670
00671 int
00672 TemplateMatcher::adjustForBlanks(const BlankFrameDetector *blankFrameDetector,
00673 long long nframes)
00674 {
00675 const FrameAnalyzer::FrameMap *blankMap = blankFrameDetector->getBlanks();
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744 const int BLANK_NEARBY = (int)roundf(0.5 * fps);
00745 const int TEMPLATE_DISAPPEARS_EARLY = (int)roundf(25 * fps);
00746 const int TEMPLATE_DISAPPEARS_LATE = (int)roundf(0 * fps);
00747 const int TEMPLATE_REAPPEARS_LATE = (int)roundf(35 * fps);
00748 const int TEMPLATE_REAPPEARS_EARLY = (int)roundf(1.5 * fps);
00749
00750 LOG(VB_COMMFLAG, LOG_INFO, QString("TemplateMatcher adjusting for blanks"));
00751
00752 FrameAnalyzer::FrameMap::Iterator ii = breakMap.begin();
00753 long long prevbrke = 0;
00754 while (ii != breakMap.end())
00755 {
00756 FrameAnalyzer::FrameMap::Iterator iinext = ii;
00757 ++iinext;
00758
00759
00760
00761
00762
00763
00764 const long long brkb = ii.key();
00765 const long long brke = brkb + *ii;
00766 FrameAnalyzer::FrameMap::const_iterator jj = blankMap->constEnd();
00767 if (brkb > 0)
00768 {
00769 jj = frameMapSearchForwards(blankMap,
00770 max(prevbrke,
00771 brkb - max(BLANK_NEARBY, TEMPLATE_DISAPPEARS_LATE)),
00772 min(brke,
00773 brkb + max(BLANK_NEARBY, TEMPLATE_DISAPPEARS_EARLY)));
00774 }
00775 long long newbrkb = brkb;
00776 if (jj != blankMap->constEnd())
00777 {
00778 newbrkb = jj.key();
00779 long long adj = *jj / 2;
00780 if (adj > MAX_BLANK_FRAMES)
00781 adj = MAX_BLANK_FRAMES;
00782 newbrkb += adj;
00783 }
00784
00785
00786
00787
00788
00789 FrameAnalyzer::FrameMap::const_iterator kk = frameMapSearchBackwards(
00790 blankMap,
00791 max(newbrkb,
00792 brke - max(BLANK_NEARBY, TEMPLATE_REAPPEARS_LATE)),
00793 min(iinext == breakMap.end() ? nframes : iinext.key(),
00794 brke + max(BLANK_NEARBY, TEMPLATE_REAPPEARS_EARLY)));
00795 long long newbrke = brke;
00796 if (kk != blankMap->constEnd())
00797 {
00798 newbrke = kk.key();
00799 long long adj = *kk;
00800 newbrke += adj;
00801 adj /= 2;
00802 if (adj > MAX_BLANK_FRAMES)
00803 adj = MAX_BLANK_FRAMES;
00804 newbrke -= adj;
00805 }
00806
00807
00808
00809
00810 long long newbrklen = newbrke - newbrkb;
00811 if (newbrkb != brkb)
00812 {
00813 breakMap.erase(ii);
00814 if (newbrkb < nframes && newbrklen)
00815 breakMap.insert(newbrkb, newbrklen);
00816 }
00817 else if (newbrke != brke)
00818 {
00819 if (newbrklen)
00820 {
00821 breakMap.remove(newbrkb);
00822 breakMap.insert(newbrkb, newbrklen);
00823 }
00824 else
00825 breakMap.erase(ii);
00826 }
00827
00828 prevbrke = newbrke;
00829 ii = iinext;
00830 }
00831
00832
00833
00834
00835 frameAnalyzerReportMap(&breakMap, fps, "TM Break");
00836 return 0;
00837 }
00838
00839 int
00840 TemplateMatcher::computeBreaks(FrameAnalyzer::FrameMap *breaks)
00841 {
00842 breaks->clear();
00843 for (FrameAnalyzer::FrameMap::Iterator bb = breakMap.begin();
00844 bb != breakMap.end();
00845 ++bb)
00846 {
00847 breaks->insert(bb.key(), *bb);
00848 }
00849 return 0;
00850 }
00851
00852