Ticket #4872: detectLetterboxV8.patch

File detectLetterboxV8.patch, 17.5 KB (added by Rob Smith, 18 years ago)

Updated V7 + widescreen backswitch fix to work with current trunk ([18991])

  • libs/libmythtv/NuppelVideoPlayer.cpp

     
    294294    text_size = 8 * (sizeof(teletextsubtitle) + VT_WIDTH);
    295295    for (int i = 0; i < MAXTBUFFER; i++)
    296296        txtbuffers[i].buffer = new unsigned char[text_size + 1];
     297   
     298    int dbAdjustFill = gContext->GetNumSetting("AdjustFill", 0);
     299    isDetectLetterbox = dbAdjustFill >= kAdjustFill_AutoDetect_DefaultOff;
     300    detectLetterboxDefaultMode = (AdjustFillMode) max((int) kAdjustFill_Off,
     301                                 dbAdjustFill - kAdjustFill_AutoDetect_DefaultOff);
     302    detectLetterboxSwitchFrame = -1;
     303    detectLetterboxPossibleHalfFrame = -1;
     304    detectLetterboxPossibleFullFrame = -1;
     305    detectLetterboxDetectedMode = GetAdjustFill();
     306    detectLetterboxLimit = gContext->GetNumSetting("DetectLeterboxLimit", 75);
    297307}
    298308
    299309NuppelVideoPlayer::~NuppelVideoPlayer(void)
     
    14051415    buffer->timecode = timecode;
    14061416
    14071417    videoOutput->ReleaseFrame(buffer);
     1418
     1419    if (isDetectLetterbox)
     1420        DetectLetterbox(buffer);
    14081421}
    14091422
    14101423/** \fn NuppelVideoPlayer::DiscardVideoFrame(VideoFrame*)
     
    27392752    return true;
    27402753}
    27412754
     2755/** \fn NuppelVideoPlayer::DetectLetterbox(VideoFrame*)
     2756 *  \brief Detects if this frame is or is not letterboxed
     2757 *
     2758 *  If a change is detected detectLetterboxSwitchFrame and
     2759 *  detectLetterboxDetectedMode are set.
     2760 */
     2761void NuppelVideoPlayer::DetectLetterbox(VideoFrame *frame)
     2762{
     2763    const unsigned char *buf = frame->buf;
     2764    const int width = frame->width;
     2765    const int height = frame->height;
     2766    const int *pitches = frame->pitches;
     2767    const int *offsets = frame->offsets;
     2768    const long long frameNumber = frame->frameNumber;
     2769
     2770    const int NUMBER_OF_DETECTION_LINES = 3; // How many lines are we looking at
     2771    const int THRESHOLD = 5; // Y component has to not vary more than this in the bars
     2772    const int HORIZONTAL_THRESHOLD = 4; // How tolerant are we that the image has horizontal edges
     2773
     2774    // If the black bars is larger than this limit we switch to Half or Full Mode
     2775    //    const int fullLimit = (int) (((height - width * 9 / 16) / 2) * detectLetterboxLimit / 100);
     2776    //    const int halfLimit = (int) (((height - width * 9 / 14) / 2) * detectLetterboxLimit / 100);
     2777    // If the black bars is larger than this limit we switch to Half or Full Mode
     2778    const int fullLimit = (int) ((height * (1 - video_aspect * 9 / 16) / 2) * detectLetterboxLimit / 100);
     2779    const int halfLimit = (int) ((height * (1 - video_aspect * 9 / 14) / 2) * detectLetterboxLimit / 100);
     2780
     2781
     2782    const int xPos[] = {width / 4, width / 2, width * 3 / 4};    // Lines to scan for black letterbox edge
     2783    int topHits = 0, bottomHits = 0, minTop = 0, minBottom = 0, maxTop = 0, maxBottom = 0;
     2784    int topHit[] = {0, 0, 0}, bottomHit[] = {0, 0, 0};
     2785
     2786    if (!videoOutput)
     2787        return;
     2788
     2789   
     2790    if (frame->codec != FMT_YV12)
     2791    {
     2792        VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: The source is not in YV12 (was %1)").arg(frame->codec));
     2793        isDetectLetterbox = false;
     2794        return;
     2795    }
     2796
     2797    if (frameNumber < 0)
     2798    {
     2799        VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: Strange frame number %1").arg(frameNumber));
     2800        return;
     2801    }
     2802
     2803    if (video_aspect > 1.5)
     2804    {
     2805        if (detectLetterboxDetectedMode != detectLetterboxDefaultMode)
     2806        {
     2807            VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: The source is already in widescreen (aspect: %1)").arg(video_aspect));
     2808            detectLetterboxLock.lock();
     2809            detectLetterboxConsecutiveCounter = 0;
     2810            detectLetterboxDetectedMode = detectLetterboxDefaultMode;
     2811            detectLetterboxSwitchFrame = frameNumber;
     2812            detectLetterboxLock.unlock();
     2813        }
     2814        else
     2815        {
     2816            detectLetterboxConsecutiveCounter++;
     2817        }
     2818        //VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: The source is already in widescreen (aspect: %1)").arg(video_aspect));
     2819        //isDetectLetterbox = false;
     2820        return;
     2821    }
     2822
     2823    // Establish the level of light in the edge
     2824    int averageY = 0;
     2825    for (int detectionLine = 0; detectionLine < NUMBER_OF_DETECTION_LINES; detectionLine++)
     2826    {
     2827        averageY += buf[offsets[0] + 5 * pitches[0]            + xPos[detectionLine]];
     2828        averageY += buf[offsets[0] + (height - 6) * pitches[0] + xPos[detectionLine]];
     2829    }
     2830    averageY /= NUMBER_OF_DETECTION_LINES * 2;
     2831    if (averageY > 64) // To bright to be a letterbox border
     2832        averageY = 0;
     2833
     2834    // Scan the detection lines
     2835    for (int y = 5; y < height / 4; y++) // skip first pixels incase of noise in the edge
     2836    {
     2837        for (int detectionLine = 0; detectionLine < NUMBER_OF_DETECTION_LINES; detectionLine++)
     2838        {
     2839            int Y = buf[offsets[0] +  y     * pitches[0] +  xPos[detectionLine]];
     2840            int U = buf[offsets[1] + (y>>1) * pitches[1] + (xPos[detectionLine]>>1)];
     2841            int V = buf[offsets[2] + (y>>1) * pitches[2] + (xPos[detectionLine]>>1)];
     2842            if ((!topHit[detectionLine]) &&
     2843                ( Y > averageY + THRESHOLD || Y < averageY - THRESHOLD ||
     2844                  U < 128 - 32 || U > 128 + 32 ||
     2845                  V < 128 - 32 || V > 128 + 32 ))
     2846            {
     2847                topHit[detectionLine] = y;
     2848                topHits++;
     2849                if (!minTop)
     2850                    minTop = y;
     2851                maxTop = y;
     2852            }
     2853
     2854            Y = buf[offsets[0] + (height-y-1     ) * pitches[0] + xPos[detectionLine]];
     2855            U = buf[offsets[1] + (height-y-1 >> 1) * pitches[1] + (xPos[detectionLine]>>1)];
     2856            V = buf[offsets[2] + (height-y-1 >> 1) * pitches[2] + (xPos[detectionLine]>>1)];
     2857            if ((!bottomHit[detectionLine]) &&
     2858                ( Y > averageY + THRESHOLD || Y < averageY - THRESHOLD ||
     2859                  U < 128 - 32 || U > 128 + 32 ||
     2860                  V < 128 - 32 || V > 128 + 32 ))
     2861            {
     2862                bottomHit[detectionLine] = y;
     2863                bottomHits++;
     2864                if (!minBottom)
     2865                    minBottom = y;
     2866                maxBottom = y;
     2867            }
     2868        }
     2869
     2870        if (topHits == NUMBER_OF_DETECTION_LINES && bottomHits == NUMBER_OF_DETECTION_LINES)
     2871        {           
     2872            break;
     2873        }
     2874    }
     2875    if (topHits != NUMBER_OF_DETECTION_LINES) maxTop = height / 4;
     2876    if (!minTop) minTop = height / 4;
     2877    if (bottomHits != NUMBER_OF_DETECTION_LINES) maxBottom = height / 4;
     2878    if (!minBottom) minBottom = height / 4;
     2879
     2880    bool horizontal = ((minTop && maxTop - minTop < HORIZONTAL_THRESHOLD) &&
     2881                       (minBottom && maxBottom - minBottom < HORIZONTAL_THRESHOLD));
     2882
     2883    if (detectLetterboxSwitchFrame > frameNumber) // user is reversing
     2884    {
     2885        detectLetterboxLock.lock();
     2886        detectLetterboxDetectedMode = GetAdjustFill();
     2887        detectLetterboxSwitchFrame = -1;
     2888        detectLetterboxPossibleHalfFrame = -1;
     2889        detectLetterboxPossibleFullFrame = -1;
     2890        detectLetterboxLock.unlock();
     2891    }
     2892
     2893    if (minTop < halfLimit || minBottom < halfLimit)
     2894        detectLetterboxPossibleHalfFrame = -1;
     2895    if (minTop < fullLimit || minBottom < fullLimit)
     2896        detectLetterboxPossibleFullFrame = -1;
     2897
     2898    if (detectLetterboxDetectedMode != kAdjustFill_Full)
     2899    {
     2900        if (detectLetterboxPossibleHalfFrame == -1 &&
     2901            minTop > halfLimit && minBottom > halfLimit) {
     2902            detectLetterboxPossibleHalfFrame = frameNumber;
     2903        }
     2904    }
     2905    else
     2906    {
     2907        if (detectLetterboxPossibleHalfFrame == -1 &&
     2908            minTop < fullLimit && minBottom < fullLimit) {
     2909            detectLetterboxPossibleHalfFrame = frameNumber;
     2910        }
     2911    }
     2912    if (detectLetterboxPossibleFullFrame == -1 && minTop > fullLimit && minBottom > fullLimit)
     2913        detectLetterboxPossibleFullFrame = frameNumber;
     2914
     2915    if ( maxTop < halfLimit || maxBottom < halfLimit) // Not to restrictive when switching to off
     2916    {
     2917        // No Letterbox
     2918        if (detectLetterboxDetectedMode != detectLetterboxDefaultMode)
     2919        {
     2920            VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: Non Letterbox detected on line: %1 (limit: %2)").arg(min(maxTop, maxBottom)).arg(halfLimit));
     2921            detectLetterboxLock.lock();
     2922            detectLetterboxConsecutiveCounter = 0;
     2923            detectLetterboxDetectedMode = detectLetterboxDefaultMode;
     2924            detectLetterboxSwitchFrame = frameNumber;
     2925            detectLetterboxLock.unlock();
     2926        }
     2927        else
     2928        {
     2929            detectLetterboxConsecutiveCounter++;
     2930        }
     2931    }
     2932    else if (horizontal && minTop > halfLimit && minBottom > halfLimit &&
     2933             maxTop < fullLimit && maxBottom < fullLimit)
     2934    {
     2935        // Letterbox (with narrow bars)
     2936        if (detectLetterboxDetectedMode != kAdjustFill_Half)
     2937        {
     2938            VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: Narrow Letterbox detected on line: %1 (limit: %2) frame: %3").arg(minTop).arg(halfLimit).arg(detectLetterboxPossibleHalfFrame));
     2939            detectLetterboxLock.lock();
     2940            detectLetterboxConsecutiveCounter = 0;
     2941            if (detectLetterboxDetectedMode == kAdjustFill_Full &&
     2942                detectLetterboxSwitchFrame != -1) {
     2943                // Do not change switch frame if switch to Full mode has not been executed yet
     2944            }
     2945            else
     2946                detectLetterboxSwitchFrame = detectLetterboxPossibleHalfFrame;
     2947            detectLetterboxDetectedMode = kAdjustFill_Half;
     2948            detectLetterboxLock.unlock();
     2949        }
     2950        else
     2951        {
     2952            detectLetterboxConsecutiveCounter++;
     2953        }
     2954    }
     2955    else if (horizontal && minTop > fullLimit && minBottom > fullLimit)
     2956    {
     2957        // Letterbox
     2958        detectLetterboxPossibleHalfFrame = -1;
     2959        if (detectLetterboxDetectedMode != kAdjustFill_Full)
     2960        {
     2961            VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: Detected Letterbox on line: %1 (limit: %2) frame: %2").arg(minTop).arg(fullLimit).arg(detectLetterboxPossibleFullFrame));
     2962            detectLetterboxLock.lock();
     2963            detectLetterboxConsecutiveCounter = 0;
     2964            detectLetterboxDetectedMode = kAdjustFill_Full;
     2965            detectLetterboxSwitchFrame = detectLetterboxPossibleFullFrame;
     2966            detectLetterboxLock.unlock();
     2967        }
     2968        else
     2969        {
     2970            detectLetterboxConsecutiveCounter++;
     2971        }
     2972    }
     2973    else
     2974    {
     2975        if (detectLetterboxConsecutiveCounter <= 3)
     2976            detectLetterboxConsecutiveCounter = 0;
     2977    }
     2978}
     2979
     2980/** \fn NuppelVideoPlayer::SwitchToDetectedLetterbox(VideoFrame*)
     2981 *  \brief Switch to the mode detected by DetectLetterbox
     2982 *
     2983 *  Switch fill mode if a switch was detected for this frame.
     2984 */
     2985void NuppelVideoPlayer::SwitchToDetectedLetterbox(VideoFrame *frame)
     2986{
     2987    if (detectLetterboxSwitchFrame != -1)
     2988    {
     2989        detectLetterboxLock.lock();
     2990        if (detectLetterboxSwitchFrame <= frame->frameNumber &&
     2991            detectLetterboxConsecutiveCounter > 3)
     2992        {
     2993            if (GetAdjustFill() != detectLetterboxDetectedMode)
     2994            {
     2995                VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: Switched to %1 on frame %2 (%3)").arg(detectLetterboxDetectedMode).arg(frame->frameNumber).arg(detectLetterboxSwitchFrame));
     2996                videoOutput->ToggleAdjustFill(detectLetterboxDetectedMode);
     2997                ReinitOSD();           
     2998            }
     2999            detectLetterboxSwitchFrame = -1;
     3000        }
     3001        else if (detectLetterboxSwitchFrame <= frame->frameNumber)
     3002            VERBOSE(VB_PLAYBACK, QString("Detect Letterbox: Not Switched to %1 on frame %2 (%3) Not enough consecutive detections (%4)").arg(detectLetterboxDetectedMode).arg(frame->frameNumber).arg(detectLetterboxSwitchFrame).arg(detectLetterboxConsecutiveCounter));
     3003
     3004        detectLetterboxLock.unlock();
     3005    }
     3006}
     3007
    27423008void NuppelVideoPlayer::DisplayNormalFrame(void)
    27433009{
    27443010    SetVideoActuallyPaused(false);
     
    28483114    // handle scan type changes
    28493115    AutoDeint(frame);
    28503116
     3117    if (isDetectLetterbox)
     3118        SwitchToDetectedLetterbox(frame);
     3119
    28513120    videofiltersLock.lock();
    28523121    if (ringBuffer->isDVD() &&
    28533122        ringBuffer->DVD()->InStillFrame() &&
     
    50345303{
    50355304    if (videoOutput)
    50365305    {
     5306        isDetectLetterbox = false;
    50375307        videoOutput->ToggleAdjustFill(adjustfillMode);
    50385308        ReinitOSD();
    50395309    }
    50405310}
    50415311
     5312void NuppelVideoPlayer::SetDetectLetterbox(bool detect)
     5313{
     5314    isDetectLetterbox = detect;
     5315    detectLetterboxSwitchFrame = -1;
     5316    detectLetterboxDetectedMode = GetAdjustFill();
     5317}
     5318
     5319bool NuppelVideoPlayer::GetDetectLetterbox()
     5320{
     5321    return isDetectLetterbox;
     5322}
     5323
    50425324void NuppelVideoPlayer::Zoom(ZoomDirection direction)
    50435325{
    50445326    if (videoOutput)
  • libs/libmythtv/NuppelVideoPlayer.h

     
    179179    void ToggleAspectOverride(AspectOverrideMode aspectMode = kAspect_Toggle);
    180180    void ToggleAdjustFill(AdjustFillMode adjustfillMode = kAdjustFill_Toggle);
    181181
     182    void SetDetectLetterbox(bool detect);
     183    bool GetDetectLetterbox();
     184
    182185    // Gets
    183186    QSize   GetVideoBufferSize(void) const    { return video_dim; }
    184187    QSize   GetVideoSize(void) const          { return video_disp_dim; }
     
    521524    long long GetDVDBookmark(void) const;
    522525    void SetDVDBookmark(long long frames);
    523526
     527    void DetectLetterbox(VideoFrame *frame);
     528    void SwitchToDetectedLetterbox(VideoFrame *frame);
    524529  private:
    525530    DecoderBase   *decoder;
    526531    QMutex         decoder_change_lock;
     
    801806
    802807    // Debugging variables
    803808    Jitterometer *output_jmeter;
     809
     810    bool isDetectLetterbox;
     811
     812    AdjustFillMode detectLetterboxDefaultMode;
     813    AdjustFillMode detectLetterboxDetectedMode; // Wich mode was last detected
     814    long long  detectLetterboxSwitchFrame; // On wich frame was the mode switch detected
     815    long long detectLetterboxPossibleHalfFrame;
     816    long long detectLetterboxPossibleFullFrame;
     817    int detectLetterboxConsecutiveCounter;
     818
     819    int detectLetterboxLimit;
     820    QMutex detectLetterboxLock;
    804821};
    805822
    806823#endif
  • libs/libmythtv/tv_play.cpp

     
    73977397    {
    73987398        ToggleAdjustFill((AdjustFillMode) action.right(1).toInt());
    73997399    }
     7400    else if (action == "AUTODETECT_FILL")
     7401    {
     7402        nvp->SetDetectLetterbox(!nvp->GetDetectLetterbox());
     7403    }
    74007404    else if (action == "GUIDE")
    74017405        EditSchedule(kScheduleProgramGuide);
    74027406    else if (action == "FINDER")
     
    75697573
    75707574    AdjustFillMode adjustfill = nvp->GetAdjustFill();
    75717575    OSDGenericTree *af_item = new OSDGenericTree(treeMenu, tr("Adjust Fill"));
     7576    OSDGenericTree *subitem = new OSDGenericTree(af_item, tr("Auto Detect"),
     7577                                 "AUTODETECT_FILL",
     7578                                 (nvp->GetDetectLetterbox()) ? 1 : 0,
     7579                                 NULL, "ADJUSTFILLGROUP");
     7580
    75727581    for (int i = kAdjustFill_Off; i < kAdjustFill_END; i++)
    75737582    {
    75747583        bool sel = (i != kAdjustFill_Off) ? (adjustfill == i) :
  • libs/libmythtv/videoouttypes.h

     
    4545    kAdjustFill_Half,
    4646    kAdjustFill_Full,
    4747    kAdjustFill_Stretch,
    48     kAdjustFill_END
     48    kAdjustFill_END,
     49    kAdjustFill_AutoDetect_DefaultOff = 16,
     50    kAdjustFill_AutoDetect_DefaultHalf
    4951} AdjustFillMode;
    5052
    5153typedef enum LetterBoxColour
     
    217219        case kAdjustFill_Toggle:
    218220        case kAdjustFill_Off:
    219221        case kAdjustFill_END: break;
     222        case kAdjustFill_AutoDetect_DefaultOff: ret = QObject::tr("Auto Detect (Default Off)");    break;
     223        case kAdjustFill_AutoDetect_DefaultHalf: ret = QObject::tr("Auto Detect (Default Half)");    break;
    220224    }
    221225
    222226    ret.detach();
  • libs/libmythtv/videooutbase.cpp

     
    392392        db_vdisp_profile->SetInput(video_dim);
    393393
    394394    aspectoverride  = db_aspectoverride;
    395     adjustfill      = db_adjustfill;
     395    // If autodection is enabled. Start in the defaultmode
     396    adjustfill      = db_adjustfill >= kAdjustFill_AutoDetect_DefaultOff ?
     397        (AdjustFillMode) (db_adjustfill - kAdjustFill_AutoDetect_DefaultOff) : db_adjustfill;
    396398
    397399    VideoAspectRatioChanged(aspect); // apply aspect ratio and letterbox mode
    398400
  • programs/mythfrontend/globalsettings.cpp

     
    23862386{
    23872387    HostComboBox *gc = new HostComboBox("AdjustFill");
    23882388    gc->setLabel(QObject::tr("Zoom"));
     2389    gc->addSelection(toString(kAdjustFill_AutoDetect_DefaultOff), QString::number(kAdjustFill_AutoDetect_DefaultOff));
     2390    gc->addSelection(toString(kAdjustFill_AutoDetect_DefaultHalf), QString::number(kAdjustFill_AutoDetect_DefaultHalf));
    23892391    for (int m = kAdjustFill_Off; m < kAdjustFill_END; m++)
    23902392        gc->addSelection(toString((AdjustFillMode)m), QString::number(m));
    23912393    gc->setHelpText(QObject::tr(