Skip to content
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
Mark Kendall
Mark Kendall committed Jan 18, 2011
1 parent d1e7906 commit ed2ba06c5f5758a407632d044a9814a6624a5d78
@@ -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);
}
@@ -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
@@ -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;
@@ -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;
@@ -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
@@ -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)
@@ -34,8 +34,6 @@ class MythBDPlayer : public MythPlayer

private:
void DisplayMenu(void);

bool m_inMenu;
};

#endif // MYTHBDPLAYER_H
@@ -1275,7 +1275,6 @@ void MythPlayer::ResetCaptions(void)
(textDisplayMode & kDisplayTextSubtitle) ||
(textDisplayMode & kDisplayRawTextSubtitle) ||
(textDisplayMode & kDisplayDVDButton) ||
(textDisplayMode & kDisplayBDOverlay) ||
(textDisplayMode & kDisplayCC608) ||
(textDisplayMode & kDisplayCC708)))
{
@@ -76,7 +76,6 @@ enum
kDisplayTextSubtitle = 0x020,
kDisplayDVDButton = 0x040,
kDisplayRawTextSubtitle = 0x080,
kDisplayBDOverlay = 0x0ff,
kDisplayAllCaptions = 0x100,
kDisplayTeletextMenu = 0x200,
};

0 comments on commit ed2ba06

Please sign in to comment.
You can’t perform that action at this time.