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