|
MythTV
0.26-pre
|
00001 // ANSI C headers 00002 #include <cstdlib> 00003 #include <cmath> 00004 00005 // MythTV headers 00006 #include "mythcorecontext.h" /* gContext */ 00007 #include "mythplayer.h" 00008 #include "mythlogging.h" 00009 00010 // Commercial Flagging headers 00011 #include "CommDetector2.h" 00012 #include "FrameAnalyzer.h" 00013 #include "quickselect.h" 00014 #include "HistogramAnalyzer.h" 00015 #include "SceneChangeDetector.h" 00016 00017 using namespace commDetector2; 00018 using namespace frameAnalyzer; 00019 00020 namespace { 00021 00022 int 00023 scenechange_data_sort_desc_frequency(const void *aa, const void *bb) 00024 { 00025 /* Descending by frequency, then ascending by color. */ 00026 const struct SceneChangeDetector::scenechange_data *sc1 = 00027 (const struct SceneChangeDetector::scenechange_data*)aa; 00028 const struct SceneChangeDetector::scenechange_data *sc2 = 00029 (const struct SceneChangeDetector::scenechange_data*)bb; 00030 int freqdiff = sc2->frequency - sc1->frequency; 00031 return freqdiff ? freqdiff : sc1->color - sc2->color; 00032 } 00033 00034 void 00035 scenechange_data_init(SceneChangeDetector::SceneChangeData *scdata, 00036 const HistogramAnalyzer::Histogram *hh) 00037 { 00038 unsigned int ncolors = sizeof(*hh)/sizeof((*hh)[0]); 00039 00040 for (unsigned int ii = 0; ii < ncolors; ii++) 00041 { 00042 (*scdata)[ii].color = ii; 00043 (*scdata)[ii].frequency = (*hh)[ii]; 00044 } 00045 qsort(*scdata, sizeof(*scdata)/sizeof((*scdata)[0]), sizeof((*scdata)[0]), 00046 scenechange_data_sort_desc_frequency); 00047 } 00048 00049 unsigned short 00050 scenechange_data_diff(const SceneChangeDetector::SceneChangeData *sc1, 00051 const SceneChangeDetector::SceneChangeData *sc2) 00052 { 00053 /* 00054 * Compute a notion of "difference" that takes into account the difference 00055 * in relative frequencies of the dominant colors. 00056 */ 00057 unsigned short diff = 0; 00058 for (unsigned int ii = 0; ii < sizeof(*sc1)/sizeof((*sc1)[0]); ii++) 00059 diff += abs((*sc1)[ii].frequency - (*sc2)[ii].frequency) + 00060 abs((*sc1)[ii].color - (*sc2)[ii].color); 00061 return diff; 00062 } 00063 00064 bool 00065 writeData(QString filename, const unsigned short *scdiff, long long nframes) 00066 { 00067 FILE *fp; 00068 long long frameno; 00069 00070 QByteArray fname = filename.toLocal8Bit(); 00071 if (!(fp = fopen(fname.constData(), "w"))) 00072 return false; 00073 for (frameno = 0; frameno < nframes; frameno++) 00074 (void)fprintf(fp, "%5u\n", scdiff[frameno]); 00075 if (fclose(fp)) 00076 LOG(VB_COMMFLAG, LOG_ERR, QString("Error closing %1: %2") 00077 .arg(filename).arg(strerror(errno))); 00078 return true; 00079 } 00080 00081 void 00082 computeChangeMap(FrameAnalyzer::FrameMap *changeMap, long long nframes, 00083 const unsigned short *scdiff, unsigned short mindiff) 00084 { 00085 /* 00086 * Look for sudden changes in histogram. 00087 */ 00088 long long frameno; 00089 00090 changeMap->clear(); 00091 for (frameno = 0; frameno < nframes; frameno++) 00092 { 00093 if (scdiff[frameno] > mindiff) 00094 changeMap->insert(frameno, 0); 00095 } 00096 } 00097 00098 }; /* namespace */ 00099 00100 SceneChangeDetector::SceneChangeDetector(HistogramAnalyzer *ha, 00101 QString debugdir) 00102 : FrameAnalyzer() 00103 , histogramAnalyzer(ha) 00104 , fps(0.0f) 00105 , scdata(NULL) 00106 , scdiff(NULL) 00107 , debugLevel(0) 00108 , debugdata(debugdir + "/SceneChangeDetector.txt") 00109 , debug_scenechange(false) 00110 , scenechange_done(false) 00111 { 00112 LOG(VB_COMMFLAG, LOG_INFO, "SceneChangeDetector"); 00113 00114 /* 00115 * debugLevel: 00116 * 0: no debugging 00117 * 2: extra verbosity [O(nframes)] 00118 */ 00119 debugLevel = gCoreContext->GetNumSetting("SceneChangeDetectorDebugLevel", 0); 00120 00121 if (debugLevel >= 1) 00122 { 00123 createDebugDirectory(debugdir, 00124 QString("SceneChangeDetector debugLevel %1").arg(debugLevel)); 00125 debug_scenechange = true; 00126 } 00127 } 00128 00129 void SceneChangeDetector::deleteLater(void) 00130 { 00131 if (scdata) 00132 delete []scdata; 00133 if (scdiff) 00134 delete []scdiff; 00135 } 00136 00137 enum FrameAnalyzer::analyzeFrameResult 00138 SceneChangeDetector::MythPlayerInited(MythPlayer *player, 00139 long long nframes) 00140 { 00141 FrameAnalyzer::analyzeFrameResult ares = 00142 histogramAnalyzer->MythPlayerInited(player, nframes); 00143 00144 fps = player->GetFrameRate(); 00145 00146 scdata = new SceneChangeData[nframes]; 00147 memset(scdata, 0, nframes * sizeof(*scdata)); 00148 00149 scdiff = new unsigned short[nframes]; 00150 memset(scdiff, 0, nframes * sizeof(*scdiff)); 00151 00152 QSize video_disp_dim = player->GetVideoSize(); 00153 00154 LOG(VB_COMMFLAG, LOG_INFO, 00155 QString("SceneChangeDetector::MythPlayerInited %1x%2") 00156 .arg(video_disp_dim.width()) 00157 .arg(video_disp_dim.height())); 00158 00159 return ares; 00160 } 00161 00162 enum FrameAnalyzer::analyzeFrameResult 00163 SceneChangeDetector::analyzeFrame(const VideoFrame *frame, long long frameno, 00164 long long *pNextFrame) 00165 { 00166 *pNextFrame = NEXTFRAME; 00167 00168 if (histogramAnalyzer->analyzeFrame(frame, frameno) == 00169 FrameAnalyzer::ANALYZE_OK) 00170 return ANALYZE_OK; 00171 00172 LOG(VB_COMMFLAG, LOG_ERR, 00173 QString("SceneChangeDetector::analyzeFrame error at frame %1") 00174 .arg(frameno)); 00175 return ANALYZE_ERROR; 00176 } 00177 00178 int 00179 SceneChangeDetector::finished(long long nframes, bool final) 00180 { 00181 if (histogramAnalyzer->finished(nframes, final)) 00182 return -1; 00183 00184 LOG(VB_COMMFLAG, LOG_INFO, QString("SceneChangeDetector::finished(%1)") 00185 .arg(nframes)); 00186 00187 const HistogramAnalyzer::Histogram *histogram = 00188 histogramAnalyzer->getHistograms(); 00189 for (unsigned int frameno = 0; frameno < nframes; frameno++) 00190 (void)scenechange_data_init(&scdata[frameno], &histogram[frameno]); 00191 scdiff[0] = 0; 00192 for (unsigned int frameno = 1; frameno < nframes; frameno++) 00193 scdiff[frameno] = scenechange_data_diff(&scdata[frameno - 1], 00194 &scdata[frameno]); 00195 00196 if (!scenechange_done && debug_scenechange) 00197 { 00198 if (final && writeData(debugdata, scdiff, nframes)) 00199 { 00200 LOG(VB_COMMFLAG, LOG_INFO, 00201 QString("SceneChangeDetector::finished wrote %1") 00202 .arg(debugdata)); 00203 scenechange_done = true; 00204 } 00205 } 00206 00207 /* Identify all scene-change frames (changeMap). */ 00208 unsigned short *scdiffsort = new unsigned short[nframes]; 00209 memcpy(scdiffsort, scdiff, nframes * sizeof(*scdiff)); 00210 unsigned short mindiff = quick_select_ushort(scdiffsort, nframes, 00211 (int)(0.979472 * nframes)); 00212 LOG(VB_COMMFLAG, LOG_INFO, 00213 QString("SceneChangeDetector::finished applying threshold value %1") 00214 .arg(mindiff)); 00215 computeChangeMap(&changeMap, nframes, scdiff, mindiff); 00216 delete []scdiffsort; 00217 if (debugLevel >= 2) 00218 frameAnalyzerReportMapms(&changeMap, fps, "SC frame"); 00219 00220 return 0; 00221 } 00222 00223 int 00224 SceneChangeDetector::reportTime(void) const 00225 { 00226 return histogramAnalyzer->reportTime(); 00227 } 00228 00229 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1.7.6.1