00001
00002
00003
00004 #include "DetectLetterbox.h"
00005 #include "mythplayer.h"
00006 #include "videoouttypes.h"
00007 #include "mythcorecontext.h"
00008
00009 DetectLetterbox::DetectLetterbox(MythPlayer* const player)
00010 {
00011 int dbAdjustFill = gCoreContext->GetNumSetting("AdjustFill", 0);
00012 isDetectLetterbox = dbAdjustFill >= kAdjustFill_AutoDetect_DefaultOff;
00013 firstFrameChecked = 0;
00014 detectLetterboxDefaultMode = (AdjustFillMode) max((int) kAdjustFill_Off,
00015 dbAdjustFill - kAdjustFill_AutoDetect_DefaultOff);
00016 detectLetterboxSwitchFrame = -1;
00017 detectLetterboxPossibleHalfFrame = -1;
00018 detectLetterboxPossibleFullFrame = -1;
00019 detectLetterboxConsecutiveCounter = 0;
00020 detectLetterboxDetectedMode = player->GetAdjustFill();
00021 detectLetterboxLimit = gCoreContext->GetNumSetting("DetectLeterboxLimit", 75);
00022 m_player = player;
00023 }
00024
00025 DetectLetterbox::~DetectLetterbox()
00026 {
00027 }
00028
00035 void DetectLetterbox::Detect(VideoFrame *frame)
00036 {
00037 unsigned char *buf = frame->buf;
00038 int *pitches = frame->pitches;
00039 int *offsets = frame->offsets;
00040 const int width = frame->width;
00041 const int height = frame->height;
00042 const long long frameNumber = frame->frameNumber;
00043 const int NUMBER_OF_DETECTION_LINES = 3;
00044 const int THRESHOLD = 5;
00045 const int HORIZONTAL_THRESHOLD = 4;
00046
00047
00048
00049
00050
00051 const int fullLimit = (int) ((height * (1 - m_player->GetVideoAspect() * 9 / 16) / 2) * detectLetterboxLimit / 100);
00052 const int halfLimit = (int) ((height * (1 - m_player->GetVideoAspect() * 9 / 14) / 2) * detectLetterboxLimit / 100);
00053
00054 const int xPos[] = {width / 4, width / 2, width * 3 / 4};
00055 int topHits = 0, bottomHits = 0, minTop = 0, minBottom = 0, maxTop = 0, maxBottom = 0;
00056 int topHit[] = {0, 0, 0}, bottomHit[] = {0, 0, 0};
00057
00058 if (!GetDetectLetterbox())
00059 return;
00060
00061 if (!m_player->GetVideoOutput())
00062 return;
00063
00064 switch (frame->codec) {
00065 case FMT_YV12:
00066 if (!firstFrameChecked)
00067 {
00068 firstFrameChecked = frameNumber;
00069 LOG(VB_PLAYBACK, LOG_INFO,
00070 QString("Detect Letterbox: YV12 frame format detected"));
00071 }
00072 break;
00073 default:
00074 LOG(VB_PLAYBACK, LOG_INFO,
00075 QString("Detect Letterbox: The source is not "
00076 "a supported frame format (was %1)").arg(frame->codec));
00077 isDetectLetterbox = false;
00078 return;
00079 }
00080
00081 if (frameNumber < 0)
00082 {
00083 LOG(VB_PLAYBACK, LOG_INFO,
00084 QString("Detect Letterbox: Strange frame number %1")
00085 .arg(frameNumber));
00086 return;
00087 }
00088
00089 if (m_player->GetVideoAspect() > 1.5)
00090 {
00091 if (detectLetterboxDetectedMode != detectLetterboxDefaultMode)
00092 {
00093 LOG(VB_PLAYBACK, LOG_INFO,
00094 QString("Detect Letterbox: The source is "
00095 "already in widescreen (aspect: %1)")
00096 .arg(m_player->GetVideoAspect()));
00097 detectLetterboxLock.lock();
00098 detectLetterboxConsecutiveCounter = 0;
00099 detectLetterboxDetectedMode = detectLetterboxDefaultMode;
00100 detectLetterboxSwitchFrame = frameNumber;
00101 detectLetterboxLock.unlock();
00102 }
00103 else
00104 {
00105 detectLetterboxConsecutiveCounter++;
00106 }
00107 LOG(VB_PLAYBACK, LOG_INFO,
00108 QString("Detect Letterbox: The source is already "
00109 "in widescreen (aspect: %1)")
00110 .arg(m_player->GetVideoAspect()));
00111 isDetectLetterbox = false;
00112 return;
00113 }
00114
00115
00116 int averageY = 0;
00117 for (int detectionLine = 0;
00118 detectionLine < NUMBER_OF_DETECTION_LINES;
00119 detectionLine++)
00120 {
00121 averageY += buf[offsets[0] + 5 * pitches[0] + xPos[detectionLine]];
00122 averageY += buf[offsets[0] + (height - 6) * pitches[0] + xPos[detectionLine]];
00123 }
00124 averageY /= NUMBER_OF_DETECTION_LINES * 2;
00125 if (averageY > 64)
00126 averageY = 0;
00127
00128
00129 for (int y = 5; y < height / 4; y++)
00130 {
00131 for (int detectionLine = 0;
00132 detectionLine < NUMBER_OF_DETECTION_LINES;
00133 detectionLine++)
00134 {
00135 int Y = buf[offsets[0] + y * pitches[0] + xPos[detectionLine]];
00136 int U = buf[offsets[1] + (y>>1) * pitches[1] + (xPos[detectionLine]>>1)];
00137 int V = buf[offsets[2] + (y>>1) * pitches[2] + (xPos[detectionLine]>>1)];
00138 if ((!topHit[detectionLine]) &&
00139 ( Y > averageY + THRESHOLD || Y < averageY - THRESHOLD ||
00140 U < 128 - 32 || U > 128 + 32 ||
00141 V < 128 - 32 || V > 128 + 32 ))
00142 {
00143 topHit[detectionLine] = y;
00144 topHits++;
00145 if (!minTop)
00146 minTop = y;
00147 maxTop = y;
00148 }
00149
00150 Y = buf[offsets[0] + (height-y-1 ) * pitches[0] + xPos[detectionLine]];
00151 U = buf[offsets[1] + ((height-y-1) >> 1) * pitches[1] + (xPos[detectionLine]>>1)];
00152 V = buf[offsets[2] + ((height-y-1) >> 1) * pitches[2] + (xPos[detectionLine]>>1)];
00153 if ((!bottomHit[detectionLine]) &&
00154 ( Y > averageY + THRESHOLD || Y < averageY - THRESHOLD ||
00155 U < 128 - 32 || U > 128 + 32 ||
00156 V < 128 - 32 || V > 128 + 32 ))
00157 {
00158 bottomHit[detectionLine] = y;
00159 bottomHits++;
00160 if (!minBottom)
00161 minBottom = y;
00162 maxBottom = y;
00163 }
00164 }
00165
00166 if (topHits == NUMBER_OF_DETECTION_LINES &&
00167 bottomHits == NUMBER_OF_DETECTION_LINES)
00168 {
00169 break;
00170 }
00171 }
00172 if (topHits != NUMBER_OF_DETECTION_LINES) maxTop = height / 4;
00173 if (!minTop) minTop = height / 4;
00174 if (bottomHits != NUMBER_OF_DETECTION_LINES) maxBottom = height / 4;
00175 if (!minBottom) minBottom = height / 4;
00176
00177 bool horizontal = ((minTop && maxTop - minTop < HORIZONTAL_THRESHOLD) &&
00178 (minBottom && maxBottom - minBottom < HORIZONTAL_THRESHOLD));
00179
00180 if (detectLetterboxSwitchFrame > frameNumber)
00181 {
00182 detectLetterboxLock.lock();
00183 detectLetterboxDetectedMode = m_player->GetAdjustFill();
00184 detectLetterboxSwitchFrame = -1;
00185 detectLetterboxPossibleHalfFrame = -1;
00186 detectLetterboxPossibleFullFrame = -1;
00187 detectLetterboxLock.unlock();
00188 }
00189
00190 if (minTop < halfLimit || minBottom < halfLimit)
00191 detectLetterboxPossibleHalfFrame = -1;
00192 if (minTop < fullLimit || minBottom < fullLimit)
00193 detectLetterboxPossibleFullFrame = -1;
00194
00195 if (detectLetterboxDetectedMode != kAdjustFill_Full)
00196 {
00197 if (detectLetterboxPossibleHalfFrame == -1 &&
00198 minTop > halfLimit && minBottom > halfLimit) {
00199 detectLetterboxPossibleHalfFrame = frameNumber;
00200 }
00201 }
00202 else
00203 {
00204 if (detectLetterboxPossibleHalfFrame == -1 &&
00205 minTop < fullLimit && minBottom < fullLimit) {
00206 detectLetterboxPossibleHalfFrame = frameNumber;
00207 }
00208 }
00209 if (detectLetterboxPossibleFullFrame == -1 &&
00210 minTop > fullLimit && minBottom > fullLimit)
00211 detectLetterboxPossibleFullFrame = frameNumber;
00212
00213 if ( maxTop < halfLimit || maxBottom < halfLimit)
00214 {
00215
00216 if (detectLetterboxDetectedMode != detectLetterboxDefaultMode)
00217 {
00218 LOG(VB_PLAYBACK, LOG_INFO,
00219 QString("Detect Letterbox: Non Letterbox "
00220 "detected on line: %1 (limit: %2)")
00221 .arg(min(maxTop, maxBottom)).arg(halfLimit));
00222 detectLetterboxLock.lock();
00223 detectLetterboxConsecutiveCounter = 0;
00224 detectLetterboxDetectedMode = detectLetterboxDefaultMode;
00225 detectLetterboxSwitchFrame = frameNumber;
00226 detectLetterboxLock.unlock();
00227 }
00228 else
00229 {
00230 detectLetterboxConsecutiveCounter++;
00231 }
00232 }
00233 else if (horizontal && minTop > halfLimit && minBottom > halfLimit &&
00234 maxTop < fullLimit && maxBottom < fullLimit)
00235 {
00236
00237 if (detectLetterboxDetectedMode != kAdjustFill_Half)
00238 {
00239 LOG(VB_PLAYBACK, LOG_INFO,
00240 QString("Detect Letterbox: Narrow Letterbox "
00241 "detected on line: %1 (limit: %2) frame: %3")
00242 .arg(minTop).arg(halfLimit)
00243 .arg(detectLetterboxPossibleHalfFrame));
00244 detectLetterboxLock.lock();
00245 detectLetterboxConsecutiveCounter = 0;
00246 if (detectLetterboxDetectedMode == kAdjustFill_Full &&
00247 detectLetterboxSwitchFrame != -1) {
00248
00249 }
00250 else
00251 detectLetterboxSwitchFrame = detectLetterboxPossibleHalfFrame;
00252 detectLetterboxDetectedMode = kAdjustFill_Half;
00253 detectLetterboxLock.unlock();
00254 }
00255 else
00256 {
00257 detectLetterboxConsecutiveCounter++;
00258 }
00259 }
00260 else if (horizontal && minTop > fullLimit && minBottom > fullLimit)
00261 {
00262
00263 detectLetterboxPossibleHalfFrame = -1;
00264 if (detectLetterboxDetectedMode != kAdjustFill_Full)
00265 {
00266 LOG(VB_PLAYBACK, LOG_INFO,
00267 QString("Detect Letterbox: Detected Letterbox "
00268 "on line: %1 (limit: %2) frame: %3").arg(minTop)
00269 .arg(fullLimit).arg(detectLetterboxPossibleFullFrame));
00270 detectLetterboxLock.lock();
00271 detectLetterboxConsecutiveCounter = 0;
00272 detectLetterboxDetectedMode = kAdjustFill_Full;
00273 detectLetterboxSwitchFrame = detectLetterboxPossibleFullFrame;
00274 detectLetterboxLock.unlock();
00275 }
00276 else
00277 {
00278 detectLetterboxConsecutiveCounter++;
00279 }
00280 }
00281 else
00282 {
00283 if (detectLetterboxConsecutiveCounter <= 3)
00284 detectLetterboxConsecutiveCounter = 0;
00285 }
00286 }
00287
00293 void DetectLetterbox::SwitchTo(VideoFrame *frame)
00294 {
00295 if (!GetDetectLetterbox())
00296 return;
00297
00298 if (detectLetterboxSwitchFrame == -1)
00299 return;
00300
00301 detectLetterboxLock.lock();
00302 if (detectLetterboxSwitchFrame <= frame->frameNumber &&
00303 detectLetterboxConsecutiveCounter > 3)
00304 {
00305 if (m_player->GetAdjustFill() != detectLetterboxDetectedMode)
00306 {
00307 LOG(VB_PLAYBACK, LOG_INFO,
00308 QString("Detect Letterbox: Switched to %1 "
00309 "on frame %2 (%3)").arg(detectLetterboxDetectedMode)
00310 .arg(frame->frameNumber)
00311 .arg(detectLetterboxSwitchFrame));
00312 m_player->GetVideoOutput()->
00313 ToggleAdjustFill(detectLetterboxDetectedMode);
00314 m_player->ReinitOSD();
00315 }
00316 detectLetterboxSwitchFrame = -1;
00317 }
00318 else if (detectLetterboxSwitchFrame <= frame->frameNumber)
00319 LOG(VB_PLAYBACK, LOG_INFO,
00320 QString("Detect Letterbox: Not Switched to %1 on frame %2 "
00321 "(%3) Not enough consecutive detections (%4)")
00322 .arg(detectLetterboxDetectedMode)
00323 .arg(frame->frameNumber).arg(detectLetterboxSwitchFrame)
00324 .arg(detectLetterboxConsecutiveCounter));
00325
00326 detectLetterboxLock.unlock();
00327 }
00328
00329 void DetectLetterbox::SetDetectLetterbox(bool detect)
00330 {
00331 isDetectLetterbox = detect;
00332 detectLetterboxSwitchFrame = -1;
00333 detectLetterboxDetectedMode = m_player->GetAdjustFill();
00334 firstFrameChecked = 0;
00335 }
00336
00337 bool DetectLetterbox::GetDetectLetterbox() const
00338 {
00339 return isDetectLetterbox;
00340 }
00341
00342