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/mythtv/libs/libmythtv/subtitlescreen.cpp
+++ b/mythtv/libs/libmythtv/subtitlescreen.cpp
@@ -238,6 +238,14 @@ void SubtitleScreen::DisplayAVSubtitles(void)
         if (subtitle.start_display_time > currentFrame->timecode)
             break;
 
+        long long displayfor = subtitle.end_display_time -
+                               subtitle.start_display_time;
+        if (displayfor == 0)
+            displayfor = 60000;
+        displayfor = (displayfor < 50) ? 50 : displayfor;
+        long long late = currentFrame->timecode -
+                         subtitle.start_display_time;
+
         ClearDisplayedSubtitles();
         subs->buffers.pop_front();
         for (std::size_t i = 0; i < subtitle.num_rects; ++i)
@@ -254,11 +262,6 @@ void SubtitleScreen::DisplayAVSubtitles(void)
 
             if (displaysub && rect->type == SUBTITLE_BITMAP)
             {
-                // AVSubtitleRect's image data's not guaranteed to be 4 byte
-                // aligned.
-
-                QSize img_size(rect->w, rect->h);
-                QRect img_rect(rect->x, rect->y, rect->w, rect->h);
                 QRect display(rect->display_x, rect->display_y,
                               rect->display_w, rect->display_h);
 
@@ -269,7 +272,8 @@ void SubtitleScreen::DisplayAVSubtitles(void)
                 int right  = rect->x + rect->w;
                 int bottom = rect->y + rect->h;
                 if (subs->fixPosition || (currentFrame->height < bottom) ||
-                   (currentFrame->width  < right))
+                   (currentFrame->width  < right) ||
+                   !display.width() || !display.height())
                 {
                     int sd_height = 576;
                     if ((m_player->GetFrameRate() > 26.0f) && bottom <= 480)
@@ -285,60 +289,26 @@ void SubtitleScreen::DisplayAVSubtitles(void)
                     display = QRect(0, 0, width, height);
                 }
 
-                QRect scaled = videoOut->GetImageRect(img_rect, &display);
-                QImage qImage(img_size, QImage::Format_ARGB32);
-                for (int y = 0; y < rect->h; ++y)
-                {
-                    for (int x = 0; x < rect->w; ++x)
-                    {
-                        const uint8_t color = rect->pict.data[0][y*rect->pict.linesize[0] + x];
-                        const uint32_t pixel = *((uint32_t*)rect->pict.data[1]+color);
-                        qImage.setPixel(x, y, pixel);
-                    }
-                }
-
-                if (scaled.size() != img_size)
-                {
-                    qImage = qImage.scaled(scaled.width(), scaled.height(),
-                             Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
-                }
-
-                MythPainter *osd_painter = videoOut->GetOSDPainter();
-                MythImage* image = NULL;
-                if (osd_painter)
-                   image = osd_painter->GetFormatImage();
-
-                long long displayfor = subtitle.end_display_time -
-                                       subtitle.start_display_time;
-                if (displayfor == 0)
-                    displayfor = 60000;
-                displayfor = (displayfor < 50) ? 50 : displayfor;
-                long long late = currentFrame->timecode -
-                                 subtitle.start_display_time;
-                MythUIImage *uiimage = NULL;
-                if (image)
+                // split into upper/lower to allow zooming
+                QRect bbox;
+                int uh = display.height()/2 - rect->y;
+                int lh;
+                if (uh > 0)
                 {
-                    image->Assign(qImage);
-                    QString name = QString("avsub%1").arg(i);
-                    uiimage = new MythUIImage(this, name);
-                    if (uiimage)
-                    {
-                        m_refreshArea = true;
-                        uiimage->SetImage(image);
-                        uiimage->SetArea(MythRect(scaled));
-                        m_expireTimes.insert(uiimage,
-                                     currentFrame->timecode + displayfor);
-                    }
+                    bbox = QRect(0, 0, rect->w, uh);
+                    uh = DisplayScaledAVSubtitles(rect, bbox, true, display,
+                                                  subtitle.forced,
+                                                  currentFrame->timecode + displayfor, late);
                 }
-                if (uiimage)
+                else
+                    uh = 0;
+                lh = rect->h - uh;
+                if (lh > 0)
                 {
-                    LOG(VB_PLAYBACK, LOG_INFO, LOC +
-                        QString("Display %1AV subtitle for %2ms")
-                        .arg(subtitle.forced ? "FORCED " : "")
-                        .arg(displayfor));
-                    if (late > 50)
-                        LOG(VB_PLAYBACK, LOG_INFO, LOC +
-                            QString("AV Sub was %1ms late").arg(late));
+                    bbox = QRect(0, uh, rect->w, lh);
+                    lh = DisplayScaledAVSubtitles(rect, bbox, false, display,
+                                                  subtitle.forced,
+                                                  currentFrame->timecode + displayfor, late);
                 }
             }
 #ifdef USING_LIBASS
@@ -356,6 +326,166 @@ void SubtitleScreen::DisplayAVSubtitles(void)
 #endif
 }
 
+int SubtitleScreen::DisplayScaledAVSubtitles(const AVSubtitleRect *rect, QRect &bbox,
+                                             bool top, QRect &display, int forced,
+                                             long long displayuntil, long long late)
+{
+    // split image vertically if it spans middle of display
+    // - split point is empty line nearest the middle
+    // crop image to reduce scaling time
+    int xmin, xmax, ymin, ymax;
+    int ylast, ysplit;
+    bool prev_empty = false;
+
+    // initialize to opposite edges
+    xmin = bbox.right();
+    xmax = bbox.left();
+    ymin = bbox.bottom();
+    ymax = bbox.top();
+    ylast = bbox.top();
+    ysplit = bbox.bottom();
+
+    // find bounds of active image
+    for (int y = bbox.top(); y <= bbox.bottom(); ++y)
+    {
+        if (y >= rect->h)
+        {
+            // end of image
+            if (!prev_empty)
+                ylast = y;
+            break;
+        }
+
+        bool empty = true;
+        for (int x = bbox.left(); x <= bbox.right(); ++x)
+        {
+            const uint8_t color = rect->pict.data[0][y*rect->pict.linesize[0] + x];
+            const uint32_t pixel = *((uint32_t *)rect->pict.data[1]+color);
+            if (pixel & 0xff000000)
+            {
+                empty = false;
+                if (x < xmin)
+                    xmin = x;
+                if (x > xmax)
+                    xmax = x;
+            }
+        }
+
+        if (!empty)
+        {
+            if (y < ymin)
+                ymin = y;
+            if (y > ymax)
+                ymax = y;
+        }
+        else if (!prev_empty)
+        {
+            // remember uppermost empty line
+            ylast = y;
+        }
+        prev_empty = empty;
+    }
+
+    if (ymax <= ymin)
+        return 0;
+
+    if (top)
+    {
+        if (ylast < ymin)
+            // no empty lines
+            return 0;
+
+        if (ymax == bbox.bottom())
+        {
+            ymax = ylast;
+            ysplit = ylast;
+        }
+    }
+
+    // set new bounds
+    bbox.setLeft(xmin);
+    bbox.setRight(xmax);
+    bbox.setTop(ymin);
+    bbox.setBottom(ymax);
+
+    // copy active region
+    // AVSubtitleRect's image data's not guaranteed to be 4 byte
+    // aligned.
+
+    QRect orig_rect(bbox.left(), bbox.top(), bbox.width(), bbox.height());
+
+    QImage qImage(bbox.width(), bbox.height(), QImage::Format_ARGB32);
+    for (int y = 0; y < bbox.height(); ++y)
+    {
+        int ysrc = y + bbox.top();
+        for (int x = 0; x < bbox.width(); ++x)
+        {
+            int xsrc = x + bbox.left();
+            const uint8_t color = rect->pict.data[0][ysrc*rect->pict.linesize[0] + xsrc];
+            const uint32_t pixel = *((uint32_t *)rect->pict.data[1]+color);
+            qImage.setPixel(x, y, pixel);
+        }
+    }
+
+    // translate to absolute coordinates
+    bbox.translate(rect->x, rect->y);
+
+    // scale and move according to zoom factor
+    bbox.setWidth(bbox.width() * m_textFontZoom/100);
+    bbox.setHeight(bbox.height() * m_textFontZoom/100);
+
+    VideoOutput *videoOut = m_player->GetVideoOutput();
+    QRect scaled = videoOut->GetImageRect(bbox, &display);
+
+    if (scaled.size() != orig_rect.size())
+        qImage = qImage.scaled(scaled.width(), scaled.height(),
+                               Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+
+    int hsize = m_safeArea.width();
+    int vsize = m_safeArea.height();
+
+    scaled.moveLeft(((100-m_textFontZoom)*hsize/2 + m_textFontZoom*scaled.left())/100);
+    if (top)
+        // anchor up
+        scaled.moveTop(scaled.top() * m_textFontZoom/100);
+    else
+        // anchor down
+        scaled.moveTop(((100-m_textFontZoom)*vsize + m_textFontZoom*scaled.top())/100);
+
+
+    MythPainter *osd_painter = videoOut->GetOSDPainter();
+    MythImage* image = NULL;
+    if (osd_painter)
+       image = osd_painter->GetFormatImage();
+
+    MythUIImage *uiimage = NULL;
+    if (image)
+    {
+        image->Assign(qImage);
+        QString name = QString("avsub");
+        uiimage = new MythUIImage(this, name);
+        if (uiimage)
+        {
+            m_refreshArea = true;
+            uiimage->SetImage(image);
+            uiimage->SetArea(MythRect(scaled));
+            m_expireTimes.insert(uiimage, displayuntil);
+        }
+    }
+    if (uiimage)
+    {
+        LOG(VB_PLAYBACK, LOG_INFO, LOC +
+            QString("Display %1AV sub until %1ms")
+           .arg(forced ? "FORCED " : "")
+           .arg(displayuntil));
+        if (late > 50)
+            LOG(VB_PLAYBACK, LOG_INFO, LOC +
+                QString("AV Sub was %1ms late").arg(late));
+    }
+
+    return (ysplit+1);
+}
+
 void SubtitleScreen::DisplayTextSubtitles(void)
 {
     if (!m_player || !m_subreader)
diff --git a/mythtv/libs/libmythtv/subtitlescreen.h b/mythtv/libs/libmythtv/subtitlescreen.h
index 44b3f6a..d25226c 100644
--- a/mythtv/libs/libmythtv/subtitlescreen.h
+++ b/mythtv/libs/libmythtv/subtitlescreen.h
@@ -58,6 +58,9 @@ class SubtitleScreen : public MythScreenType
   private:
     void OptimiseDisplayedArea(void);
     void DisplayAVSubtitles(void);
+    int  DisplayScaledAVSubtitles(const AVSubtitleRect *rect, QRect &bbox,
+                                  bool top, QRect &display, int forced,
+                                  long long displayuntil, long long late);
     void DisplayTextSubtitles(void);
     void DisplayRawTextSubtitles(void);
     void DrawTextSubtitles(QStringList &wrappedsubs, uint64_t start,
