Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Subtitles: Allow scaling and smart layout of AV subtitles (DVD/BD).

Fixes #10402.  Note that at present, playback always starts out with a
zoom factor of 100% for AV subtitles, and the zoom factor is not saved
back to the database.

Signed-off-by: Jim Stichnoth <jstichnoth@mythtv.org>
  • Loading branch information...
commit 461f42d14324221e3a94fe84a6ae759e62569e6f 1 parent d418754
@ggervasio ggervasio authored stichnot committed
View
255 mythtv/libs/libmythtv/subtitlescreen.cpp
@@ -750,6 +750,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)
@@ -766,11 +774,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);
@@ -781,7 +784,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)
@@ -797,60 +801,29 @@ 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;
+ long long displayuntil = currentFrame->timecode + displayfor;
+ 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,
+ QString("avsub%1t").arg(i),
+ displayuntil, 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,
+ QString("avsub%1b").arg(i),
+ displayuntil, late);
}
}
#ifdef USING_LIBASS
@@ -868,6 +841,174 @@ void SubtitleScreen::DisplayAVSubtitles(void)
#endif
}
+int SubtitleScreen::DisplayScaledAVSubtitles(const AVSubtitleRect *rect,
+ QRect &bbox, bool top,
+ QRect &display, int forced,
+ QString imagename,
+ 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);
+ uiimage = new MythUIImage(this, imagename);
+ 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 %2ms")
+ .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)
View
4 mythtv/libs/libmythtv/subtitlescreen.h
@@ -65,6 +65,10 @@ class SubtitleScreen : public MythScreenType
private:
void OptimiseDisplayedArea(void);
void DisplayAVSubtitles(void);
+ int DisplayScaledAVSubtitles(const AVSubtitleRect *rect, QRect &bbox,
+ bool top, QRect &display, int forced,
+ QString imagename,
+ long long displayuntil, long long late);
void DisplayTextSubtitles(void);
void DisplayRawTextSubtitles(void);
void DrawTextSubtitles(QStringList &wrappedsubs, uint64_t start,

0 comments on commit 461f42d

Please sign in to comment.
Something went wrong with that request. Please try again.