27 int *frow,
int *fcol,
int *fwidth,
int *fheight,
31 std::array<quint32,UCHAR_MAX + 1> counter {};
33 QByteArray fname =
filename.toLocal8Bit();
34 FILE *fp = fopen(fname.constData(),
"r");
39 auto close_fp = [&](
FILE *fp2) {
42 LOG(VB_COMMFLAG, LOG_ERR, QString(
"Error closing %1: %2")
45 std::unique_ptr<
FILE,
decltype(close_fp)>
cleanup { fp, close_fp };
47 for (
long long frameno = 0; frameno < nframes; frameno++)
49 int monochromaticval = 0;
56 float stddevval = NAN;
57 int nitems = fscanf(fp,
"%20d %20f %20d %20f %20d %20d %20d %20d",
58 &monochromaticval, &meanval, &medianval, &stddevval,
59 &widthval, &heightval, &colval, &rowval);
62 LOG(VB_COMMFLAG, LOG_ERR,
63 QString(
"Not enough data in %1: frame %2")
67 if (monochromaticval < 0 || monochromaticval > 1 ||
68 medianval < 0 || (
uint)medianval > UCHAR_MAX ||
69 widthval < 0 || heightval < 0 || colval < 0 || rowval < 0)
71 LOG(VB_COMMFLAG, LOG_ERR,
72 QString(
"Data out of range in %1: frame %2")
76 for (
uint & ctr : counter)
78 if (fscanf(fp,
"%20x", &ctr) != 1)
80 LOG(VB_COMMFLAG, LOG_ERR,
81 QString(
"Not enough data in %1: frame %2")
87 LOG(VB_COMMFLAG, LOG_ERR,
88 QString(
"Data out of range in %1: frame %2")
93 mean[frameno] = meanval;
94 median[frameno] = medianval;
95 stddev[frameno] = stddevval;
96 frow[frameno] = rowval;
97 fcol[frameno] = colval;
98 fwidth[frameno] = widthval;
99 fheight[frameno] = heightval;
100 for (
size_t ii = 0; ii < counter.size(); ii++)
101 histogram[frameno][ii] = counter[ii];
102 monochromatic[frameno] = !widthval || !heightval ? 1 : 0;
113 int *frow,
int *fcol,
int *fwidth,
int *fheight,
117 QByteArray fname =
filename.toLocal8Bit();
118 FILE *fp = fopen(fname,
"w");
121 for (
long long frameno = 0; frameno < nframes; frameno++)
123 (void)fprintf(fp,
"%3u %10.6f %3u %10.6f %5d %5d %5d %5d",
124 monochromatic[frameno],
125 static_cast<double>(mean[frameno]), median[frameno],
126 static_cast<double>(stddev[frameno]),
127 fwidth[frameno], fheight[frameno],
128 fcol[frameno], frow[frameno]);
129 for (
unsigned int ii = 0; ii < UCHAR_MAX + 1; ii++)
130 (
void)fprintf(fp,
" %02x", histogram[frameno][ii]);
131 (void)fprintf(fp,
"\n");
134 LOG(VB_COMMFLAG, LOG_ERR, QString(
"Error closing %1: %2")
142 std::shared_ptr<BorderDetector> bd,
143 const QString& debugdir)
144 : m_pgmConverter(
std::move(pgmc))
145 , m_borderDetector(
std::move(bd))
147 , m_debugdata(debugdir +
"/HistogramAnalyzer-pgm.txt")
149 , m_debugdata(debugdir +
"/HistogramAnalyzer-yuv.txt")
162 QString(
"HistogramAnalyzer debugLevel %1").arg(
m_debugLevel));
191 unsigned int width = buf_dim.width();
192 unsigned int height = buf_dim.height();
204 QString details =
m_logo ? QString(
"logo %1x%2@(%3,%4)")
208 LOG(VB_COMMFLAG, LOG_INFO,
209 QString(
"HistogramAnalyzer::MythPlayerInited %1x%2: %3")
210 .arg(width).arg(height).arg(details));
221 LOG(VB_COMMFLAG, LOG_INFO,
222 QString(
"HistogramAnalyzer::MythPlayerInited nframes %1, allocating %2")
223 .arg(nframes).arg(nframes+128));
225 m_mean =
new float[nframes];
226 m_median =
new unsigned char[nframes];
228 m_fRow =
new int[nframes];
229 m_fCol =
new int[nframes];
245 unsigned int npixels = width * height;
246 m_buf =
new unsigned char[npixels];
253 LOG(VB_COMMFLAG, LOG_INFO,
254 QString(
"HistogramAnalyzer::MythPlayerInited read %1")
270static constexpr int ROUNDUP(
int a,
int b) {
return (a + b - 1) / b * b; }
279 static constexpr int kDefaultColor = 0;
289 static constexpr int kRInc = 4;
290 static constexpr int kCInc = 4;
294 bool ismonochromatic =
false;
299 unsigned int borderpixels = 0;
300 unsigned int livepixels = 0;
301 unsigned int npixels = 0;
302 unsigned int halfnpixels = 0;
303 unsigned char *
pp =
nullptr;
304 unsigned char bordercolor = 0;
305 unsigned long long sumval = 0;
306 unsigned long long sumsquares = 0;
313 std::chrono::microseconds start {0us};
314 std::chrono::microseconds end {0us};
322 LOG(VB_COMMFLAG, LOG_ERR,
323 QString(
"HistogramAnalyzer::analyzeFrame error at frame %1")
330 &croprow, &cropcol, &cropwidth, &cropheight) != 0;
332 start = nowAsDuration<std::chrono::microseconds>();
334 m_fRow[frameno] = croprow;
335 m_fCol[frameno] = cropcol;
342 croprow = pgmheight * 3 / 8;
343 cropheight = pgmheight / 4;
344 cropcol = pgmwidth * 3 / 8;
345 cropwidth = pgmwidth / 4;
350 rr2 =
ROUNDUP(croprow + cropheight, kRInc);
351 cc2 =
ROUNDUP(cropcol + cropwidth, kCInc);
352 rr3 =
ROUNDUP(pgmheight, kRInc);
353 cc3 =
ROUNDUP(pgmwidth, kCInc);
355 borderpixels = ((rr1 / kRInc) * (cc3 / kCInc)) +
356 (((rr2 - rr1) / kRInc) * (cc1 / kCInc)) +
357 (((rr2 - rr1) / kRInc) * ((cc3 - cc2) / kCInc)) +
358 (((rr3 - rr2) / kRInc) * (cc3 / kCInc));
362 m_histVal[kDefaultColor] += borderpixels;
363 for (
int rr = rr1; rr < rr2; rr += kRInc)
365 int rroffset = rr * pgmwidth;
367 for (
int cc = cc1; cc < cc2; cc += kCInc)
373 unsigned char val = pgm->data[0][rroffset + cc];
376 sumsquares += 1ULL * val * val;
381 npixels = borderpixels + livepixels;
384 halfnpixels = npixels / 2;
385 for (
unsigned int color = 0; color < UCHAR_MAX + 1; color++)
387 (
m_histVal[color] * UCHAR_MAX + halfnpixels) / npixels;
390 if (ismonochromatic && livepixels)
396 bordercolor = (sumval + livepixels - 1) / livepixels;
397 sumval += 1ULL * borderpixels * bordercolor;
398 sumsquares += 1ULL * borderpixels * bordercolor * bordercolor;
401 memset(
m_buf, bordercolor, borderpixels *
sizeof(*
m_buf));
403 m_mean[frameno] = (float)sumval / npixels;
404 m_median[frameno] = quick_select_median<uint8_t>(
m_buf, npixels);
406 sqrt((sumsquares - (
float)sumval * sumval / npixels) / (npixels - 1)) :
409 end = nowAsDuration<std::chrono::microseconds>();
425 LOG(VB_COMMFLAG, LOG_INFO,
426 QString(
"HistogramAnalyzer::finished wrote %1")
444 LOG(VB_COMMFLAG, LOG_INFO, QString(
"HA Time: analyze=%1s")
static constexpr int ROUNDUP(int a, int b)
#define PGM_CONVERT_GREYSCALE
static const long long kUncached
HistogramAnalyzer(std::shared_ptr< PGMConverter > pgmc, std::shared_ptr< BorderDetector > bd, const QString &debugdir)
TemplateFinder * m_logoFinder
unsigned char * m_monochromatic
enum FrameAnalyzer::analyzeFrameResult MythPlayerInited(MythPlayer *player, long long nframes)
const struct AVFrame * m_logo
std::array< int, UCHAR_MAX+1 > m_histVal
std::array< uint8_t, UCHAR_MAX+1 > Histogram
int finished(long long nframes, bool final)
std::shared_ptr< BorderDetector > m_borderDetector
void setLogoState(TemplateFinder *finder)
std::chrono::microseconds m_analyzeTime
int reportTime(void) const
enum FrameAnalyzer::analyzeFrameResult analyzeFrame(const MythVideoFrame *frame, long long frameno)
std::shared_ptr< PGMConverter > m_pgmConverter
int GetNumSetting(const QString &key, int defaultval=0)
QSize GetVideoBufferSize(void) const
const struct AVFrame * getTemplate(int *prow, int *pcol, int *pwidth, int *pheight) const
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
bool writeData(const QString &filename, float *mean, unsigned char *median, float *stddev, int *frow, int *fcol, int *fwidth, int *fheight, HistogramAnalyzer::Histogram *histogram, unsigned char *monochromatic, long long nframes)
bool readData(const QString &filename, float *mean, unsigned char *median, float *stddev, int *frow, int *fcol, int *fwidth, int *fheight, HistogramAnalyzer::Histogram *histogram, unsigned char *monochromatic, long long nframes)
void createDebugDirectory(const QString &dirname, const QString &comment)
QString strftimeval(std::chrono::microseconds usecs)
static QString cleanup(const QString &str)