Permalink
Browse files

Re-visit the bluray menu OSD

- Move the overlay into its own UI/OSD screen. The bluray menus are not
captions and need separate treatment - the popup menu is, for example,
displayed over the current video stream and hence potentially over
subtitles.
- Clear overlay images that are submitted but already displayed (based
upon size and position) and replace them with the new version.
- Clear the overlay when a NULL image is presented (not NULL overlay)
and use the associated size to prepare the overlay.
- Add some sense checking and memory alignment/allocation fixes in the
callback function.

All told this appears to give far more reliable and consistent results,
though the menu does seem to go missing under certain circumstances.

There is also a strange performance problem when using VDPAU (this was
happening before as well).
  • Loading branch information...
1 parent d1e7906 commit ed2ba06c5f5758a407632d044a9814a6624a5d78 Mark Kendall committed Jan 18, 2011
View
128 mythtv/libs/libmythtv/bdoverlayscreen.cpp
@@ -0,0 +1,128 @@
+#include <QPainter>
+
+#include "mythuiimage.h"
+#include "mythpainter.h"
+
+#include "bdringbuffer.h"
+#include "bdoverlayscreen.h"
+
+#define LOC QString("BDScreen: ")
+#define ERR QString("BDScreen Error: ")
+
+BDOverlayScreen::BDOverlayScreen(MythPlayer *player, const QString &name)
+ : MythScreenType((MythScreenType*)NULL, name),
+ m_player(player), m_overlayArea(QRect())
+{
+}
+
+BDOverlayScreen::~BDOverlayScreen()
+{
+ VERBOSE(VB_PLAYBACK, LOC + "dtor");
+ m_overlayMap.clear();
+}
+
+void BDOverlayScreen::DisplayBDOverlay(BDOverlay *overlay)
+{
+ if (!overlay || !m_player)
+ return;
+
+ if (!overlay->m_data)
+ {
+ m_overlayArea = overlay->m_position;
+ SetArea(MythRect(m_overlayArea));
+ DeleteAllChildren();
+ m_overlayMap.clear();
+ SetRedraw();
+ VERBOSE(VB_PLAYBACK, LOC +
+ QString("Initialised Size: %1x%2 (%3+%4) Plane: %5 Pts: %6")
+ .arg(overlay->m_position.width())
+ .arg(overlay->m_position.height())
+ .arg(overlay->m_position.left())
+ .arg(overlay->m_position.top())
+ .arg(overlay->m_plane)
+ .arg(overlay->m_pts));
+ BDOverlay::DeleteOverlay(overlay);
+ return;
+ }
+
+ if (!m_overlayArea.isValid())
+ {
+ VERBOSE(VB_IMPORTANT, ERR + "Error: Overlay image submitted "
+ "before initialisation.");
+ }
+
+ VideoOutput *vo = m_player->getVideoOutput();
+ if (!vo)
+ return;
+
+ QRect rect = overlay->m_position;
+ QString hash = QString("%1+%2+%3x%4")
+ .arg(rect.left()).arg(rect.top())
+ .arg(rect.width()).arg(rect.height());
+
+ // remove if we already have this overlay
+ if (m_overlayMap.contains(hash))
+ {
+ VERBOSE(VB_PLAYBACK|VB_EXTRA, LOC + QString("Removing %1 (%2 left)")
+ .arg(hash).arg(m_overlayMap.size()));
+ MythUIImage *old = m_overlayMap.take(hash);
+ DeleteChild(old);
+ }
+
+ // convert the overlay palette to ARGB
+ uint32_t *origpalette = (uint32_t *)(overlay->m_palette);
+ QVector<unsigned int> palette;
+ for (int i = 0; i < 256; i++)
+ {
+ int y = (origpalette[i] >> 0) & 0xff;
+ int cr = (origpalette[i] >> 8) & 0xff;
+ int cb = (origpalette[i] >> 16) & 0xff;
+ int a = (origpalette[i] >> 24) & 0xff;
+ int r = int(y + 1.4022 * (cr - 128));
+ int b = int(y + 1.7710 * (cb - 128));
+ int g = int(1.7047 * y - (0.1952 * b) - (0.5647 * r));
+ if (r < 0) r = 0;
+ if (g < 0) g = 0;
+ if (b < 0) b = 0;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ palette.push_back((a << 24) | (r << 16) | (g << 8) | b);
+ }
+
+ // convert the image to QImage
+ QImage img(rect.size(), QImage::Format_Indexed8);
+ memcpy(img.bits(), overlay->m_data, rect.width() * rect.height());
+ img.setColorTable(palette);
+ img.convertToFormat(QImage::Format_ARGB32);
+
+ // add to screen
+ QRect scaled = vo->GetImageRect(rect);
+ if (scaled.size() != rect.size())
+ {
+ img = img.scaled(scaled.width(), scaled.height(),
+ Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ }
+
+ MythPainter *osd_painter = vo->GetOSDPainter();
+ MythImage* image = NULL;
+ if (osd_painter)
+ image = osd_painter->GetFormatImage();
+
+ if (image)
+ {
+ image->Assign(img);
+ MythUIImage *uiimage = new MythUIImage(this, "bdoverlay");
+ if (uiimage)
+ {
+ uiimage->SetImage(image);
+ uiimage->SetArea(MythRect(scaled));
+ m_overlayMap.insert(hash, uiimage);
+ VERBOSE(VB_PLAYBACK|VB_EXTRA, LOC + QString("Added %1 (%2 tot)")
+ .arg(hash).arg(m_overlayMap.size()));
+ }
+ }
+
+ SetRedraw();
+ BDOverlay::DeleteOverlay(overlay);
+}
View
23 mythtv/libs/libmythtv/bdoverlayscreen.h
@@ -0,0 +1,23 @@
+#ifndef BDOVERLAYSCREEN_H
+#define BDOVERLAYSCREEN_H
+
+#include "mythscreentype.h"
+#include "mythplayer.h"
+
+class BDOverlay;
+
+class BDOverlayScreen : public MythScreenType
+{
+ public:
+ BDOverlayScreen(MythPlayer *player, const QString &name);
+ ~BDOverlayScreen();
+
+ void DisplayBDOverlay(BDOverlay *overlay);
+
+ private:
+ MythPlayer *m_player;
+ QRect m_overlayArea;
+ QMap<QString,MythUIImage*> m_overlayMap;
+};
+
+#endif // BDOVERLAYSCREEN_H
View
52 mythtv/libs/libmythtv/bdringbuffer.cpp
@@ -20,8 +20,7 @@
#define LOC_WARN QString("BDRingBuf(%1) Warning: ").arg(filename)
#define LOC_ERR QString("BDRingBuf(%1) Error: ").arg(filename)
-static void HandleOverlayCallback(
- void *data, const bd_overlay_s * const overlay)
+static void HandleOverlayCallback(void *data, const bd_overlay_s *const overlay)
{
BDRingBuffer *bdrb = (BDRingBuffer*) data;
if (bdrb)
@@ -31,7 +30,7 @@ static void HandleOverlayCallback(
BDRingBuffer::BDRingBuffer(const QString &lfilename)
: bdnav(NULL), m_is_hdmv_navigation(false),
m_numTitles(0), m_titleChanged(false), m_playerWait(false),
- m_ignorePlayerWait(true), m_overlayCleared(false)
+ m_ignorePlayerWait(true)
{
OpenFile(lfilename);
}
@@ -267,7 +266,7 @@ bool BDRingBuffer::OpenFile(const QString &lfilename, uint retry_ms)
m_still = 0;
m_inMenu = false;
-#if 0
+#if 1
// First, attempt to initialize the disc in HDMV navigation mode.
// If this fails, fall back to the traditional built-in title switching
// mode.
@@ -794,13 +793,7 @@ void BDRingBuffer::ClearOverlays(void)
QMutexLocker lock(&m_overlayLock);
while (!m_overlayImages.isEmpty())
- {
- BDOverlay *img = m_overlayImages.takeFirst();
- delete img->m_data;
- delete img->m_palette;
- delete img;
- }
- OverlayCleared(false);
+ BDOverlay::DeleteOverlay(m_overlayImages.takeFirst());
}
BDOverlay* BDRingBuffer::GetOverlay(void)
@@ -815,29 +808,37 @@ void BDRingBuffer::SubmitOverlay(const bd_overlay_s * const overlay)
{
QMutexLocker lock(&m_overlayLock);
- if (!overlay || overlay->plane == 1)
- m_inMenu = false;
+ if (!overlay)
+ return;
- if (!overlay || !overlay->img)
+ if ((overlay->w <= 0) || (overlay->w > 1920) ||
+ (overlay->x < 0) || (overlay->x > 1920) ||
+ (overlay->h <= 0) || (overlay->h > 1080) ||
+ (overlay->y < 0) || (overlay->y > 1080))
{
- VERBOSE(VB_PLAYBACK, LOC + "Null overlay submitted.");
- OverlayCleared(true);
+ VERBOSE(VB_IMPORTANT, LOC_ERR +
+ QString("Invalid overlay size: %1x%2+%3+%4")
+ .arg(overlay->w).arg(overlay->h).arg(overlay->x).arg(overlay->y));
return;
}
- VERBOSE(VB_PLAYBACK, LOC + QString("New overlay image %1x%2 %3+%4")
- .arg(overlay->w).arg(overlay->h)
- .arg(overlay->x).arg(overlay->y));
- m_inMenu = true;
+ if (!overlay->img)
+ {
+ m_inMenu = false;
+ QRect pos(overlay->x, overlay->y, overlay->w, overlay->h);
+ m_overlayImages.append(new BDOverlay(NULL, NULL, pos,
+ overlay->plane, overlay->pts));
+ return;
+ }
const BD_PG_RLE_ELEM *rlep = overlay->img;
static const unsigned palettesize = 256 * 4;
unsigned width = (overlay->w + 0x3) & (~0x3);
- unsigned pixels = width * overlay->h;
+ unsigned pixels = ((overlay->w + 0xf) & (~0xf)) *
+ ((overlay->h + 0xf) & (~0xf));
unsigned actual = overlay->w * overlay->h;
- uint8_t *data = (uint8_t*)malloc(pixels);
- uint8_t *palette = (uint8_t*)malloc(palettesize);
- memset(data, 0, pixels);
+ uint8_t *data = (uint8_t*)av_mallocz(pixels);
+ uint8_t *palette = (uint8_t*)av_mallocz(palettesize);
int line = 0;
int this_line = 0;
@@ -859,7 +860,8 @@ void BDRingBuffer::SubmitOverlay(const bd_overlay_s * const overlay)
memcpy(palette, overlay->palette, palettesize);
QRect pos(overlay->x, overlay->y, width, overlay->h);
- m_overlayImages.append(new BDOverlay(data, palette, pos));
+ m_overlayImages.append(new BDOverlay(data, palette, pos,
+ overlay->plane, overlay->pts));
if (overlay->plane == 1)
m_inMenu = true;
View
23 mythtv/libs/libmythtv/bdringbuffer.h
@@ -21,12 +21,28 @@
class BDOverlay
{
public:
- BDOverlay(uint8_t *data, uint8_t *palette, QRect position)
- : m_data(data), m_palette(palette), m_position(position) { }
+ static void DeleteOverlay(BDOverlay *overlay)
+ {
+ if (!overlay)
+ return;
+ if (overlay->m_data)
+ av_free(overlay->m_data);
+ if (overlay->m_palette)
+ av_free(overlay->m_palette);
+ delete overlay;
+ overlay = NULL;
+ }
+
+ BDOverlay(uint8_t *data, uint8_t *palette, QRect position, int plane,
+ int64_t pts)
+ : m_data(data), m_palette(palette), m_position(position),
+ m_plane(plane), m_pts(pts) { }
uint8_t *m_data;
uint8_t *m_palette;
QRect m_position;
+ int m_plane;
+ int64_t m_pts;
};
class MPUBLIC BDRingBuffer : public RingBuffer
@@ -44,8 +60,6 @@ class MPUBLIC BDRingBuffer : public RingBuffer
void ClearOverlays(void);
BDOverlay* GetOverlay(void);
void SubmitOverlay(const bd_overlay_s * const overlay);
- bool OverlayCleared(void) { return m_overlayCleared; }
- void OverlayCleared(bool cleared) { m_overlayCleared = cleared; }
uint32_t GetNumTitles(void) const { return m_numTitles; }
@@ -137,7 +151,6 @@ class MPUBLIC BDRingBuffer : public RingBuffer
QMutex m_overlayLock;
QList<BDOverlay*> m_overlayImages;
- bool m_overlayCleared;
public:
uint8_t m_still;
View
2 mythtv/libs/libmythtv/libmythtv.pro
@@ -295,8 +295,10 @@ using_frontend {
# On screen display (video output overlay)
HEADERS += osd.h teletextscreen.h
HEADERS += subtitlescreen.h interactivescreen.h
+ HEADERS += bdoverlayscreen.h
SOURCES += osd.cpp teletextscreen.cpp
SOURCES += subtitlescreen.cpp interactivescreen.cpp
+ SOURCES += bdoverlayscreen.cpp
# Video output
HEADERS += videooutbase.h videoout_null.h
View
25 mythtv/libs/libmythtv/mythbdplayer.cpp
@@ -4,7 +4,7 @@
#define LOC QString("BDPlayer: ")
#define LOC_ERR QString("BDPlayer error: ")
-MythBDPlayer::MythBDPlayer(bool muted) : MythPlayer(muted), m_inMenu(false)
+MythBDPlayer::MythBDPlayer(bool muted) : MythPlayer(muted)
{
}
@@ -31,30 +31,11 @@ void MythBDPlayer::DisplayMenu(void)
if (!player_ctx->buffer->IsBD())
return;
- if (!player_ctx->buffer->BD()->IsInMenu())
- {
- if (m_inMenu)
- {
- m_inMenu = false;
- player_ctx->buffer->BD()->ClearOverlays();
- SetCaptionsEnabled(false, false);
- osd->ClearSubtitles();
- }
- return;
- }
-
- if (player_ctx->buffer->BD()->OverlayCleared())
- {
- osd->ClearSubtitles();
- player_ctx->buffer->BD()->OverlayCleared(false);
- }
-
+ osdLock.lock();
BDOverlay *overlay = NULL;
while (NULL != (overlay = player_ctx->buffer->BD()->GetOverlay()))
- {
- m_inMenu = true;
osd->DisplayBDOverlay(overlay);
- }
+ osdLock.unlock();
}
bool MythBDPlayer::VideoLoop(void)
View
2 mythtv/libs/libmythtv/mythbdplayer.h
@@ -34,8 +34,6 @@ class MythBDPlayer : public MythPlayer
private:
void DisplayMenu(void);
-
- bool m_inMenu;
};
#endif // MYTHBDPLAYER_H
View
1 mythtv/libs/libmythtv/mythplayer.cpp
@@ -1275,7 +1275,6 @@ void MythPlayer::ResetCaptions(void)
(textDisplayMode & kDisplayTextSubtitle) ||
(textDisplayMode & kDisplayRawTextSubtitle) ||
(textDisplayMode & kDisplayDVDButton) ||
- (textDisplayMode & kDisplayBDOverlay) ||
(textDisplayMode & kDisplayCC608) ||
(textDisplayMode & kDisplayCC708)))
{
View
1 mythtv/libs/libmythtv/mythplayer.h
@@ -76,7 +76,6 @@ enum
kDisplayTextSubtitle = 0x020,
kDisplayDVDButton = 0x040,
kDisplayRawTextSubtitle = 0x080,
- kDisplayBDOverlay = 0x0ff,
kDisplayAllCaptions = 0x100,
kDisplayTeletextMenu = 0x200,
};
View
25 mythtv/libs/libmythtv/osd.cpp
@@ -22,6 +22,7 @@
#include "teletextscreen.h"
#include "subtitlescreen.h"
#include "interactivescreen.h"
+#include "bdoverlayscreen.h"
#include "osd.h"
#define LOC QString("OSD: ")
@@ -789,6 +790,11 @@ MythScreenType *OSD::GetWindow(const QString &window)
InteractiveScreen *screen = new InteractiveScreen(m_parent, window);
new_window = (MythScreenType*) screen;
}
+ else if (window == OSD_WIN_BDOVERLAY)
+ {
+ BDOverlayScreen *screen = new BDOverlayScreen(m_parent, window);
+ new_window = (MythScreenType*) screen;
+ }
else
{
MythOSDWindow *screen = new MythOSDWindow(NULL, window, false);
@@ -1141,8 +1147,11 @@ void OSD::ClearSubtitles(void)
void OSD::DisplayDVDButton(AVSubtitle* dvdButton, QRect &pos)
{
+ if (!dvdButton)
+ return;
+
SubtitleScreen* sub = InitSubtitles();
- if (sub && dvdButton)
+ if (sub)
{
EnableSubtitles(kDisplayDVDButton);
sub->DisplayDVDButton(dvdButton, pos);
@@ -1151,12 +1160,10 @@ void OSD::DisplayDVDButton(AVSubtitle* dvdButton, QRect &pos)
void OSD::DisplayBDOverlay(BDOverlay* overlay)
{
- SubtitleScreen* sub = InitSubtitles();
- if (sub && overlay)
- {
- // this ensures we don't delete existing items
- if (sub->EnabledSubtitleType() != kDisplayBDOverlay)
- EnableSubtitles(kDisplayBDOverlay);
- sub->DisplayBDOverlay(overlay);
- }
+ if (!overlay)
+ return;
+
+ BDOverlayScreen* bd = (BDOverlayScreen*)GetWindow(OSD_WIN_BDOVERLAY);
+ if (bd)
+ bd->DisplayBDOverlay(overlay);
}
View
5 mythtv/libs/libmythtv/osd.h
@@ -20,6 +20,7 @@ using namespace std;
#define OSD_WIN_TELETEXT "OSD_TELETEXT"
#define OSD_WIN_SUBTITLE "OSD_SUBTITLES"
#define OSD_WIN_INTERACT "OSD_INTERACTIVE"
+#define OSD_WIN_BDOVERLAY "OSD_BDOVERLAY"
#define kOSDFadeTime 1000
@@ -139,6 +140,7 @@ class OSD
bool HasWindow(const QString &window);
void ResetWindow(const QString &window);
void PositionWindow(MythScreenType *window);
+ void RemoveWindow(const QString &window);
bool DrawDirect(MythPainter* painter, QSize size, bool repaint = false);
QRegion Draw(MythPainter* painter, QPaintDevice *device, QSize size,
@@ -174,12 +176,13 @@ class OSD
void EnableSubtitles(int type);
void ClearSubtitles(void);
void DisplayDVDButton(AVSubtitle* dvdButton, QRect &pos);
+
void DisplayBDOverlay(BDOverlay *overlay);
private:
void TearDown(void);
void LoadWindows(void);
- void RemoveWindow(const QString &window);
+
void CheckExpiry(void);
void SendHideEvent(void);
View
53 mythtv/libs/libmythtv/subtitlescreen.cpp
@@ -551,59 +551,6 @@ void SubtitleScreen::DisplayDVDButton(AVSubtitle* dvdButton, QRect &buttonPos)
AddScaledImage(fg_image, button);
}
-void SubtitleScreen::DisplayBDOverlay(BDOverlay *overlay)
-{
- if (!overlay || !m_player)
- return;
-
- VideoOutput *vo = m_player->getVideoOutput();
- if (!vo)
- return;
-
- // set the screen area
- float tmp = 0.0;
- QRect dummy;
- vo->GetOSDBounds(dummy, m_safeArea, tmp, tmp, tmp);
-
- // convert the palette to ARGB
- uint32_t *origpalette = (uint32_t *)(overlay->m_palette);
- QVector<unsigned int> palette;
- for (int i = 0; i < 256; i++)
- {
- int y = (origpalette[i] >> 0) & 0xff;
- int cr = (origpalette[i] >> 8) & 0xff;
- int cb = (origpalette[i] >> 16) & 0xff;
- int a = (origpalette[i] >> 24) & 0xff;
- int r = int(y + 1.4022 * (cr - 128));
- int b = int(y + 1.7710 * (cb - 128));
- int g = int(1.7047 * y - (0.1952 * b) - (0.5647 * r));
- if (r < 0) r = 0;
- if (g < 0) g = 0;
- if (b < 0) b = 0;
- if (r > 0xff) r = 0xff;
- if (g > 0xff) g = 0xff;
- if (b > 0xff) b = 0xff;
- palette.push_back((a << 24) | (r << 16) | (g << 8) | b);
- }
-
- // convert the image to QImage
- QImage img(overlay->m_position.size(), QImage::Format_Indexed8);
- memcpy(img.bits(), overlay->m_data,
- overlay->m_position.width() * overlay->m_position.height());
- img.setColorTable(palette);
- QImage converted = img.convertToFormat(QImage::Format_ARGB32);
-
- // add to screen
- AddScaledImage(converted, overlay->m_position);
- SetRedraw();
- m_refreshArea = false; // N.B. this disables some optimisations
-
- // release the overlay
- delete overlay->m_data;
- delete overlay->m_palette;
- delete overlay;
-}
-
void SubtitleScreen::DisplayCC608Subtitles(void)
{
static const QColor clr[8] =
View
1 mythtv/libs/libmythtv/subtitlescreen.h
@@ -24,7 +24,6 @@ class SubtitleScreen : public MythScreenType
void ClearDisplayedSubtitles(void);
void ExpireSubtitles(void);
void DisplayDVDButton(AVSubtitle* dvdButton, QRect &buttonPos);
- void DisplayBDOverlay(BDOverlay* overlay);
// MythScreenType methods
virtual bool Create(void);
View
2 mythtv/libs/libmythtv/tv_play.cpp
@@ -3903,7 +3903,7 @@ bool TV::DiscMenuHandleAction(PlayerContext *ctx, const QStringList &actions)
return true;
}
- if (!bdrb->IsInDiscMenuOrStillFrame())
+ if (!bdrb->IsInMenu())
return false;
handled = true;

0 comments on commit ed2ba06

Please sign in to comment.