Ticket #10402: sub_zoom.patch

File sub_zoom.patch, 11.1 KB (added by ggervasio@…, 9 years ago)
  • mythtv/libs/libmythtv/subtitlescreen.cpp

    commit cb8a4fb430af5244890f46e02904fcdc14a71d65
    Author: Gregorio Gervasio, Jr <ggervasio@yahoo.com>
    Date:   Sat Mar 3 16:11:01 2012 -0800
    
        Modified to scale AV subtitle region according to text zoom setting.
    
    diff --git a/mythtv/libs/libmythtv/subtitlescreen.cpp b/mythtv/libs/libmythtv/subtitlescreen.cpp
    index 147adbd..1733ea3 100644
    a b void SubtitleScreen::DisplayAVSubtitles(void) 
    238238        if (subtitle.start_display_time > currentFrame->timecode)
    239239            break;
    240240
     241        long long displayfor = subtitle.end_display_time -
     242                               subtitle.start_display_time;
     243        if (displayfor == 0)
     244            displayfor = 60000;
     245        displayfor = (displayfor < 50) ? 50 : displayfor;
     246        long long late = currentFrame->timecode -
     247                         subtitle.start_display_time;
     248
    241249        ClearDisplayedSubtitles();
    242250        subs->buffers.pop_front();
    243251        for (std::size_t i = 0; i < subtitle.num_rects; ++i)
    void SubtitleScreen::DisplayAVSubtitles(void) 
    254262
    255263            if (displaysub && rect->type == SUBTITLE_BITMAP)
    256264            {
    257                 // AVSubtitleRect's image data's not guaranteed to be 4 byte
    258                 // aligned.
    259 
    260                 QSize img_size(rect->w, rect->h);
    261                 QRect img_rect(rect->x, rect->y, rect->w, rect->h);
    262265                QRect display(rect->display_x, rect->display_y,
    263266                              rect->display_w, rect->display_h);
    264267
    void SubtitleScreen::DisplayAVSubtitles(void) 
    269272                int right  = rect->x + rect->w;
    270273                int bottom = rect->y + rect->h;
    271274                if (subs->fixPosition || (currentFrame->height < bottom) ||
    272                    (currentFrame->width  < right))
     275                   (currentFrame->width  < right) ||
     276                   !display.width() || !display.height())
    273277                {
    274278                    int sd_height = 576;
    275279                    if ((m_player->GetFrameRate() > 26.0f) && bottom <= 480)
    void SubtitleScreen::DisplayAVSubtitles(void) 
    285289                    display = QRect(0, 0, width, height);
    286290                }
    287291
    288                 QRect scaled = videoOut->GetImageRect(img_rect, &display);
    289                 QImage qImage(img_size, QImage::Format_ARGB32);
    290                 for (int y = 0; y < rect->h; ++y)
    291                 {
    292                     for (int x = 0; x < rect->w; ++x)
    293                     {
    294                         const uint8_t color = rect->pict.data[0][y*rect->pict.linesize[0] + x];
    295                         const uint32_t pixel = *((uint32_t*)rect->pict.data[1]+color);
    296                         qImage.setPixel(x, y, pixel);
    297                     }
    298                 }
    299 
    300                 if (scaled.size() != img_size)
    301                 {
    302                     qImage = qImage.scaled(scaled.width(), scaled.height(),
    303                              Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
    304                 }
    305 
    306                 MythPainter *osd_painter = videoOut->GetOSDPainter();
    307                 MythImage* image = NULL;
    308                 if (osd_painter)
    309                    image = osd_painter->GetFormatImage();
    310 
    311                 long long displayfor = subtitle.end_display_time -
    312                                        subtitle.start_display_time;
    313                 if (displayfor == 0)
    314                     displayfor = 60000;
    315                 displayfor = (displayfor < 50) ? 50 : displayfor;
    316                 long long late = currentFrame->timecode -
    317                                  subtitle.start_display_time;
    318                 MythUIImage *uiimage = NULL;
    319                 if (image)
     292                // split into upper/lower to allow zooming
     293                QRect bbox;
     294                int uh = display.height()/2 - rect->y;
     295                int lh;
     296                if (uh > 0)
    320297                {
    321                     image->Assign(qImage);
    322                     QString name = QString("avsub%1").arg(i);
    323                     uiimage = new MythUIImage(this, name);
    324                     if (uiimage)
    325                     {
    326                         m_refreshArea = true;
    327                         uiimage->SetImage(image);
    328                         uiimage->SetArea(MythRect(scaled));
    329                         m_expireTimes.insert(uiimage,
    330                                      currentFrame->timecode + displayfor);
    331                     }
     298                    bbox = QRect(0, 0, rect->w, uh);
     299                    uh = DisplayScaledAVSubtitles(rect, bbox, true, display,
     300                                                  subtitle.forced,
     301                                                  currentFrame->timecode + displayfor, late);
    332302                }
    333                 if (uiimage)
     303                else
     304                    uh = 0;
     305                lh = rect->h - uh;
     306                if (lh > 0)
    334307                {
    335                     LOG(VB_PLAYBACK, LOG_INFO, LOC +
    336                         QString("Display %1AV subtitle for %2ms")
    337                         .arg(subtitle.forced ? "FORCED " : "")
    338                         .arg(displayfor));
    339                     if (late > 50)
    340                         LOG(VB_PLAYBACK, LOG_INFO, LOC +
    341                             QString("AV Sub was %1ms late").arg(late));
     308                    bbox = QRect(0, uh, rect->w, lh);
     309                    lh = DisplayScaledAVSubtitles(rect, bbox, false, display,
     310                                                  subtitle.forced,
     311                                                  currentFrame->timecode + displayfor, late);
    342312                }
    343313            }
    344314#ifdef USING_LIBASS
    void SubtitleScreen::DisplayAVSubtitles(void) 
    356326#endif
    357327}
    358328
     329int SubtitleScreen::DisplayScaledAVSubtitles(const AVSubtitleRect *rect, QRect &bbox,
     330                                             bool top, QRect &display, int forced,
     331                                             long long displayuntil, long long late)
     332{
     333    // split image vertically if it spans middle of display
     334    // - split point is empty line nearest the middle
     335    // crop image to reduce scaling time
     336    int xmin, xmax, ymin, ymax;
     337    int ylast, ysplit;
     338    bool prev_empty = false;
     339
     340    // initialize to opposite edges
     341    xmin = bbox.right();
     342    xmax = bbox.left();
     343    ymin = bbox.bottom();
     344    ymax = bbox.top();
     345    ylast = bbox.top();
     346    ysplit = bbox.bottom();
     347
     348    // find bounds of active image
     349    for (int y = bbox.top(); y <= bbox.bottom(); ++y)
     350    {
     351        if (y >= rect->h)
     352        {
     353            // end of image
     354            if (!prev_empty)
     355                ylast = y;
     356            break;
     357        }
     358
     359        bool empty = true;
     360        for (int x = bbox.left(); x <= bbox.right(); ++x)
     361        {
     362            const uint8_t color = rect->pict.data[0][y*rect->pict.linesize[0] + x];
     363            const uint32_t pixel = *((uint32_t *)rect->pict.data[1]+color);
     364            if (pixel & 0xff000000)
     365            {
     366                empty = false;
     367                if (x < xmin)
     368                    xmin = x;
     369                if (x > xmax)
     370                    xmax = x;
     371            }
     372        }
     373
     374        if (!empty)
     375        {
     376            if (y < ymin)
     377                ymin = y;
     378            if (y > ymax)
     379                ymax = y;
     380        }
     381        else if (!prev_empty)
     382        {
     383            // remember uppermost empty line
     384            ylast = y;
     385        }
     386        prev_empty = empty;
     387    }
     388
     389    if (ymax <= ymin)
     390        return 0;
     391
     392    if (top)
     393    {
     394        if (ylast < ymin)
     395            // no empty lines
     396            return 0;
     397
     398        if (ymax == bbox.bottom())
     399        {
     400            ymax = ylast;
     401            ysplit = ylast;
     402        }
     403    }
     404
     405    // set new bounds
     406    bbox.setLeft(xmin);
     407    bbox.setRight(xmax);
     408    bbox.setTop(ymin);
     409    bbox.setBottom(ymax);
     410
     411    // copy active region
     412    // AVSubtitleRect's image data's not guaranteed to be 4 byte
     413    // aligned.
     414
     415    QRect orig_rect(bbox.left(), bbox.top(), bbox.width(), bbox.height());
     416
     417    QImage qImage(bbox.width(), bbox.height(), QImage::Format_ARGB32);
     418    for (int y = 0; y < bbox.height(); ++y)
     419    {
     420        int ysrc = y + bbox.top();
     421        for (int x = 0; x < bbox.width(); ++x)
     422        {
     423            int xsrc = x + bbox.left();
     424            const uint8_t color = rect->pict.data[0][ysrc*rect->pict.linesize[0] + xsrc];
     425            const uint32_t pixel = *((uint32_t *)rect->pict.data[1]+color);
     426            qImage.setPixel(x, y, pixel);
     427        }
     428    }
     429
     430    // translate to absolute coordinates
     431    bbox.translate(rect->x, rect->y);
     432
     433    // scale and move according to zoom factor
     434    bbox.setWidth(bbox.width() * m_textFontZoom/100);
     435    bbox.setHeight(bbox.height() * m_textFontZoom/100);
     436
     437    VideoOutput *videoOut = m_player->GetVideoOutput();
     438    QRect scaled = videoOut->GetImageRect(bbox, &display);
     439
     440    if (scaled.size() != orig_rect.size())
     441        qImage = qImage.scaled(scaled.width(), scaled.height(),
     442                               Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
     443
     444    int hsize = m_safeArea.width();
     445    int vsize = m_safeArea.height();
     446
     447    scaled.moveLeft(((100-m_textFontZoom)*hsize/2 + m_textFontZoom*scaled.left())/100);
     448    if (top)
     449        // anchor up
     450        scaled.moveTop(scaled.top() * m_textFontZoom/100);
     451    else
     452        // anchor down
     453        scaled.moveTop(((100-m_textFontZoom)*vsize + m_textFontZoom*scaled.top())/100);
     454
     455
     456    MythPainter *osd_painter = videoOut->GetOSDPainter();
     457    MythImage* image = NULL;
     458    if (osd_painter)
     459       image = osd_painter->GetFormatImage();
     460
     461    MythUIImage *uiimage = NULL;
     462    if (image)
     463    {
     464        image->Assign(qImage);
     465        QString name = QString("avsub");
     466        uiimage = new MythUIImage(this, name);
     467        if (uiimage)
     468        {
     469            m_refreshArea = true;
     470            uiimage->SetImage(image);
     471            uiimage->SetArea(MythRect(scaled));
     472            m_expireTimes.insert(uiimage, displayuntil);
     473        }
     474    }
     475    if (uiimage)
     476    {
     477        LOG(VB_PLAYBACK, LOG_INFO, LOC +
     478            QString("Display %1AV sub until %1ms")
     479           .arg(forced ? "FORCED " : "")
     480           .arg(displayuntil));
     481        if (late > 50)
     482            LOG(VB_PLAYBACK, LOG_INFO, LOC +
     483                QString("AV Sub was %1ms late").arg(late));
     484    }
     485
     486    return (ysplit+1);
     487}
     488
    359489void SubtitleScreen::DisplayTextSubtitles(void)
    360490{
    361491    if (!m_player || !m_subreader)
  • mythtv/libs/libmythtv/subtitlescreen.h

    diff --git a/mythtv/libs/libmythtv/subtitlescreen.h b/mythtv/libs/libmythtv/subtitlescreen.h
    index 44b3f6a..d25226c 100644
    a b class SubtitleScreen : public MythScreenType 
    5858  private:
    5959    void OptimiseDisplayedArea(void);
    6060    void DisplayAVSubtitles(void);
     61    int  DisplayScaledAVSubtitles(const AVSubtitleRect *rect, QRect &bbox,
     62                                  bool top, QRect &display, int forced,
     63                                  long long displayuntil, long long late);
    6164    void DisplayTextSubtitles(void);
    6265    void DisplayRawTextSubtitles(void);
    6366    void DrawTextSubtitles(QStringList &wrappedsubs, uint64_t start,