Skip to content
Permalink
Browse files

Add bluray OSD menu support (HDMV only).

There are a number of outstanding issues:-

- the RLE decoding of certain images is still not quite correct, so
there are a few image errors.
- certain OSD optimisations are disabled for the menus due to the way we
receive the images (individually rather than as a set).
- there is currently no mechanism for removing duplicate images. So
until a reset is triggered by the bd object, some menus are continually
overpainted with the same, duplicated image.
  • Loading branch information
Mark Kendall
Mark Kendall committed Jan 15, 2011
1 parent 3526655 commit 5479b3af7afa85b23ac41ab4c986e75919c9b220
@@ -24,66 +24,14 @@ static void HandleOverlayCallback(
void *data, const bd_overlay_s * const overlay)
{
BDRingBuffer *bdrb = (BDRingBuffer*) data;

if (!bdrb)
return;

if (!overlay || overlay->plane == 1)
bdrb->m_inMenu = false;

if (!overlay || !overlay->img)
return;

bdrb->m_inMenu = true;

const BD_PG_RLE_ELEM *rlep = overlay->img;

uint8_t *yuvimg = (uint8_t*)malloc(overlay->w * overlay->h);
unsigned pixels = overlay->w * overlay->h;

for (unsigned i = 0; i < pixels; i += rlep->len, rlep++)
{
memset(yuvimg + i, rlep->color, rlep->len);
}

QImage qoverlay(yuvimg, overlay->w, overlay->h, QImage::Format_Indexed8);

uint32_t *origpalette = (uint32_t *)(overlay->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);
}

qoverlay.setColorTable(palette);
qoverlay.save(QString("%1/bluray.menuimg.%2.%3.jpg").arg(QDir::home().path()).arg(overlay->w).arg(overlay->h));

VERBOSE(VB_PLAYBACK|VB_EXTRA, QString("In Menu Callback, ready to draw "
"an overlay of %1x%2 at %3,%4 (%5 pixels).")
.arg(overlay->w).arg(overlay->h).arg(overlay->x)
.arg(overlay->y).arg(pixels));

if (overlay->plane == 1)
bdrb->m_inMenu = true;
if (bdrb)
bdrb->SubmitOverlay(overlay);
}

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_ignorePlayerWait(true), m_overlayCleared(false)
{
OpenFile(lfilename);
}
@@ -102,6 +50,8 @@ void BDRingBuffer::close(void)
bd_close(bdnav);
bdnav = NULL;
}

ClearOverlays();
}

long long BDRingBuffer::Seek(long long pos, int whence, bool has_lock)
@@ -839,3 +789,78 @@ bool BDRingBuffer::StartFromBeginning(void)
return true;
}

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* BDRingBuffer::GetOverlay(void)
{
QMutexLocker lock(&m_overlayLock);
if (!m_overlayImages.isEmpty())
return m_overlayImages.takeFirst();
return NULL;
}

void BDRingBuffer::SubmitOverlay(const bd_overlay_s * const overlay)
{
QMutexLocker lock(&m_overlayLock);

if (!overlay || overlay->plane == 1)
m_inMenu = false;

if (!overlay || !overlay->img)
{
VERBOSE(VB_PLAYBACK, LOC + "Null overlay submitted.");
OverlayCleared(true);
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;

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 actual = overlay->w * overlay->h;
uint8_t *data = (uint8_t*)malloc(pixels);
uint8_t *palette = (uint8_t*)malloc(palettesize);
memset(data, 0, pixels);

int line = 0;
int this_line = 0;
for (unsigned i = 0; i < actual; i += rlep->len, rlep++)
{
if ((rlep->color == 0 && rlep->len == 0) || this_line >= overlay->w)
{
this_line = 0;
line++;
i = (line * width) + 1;
}
else
{
this_line += rlep->len;
memset(data + i, rlep->color, rlep->len);
}
}

memcpy(palette, overlay->palette, palettesize);

QRect pos(overlay->x, overlay->y, width, overlay->h);
m_overlayImages.append(new BDOverlay(data, palette, pos));

if (overlay->plane == 1)
m_inMenu = true;
}
@@ -4,6 +4,7 @@
#define BD_BLOCK_SIZE 6144LL

#include <QString>
#include <QRect>

#include "libmythbluray/bluray.h"
#include "libmythbluray/keys.h"
@@ -17,6 +18,17 @@
* A class to allow a RingBuffer to read from BDs.
*/

class BDOverlay
{
public:
BDOverlay(uint8_t *data, uint8_t *palette, QRect position)
: m_data(data), m_palette(palette), m_position(position) { }

uint8_t *m_data;
uint8_t *m_palette;
QRect m_position;
};

class MPUBLIC BDRingBuffer : public RingBuffer
{
public:
@@ -29,6 +41,13 @@ class MPUBLIC BDRingBuffer : public RingBuffer
void IgnoreWaitStates(bool ignore) { m_ignorePlayerWait = ignore; }
bool StartFromBeginning(void);

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; }
int GetCurrentTitle(void) const;
uint64_t GetCurrentAngle(void) const { return m_currentAngle; }
@@ -116,6 +135,10 @@ class MPUBLIC BDRingBuffer : public RingBuffer
bool m_playerWait;
bool m_ignorePlayerWait;

QMutex m_overlayLock;
QList<BDOverlay*> m_overlayImages;
bool m_overlayCleared;

public:
uint8_t m_still;
volatile bool m_inMenu;
@@ -4,10 +4,46 @@
#define LOC QString("BDPlayer: ")
#define LOC_ERR QString("BDPlayer error: ")

MythBDPlayer::MythBDPlayer(bool muted) : MythPlayer(muted)
MythBDPlayer::MythBDPlayer(bool muted) : MythPlayer(muted), m_inMenu(false)
{
}

void MythBDPlayer::PreProcessNormalFrame(void)
{
DisplayMenu();
}

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);
}

BDOverlay *overlay = NULL;
while (NULL != (overlay = player_ctx->buffer->BD()->GetOverlay()))
{
m_inMenu = true;
osd->DisplayBDOverlay(overlay);
}
}

bool MythBDPlayer::VideoLoop(void)
{
if (!player_ctx->buffer->IsBD())
@@ -29,6 +29,12 @@ class MythBDPlayer : public MythPlayer
protected:
// Playback
virtual bool VideoLoop(void);
virtual void PreProcessNormalFrame(void);

private:
void DisplayMenu(void);

bool m_inMenu;
};

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

class DecoderThread : public QThread
@@ -17,6 +17,7 @@
#include "mythuistatetype.h"

// libmythtv
#include "bdringbuffer.h"
#include "channelutil.h"
#include "teletextscreen.h"
#include "subtitlescreen.h"
@@ -1147,3 +1148,15 @@ void OSD::DisplayDVDButton(AVSubtitle* dvdButton, QRect &pos)
sub->DisplayDVDButton(dvdButton, 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);
}
}
@@ -27,6 +27,7 @@ class MythPlayer;
class TeletextScreen;
class SubtitleScreen;
struct AVSubtitle;
class BDOverlay;

enum OSDFunctionalType
{
@@ -173,6 +174,7 @@ class OSD
void EnableSubtitles(int type);
void ClearSubtitles(void);
void DisplayDVDButton(AVSubtitle* dvdButton, QRect &pos);
void DisplayBDOverlay(BDOverlay *overlay);

private:
void TearDown(void);
@@ -7,6 +7,7 @@
#include "mythuiimage.h"
#include "mythpainter.h"
#include "subtitlescreen.h"
#include "bdringbuffer.h"

#define LOC QString("Subtitles: ")
#define LOC_WARN QString("Subtitles Warning: ")
@@ -550,6 +551,59 @@ 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] =

0 comments on commit 5479b3a

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