Ticket #4872: detectLetterboxV5.patch

File detectLetterboxV5.patch, 15.5 KB (added by Mårten <mabo@…>, 16 years ago)

Patch to autodetect letterbox for release-0-21-fixes rev :16402

  • libs/libmythtv/NuppelVideoPlayer.cpp

     
    289289    text_size = 8 * (sizeof(teletextsubtitle) + VT_WIDTH);
    290290    for (int i = 0; i < MAXTBUFFER; i++)
    291291        txtbuffers[i].buffer = new unsigned char[text_size + 1];
     292   
     293    int dbAdjustFill = gContext->GetNumSetting("AdjustFill", 0);
     294    isDetectLetterbox = dbAdjustFill >= kAdjustFill_AutoDetect_DefaultOff;
     295    isDetectLetterboxDebugging = false;
     296    detectLetterboxDefaultMode = (AdjustFillMode) max((int) kAdjustFill_Off,
     297                                                      dbAdjustFill - kAdjustFill_AutoDetect_DefaultOff);
     298    detectLetterboxCounterOff = 0;
     299    detectLetterboxCounterHalf = 0;
     300    detectLetterboxCounterFull = 0;
     301    detectLetterboxLimit = gContext->GetNumSetting("DetectLeterboxLimit", 60);
    292302}
    293303
    294304NuppelVideoPlayer::~NuppelVideoPlayer(void)
     
    26052615    return true;
    26062616}
    26072617
     2618// Debug method for DetectLetterbox
     2619// RED:    76, 109, 207
     2620// GREEN: 150,  91,  62
     2621void draw(VideoFrame *frame,int x, int y, unsigned char Y, unsigned char U, unsigned char V) {
     2622    unsigned char *buf = frame->buf;
     2623    int *pitches = frame->pitches; // Y, U, & V pitches
     2624    int *offsets = frame->offsets; // Y, U, & V offsets
     2625
     2626    buf[offsets[0] +  y     * pitches[0] +  x]     = Y;
     2627    buf[offsets[1] + (y>>1) * pitches[1] + (x>>1)] = U;
     2628    buf[offsets[2] + (y>>1) * pitches[2] + (x>>1)] = V;
     2629}
     2630
     2631void NuppelVideoPlayer::DetectLetterbox(VideoFrame *frame)   
     2632{
     2633
     2634    unsigned char *buf = frame->buf;
     2635    int width = frame->width;
     2636    int height = frame->height;
     2637    int pitch = frame->pitches[0];
     2638    int offset = frame->offsets[0];
     2639
     2640   
     2641    const int THRESHOLD = 5; // Y component has to not vary more than this in the bars
     2642    const int SWITCH_DELAY = 3; // How many frames of posetive detection to wait before switching
     2643    const int HORIZONTAL_THRESHOLD = 4; // How tolerant are we that the image has horizontal edges
     2644    const int NUMBER_OF_DETECTION_LINES = 3; // How many lines are we looking at
     2645
     2646    // If the black bars is larger than this limit we switch to Half or Full Mode
     2647    const int fullLimit = (int) (((height - width * 9 / 16) / 2) * detectLetterboxLimit / 100);
     2648    const int halfLimit = (int) (((height - width * 9 / 14) / 2) * detectLetterboxLimit / 100);
     2649
     2650    int xPos[] = {width / 4, width / 2, width * 3 / 4};    // Lines to scan for black letterbox edge
     2651    int topHits = 0, bottomHits = 0, minTop = 0, minBottom = 0, maxTop = 0, maxBottom = 0;
     2652    int topHit[] = {0, 0, 0}, bottomHit[] = {0, 0, 0};
     2653
     2654    int x,y;
     2655    int sourceAspect = width * 10 / height;
     2656
     2657
     2658
     2659    if (!isDetectLetterbox)
     2660        return;   
     2661    if (!videoOutput)
     2662        return;
     2663
     2664   
     2665    if (frame->codec != FMT_YV12)
     2666    {
     2667        VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: The source is not in YV12"));
     2668        return;
     2669    }
     2670
     2671    if (sourceAspect > 15)
     2672    {
     2673        VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: The source is already in widescreen"));
     2674        return;
     2675    }
     2676
     2677    // Establish the level of light in the edge
     2678    long averageY = 0;
     2679    for (int detectionLine = 0; detectionLine < NUMBER_OF_DETECTION_LINES; detectionLine++)
     2680    {
     2681        averageY += buf[offset + 5 * pitch            + xPos[detectionLine]];
     2682        averageY += buf[offset + (height - 6) * pitch + xPos[detectionLine]];
     2683    }
     2684    averageY /= NUMBER_OF_DETECTION_LINES * 2;
     2685    if (averageY > 64)
     2686        averageY = 0; // To bright setting to zero
     2687
     2688    // Scan the detection lines
     2689    for (y = 5; y < height / 4; y++) // skip first pixels incase of noise in the edge
     2690    {
     2691        for (int detectionLine = 0; detectionLine < NUMBER_OF_DETECTION_LINES; detectionLine++)
     2692        {
     2693            int Y = buf[offset + y * pitch + xPos[detectionLine]];
     2694            if ((!topHit[detectionLine]) && ( Y > averageY + THRESHOLD || Y < averageY - THRESHOLD))
     2695            {
     2696                topHit[detectionLine] = y;
     2697                topHits++;
     2698                if (!minTop)
     2699                    minTop = y;
     2700                maxTop = y;
     2701            }
     2702
     2703            Y = buf[offset + (height - y -1) * pitch + xPos[detectionLine]];
     2704            if ((!bottomHit[detectionLine]) && ( Y > averageY + THRESHOLD || Y < averageY - THRESHOLD))
     2705            {
     2706                bottomHit[detectionLine] = y;
     2707                bottomHits++;
     2708                if (!minBottom)
     2709                    minBottom = y;
     2710                maxBottom = y;
     2711            }
     2712        }
     2713
     2714        if ((minTop && maxTop - minTop > HORIZONTAL_THRESHOLD) ||
     2715            (minBottom && maxBottom - minBottom > HORIZONTAL_THRESHOLD))
     2716        {
     2717            // No horizontal lines
     2718            break;
     2719        }
     2720
     2721        if (topHits == NUMBER_OF_DETECTION_LINES && bottomHits == NUMBER_OF_DETECTION_LINES)
     2722        {           
     2723            // Found the a image on all lines
     2724            if ( maxTop < halfLimit && maxBottom < halfLimit)
     2725            {
     2726                // No Letterbox
     2727                detectLetterboxCounterOff++;
     2728                detectLetterboxCounterHalf = 0;
     2729                detectLetterboxCounterFull = 0;
     2730                if (GetAdjustFill() != detectLetterboxDefaultMode)
     2731                {
     2732                  VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: Non Letterbox detected on line: %1 (limit: %2 counter: %3)").arg(y).arg(halfLimit).arg(detectLetterboxCounterOff));
     2733                    if (detectLetterboxCounterOff >= SWITCH_DELAY)
     2734                    {
     2735                        VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: Switched to Fill Off"));
     2736                        videoOutput->ToggleAdjustFill(detectLetterboxDefaultMode);
     2737                        ReinitOSD();
     2738                    }
     2739                }
     2740            }
     2741            else if (minTop > halfLimit && minBottom > halfLimit &&
     2742                     maxTop < fullLimit && maxBottom < fullLimit)
     2743            {
     2744                // Letterbox (with narrow bars)
     2745                detectLetterboxCounterOff = 0;
     2746                detectLetterboxCounterHalf++;
     2747                detectLetterboxCounterFull = 0;
     2748                if (GetAdjustFill() != kAdjustFill_Half)
     2749                {
     2750                  VERBOSE(VB_PLAYBACK, QString("Detect Narrow Letterbox: Letterbox detected on line: %1 (limit: %2 counter: %3)").arg(y).arg(halfLimit).arg(detectLetterboxCounterHalf));
     2751                    if (detectLetterboxCounterHalf >= SWITCH_DELAY)
     2752                    {
     2753                        VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: Switched to Fill Half"));
     2754                        videoOutput->ToggleAdjustFill(kAdjustFill_Half);
     2755                        ReinitOSD();
     2756                    }
     2757                }
     2758            }
     2759            else if ( minTop > fullLimit && minBottom > fullLimit)
     2760            {
     2761                // Letterbox
     2762                detectLetterboxCounterOff = 0;
     2763                detectLetterboxCounterHalf = 0;
     2764                detectLetterboxCounterFull++;
     2765                if (GetAdjustFill() != kAdjustFill_Full)
     2766                {
     2767                  VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: Detected Letterbox on line: %1 (limit: %2 counter: %3)\n").arg(y).arg(fullLimit).arg(detectLetterboxCounterFull));
     2768                    if (detectLetterboxCounterFull >= SWITCH_DELAY)
     2769                    {
     2770                        VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: Switched to Fill Full"));
     2771                        videoOutput->ToggleAdjustFill(kAdjustFill_Full);
     2772                        ReinitOSD();
     2773                    }
     2774                }
     2775            }
     2776            break;
     2777        }
     2778    }
     2779
     2780    if (!isDetectLetterboxDebugging)
     2781        return;
     2782
     2783    // draw debug output
     2784    for (x = 0; x < width; x++)
     2785    {
     2786        // detection lines
     2787        if (topHits == NUMBER_OF_DETECTION_LINES && maxTop - minTop <= HORIZONTAL_THRESHOLD)
     2788        {
     2789            // horizontal line
     2790            draw (frame, x, halfLimit, 150, 91, 62);
     2791            draw (frame, x, fullLimit, 150, 91, 62);
     2792        }
     2793        else
     2794        {
     2795            draw (frame, x, halfLimit, 255, 128, 128);
     2796            draw (frame, x, fullLimit, 255, 128, 128);
     2797        }
     2798
     2799        if (bottomHits == NUMBER_OF_DETECTION_LINES && maxBottom - minBottom <= HORIZONTAL_THRESHOLD)
     2800        {
     2801            // horizontal line
     2802            draw (frame, x, height - 1 - halfLimit, 150, 91, 62);
     2803            draw (frame, x, height - 1 - fullLimit, 150, 91, 62);
     2804        }
     2805        else
     2806        {
     2807            draw (frame, x, height - 1 - halfLimit, 255, 128, 128);
     2808            draw (frame, x, height - 1 - fullLimit, 255, 128, 128);
     2809        }
     2810    }
     2811
     2812    for (y = 5; y < height / 4; y++)
     2813    {
     2814        int line;
     2815        for (line = 0; line < NUMBER_OF_DETECTION_LINES; line++)
     2816        {
     2817            if (topHit[line] > y || !topHit[line])
     2818            {
     2819                draw (frame, xPos[line], y, 150, 91, 62);
     2820            }
     2821            else
     2822            {
     2823                draw (frame, xPos[line], y, 76, 109, 207);
     2824            }
     2825       
     2826            if (bottomHit[line] > y || !bottomHit[line])
     2827            {
     2828                draw (frame, xPos[line], height - 1 - y, 150, 91, 62);
     2829            }
     2830            else
     2831            {
     2832                draw (frame, xPos[line], height - 1 - y, 76, 109, 207);
     2833            }
     2834        }
     2835
     2836    }
     2837
     2838    for (x = 0; x < 25; x ++)
     2839    {
     2840        for (y = 0; y < 25; y++)
     2841        {
     2842            draw (frame, x + 30, y, averageY, x*10, y*10);           
     2843            draw (frame, x, y, averageY, 128, 128);
     2844        }
     2845    }
     2846}
     2847
    26082848void NuppelVideoPlayer::DisplayNormalFrame(void)
    26092849{
    26102850    SetVideoActuallyPaused(false);
     
    27132953    // handle scan type changes
    27142954    AutoDeint(frame);
    27152955
     2956    DetectLetterbox(frame);
     2957
    27162958    videofiltersLock.lock();
    27172959    if (ringBuffer->isDVD() &&
    27182960        ringBuffer->DVD()->InStillFrame() &&
     
    48905132{
    48915133    if (videoOutput)
    48925134    {
     5135        isDetectLetterbox = false;
    48935136        videoOutput->ToggleAdjustFill(adjustfillMode);
    48945137        ReinitOSD();
    48955138    }
    48965139}
    48975140
     5141void NuppelVideoPlayer::SetDetectLetterbox(bool detect)
     5142{
     5143    isDetectLetterbox = detect;
     5144}
     5145
     5146bool NuppelVideoPlayer::GetDetectLetterbox()
     5147{
     5148    return isDetectLetterbox;
     5149}
     5150
     5151void NuppelVideoPlayer::SetDetectLetterboxDebugging(bool debug)
     5152{
     5153    isDetectLetterboxDebugging = debug;
     5154}
     5155
     5156bool NuppelVideoPlayer::GetDetectLetterboxDebugging()
     5157{
     5158    return isDetectLetterboxDebugging;
     5159}
     5160
    48985161void NuppelVideoPlayer::Zoom(ZoomDirection direction)
    48995162{
    49005163    if (videoOutput)
  • libs/libmythtv/NuppelVideoPlayer.h

     
    176176    void ToggleAspectOverride(AspectOverrideMode aspectMode = kAspect_Toggle);
    177177    void ToggleAdjustFill(AdjustFillMode adjustfillMode = kAdjustFill_Toggle);
    178178
     179    void SetDetectLetterbox(bool detect);
     180    bool GetDetectLetterbox();
     181    void SetDetectLetterboxDebugging(bool detect);
     182    bool GetDetectLetterboxDebugging();
     183
    179184    // Gets
    180185    int     GetVideoWidth(void) const         { return video_width; }
    181186    int     GetVideoHeight(void) const        { return video_height; }
     
    516521    long long GetDVDBookmark(void) const;
    517522    void SetDVDBookmark(long long frames);
    518523
     524    void DetectLetterbox(VideoFrame *frame);
    519525  private:
    520526    DecoderBase   *decoder;
    521527    QMutex         decoder_change_lock;
     
    796802
    797803    // Debugging variables
    798804    Jitterometer *output_jmeter;
     805
     806    bool isDetectLetterbox;
     807    bool isDetectLetterboxDebugging;
     808    AdjustFillMode detectLetterboxDefaultMode;
     809    int detectLetterboxCounterOff;
     810    int detectLetterboxCounterHalf;
     811    int detectLetterboxCounterFull;
     812    int detectLetterboxLimit;
    799813};
    800814
    801815#endif
  • libs/libmythtv/tv_play.cpp

     
    73177317    {
    73187318        ToggleAdjustFill((AdjustFillMode) action.right(1).toInt());
    73197319    }
     7320    else if (action == "AUTODETECT_FILL")
     7321    {
     7322        nvp->SetDetectLetterbox(!nvp->GetDetectLetterbox());
     7323    }
     7324    else if (action == "TOGG_AUTODETECT_DEBUG")
     7325    {
     7326        nvp->SetDetectLetterboxDebugging(!nvp->GetDetectLetterboxDebugging());
     7327    }
    73207328    else if (action == "GUIDE")
    73217329        EditSchedule(kScheduleProgramGuide);
    73227330    else if (action == "FINDER")
     
    74837491
    74847492    AdjustFillMode adjustfill = nvp->GetAdjustFill();
    74857493    item = new OSDGenericTree(treeMenu, tr("Adjust Fill"));
     7494    subitem = new OSDGenericTree(item, tr("Auto Detect"), "AUTODETECT_FILL",
     7495                                 (nvp->GetDetectLetterbox()) ? 1 : 0,
     7496                                 NULL, "ADJUSTFILLGROUP");
     7497
     7498    subitem = new OSDGenericTree(item, tr("Debugg Auto Detect"), "TOGG_AUTODETECT_DEBUG",
     7499                                 (nvp->GetDetectLetterboxDebugging()) ? 1 : 0,
     7500                                 NULL, "ADJUSTFILLGROUP");
     7501
    74867502    for (int i = kAdjustFill_Off; i < kAdjustFill_END; i++)
    74877503    {
    74887504        bool sel = (i != kAdjustFill_Off) ? (adjustfill == i) :
  • libs/libmythtv/videoouttypes.h

     
    4646    kAdjustFill_Half,
    4747    kAdjustFill_Full,
    4848    kAdjustFill_Stretch,
    49     kAdjustFill_END
     49    kAdjustFill_END,
     50    kAdjustFill_AutoDetect_DefaultOff = 16,
     51    kAdjustFill_AutoDetect_DefaultHalf
    5052} AdjustFillMode;
    5153
    5254typedef enum LetterBoxColour
     
    208210        case kAdjustFill_Toggle:
    209211        case kAdjustFill_Off:
    210212        case kAdjustFill_END: break;
     213        case kAdjustFill_AutoDetect_DefaultOff: ret = QObject::tr("Auto Detect (Default Off)");    break;
     214        case kAdjustFill_AutoDetect_DefaultHalf: ret = QObject::tr("Auto Detect (Default Half)");    break;
    211215    }
    212216    return QDeepCopy<QString>(ret);
    213217}
  • libs/libmythtv/videooutbase.cpp

     
    381381    db_vdisp_profile->SetInput(video_dim);
    382382
    383383    aspectoverride  = db_aspectoverride;
    384     adjustfill      = db_adjustfill;
     384    // If autodection is enabled. Start in the defaultmode
     385    adjustfill      = db_adjustfill >= kAdjustFill_AutoDetect_DefaultOff ?
     386        (AdjustFillMode) (db_adjustfill - kAdjustFill_AutoDetect_DefaultOff) : db_adjustfill;
    385387
    386388    VideoAspectRatioChanged(aspect); // apply aspect ratio and letterbox mode
    387389
  • programs/mythfrontend/globalsettings.cpp

     
    23092309{
    23102310    HostComboBox *gc = new HostComboBox("AdjustFill");
    23112311    gc->setLabel(QObject::tr("Zoom"));
     2312    gc->addSelection(toString(kAdjustFill_AutoDetect_DefaultOff), QString::number(kAdjustFill_AutoDetect_DefaultOff));
     2313    gc->addSelection(toString(kAdjustFill_AutoDetect_DefaultHalf), QString::number(kAdjustFill_AutoDetect_DefaultHalf));
    23122314    for (int m = kAdjustFill_Off; m < kAdjustFill_END; m++)
    23132315        gc->addSelection(toString((AdjustFillMode)m), QString::number(m));
    23142316    gc->setHelpText(QObject::tr(