Ticket #1821: logodetectorpatch

File logodetectorpatch, 44.1 KB (added by lucas@…, 20 years ago)

the patch

Line 
1Index: programs/mythcommflag/ClassicLogoDetector.h
2===================================================================
3--- programs/mythcommflag/ClassicLogoDetector.h (revision 0)
4+++ programs/mythcommflag/ClassicLogoDetector.h (revision 0)
5@@ -0,0 +1,60 @@
6+#ifndef _CLASSICLOGOGEDETECTOR_H_
7+#define _CLASSICLOGOGEDETECTOR_H_
8+
9+#include "LogoDetectorBase.h"
10+
11+typedef struct edgemaskentry EdgeMaskEntry;
12+typedef struct VideoFrame_ VideoFrame;
13+class ClassicCommDetector;
14+
15+class ClassicLogoDetector : public LogoDetectorBase
16+{
17+public:
18+ ClassicLogoDetector(ClassicCommDetector* commDetector,unsigned int width, unsigned int height, unsigned int commdetectborder, unsigned int xspacing, unsigned int yspacing);
19+ ~ClassicLogoDetector();
20+
21+ bool searchForLogo(NuppelVideoPlayer* nvp);
22+ bool doesThisFrameContainTheFoundLogo(unsigned char* frame);
23+ bool pixelInsideLogo(unsigned int x, unsigned int y);
24+
25+ unsigned int getRequiredAvailableBufferForSearch();
26+
27+private:
28+ void SetLogoMaskArea();
29+ void SetLogoMask(unsigned char *mask);
30+ void DumpLogo(bool fromCurrentFrame,unsigned char* framePtr);
31+ void DetectEdges(VideoFrame *frame, EdgeMaskEntry *edges, int edgeDiff);
32+
33+ ClassicCommDetector* commDetector;
34+ unsigned int frameNumber;
35+ bool previousFrameWasSceneChange;
36+ unsigned int xspacing, yspacing;
37+ unsigned int commDetectBorder;
38+
39+ int commDetectLogoSamplesNeeded;
40+ int commDetectLogoSampleSpacing;
41+ int commDetectLogoSecondsNeeded;
42+ double commDetectLogoGoodEdgeThreshold;
43+ double commDetectLogoBadEdgeThreshold;
44+
45+ EdgeMaskEntry *edgeMask;
46+
47+ unsigned char *logoMaxValues;
48+ unsigned char *logoMinValues;
49+ unsigned char *logoFrame;
50+ unsigned char *logoMask;
51+ unsigned char *logoCheckMask;
52+ unsigned char *tmpBuf;
53+
54+ int logoEdgeDiff;
55+ unsigned int logoFrameCount;
56+ unsigned int logoMinX;
57+ unsigned int logoMaxX;
58+ unsigned int logoMinY;
59+ unsigned int logoMaxY;
60+
61+ bool logoInfoAvailable;
62+};
63+
64+
65+#endif
66Index: programs/mythcommflag/mythcommflag.pro
67===================================================================
68--- programs/mythcommflag/mythcommflag.pro (revision 9932)
69+++ programs/mythcommflag/mythcommflag.pro (working copy)
70@@ -10,5 +10,5 @@
71 QMAKE_CLEAN += $(TARGET)
72
73 # Input
74-SOURCES += main.cpp ClassicCommDetector.cpp CommDetectorFactory.cpp CommDetectorBase.cpp
75-HEADERS += CommDetectorBase.h ClassicCommDetector.h SlotRelayer.h CustomEventRelayer.h CommDetectorFactory.h
76+SOURCES += main.cpp ClassicCommDetector.cpp CommDetectorFactory.cpp CommDetectorBase.cpp ClassicLogoDetector.cpp
77+HEADERS += CommDetectorBase.h ClassicCommDetector.h SlotRelayer.h CustomEventRelayer.h CommDetectorFactory.h ClassicLogoDetector.h LogoDetectorBase.h
78Index: programs/mythcommflag/ClassicCommDetector.cpp
79===================================================================
80--- programs/mythcommflag/ClassicCommDetector.cpp (revision 9932)
81+++ programs/mythcommflag/ClassicCommDetector.cpp (working copy)
82@@ -4,6 +4,7 @@
83 #include "CommDetector.h"
84 #include "ClassicCommDetector.h"
85 #include "libmythtv/NuppelVideoPlayer.h"
86+#include "ClassicLogoDetector.h"
87
88 #include "qstring.h"
89 #include "libmyth/mythcontext.h"
90@@ -48,17 +49,10 @@
91 stopsAt(stopsAt_in),
92 recordingStartedAt(recordingStartedAt_in),
93 recordingStopsAt(recordingStopsAt_in),
94- framesProcessed(0),preRoll(0),postRoll(0)
95+ framesProcessed(0),preRoll(0),postRoll(0),
96+ logoDetector(0)
97 {
98
99- edgeMask = NULL;
100- logoFrame = NULL;
101- logoMask = NULL;
102- logoCheckMask = NULL;
103- logoMaxValues = NULL;
104- logoMinValues = NULL;
105- tmpBuf = NULL;
106-
107 stillRecording = recordingStopsAt > QDateTime::currentDateTime();
108
109 commDetectBorder =
110@@ -81,18 +75,7 @@
111 gContext->GetNumSetting("CommDetectMinShowLength", 65);
112 commDetectMaxCommLength =
113 gContext->GetNumSetting("CommDetectMaxCommLength", 125);
114- commDetectLogoSamplesNeeded =
115- gContext->GetNumSetting("CommDetectLogoSamplesNeeded", 240);
116- commDetectLogoSampleSpacing =
117- gContext->GetNumSetting("CommDetectLogoSampleSpacing", 2);
118- commDetectLogoSecondsNeeded = commDetectLogoSamplesNeeded *
119- commDetectLogoSampleSpacing;
120- commDetectLogoGoodEdgeThreshold =
121- gContext->GetSetting("CommDetectLogoGoodEdgeThreshold", "0.75")
122- .toDouble();
123- commDetectLogoBadEdgeThreshold =
124- gContext->GetSetting("CommDetectLogoBadEdgeThreshold", "0.85")
125- .toDouble();
126+
127 skipAllBlanks = !!gContext->GetNumSetting("CommSkipAllBlanks", 1);
128 commDetectBlankCanHaveLogo =
129 !!gContext->GetNumSetting("CommDetectBlankCanHaveLogo", 1);
130@@ -184,35 +167,6 @@
131
132 framePtr = NULL;
133
134- if (edgeMask)
135- delete [] edgeMask;
136- edgeMask = new EdgeMaskEntry[width * height];
137-
138- if (logoFrame)
139- delete [] logoFrame;
140- logoFrame = new unsigned char[width * height];
141-
142- if (logoMask)
143- delete [] logoMask;
144- logoMask = new unsigned char[width * height];
145-
146- if (logoCheckMask)
147- delete [] logoCheckMask;
148- logoCheckMask = new unsigned char[width * height];
149-
150- if (logoMaxValues)
151- delete [] logoMaxValues;
152- logoMaxValues = new unsigned char[width * height];
153-
154- if (logoMinValues)
155- delete [] logoMinValues;
156- logoMinValues = new unsigned char[width * height];
157-
158- if (tmpBuf)
159- delete [] tmpBuf;
160- tmpBuf = new unsigned char[width * height];
161-
162- logoFrameCount = 0;
163 logoInfoAvailable = false;
164
165 ClearAllMaps();
166@@ -226,20 +180,7 @@
167
168 ClassicCommDetector::~ClassicCommDetector()
169 {
170- if (edgeMask)
171- delete [] edgeMask;
172- if (logoFrame)
173- delete [] logoFrame;
174- if (logoMask)
175- delete [] logoMask;
176- if (logoCheckMask)
177- delete [] logoCheckMask;
178- if (logoMaxValues)
179- delete [] logoMaxValues;
180- if (logoMinValues)
181- delete [] logoMinValues;
182- if (tmpBuf)
183- delete [] tmpBuf;
184+ if (logoDetector) delete logoDetector;
185 }
186
187 bool ClassicCommDetector::go()
188@@ -249,10 +190,17 @@
189 int requiredBuffer = 7;
190 int requiredHeadStart = requiredBuffer;
191
192+ if (nvp->OpenFile() < 0)
193+ return false;
194+
195+ Init();
196+
197 if (commDetectMethod & COMM_DETECT_LOGO)
198 {
199+ logoDetector = new ClassicLogoDetector(this,width,height,commDetectBorder,horizSpacing,vertSpacing);
200+
201 requiredHeadStart += max(0,recordingStartedAt.secsTo(startedAt));
202- requiredHeadStart += commDetectLogoSecondsNeeded;
203+ requiredHeadStart += logoDetector->getRequiredAvailableBufferForSearch();
204 }
205
206 emit statusUpdate("Building Detection Buffer");
207@@ -272,11 +220,6 @@
208 if ((wereRecording) && (!stillRecording) && (secsSince < requiredHeadStart))
209 return false;
210
211- if (nvp->OpenFile() < 0)
212- return false;
213-
214- Init();
215-
216 aggressiveDetection = gContext->GetNumSetting("AggressiveCommDetect", 1);
217
218 if (!nvp->InitVideo())
219@@ -287,9 +230,10 @@
220 }
221 nvp->SetCaptionsEnabled(false);
222
223+ unsigned int length = static_cast<unsigned int>(nvp->GetLength());
224 if ((commDetectMethod & COMM_DETECT_LOGO) &&
225- ((nvp->GetLength() == 0) ||
226- (nvp->GetLength() > commDetectLogoSecondsNeeded)))
227+ ((length == 0) ||
228+ (length > logoDetector->getRequiredAvailableBufferForSearch())))
229 {
230 emit statusUpdate("Searching for Logo");
231
232@@ -299,7 +243,7 @@
233 cerr.flush();
234 }
235
236- SearchForLogo();
237+ logoInfoAvailable = logoDetector->searchForLogo(nvp);
238
239 if (showProgress)
240 {
241@@ -714,27 +658,30 @@
242 {
243 pixel = framePtr[y * width + x];
244
245- if ((commDetectMethod & COMM_DETECT_BLANKS) &&
246- ((!commDetectBlankCanHaveLogo) ||
247- (!logoInfoAvailable) ||
248- ((logoInfoAvailable) &&
249- ((y < logoMinY) || (y > logoMaxY) ||
250- (x < logoMinX) || (x > logoMaxX)))))
251+ if (commDetectMethod & COMM_DETECT_BLANKS)
252 {
253- blankPixelsChecked++;
254- totBrightness += pixel;
255+ bool checkPixel = false;
256+ if (!commDetectBlankCanHaveLogo) checkPixel = true;
257+ if (!logoInfoAvailable) checkPixel = true;
258+ else if (!logoDetector->pixelInsideLogo(x,y)) checkPixel=true;
259
260- if (pixel < min)
261- min = pixel;
262+ if (checkPixel)
263+ {
264+ blankPixelsChecked++;
265+ totBrightness += pixel;
266+
267+ if (pixel < min)
268+ min = pixel;
269
270- if (pixel > max)
271- max = pixel;
272+ if (pixel > max)
273+ max = pixel;
274
275- if (pixel > rowMax[y])
276- rowMax[y] = pixel;
277+ if (pixel > rowMax[y])
278+ rowMax[y] = pixel;
279
280- if (pixel > colMax[x])
281- colMax[x] = pixel;
282+ if (pixel > colMax[x])
283+ colMax[x] = pixel;
284+ }
285 }
286
287 if (commDetectMethod & COMM_DETECT_SCENE)
288@@ -854,7 +801,7 @@
289
290 if ((logoInfoAvailable) && (commDetectMethod & COMM_DETECT_LOGO))
291 {
292- stationLogoPresent = CheckEdgeLogo();
293+ stationLogoPresent = logoDetector->doesThisFrameContainTheFoundLogo(framePtr);
294 }
295
296 #if 0
297@@ -2142,172 +2089,6 @@
298 VERBOSE(VB_COMMFLAG, "---------------------------------------------------");
299 }
300
301-void ClassicCommDetector::DumpLogo(bool fromCurrentFrame)
302-{
303- char scrPixels[] = " .oxX";
304-
305- if (!logoInfoAvailable)
306- return;
307-
308- cerr << "\nLogo Data ";
309- if (fromCurrentFrame)
310- cerr << "from current frame\n";
311-
312- cerr << "\n ";
313-
314- for(int x = logoMinX - 2; x <= (logoMaxX + 2); x++)
315- cerr << (x % 10);
316- cerr << "\n";
317-
318- for(int y = logoMinY - 2; y <= (logoMaxY + 2); y++)
319- {
320- cerr << QString::number(y).rightJustify(3, ' ') << ": ";
321- for(int x = logoMinX - 2; x <= (logoMaxX + 2); x++)
322- {
323- if (fromCurrentFrame)
324- {
325- cerr << scrPixels[framePtr[y * width + x] / 50];
326- }
327- else
328- {
329- switch (logoMask[y * width + x])
330- {
331- case 0:
332- case 2: cerr << " ";
333- break;
334- case 1: cerr << "*";
335- break;
336- case 3: cerr << ".";
337- break;
338- }
339- }
340- }
341- cerr << "\n";
342- }
343- cerr.flush();
344-}
345-
346-void ClassicCommDetector::SetLogoMaskArea()
347-{
348- VERBOSE(VB_COMMFLAG, "SetLogoMaskArea()");
349-
350- logoMinX = width - 1;
351- logoMaxX = 0;
352- logoMinY = height - 1;
353- logoMaxY = 0;
354-
355- for (int y = 0; y < height; y++)
356- {
357- for (int x = 0; x < width; x++)
358- {
359- if (edgeMask[y * width + x].isedge)
360- {
361- if (x < logoMinX)
362- logoMinX = x;
363- if (y < logoMinY)
364- logoMinY = y;
365- if (x > logoMaxX)
366- logoMaxX = x;
367- if (y > logoMaxY)
368- logoMaxY = y;
369- }
370- }
371- }
372-
373- logoMinX -= 5;
374- logoMaxX += 5;
375- logoMinY -= 5;
376- logoMaxY += 5;
377-
378- if (logoMinX < 4)
379- logoMinX = 4;
380- if (logoMaxX > (width-5))
381- logoMaxX = (width-5);
382- if (logoMinY < 4)
383- logoMinY = 4;
384- if (logoMaxY > (height-5))
385- logoMaxY = (height-5);
386-}
387-
388-void ClassicCommDetector::SetLogoMask(unsigned char *mask)
389-{
390- int pixels = 0;
391-
392- memcpy(logoMask, mask, width * height);
393-
394- SetLogoMaskArea();
395-
396- for(int y = logoMinY; y <= logoMaxY; y++)
397- for(int x = logoMinX; x <= logoMaxX; x++)
398- if (!logoMask[y * width + x] == 1)
399- pixels++;
400-
401- if (pixels < 30)
402- {
403- detectStationLogo = false;
404- return;
405- }
406-
407- // set the pixels around our logo
408- for(int y = (logoMinY - 1); y <= (logoMaxY + 1); y++)
409- {
410- for(int x = (logoMinX - 1); x <= (logoMaxX + 1); x++)
411- {
412- if (!logoMask[y * width + x])
413- {
414- for (int y2 = y - 1; y2 <= (y + 1); y2++)
415- {
416- for (int x2 = x - 1; x2 <= (x + 1); x2++)
417- {
418- if ((logoMask[y2 * width + x2] == 1) &&
419- (!logoMask[y * width + x]))
420- {
421- logoMask[y * width + x] = 2;
422- x2 = x + 2;
423- y2 = y + 2;
424-
425- logoCheckMask[y2 * width + x2] = 1;
426- logoCheckMask[y * width + x] = 1;
427- }
428- }
429- }
430- }
431- }
432- }
433-
434- for(int y = (logoMinY - 2); y <= (logoMaxY + 2); y++)
435- {
436- for(int x = (logoMinX - 2); x <= (logoMaxX + 2); x++)
437- {
438- if (!logoMask[y * width + x])
439- {
440- for (int y2 = y - 1; y2 <= (y + 1); y2++)
441- {
442- for (int x2 = x - 1; x2 <= (x + 1); x2++)
443- {
444- if ((logoMask[y2 * width + x2] == 2) &&
445- (!logoMask[y * width + x]))
446- {
447- logoMask[y * width + x] = 3;
448- x2 = x + 2;
449- y2 = y + 2;
450-
451- logoCheckMask[y * width + x] = 1;
452- }
453- }
454- }
455- }
456- }
457- }
458-
459-#ifdef SHOW_DEBUG_WIN
460- DumpLogo(true);
461-#endif
462-
463- logoFrameCount = 0;
464- logoInfoAvailable = true;
465-}
466-
467 void ClassicCommDetector::CondenseMarkMap(QMap<long long, int>&map, int spacing,
468 int length)
469 {
470@@ -2412,258 +2193,7 @@
471 /* ideas for this method ported back from comskip.c mods by Jere Jones
472 * which are partially mods based on Myth's original commercial skip
473 * code written by Chris Pinkham. */
474-bool ClassicCommDetector::CheckEdgeLogo(void)
475-{
476
477- int radius = 2;
478- int x, y;
479- int pos1, pos2, pos3;
480- int pixel;
481- int goodEdges = 0;
482- int badEdges = 0;
483- int testEdges = 0;
484- int testNotEdges = 0;
485-
486- for (y = logoMinY; y <= logoMaxY; y++ )
487- {
488- for (x = logoMinX; x <= logoMaxX; x++ )
489- {
490- pos1 = y * width + x;
491- pos2 = (y - radius) * width + x;
492- pos3 = (y + radius) * width + x;
493-
494- pixel = framePtr[pos1];
495-
496- if (edgeMask[pos1].horiz)
497- {
498- if ((abs(framePtr[pos1 - radius] - pixel) >= logoEdgeDiff) ||
499- (abs(framePtr[pos1 + radius] - pixel) >= logoEdgeDiff))
500- goodEdges++;
501- testEdges++;
502- }
503- else
504- {
505- if ((abs(framePtr[pos1 - radius] - pixel) >= logoEdgeDiff) ||
506- (abs(framePtr[pos1 + radius] - pixel) >= logoEdgeDiff))
507- badEdges++;
508- testNotEdges++;
509- }
510-
511- if (edgeMask[pos1].vert)
512- {
513- if ((abs(framePtr[pos2] - pixel) >= logoEdgeDiff) ||
514- (abs(framePtr[pos3] - pixel) >= logoEdgeDiff))
515- goodEdges++;
516- testEdges++;
517- }
518- else
519- {
520- if ((abs(framePtr[pos2] - pixel) >= logoEdgeDiff) ||
521- (abs(framePtr[pos3] - pixel) >= logoEdgeDiff))
522- badEdges++;
523- testNotEdges++;
524- }
525- }
526- }
527-
528- double goodEdgeRatio = (double)goodEdges / (double)testEdges;
529- double badEdgeRatio = (double)badEdges / (double)testNotEdges;
530-
531- if ((goodEdgeRatio > commDetectLogoGoodEdgeThreshold) &&
532- (badEdgeRatio < commDetectLogoBadEdgeThreshold))
533- return true;
534- else
535- return false;
536-}
537-
538-
539-void ClassicCommDetector::SearchForLogo()
540-{
541- int seekIncrement = (int)(commDetectLogoSampleSpacing * fps);
542- long long seekFrame;
543- int loops;
544- int maxLoops = commDetectLogoSamplesNeeded;
545- EdgeMaskEntry *edgeCounts;
546- int pos, i, x, y, dx, dy;
547- int edgeDiffs[] = {5, 7, 10, 15, 20, 30, 40, 50, 60, 0 };
548-
549-
550- VERBOSE(VB_COMMFLAG, "Searching for Station Logo");
551-
552- logoInfoAvailable = false;
553-
554- edgeCounts = new EdgeMaskEntry[width * height];
555-
556- for (i = 0; edgeDiffs[i] != 0 && !logoInfoAvailable; i++)
557- {
558- int pixelsInMask = 0;
559-
560- VERBOSE(VB_COMMFLAG, QString("Trying with edgeDiff == %1")
561- .arg(edgeDiffs[i]));
562-
563- memset(edgeCounts, 0, sizeof(EdgeMaskEntry) * width * height);
564- memset(edgeMask, 0, sizeof(EdgeMaskEntry) * width * height);
565-
566- nvp->DiscardVideoFrame(nvp->GetRawVideoFrame(0));
567-
568- loops = 0;
569- seekFrame = preRoll + seekIncrement;
570-
571- while(loops < maxLoops && !nvp->GetEof())
572- {
573- VideoFrame* vf = nvp->GetRawVideoFrame(seekFrame);
574-
575- if ((loops % 50) == 0)
576- emit breathe();
577-
578- if (m_bStop)
579- {
580- nvp->DiscardVideoFrame(vf);
581- return;
582- }
583-
584- if (!fullSpeed)
585- usleep(10000);
586-
587- DetectEdges(vf, edgeCounts, edgeDiffs[i]);
588-
589- seekFrame += seekIncrement;
590- loops++;
591-
592- nvp->DiscardVideoFrame(vf);
593- }
594-
595- VERBOSE(VB_COMMFLAG, "Analyzing edge data");
596-
597-#ifdef SHOW_DEBUG_WIN
598- unsigned char *fakeFrame;
599- fakeFrame = new unsigned char[width * height * 3 / 2];
600- memset(fakeFrame, 0, width * height * 3 / 2);
601-#endif
602-
603- for (y = 0; y < height; y++)
604- {
605- if ((y > (height/4)) && (y < (height * 3 / 4)))
606- continue;
607-
608- for (x = 0; x < width; x++)
609- {
610- if ((x > (width/4)) && (x < (width * 3 / 4)))
611- continue;
612-
613- pos = y * width + x;
614-
615- if (edgeCounts[pos].isedge > (maxLoops * 0.66))
616- {
617- edgeMask[pos].isedge = 1;
618- pixelsInMask++;
619-#ifdef SHOW_DEBUG_WIN
620- fakeFrame[pos] = 0xff;
621-#endif
622-
623- }
624-
625- if (edgeCounts[pos].horiz > (maxLoops * 0.66))
626- edgeMask[pos].horiz = 1;
627-
628- if (edgeCounts[pos].vert > (maxLoops * 0.66))
629- edgeMask[pos].vert = 1;
630-
631- if (edgeCounts[pos].ldiag > (maxLoops * 0.66))
632- edgeMask[pos].ldiag = 1;
633-
634- if (edgeCounts[pos].rdiag > (maxLoops * 0.66))
635- edgeMask[pos].rdiag = 1;
636- }
637- }
638-
639- SetLogoMaskArea();
640-
641- for (y = logoMinY; y < logoMaxY; y++)
642- {
643- for (x = logoMinX; x < logoMaxX; x++)
644- {
645- int neighbors = 0;
646-
647- if (!edgeMask[y * width + x].isedge)
648- continue;
649-
650- for (dy = y - 2; dy <= (y + 2); dy++ )
651- {
652- for (dx = x - 2; dx <= (x + 2); dx++ )
653- {
654- if (edgeMask[dy * width + dx].isedge)
655- neighbors++;
656- }
657- }
658-
659- if (neighbors < 5)
660- edgeMask[y * width + x].isedge = 0;
661- }
662- }
663-
664- SetLogoMaskArea();
665-
666- VERBOSE(VB_COMMFLAG, QString("Testing Logo area: topleft "
667- "(%1,%2), bottomright (%3,%4)")
668- .arg(logoMinX).arg(logoMinY)
669- .arg(logoMaxX).arg(logoMaxY));
670-
671-#ifdef SHOW_DEBUG_WIN
672- for (x = logoMinX; x < logoMaxX; x++)
673- {
674- pos = logoMinY * width + x;
675- fakeFrame[pos] = 0x7f;
676- pos = logoMaxY * width + x;
677- fakeFrame[pos] = 0x7f;
678- }
679- for (y = logoMinY; y < logoMaxY; y++)
680- {
681- pos = y * width + logoMinX;
682- fakeFrame[pos] = 0x7f;
683- pos = y * width + logoMaxX;
684- fakeFrame[pos] = 0x7f;
685- }
686-
687- comm_debug_show(fakeFrame);
688- delete [] fakeFrame;
689-
690- cerr << "Hit ENTER to continue" << endl;
691- getchar();
692-#endif
693-
694- if (((logoMaxX - logoMinX) < (width / 4)) &&
695- ((logoMaxY - logoMinY) < (height / 4)) &&
696- (pixelsInMask > 50))
697- {
698- logoInfoAvailable = true;
699- logoEdgeDiff = edgeDiffs[i];
700-
701- VERBOSE(VB_COMMFLAG, QString("Using Logo area: topleft "
702- "(%1,%2), bottomright (%3,%4)")
703- .arg(logoMinX).arg(logoMinY)
704- .arg(logoMaxX).arg(logoMaxY));
705- }
706- else
707- {
708- VERBOSE(VB_COMMFLAG, QString("Rejecting Logo area: topleft "
709- "(%1,%2), bottomright (%3,%4), "
710- "pixelsInMask (%5). "
711- "Not within specified limits.")
712- .arg(logoMinX).arg(logoMinY)
713- .arg(logoMaxX).arg(logoMaxY)
714- .arg(pixelsInMask));
715- }
716- }
717-
718- delete [] edgeCounts;
719-
720- if (!logoInfoAvailable)
721- VERBOSE(VB_COMMFLAG, "No suitable logo area found.");
722-
723- nvp->DiscardVideoFrame(nvp->GetRawVideoFrame(0));
724-}
725-
726 void ClassicCommDetector::CleanupFrameInfo(void)
727 {
728 VERBOSE(VB_COMMFLAG, "CommDetect::CleanupFrameInfo()");
729@@ -2753,63 +2283,6 @@
730 }
731 }
732
733-void ClassicCommDetector::DetectEdges(VideoFrame *frame, EdgeMaskEntry *edges,
734- int edgeDiff)
735-{
736- int r = 2;
737- unsigned char *buf = frame->buf;
738- unsigned char p;
739- int pos, x, y;
740-
741- for (y = commDetectBorder + r; y < (height - commDetectBorder - r); y++)
742- {
743- if ((y > (height/4)) && (y < (height * 3 / 4)))
744- continue;
745-
746- for (x = commDetectBorder + r; x < (width - commDetectBorder - r); x++)
747- {
748- int edgeCount = 0;
749-
750- if ((x > (width/4)) && (x < (width * 3 / 4)))
751- continue;
752-
753- pos = y * width + x;
754- p = buf[pos];
755-
756- if (( abs(buf[y * width + (x - r)] - p) >= edgeDiff) ||
757- ( abs(buf[y * width + (x + r)] - p) >= edgeDiff))
758- {
759- edges[pos].horiz++;
760- edgeCount++;
761- }
762-
763- if (( abs(buf[(y - r) * width + x] - p) >= edgeDiff) ||
764- ( abs(buf[(y + r) * width + x] - p) >= edgeDiff))
765- {
766- edges[pos].vert++;
767- edgeCount++;
768- }
769-
770- if (( abs(buf[(y - r) * width + (x - r)] - p) >= edgeDiff) ||
771- ( abs(buf[(y + r) * width + (x + r)] - p) >= edgeDiff))
772- {
773- edges[pos].ldiag++;
774- edgeCount++;
775- }
776-
777- if (( abs(buf[(y - r) * width + (x + r)] - p) >= edgeDiff) ||
778- ( abs(buf[(y + r) * width + (x - r)] - p) >= edgeDiff))
779- {
780- edges[pos].rdiag++;
781- edgeCount++;
782- }
783-
784- if (edgeCount >= 3)
785- edges[pos].isedge++;
786- }
787- }
788-}
789-
790 void ClassicCommDetector::GetLogoCommBreakMap(QMap<long long, int> &map)
791 {
792 VERBOSE(VB_COMMFLAG, "CommDetect::GetLogoCommBreakMap()");
793@@ -2841,5 +2314,9 @@
794
795 }
796
797+void ClassicCommDetector::logoDetectorBreathe()
798+{
799+ emit breathe();
800+}
801
802 /* vim: set expandtab tabstop=4 shiftwidth=4: */
803Index: programs/mythcommflag/LogoDetectorBase.h
804===================================================================
805--- programs/mythcommflag/LogoDetectorBase.h (revision 0)
806+++ programs/mythcommflag/LogoDetectorBase.h (revision 0)
807@@ -0,0 +1,30 @@
808+#ifndef _LOGODETECTORBASE_H_
809+#define _LOGODETECTORBASE_H_
810+
811+#include "qobject.h"
812+
813+class NuppelVideoPlayer;
814+
815+class LogoDetectorBase : public QObject
816+{
817+ Q_OBJECT
818+
819+public:
820+ LogoDetectorBase(unsigned int w,unsigned int h) : foundLogo(false), width(w),height(h) {};
821+ ~LogoDetectorBase() {};
822+
823+ virtual bool searchForLogo(NuppelVideoPlayer* nvp) = 0;
824+ virtual bool doesThisFrameContainTheFoundLogo(unsigned char* frame) = 0;
825+ virtual bool pixelInsideLogo(unsigned int x, unsigned int y) = 0;
826+ virtual unsigned int getRequiredAvailableBufferForSearch() = 0;
827+
828+signals:
829+ void haveNewInformation(unsigned int framenum, bool haslogo, float debugValue = 0.0);
830+
831+protected:
832+ bool foundLogo;
833+ unsigned int width, height;
834+};
835+
836+
837+#endif
838Index: programs/mythcommflag/ClassicCommDetector.h
839===================================================================
840--- programs/mythcommflag/ClassicCommDetector.h (revision 9932)
841+++ programs/mythcommflag/ClassicCommDetector.h (working copy)
842@@ -6,6 +6,7 @@
843 #include "qdatetime.h"
844
845 class NuppelVideoPlayer;
846+class LogoDetectorBase;
847
848 class ClassicCommDetector : public CommDetectorBase
849 {
850@@ -22,18 +23,11 @@
851 void recordingFinished(long long totalFileSize);
852 void requestCommBreakMapUpdate(void);
853
854+ void logoDetectorBreathe();
855+
856+ friend class ClassicLogoDetector;
857 private:
858
859- typedef struct edgemaskentry
860- {
861- int isedge;
862- int horiz;
863- int vert;
864- int rdiag;
865- int ldiag;
866- }
867- EdgeMaskEntry;
868-
869 typedef struct frameinfo
870 {
871 int minBrightness;
872@@ -81,15 +75,9 @@
873 void MergeBlankCommList(void);
874 bool FrameIsInBreakMap(long long f, QMap<long long, int> &breakMap);
875 void DumpMap(QMap<long long, int> &map);
876- void DumpLogo(bool fromCurrentFrame);
877- void SetLogoMaskArea();
878- void SetLogoMask(unsigned char *mask);
879 void CondenseMarkMap(QMap<long long, int>&map, int spacing, int length);
880 void ConvertShowMapToCommMap(QMap<long long, int>&map);
881- bool CheckEdgeLogo(void);
882- void SearchForLogo();
883 void CleanupFrameInfo(void);
884- void DetectEdges(VideoFrame *frame, EdgeMaskEntry *edges, int edgeDiff);
885 void GetLogoCommBreakMap(QMap<long long, int> &map);
886
887 int commDetectMethod;
888@@ -114,12 +102,7 @@
889 int commDetectMinCommBreakLength;
890 int commDetectMinShowLength;
891 int commDetectMaxCommLength;
892- int commDetectLogoSamplesNeeded;
893- int commDetectLogoSampleSpacing;
894- int commDetectLogoSecondsNeeded;
895 bool commDetectBlankCanHaveLogo;
896- double commDetectLogoGoodEdgeThreshold;
897- double commDetectLogoBadEdgeThreshold;
898
899 bool verboseDebugging;
900
901@@ -146,24 +129,11 @@
902 bool detectSceneChanges;
903 bool detectStationLogo;
904
905- bool skipAllBlanks;
906-
907- EdgeMaskEntry *edgeMask;
908-
909- unsigned char *logoMaxValues;
910- unsigned char *logoMinValues;
911- unsigned char *logoFrame;
912- unsigned char *logoMask;
913- unsigned char *logoCheckMask;
914- unsigned char *tmpBuf;
915 bool logoInfoAvailable;
916- int logoEdgeDiff;
917- int logoFrameCount;
918- int logoMinX;
919- int logoMaxX;
920- int logoMinY;
921- int logoMaxY;
922+ LogoDetectorBase* logoDetector;
923
924+ bool skipAllBlanks;
925+
926 unsigned char *framePtr;
927
928 QMap<long long, FrameInfoEntry> frameInfo;
929Index: programs/mythcommflag/ClassicLogoDetector.cpp
930===================================================================
931--- programs/mythcommflag/ClassicLogoDetector.cpp (revision 0)
932+++ programs/mythcommflag/ClassicLogoDetector.cpp (revision 0)
933@@ -0,0 +1,553 @@
934+#include "ClassicLogoDetector.h"
935+#include "ClassicCommDetector.h"
936+
937+#include "libmythtv/NuppelVideoPlayer.h"
938+#include "libmyth/mythcontext.h" //To be able to use VERBOSE()
939+
940+typedef struct edgemaskentry
941+{
942+ int isedge;
943+ int horiz;
944+ int vert;
945+ int rdiag;
946+ int ldiag;
947+}
948+EdgeMaskEntry;
949+
950+
951+ClassicLogoDetector::ClassicLogoDetector(ClassicCommDetector* commdetector,unsigned int w, unsigned int h, unsigned int commdetectborder_in, unsigned int xspacing_in, unsigned int yspacing_in) :
952+ LogoDetectorBase(w,h),
953+ commDetector(commdetector),
954+ frameNumber(0),
955+ previousFrameWasSceneChange(false),
956+ xspacing(xspacing_in),
957+ yspacing(yspacing_in),
958+ commDetectBorder(commdetectborder_in)
959+{
960+ commDetectLogoSamplesNeeded =
961+ gContext->GetNumSetting("CommDetectLogoSamplesNeeded", 240);
962+ commDetectLogoSampleSpacing =
963+ gContext->GetNumSetting("CommDetectLogoSampleSpacing", 2);
964+ commDetectLogoGoodEdgeThreshold =
965+ gContext->GetSetting("CommDetectLogoGoodEdgeThreshold", "0.75")
966+ .toDouble();
967+ commDetectLogoBadEdgeThreshold =
968+ gContext->GetSetting("CommDetectLogoBadEdgeThreshold", "0.85")
969+ .toDouble();
970+ commDetectLogoSecondsNeeded = commDetectLogoSamplesNeeded *
971+ commDetectLogoSampleSpacing;
972+
973+
974+
975+ edgeMask = new EdgeMaskEntry[width * height];
976+ logoFrame = new unsigned char[width * height];
977+ logoMask = new unsigned char[width * height];
978+ logoCheckMask = new unsigned char[width * height];
979+ logoMaxValues = new unsigned char[width * height];
980+ logoMinValues = new unsigned char[width * height];
981+ tmpBuf = new unsigned char[width * height];
982+
983+ logoFrameCount = 0;
984+}
985+
986+unsigned int ClassicLogoDetector::getRequiredAvailableBufferForSearch()
987+{
988+ return commDetectLogoSecondsNeeded;
989+}
990+
991+ClassicLogoDetector::~ClassicLogoDetector()
992+{
993+ commDetector = 0;
994+ if (edgeMask)
995+ delete [] edgeMask;
996+ if (logoFrame)
997+ delete [] logoFrame;
998+ if (logoMask)
999+ delete [] logoMask;
1000+ if (logoCheckMask)
1001+ delete [] logoCheckMask;
1002+ if (logoMaxValues)
1003+ delete [] logoMaxValues;
1004+ if (logoMinValues)
1005+ delete [] logoMinValues;
1006+ if (tmpBuf)
1007+ delete [] tmpBuf;
1008+}
1009+
1010+bool ClassicLogoDetector::searchForLogo(NuppelVideoPlayer* nvp)
1011+{
1012+ int seekIncrement = (int)(commDetectLogoSampleSpacing * nvp->GetFrameRate());
1013+ long long seekFrame;
1014+ int loops;
1015+ int maxLoops = commDetectLogoSamplesNeeded;
1016+ EdgeMaskEntry *edgeCounts;
1017+ unsigned int pos, i, x, y, dx, dy;
1018+ int edgeDiffs[] = {5, 7, 10, 15, 20, 30, 40, 50, 60, 0 };
1019+
1020+
1021+ VERBOSE(VB_COMMFLAG, "Searching for Station Logo");
1022+
1023+ logoInfoAvailable = false;
1024+
1025+ edgeCounts = new EdgeMaskEntry[width * height];
1026+
1027+ for (i = 0; edgeDiffs[i] != 0 && !logoInfoAvailable; i++)
1028+ {
1029+ int pixelsInMask = 0;
1030+
1031+ VERBOSE(VB_COMMFLAG, QString("Trying with edgeDiff == %1")
1032+ .arg(edgeDiffs[i]));
1033+
1034+ memset(edgeCounts, 0, sizeof(EdgeMaskEntry) * width * height);
1035+ memset(edgeMask, 0, sizeof(EdgeMaskEntry) * width * height);
1036+
1037+ nvp->DiscardVideoFrame(nvp->GetRawVideoFrame(0));
1038+
1039+ loops = 0;
1040+ seekFrame = commDetector->preRoll + seekIncrement;
1041+ while(loops < maxLoops && !nvp->GetEof())
1042+ {
1043+ VideoFrame* vf = nvp->GetRawVideoFrame(seekFrame);
1044+
1045+ if ((loops % 50) == 0)
1046+ commDetector->logoDetectorBreathe();
1047+
1048+ if (commDetector->m_bStop)
1049+ {
1050+ nvp->DiscardVideoFrame(vf);
1051+ return false;
1052+ }
1053+
1054+ if (!commDetector->fullSpeed)
1055+ usleep(10000);
1056+
1057+ DetectEdges(vf, edgeCounts, edgeDiffs[i]);
1058+
1059+ seekFrame += seekIncrement;
1060+ loops++;
1061+
1062+ nvp->DiscardVideoFrame(vf);
1063+ }
1064+
1065+ VERBOSE(VB_COMMFLAG, "Analyzing edge data");
1066+
1067+#ifdef SHOW_DEBUG_WIN
1068+ unsigned char *fakeFrame;
1069+ fakeFrame = new unsigned char[width * height * 3 / 2];
1070+ memset(fakeFrame, 0, width * height * 3 / 2);
1071+#endif
1072+
1073+ for (y = 0; y < height; y++)
1074+ {
1075+ if ((y > (height/4)) && (y < (height * 3 / 4)))
1076+ continue;
1077+
1078+ for (x = 0; x < width; x++)
1079+ {
1080+ if ((x > (width/4)) && (x < (width * 3 / 4)))
1081+ continue;
1082+
1083+ pos = y * width + x;
1084+
1085+ if (edgeCounts[pos].isedge > (maxLoops * 0.66))
1086+ {
1087+ edgeMask[pos].isedge = 1;
1088+ pixelsInMask++;
1089+#ifdef SHOW_DEBUG_WIN
1090+ fakeFrame[pos] = 0xff;
1091+#endif
1092+
1093+ }
1094+
1095+ if (edgeCounts[pos].horiz > (maxLoops * 0.66))
1096+ edgeMask[pos].horiz = 1;
1097+
1098+ if (edgeCounts[pos].vert > (maxLoops * 0.66))
1099+ edgeMask[pos].vert = 1;
1100+
1101+ if (edgeCounts[pos].ldiag > (maxLoops * 0.66))
1102+ edgeMask[pos].ldiag = 1;
1103+ if (edgeCounts[pos].rdiag > (maxLoops * 0.66))
1104+ edgeMask[pos].rdiag = 1;
1105+ }
1106+ }
1107+
1108+ SetLogoMaskArea();
1109+
1110+ for (y = logoMinY; y < logoMaxY; y++)
1111+ {
1112+ for (x = logoMinX; x < logoMaxX; x++)
1113+ {
1114+ int neighbors = 0;
1115+
1116+ if (!edgeMask[y * width + x].isedge)
1117+ continue;
1118+
1119+ for (dy = y - 2; dy <= (y + 2); dy++ )
1120+ {
1121+ for (dx = x - 2; dx <= (x + 2); dx++ )
1122+ {
1123+ if (edgeMask[dy * width + dx].isedge)
1124+ neighbors++;
1125+ }
1126+ }
1127+
1128+ if (neighbors < 5)
1129+ edgeMask[y * width + x].isedge = 0;
1130+ }
1131+ }
1132+
1133+ SetLogoMaskArea();
1134+ VERBOSE(VB_COMMFLAG, QString("Testing Logo area: topleft "
1135+ "(%1,%2), bottomright (%3,%4)")
1136+ .arg(logoMinX).arg(logoMinY)
1137+ .arg(logoMaxX).arg(logoMaxY));
1138+
1139+#ifdef SHOW_DEBUG_WIN
1140+ for (x = logoMinX; x < logoMaxX; x++)
1141+ {
1142+ pos = logoMinY * width + x;
1143+ fakeFrame[pos] = 0x7f;
1144+ pos = logoMaxY * width + x;
1145+ fakeFrame[pos] = 0x7f;
1146+ }
1147+ for (y = logoMinY; y < logoMaxY; y++)
1148+ {
1149+ pos = y * width + logoMinX;
1150+ fakeFrame[pos] = 0x7f;
1151+ pos = y * width + logoMaxX;
1152+ fakeFrame[pos] = 0x7f;
1153+ }
1154+
1155+ comm_debug_show(fakeFrame);
1156+ delete [] fakeFrame;
1157+
1158+ cerr << "Hit ENTER to continue" << endl;
1159+ getchar();
1160+#endif
1161+ if (((logoMaxX - logoMinX) < (width / 4)) &&
1162+ ((logoMaxY - logoMinY) < (height / 4)) &&
1163+ (pixelsInMask > 50))
1164+ {
1165+ logoInfoAvailable = true;
1166+ logoEdgeDiff = edgeDiffs[i];
1167+
1168+ VERBOSE(VB_COMMFLAG, QString("Using Logo area: topleft "
1169+ "(%1,%2), bottomright (%3,%4)")
1170+ .arg(logoMinX).arg(logoMinY)
1171+ .arg(logoMaxX).arg(logoMaxY));
1172+ }
1173+ else
1174+ {
1175+ VERBOSE(VB_COMMFLAG, QString("Rejecting Logo area: topleft "
1176+ "(%1,%2), bottomright (%3,%4), "
1177+ "pixelsInMask (%5). "
1178+ "Not within specified limits.")
1179+ .arg(logoMinX).arg(logoMinY)
1180+ .arg(logoMaxX).arg(logoMaxY)
1181+ .arg(pixelsInMask));
1182+ }
1183+ }
1184+
1185+ delete [] edgeCounts;
1186+
1187+ if (!logoInfoAvailable)
1188+ VERBOSE(VB_COMMFLAG, "No suitable logo area found.");
1189+
1190+ nvp->DiscardVideoFrame(nvp->GetRawVideoFrame(0));
1191+ return logoInfoAvailable;
1192+}
1193+
1194+
1195+void ClassicLogoDetector::SetLogoMaskArea()
1196+{
1197+ VERBOSE(VB_COMMFLAG, "SetLogoMaskArea()");
1198+
1199+ logoMinX = width - 1;
1200+ logoMaxX = 0;
1201+ logoMinY = height - 1;
1202+ logoMaxY = 0;
1203+
1204+ for (unsigned int y = 0; y < height; y++)
1205+ {
1206+ for (unsigned int x = 0; x < width; x++)
1207+ {
1208+ if (edgeMask[y * width + x].isedge)
1209+ {
1210+ if (x < logoMinX)
1211+ logoMinX = x;
1212+ if (y < logoMinY)
1213+ logoMinY = y;
1214+ if (x > logoMaxX)
1215+ logoMaxX = x;
1216+ if (y > logoMaxY)
1217+ logoMaxY = y;
1218+ }
1219+ }
1220+ }
1221+
1222+ logoMinX -= 5;
1223+ logoMaxX += 5;
1224+ logoMinY -= 5;
1225+ logoMaxY += 5;
1226+
1227+ if (logoMinX < 4)
1228+ logoMinX = 4;
1229+ if (logoMaxX > (width-5))
1230+ logoMaxX = (width-5);
1231+ if (logoMinY < 4)
1232+ logoMinY = 4;
1233+ if (logoMaxY > (height-5))
1234+ logoMaxY = (height-5);
1235+}
1236+
1237+void ClassicLogoDetector::SetLogoMask(unsigned char *mask)
1238+{
1239+ int pixels = 0;
1240+
1241+ memcpy(logoMask, mask, width * height);
1242+
1243+ SetLogoMaskArea();
1244+
1245+ for(unsigned int y = logoMinY; y <= logoMaxY; y++)
1246+ for(unsigned int x = logoMinX; x <= logoMaxX; x++)
1247+ if (!logoMask[y * width + x] == 1)
1248+ pixels++;
1249+
1250+ if (pixels < 30)
1251+ return;
1252+
1253+ // set the pixels around our logo
1254+ for(unsigned int y = (logoMinY - 1); y <= (logoMaxY + 1); y++)
1255+ {
1256+ for(unsigned int x = (logoMinX - 1); x <= (logoMaxX + 1); x++)
1257+ {
1258+ if (!logoMask[y * width + x])
1259+ {
1260+ for (unsigned int y2 = y - 1; y2 <= (y + 1); y2++)
1261+ {
1262+ for (unsigned int x2 = x - 1; x2 <= (x + 1); x2++)
1263+ {
1264+ if ((logoMask[y2 * width + x2] == 1) &&
1265+ (!logoMask[y * width + x]))
1266+ {
1267+ logoMask[y * width + x] = 2;
1268+ x2 = x + 2;
1269+ y2 = y + 2;
1270+
1271+ logoCheckMask[y2 * width + x2] = 1;
1272+ logoCheckMask[y * width + x] = 1;
1273+ }
1274+ }
1275+ }
1276+ }
1277+ }
1278+ }
1279+ for(unsigned int y = (logoMinY - 2); y <= (logoMaxY + 2); y++)
1280+ {
1281+ for(unsigned int x = (logoMinX - 2); x <= (logoMaxX + 2); x++)
1282+ {
1283+ if (!logoMask[y * width + x])
1284+ {
1285+ for (unsigned int y2 = y - 1; y2 <= (y + 1); y2++)
1286+ {
1287+ for (unsigned int x2 = x - 1; x2 <= (x + 1); x2++)
1288+ {
1289+ if ((logoMask[y2 * width + x2] == 2) &&
1290+ (!logoMask[y * width + x]))
1291+ {
1292+ logoMask[y * width + x] = 3;
1293+ x2 = x + 2;
1294+ y2 = y + 2;
1295+
1296+ logoCheckMask[y * width + x] = 1;
1297+ }
1298+ }
1299+ }
1300+ }
1301+ }
1302+ }
1303+
1304+#ifdef SHOW_DEBUG_WIN
1305+ DumpLogo(true,framePtr);
1306+#endif
1307+
1308+ logoFrameCount = 0;
1309+ logoInfoAvailable = true;
1310+}
1311+
1312+
1313+void ClassicLogoDetector::DumpLogo(bool fromCurrentFrame, unsigned char* framePtr)
1314+{
1315+ char scrPixels[] = " .oxX";
1316+
1317+ if (!logoInfoAvailable)
1318+ return;
1319+
1320+ cerr << "\nLogo Data ";
1321+ if (fromCurrentFrame)
1322+ cerr << "from current frame\n";
1323+
1324+ cerr << "\n ";
1325+
1326+ for(unsigned int x = logoMinX - 2; x <= (logoMaxX + 2); x++)
1327+ cerr << (x % 10);
1328+ cerr << "\n";
1329+
1330+ for(unsigned int y = logoMinY - 2; y <= (logoMaxY + 2); y++)
1331+ {
1332+ cerr << QString::number(y).rightJustify(3, ' ') << ": ";
1333+ for(unsigned int x = logoMinX - 2; x <= (logoMaxX + 2); x++)
1334+ {
1335+ if (fromCurrentFrame)
1336+ {
1337+ cerr << scrPixels[framePtr[y * width + x] / 50];
1338+ }
1339+ else
1340+ {
1341+ switch (logoMask[y * width + x])
1342+ {
1343+ case 0:
1344+ case 2: cerr << " ";
1345+ break;
1346+ case 1: cerr << "*";
1347+ break;
1348+ case 3: cerr << ".";
1349+ break;
1350+ }
1351+ }
1352+ }
1353+ cerr << "\n";
1354+ }
1355+ cerr.flush();
1356+}
1357+
1358+
1359+/* ideas for this method ported back from comskip.c mods by Jere Jones
1360+ * which are partially mods based on Myth's original commercial skip
1361+ * code written by Chris Pinkham. */
1362+bool ClassicLogoDetector::doesThisFrameContainTheFoundLogo(unsigned char* framePtr)
1363+{
1364+ int radius = 2;
1365+ unsigned int x, y;
1366+ int pos1, pos2, pos3;
1367+ int pixel;
1368+ int goodEdges = 0;
1369+ int badEdges = 0;
1370+ int testEdges = 0;
1371+ int testNotEdges = 0;
1372+
1373+ for (y = logoMinY; y <= logoMaxY; y++ )
1374+ {
1375+ for (x = logoMinX; x <= logoMaxX; x++ )
1376+ {
1377+ pos1 = y * width + x;
1378+ pos2 = (y - radius) * width + x;
1379+ pos3 = (y + radius) * width + x;
1380+
1381+ pixel = framePtr[pos1];
1382+
1383+ if (edgeMask[pos1].horiz)
1384+ {
1385+ if ((abs(framePtr[pos1 - radius] - pixel) >= logoEdgeDiff) ||
1386+ (abs(framePtr[pos1 + radius] - pixel) >= logoEdgeDiff))
1387+ goodEdges++;
1388+ testEdges++;
1389+ }
1390+ else
1391+ {
1392+ if ((abs(framePtr[pos1 - radius] - pixel) >= logoEdgeDiff) ||
1393+ (abs(framePtr[pos1 + radius] - pixel) >= logoEdgeDiff))
1394+ badEdges++;
1395+ testNotEdges++;
1396+ }
1397+
1398+ if (edgeMask[pos1].vert)
1399+ {
1400+ if ((abs(framePtr[pos2] - pixel) >= logoEdgeDiff) ||
1401+ (abs(framePtr[pos3] - pixel) >= logoEdgeDiff))
1402+ goodEdges++;
1403+ testEdges++;
1404+ }
1405+ else
1406+ {
1407+ if ((abs(framePtr[pos2] - pixel) >= logoEdgeDiff) ||
1408+ (abs(framePtr[pos3] - pixel) >= logoEdgeDiff))
1409+ badEdges++;
1410+ testNotEdges++;
1411+ }
1412+ }
1413+ }
1414+
1415+ frameNumber++;
1416+ double goodEdgeRatio = (double)goodEdges / (double)testEdges;
1417+ double badEdgeRatio = (double)badEdges / (double)testNotEdges;
1418+ if ((goodEdgeRatio > commDetectLogoGoodEdgeThreshold) &&
1419+ (badEdgeRatio < commDetectLogoBadEdgeThreshold))
1420+ return true;
1421+ else
1422+ return false;
1423+}
1424+
1425+bool ClassicLogoDetector::pixelInsideLogo(unsigned int x, unsigned int y)
1426+{
1427+ if (!logoInfoAvailable) return false;
1428+ return ((x > logoMinX) && (x < logoMaxX) && (y > logoMinY) && (y < logoMaxY));
1429+}
1430+
1431+void ClassicLogoDetector::DetectEdges(VideoFrame *frame, EdgeMaskEntry *edges,
1432+ int edgeDiff)
1433+{
1434+ int r = 2;
1435+ unsigned char *buf = frame->buf;
1436+ unsigned char p;
1437+ unsigned int pos, x, y;
1438+
1439+ for (y = commDetectBorder + r; y < (height - commDetectBorder - r); y++)
1440+ {
1441+ if ((y > (height/4)) && (y < (height * 3 / 4)))
1442+ continue;
1443+
1444+ for (x = commDetectBorder + r; x < (width - commDetectBorder - r); x++)
1445+ {
1446+ int edgeCount = 0;
1447+
1448+ if ((x > (width/4)) && (x < (width * 3 / 4)))
1449+ continue;
1450+
1451+ pos = y * width + x;
1452+ p = buf[pos];
1453+
1454+ if (( abs(buf[y * width + (x - r)] - p) >= edgeDiff) ||
1455+ ( abs(buf[y * width + (x + r)] - p) >= edgeDiff))
1456+ {
1457+ edges[pos].horiz++;
1458+ edgeCount++;
1459+ }
1460+ if (( abs(buf[(y - r) * width + x] - p) >= edgeDiff) ||
1461+ ( abs(buf[(y + r) * width + x] - p) >= edgeDiff))
1462+ {
1463+ edges[pos].vert++;
1464+ edgeCount++;
1465+ }
1466+
1467+ if (( abs(buf[(y - r) * width + (x - r)] - p) >= edgeDiff) ||
1468+ ( abs(buf[(y + r) * width + (x + r)] - p) >= edgeDiff))
1469+ {
1470+ edges[pos].ldiag++;
1471+ edgeCount++;
1472+ }
1473+
1474+ if (( abs(buf[(y - r) * width + (x + r)] - p) >= edgeDiff) ||
1475+ ( abs(buf[(y + r) * width + (x - r)] - p) >= edgeDiff))
1476+ {
1477+ edges[pos].rdiag++;
1478+ edgeCount++;
1479+ }
1480+
1481+ if (edgeCount >= 3)
1482+ edges[pos].isedge++;
1483+ }
1484+ }
1485+}
1486+