00001 #include <sys/time.h>
00002
00003 extern "C" {
00004 #include "avcodec.h"
00005 }
00006 #include "mythcontext.h"
00007 #include "compat.h"
00008
00009 #include "CommDetector2.h"
00010 #include "FrameAnalyzer.h"
00011 #include "TemplateFinder.h"
00012 #include "BorderDetector.h"
00013
00014 using namespace frameAnalyzer;
00015 using namespace commDetector2;
00016
00017 BorderDetector::BorderDetector(void)
00018 : logoFinder(NULL)
00019 , logo(NULL)
00020 , frameno(-1)
00021 , ismonochromatic(false)
00022 , debugLevel(0)
00023 , time_reported(false)
00024 {
00025 debugLevel = gContext->GetNumSetting("BorderDetectorDebugLevel", 0);
00026
00027 if (debugLevel >= 1)
00028 VERBOSE(VB_COMMFLAG,
00029 QString("BorderDetector debugLevel %1").arg(debugLevel));
00030 }
00031
00032 BorderDetector::~BorderDetector(void)
00033 {
00034 }
00035
00036 int
00037 BorderDetector::nuppelVideoPlayerInited(const NuppelVideoPlayer *nvp)
00038 {
00039 (void)nvp;
00040 time_reported = false;
00041 memset(&analyze_time, 0, sizeof(analyze_time));
00042 return 0;
00043 }
00044
00045 void
00046 BorderDetector::setLogoState(TemplateFinder *finder)
00047 {
00048 if ((logoFinder = finder) && (logo = logoFinder->getTemplate(
00049 &logorow, &logocol, &logowidth, &logoheight)))
00050 {
00051 VERBOSE(VB_COMMFLAG, QString(
00052 "BorderDetector::setLogoState: %1x%2@(%3,%4)")
00053 .arg(logowidth).arg(logoheight).arg(logocol).arg(logorow));
00054 }
00055 }
00056
00057 int
00058 BorderDetector::getDimensions(const AVPicture *pgm, int pgmheight,
00059 long long _frameno, int *prow, int *pcol, int *pwidth, int *pheight)
00060 {
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 static const unsigned char MAXRANGE = 32;
00093
00094
00095
00096
00097
00098
00099 static const int MAXLINES = 2;
00100
00101 const int pgmwidth = pgm->linesize[0];
00102
00103
00104
00105
00106
00107
00108 const int MAXOUTLIERS = pgmwidth * 12 / 1000;
00109
00110
00111
00112
00113
00114 const int VERTMARGIN = max(2, pgmheight * 1 / 60);
00115 const int HORIZMARGIN = max(2, pgmwidth * 1 / 80);
00116
00117
00118
00119
00120
00121
00122 const int VERTSLOP = max(MAXLINES, pgmheight * 1 / 120);
00123 const int HORIZSLOP = max(MAXLINES, pgmwidth * 1 / 160);
00124
00125 struct timeval start, end, elapsed;
00126 unsigned char minval, maxval, val;
00127 int rr, cc, minrow, mincol, maxrow1, maxcol1, saved;
00128 int newrow, newcol, newwidth, newheight;
00129 bool top, bottom, left, right, inrange;
00130 int range, outliers, lines;
00131
00132 (void)gettimeofday(&start, NULL);
00133
00134 if (_frameno != UNCACHED && _frameno == frameno)
00135 goto done;
00136
00137 top = false;
00138 bottom = false;
00139 left = false;
00140 right = false;
00141
00142 minrow = VERTMARGIN;
00143 maxrow1 = pgmheight - VERTMARGIN;
00144
00145 mincol = HORIZMARGIN;
00146 maxcol1 = pgmwidth - HORIZMARGIN;
00147
00148 newrow = minrow - 1;
00149 newcol = mincol - 1;
00150 newwidth = maxcol1 + 1 - mincol;
00151 newheight = maxrow1 + 1 - minrow;
00152
00153 for (;;)
00154 {
00155
00156 left = false;
00157 minval = UCHAR_MAX;
00158 maxval = 0;
00159 lines = 0;
00160 saved = mincol;
00161 for (cc = mincol; cc < maxcol1; cc++)
00162 {
00163 outliers = 0;
00164 inrange = true;
00165 for (rr = minrow; rr < maxrow1; rr++)
00166 {
00167 if (logo && rrccinrect(rr, cc, logorow, logocol,
00168 logowidth, logoheight))
00169 continue;
00170
00171 val = pgm->data[0][rr * pgmwidth + cc];
00172 range = max(maxval, val) - min(minval, val) + 1;
00173 if (range > MAXRANGE)
00174 {
00175 if (outliers++ < MAXOUTLIERS)
00176 continue;
00177 inrange = false;
00178 if (lines++ < MAXLINES)
00179 break;
00180 goto found_left;
00181 }
00182 if (val < minval)
00183 minval = val;
00184 if (val > maxval)
00185 maxval = val;
00186 }
00187 if (inrange)
00188 {
00189 saved = cc;
00190 lines = 0;
00191 }
00192 }
00193 found_left:
00194 if (newcol != saved + 1 + HORIZSLOP)
00195 {
00196 newcol = min(maxcol1, saved + 1 + HORIZSLOP);
00197 newwidth = max(0, maxcol1 - newcol);
00198 left = true;
00199 }
00200
00201 if (!newwidth)
00202 goto monochromatic_frame;
00203
00204 mincol = newcol;
00205
00206
00207
00208
00209
00210 right = false;
00211 lines = 0;
00212 saved = maxcol1 - 1;
00213 for (cc = maxcol1 - 1; cc >= mincol; cc--)
00214 {
00215 outliers = 0;
00216 inrange = true;
00217 for (rr = minrow; rr < maxrow1; rr++)
00218 {
00219 if (logo && rrccinrect(rr, cc, logorow, logocol,
00220 logowidth, logoheight))
00221 continue;
00222
00223 val = pgm->data[0][rr * pgmwidth + cc];
00224 range = max(maxval, val) - min(minval, val) + 1;
00225 if (range > MAXRANGE)
00226 {
00227 if (outliers++ < MAXOUTLIERS)
00228 continue;
00229 inrange = false;
00230 if (lines++ < MAXLINES)
00231 break;
00232 goto found_right;
00233 }
00234 if (val < minval)
00235 minval = val;
00236 if (val > maxval)
00237 maxval = val;
00238 }
00239 if (inrange)
00240 {
00241 saved = cc;
00242 lines = 0;
00243 }
00244 }
00245 found_right:
00246 if (newwidth != saved - mincol - HORIZSLOP)
00247 {
00248 newwidth = max(0, saved - mincol - HORIZSLOP);
00249 right = true;
00250 }
00251
00252 if (!newwidth)
00253 goto monochromatic_frame;
00254
00255 if (top || bottom)
00256 break;
00257
00258 maxcol1 = mincol + newwidth;
00259
00260
00261 top = false;
00262 minval = UCHAR_MAX;
00263 maxval = 0;
00264 lines = 0;
00265 saved = minrow;
00266 for (rr = minrow; rr < maxrow1; rr++)
00267 {
00268 outliers = 0;
00269 inrange = true;
00270 for (cc = mincol; cc < maxcol1; cc++)
00271 {
00272 if (logo && rrccinrect(rr, cc, logorow, logocol,
00273 logowidth, logoheight))
00274 continue;
00275
00276 val = pgm->data[0][rr * pgmwidth + cc];
00277 range = max(maxval, val) - min(minval, val) + 1;
00278 if (range > MAXRANGE)
00279 {
00280 if (outliers++ < MAXOUTLIERS)
00281 continue;
00282 inrange = false;
00283 if (lines++ < MAXLINES)
00284 break;
00285 goto found_top;
00286 }
00287 if (val < minval)
00288 minval = val;
00289 if (val > maxval)
00290 maxval = val;
00291 }
00292 if (inrange)
00293 {
00294 saved = rr;
00295 lines = 0;
00296 }
00297 }
00298 found_top:
00299 if (newrow != saved + 1 + VERTSLOP)
00300 {
00301 newrow = min(maxrow1, saved + 1 + VERTSLOP);
00302 newheight = max(0, maxrow1 - newrow);
00303 top = true;
00304 }
00305
00306 if (!newheight)
00307 goto monochromatic_frame;
00308
00309 minrow = newrow;
00310
00311
00312 bottom = false;
00313 lines = 0;
00314 saved = maxrow1 - 1;
00315 for (rr = maxrow1 - 1; rr >= minrow; rr--)
00316 {
00317 outliers = 0;
00318 inrange = true;
00319 for (cc = mincol; cc < maxcol1; cc++)
00320 {
00321 if (logo && rrccinrect(rr, cc, logorow, logocol,
00322 logowidth, logoheight))
00323 continue;
00324
00325 val = pgm->data[0][rr * pgmwidth + cc];
00326 range = max(maxval, val) - min(minval, val) + 1;
00327 if (range > MAXRANGE)
00328 {
00329 if (outliers++ < MAXOUTLIERS)
00330 continue;
00331 inrange = false;
00332 if (lines++ < MAXLINES)
00333 break;
00334 goto found_bottom;
00335 }
00336 if (val < minval)
00337 minval = val;
00338 if (val > maxval)
00339 maxval = val;
00340 }
00341 if (inrange)
00342 {
00343 saved = rr;
00344 lines = 0;
00345 }
00346 }
00347 found_bottom:
00348 if (newheight != saved - minrow - VERTSLOP)
00349 {
00350 newheight = max(0, saved - minrow - VERTSLOP);
00351 bottom = true;
00352 }
00353
00354 if (!newheight)
00355 goto monochromatic_frame;
00356
00357 if (left || right)
00358 break;
00359
00360 maxrow1 = minrow + newheight;
00361 }
00362
00363 frameno = _frameno;
00364 row = newrow;
00365 col = newcol;
00366 width = newwidth;
00367 height = newheight;
00368 ismonochromatic = false;
00369 goto done;
00370
00371 monochromatic_frame:
00372 frameno = _frameno;
00373 row = newrow;
00374 col = newcol;
00375 width = newwidth;
00376 height = newheight;
00377 ismonochromatic = true;
00378
00379 done:
00380 *prow = row;
00381 *pcol = col;
00382 *pwidth = width;
00383 *pheight = height;
00384
00385 (void)gettimeofday(&end, NULL);
00386 timersub(&end, &start, &elapsed);
00387 timeradd(&analyze_time, &elapsed, &analyze_time);
00388
00389 return ismonochromatic ? -1 : 0;
00390 }
00391
00392 int
00393 BorderDetector::reportTime(void)
00394 {
00395 if (!time_reported)
00396 {
00397 VERBOSE(VB_COMMFLAG, QString("BD Time: analyze=%1s")
00398 .arg(strftimeval(&analyze_time)));
00399 time_reported = true;
00400 }
00401 return 0;
00402 }
00403
00404