354 changes: 204 additions & 150 deletions mythtv/libs/libmythbluray/decoders/graphics_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "util/macro.h"
#include "util/logging.h"
#include "util/mutex.h"

#include "../register.h"
#include "../keys.h"
Expand All @@ -42,6 +43,8 @@ struct graphics_controller_s {

BD_REGISTERS *regs;

BD_MUTEX mutex;

/* overlay output */
void *overlay_proc_handle;
void (*overlay_proc)(void *, const struct bd_overlay_s * const);
Expand All @@ -62,16 +65,128 @@ struct graphics_controller_s {
GRAPHICS_PROCESSOR *igp;
};

GRAPHICS_CONTROLLER *gc_init(BD_REGISTERS *regs, void *handle, gc_overlay_proc_f func)
/*
* object lookup
*/

static BD_PG_OBJECT *_find_object(PG_DISPLAY_SET *s, unsigned object_id)
{
GRAPHICS_CONTROLLER *p = calloc(1, sizeof(*p));
unsigned ii;

p->regs = regs;
for (ii = 0; ii < s->num_object; ii++) {
if (s->object[ii].id == object_id) {
return &s->object[ii];
}
}

p->overlay_proc_handle = handle;
p->overlay_proc = func;
return NULL;
}

return p;
static BD_PG_PALETTE *_find_palette(PG_DISPLAY_SET *s, unsigned palette_id)
{
unsigned ii;

for (ii = 0; ii < s->num_palette; ii++) {
if (s->palette[ii].id == palette_id) {
return &s->palette[ii];
}
}

return NULL;
}

static BD_IG_BUTTON *_find_button_bog(BD_IG_BOG *bog, unsigned button_id)
{
unsigned ii;

for (ii = 0; ii < bog->num_buttons; ii++) {
if (bog->button[ii].id == button_id) {
return &bog->button[ii];
}
}

return NULL;
}

static BD_IG_BUTTON *_find_button_page(BD_IG_PAGE *page, unsigned button_id, unsigned *bog_idx)
{
unsigned ii;

for (ii = 0; ii < page->num_bogs; ii++) {
BD_IG_BUTTON *button = _find_button_bog(&page->bog[ii], button_id);
if (button) {
if (bog_idx) {
*bog_idx = ii;
}
return button;
}
}

return NULL;
}

static BD_IG_PAGE *_find_page(BD_IG_INTERACTIVE_COMPOSITION *c, unsigned page_id)
{
unsigned ii;

for (ii = 0; ii < c->num_pages; ii++) {
if (c->page[ii].id == page_id) {
return &c->page[ii];
}
}

return NULL;
}

enum { BTN_NORMAL, BTN_SELECTED, BTN_ACTIVATED };

static BD_PG_OBJECT *_find_object_for_button(PG_DISPLAY_SET *s,
BD_IG_BUTTON *button, int state)
{
BD_PG_OBJECT *object = NULL;
unsigned object_id = 0xffff;

switch (state) {
case BTN_NORMAL:
object_id = button->normal_start_object_id_ref;
break;
case BTN_SELECTED:
object_id = button->selected_start_object_id_ref;
break;
case BTN_ACTIVATED:
object_id = button->activated_start_object_id_ref;
break;
}

object = _find_object(s, object_id);

return object;
}

/*
* util
*/

static void _reset_enabled_button(GRAPHICS_CONTROLLER *gc)
{
PG_DISPLAY_SET *s = gc->igs;
BD_IG_PAGE *page = NULL;
unsigned page_id = bd_psr_read(gc->regs, PSR_MENU_PAGE_ID);
unsigned ii;

page = _find_page(&s->ics->interactive_composition, page_id);
if (!page) {
ERROR("_reset_enabled_button(): unknown page #%d (have %d pages)\n",
page_id, s->ics->interactive_composition.num_pages);
return;
}

gc->enabled_button = realloc(gc->enabled_button,
page->num_bogs * sizeof(uint16_t));

for (ii = 0; ii < page->num_bogs; ii++) {
gc->enabled_button[ii] = page->bog[ii].default_valid_button_id_ref;
}
}

static void _gc_clear_osd(GRAPHICS_CONTROLLER *gc, int plane)
Expand Down Expand Up @@ -115,6 +230,24 @@ static void _gc_reset(GRAPHICS_CONTROLLER *gc)
X_FREE(gc->enabled_button);
}

/*
* init / free
*/

GRAPHICS_CONTROLLER *gc_init(BD_REGISTERS *regs, void *handle, gc_overlay_proc_f func)
{
GRAPHICS_CONTROLLER *p = calloc(1, sizeof(*p));

p->regs = regs;

p->overlay_proc_handle = handle;
p->overlay_proc = func;

bd_mutex_init(&p->mutex);

return p;
}

void gc_free(GRAPHICS_CONTROLLER **p)
{
if (p && *p) {
Expand All @@ -125,6 +258,8 @@ void gc_free(GRAPHICS_CONTROLLER **p)
(*p)->overlay_proc((*p)->overlay_proc_handle, NULL);
}

bd_mutex_destroy(&(*p)->mutex);

X_FREE(*p);
}
}
Expand All @@ -133,20 +268,27 @@ void gc_free(GRAPHICS_CONTROLLER **p)
* graphics stream input
*/

static void _reset_enabled_button(GRAPHICS_CONTROLLER *gc);

void gc_decode_ts(GRAPHICS_CONTROLLER *gc, uint16_t pid, uint8_t *block, unsigned num_blocks, int64_t stc)
{
if (!gc) {
TRACE("gc_decode_ts(): no graphics controller\n");
return;
}

if (pid >= 0x1400 && pid < 0x1500) {
/* IG stream */

if (!gc->igp) {
gc->igp = graphics_processor_init();
}

bd_mutex_lock(&gc->mutex);

graphics_processor_decode_ts(gc->igp, &gc->igs,
pid, block, num_blocks,
stc);
if (!gc->igs || !gc->igs->complete) {
bd_mutex_unlock(&gc->mutex);
return;
}

Expand All @@ -157,6 +299,8 @@ void gc_decode_ts(GRAPHICS_CONTROLLER *gc, uint16_t pid, uint8_t *block, unsigne

_gc_clear_osd(gc, 1);
_reset_enabled_button(gc);

bd_mutex_unlock(&gc->mutex);
}

else if (pid >= 0x1200 && pid < 0x1300) {
Expand All @@ -174,105 +318,6 @@ void gc_decode_ts(GRAPHICS_CONTROLLER *gc, uint16_t pid, uint8_t *block, unsigne
}
}

/*
* object lookup
*/

static BD_PG_OBJECT *_find_object(PG_DISPLAY_SET *s, unsigned object_id)
{
unsigned ii;

for (ii = 0; ii < s->num_object; ii++) {
if (s->object[ii].id == object_id) {
return &s->object[ii];
}
}

return NULL;
}

static BD_PG_PALETTE *_find_palette(PG_DISPLAY_SET *s, unsigned palette_id)
{
unsigned ii;

for (ii = 0; ii < s->num_palette; ii++) {
if (s->palette[ii].id == palette_id) {
return &s->palette[ii];
}
}

return NULL;
}

static BD_IG_BUTTON *_find_button_bog(BD_IG_BOG *bog, unsigned button_id)
{
unsigned ii;

for (ii = 0; ii < bog->num_buttons; ii++) {
if (bog->button[ii].id == button_id) {
return &bog->button[ii];
}
}

return NULL;
}

static BD_IG_BUTTON *_find_button_page(BD_IG_PAGE *page, unsigned button_id, unsigned *bog_idx)
{
unsigned ii;

for (ii = 0; ii < page->num_bogs; ii++) {
BD_IG_BUTTON *button = _find_button_bog(&page->bog[ii], button_id);
if (button) {
if (bog_idx) {
*bog_idx = ii;
}
return button;
}
}

return NULL;
}

static BD_IG_PAGE *_find_page(BD_IG_INTERACTIVE_COMPOSITION *c, unsigned page_id)
{
unsigned ii;

for (ii = 0; ii < c->num_pages; ii++) {
if (c->page[ii].id == page_id) {
return &c->page[ii];
}
}

return NULL;
}

enum { BTN_NORMAL, BTN_SELECTED, BTN_ACTIVATED };

static BD_PG_OBJECT *_find_object_for_button(PG_DISPLAY_SET *s,
BD_IG_BUTTON *button, int state)
{
BD_PG_OBJECT *object = NULL;
unsigned object_id = 0xffff;

switch (state) {
case BTN_NORMAL:
object_id = button->normal_start_object_id_ref;
break;
case BTN_SELECTED:
object_id = button->selected_start_object_id_ref;
break;
case BTN_ACTIVATED:
object_id = button->activated_start_object_id_ref;
break;
}

object = _find_object(s, object_id);

return object;
}


/*
* IG rendering
*/
Expand Down Expand Up @@ -316,7 +361,7 @@ static void _render_page(GRAPHICS_CONTROLLER *gc,
unsigned ii;
unsigned selected_button_id = bd_psr_read(gc->regs, PSR_SELECTED_BUTTON_ID);

if (s->ics->interactive_composition.ui_model == 1 && !gc->popup_visible) {
if (s->ics->interactive_composition.ui_model == IG_UI_MODEL_POPUP && !gc->popup_visible) {
TRACE("_render_page(): popup menu not visible\n");

_gc_clear_osd(gc, 1);
Expand Down Expand Up @@ -383,7 +428,7 @@ static void _render_page(GRAPHICS_CONTROLLER *gc,
#define VK_IS_NUMERIC(vk) (/*vk >= BD_VK_0 &&*/ vk <= BD_VK_9)
#define VK_IS_CURSOR(vk) (vk >= BD_VK_UP && vk <= BD_VK_RIGHT)

static void _user_input(GRAPHICS_CONTROLLER *gc, bd_vk_key_e key, GC_NAV_CMDS *cmds)
static int _user_input(GRAPHICS_CONTROLLER *gc, bd_vk_key_e key, GC_NAV_CMDS *cmds)
{
PG_DISPLAY_SET *s = gc->igs;
BD_IG_PAGE *page = NULL;
Expand All @@ -393,9 +438,9 @@ static void _user_input(GRAPHICS_CONTROLLER *gc, bd_vk_key_e key, GC_NAV_CMDS *c
unsigned ii;
int activated_btn_id = -1;

if (s->ics->interactive_composition.ui_model == 1 && !gc->popup_visible) {
if (s->ics->interactive_composition.ui_model == IG_UI_MODEL_POPUP && !gc->popup_visible) {
TRACE("_user_input(): popup menu not visible\n");
return;
return -1;
}

TRACE("_user_input(%d)\n", key);
Expand All @@ -404,13 +449,13 @@ static void _user_input(GRAPHICS_CONTROLLER *gc, bd_vk_key_e key, GC_NAV_CMDS *c
if (!page) {
ERROR("_user_input(): unknown page id %d (have %d pages)\n",
page_id, s->ics->interactive_composition.num_pages);
return;
return -1;
}

if (key == BD_VK_MOUSE_ACTIVATE) {
if (!gc->valid_mouse_position) {
TRACE("_user_input(): BD_VK_MOUSE_ACTIVATE outside of valid buttons\n");
return;
return -1;
}
key = BD_VK_ENTER;
}
Expand Down Expand Up @@ -464,29 +509,12 @@ static void _user_input(GRAPHICS_CONTROLLER *gc, bd_vk_key_e key, GC_NAV_CMDS *c
bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, new_btn_id);

_render_page(gc, activated_btn_id, cmds);
}
}

static void _reset_enabled_button(GRAPHICS_CONTROLLER *gc)
{
PG_DISPLAY_SET *s = gc->igs;
BD_IG_PAGE *page = NULL;
unsigned page_id = bd_psr_read(gc->regs, PSR_MENU_PAGE_ID);
unsigned ii;

page = _find_page(&s->ics->interactive_composition, page_id);
if (!page) {
ERROR("_reset_enabled_button(): unknown page #%d (have %d pages)\n",
page_id, s->ics->interactive_composition.num_pages);
return;
/* found one*/
return 1;
}

gc->enabled_button = realloc(gc->enabled_button,
page->num_bogs * sizeof(uint16_t));

for (ii = 0; ii < page->num_bogs; ii++) {
gc->enabled_button[ii] = page->bog[ii].default_valid_button_id_ref;
}
return 0;
}

static void _set_button_page(GRAPHICS_CONTROLLER *gc, uint32_t param, GC_NAV_CMDS *cmds)
Expand Down Expand Up @@ -681,7 +709,7 @@ static void _update_selected_button(GRAPHICS_CONTROLLER *gc)
}
}

static void _mouse_move(GRAPHICS_CONTROLLER *gc, unsigned x, unsigned y, GC_NAV_CMDS *cmds)
static int _mouse_move(GRAPHICS_CONTROLLER *gc, unsigned x, unsigned y, GC_NAV_CMDS *cmds)
{
PG_DISPLAY_SET *s = gc->igs;
BD_IG_PAGE *page = NULL;
Expand All @@ -696,7 +724,7 @@ static void _mouse_move(GRAPHICS_CONTROLLER *gc, unsigned x, unsigned y, GC_NAV_
if (!page) {
ERROR("_mouse_move(): unknown page #%d (have %d pages)\n",
page_id, s->ics->interactive_composition.num_pages);
return;
return -1;
}

for (ii = 0; ii < page->num_bogs; ii++) {
Expand All @@ -718,12 +746,12 @@ static void _mouse_move(GRAPHICS_CONTROLLER *gc, unsigned x, unsigned y, GC_NAV_
if (x >= button->x_pos + object->width || y >= button->y_pos + object->height)
continue;

// mouse is over button
/* mouse is over button */

// is button already selected ?
/* is button already selected? */
if (button->id == cur_btn_id) {
gc->valid_mouse_position = 1;
return;
return 0;
}

new_btn_id = button->id;
Expand All @@ -737,19 +765,42 @@ static void _mouse_move(GRAPHICS_CONTROLLER *gc, unsigned x, unsigned y, GC_NAV_

gc->valid_mouse_position = 1;
}

return gc->valid_mouse_position;
}

void gc_run(GRAPHICS_CONTROLLER *gc, gc_ctrl_e ctrl, uint32_t param, GC_NAV_CMDS *cmds)
int gc_run(GRAPHICS_CONTROLLER *gc, gc_ctrl_e ctrl, uint32_t param, GC_NAV_CMDS *cmds)
{
int result = -1;

if (cmds) {
cmds->num_nav_cmds = 0;
cmds->nav_cmds = NULL;
cmds->sound_id_ref = -1;
}

if (!gc || !gc->igs || !gc->igs->ics) {
ERROR("gc_run(): no interactive composition\n");
return;
if (!gc) {
TRACE("gc_run(): no graphics controller\n");
return result;
}

bd_mutex_lock(&gc->mutex);

/* always accept reset */
switch (ctrl) {
case GC_CTRL_RESET:
_gc_reset(gc);

bd_mutex_unlock(&gc->mutex);
return 0;
default:;
}

/* other operations require complete display set */
if (!gc->igs || !gc->igs->ics || !gc->igs->complete) {
TRACE("gc_run(): no interactive composition\n");
bd_mutex_unlock(&gc->mutex);
return result;
}

switch (ctrl) {
Expand All @@ -760,14 +811,14 @@ void gc_run(GRAPHICS_CONTROLLER *gc, gc_ctrl_e ctrl, uint32_t param, GC_NAV_CMDS

case GC_CTRL_VK_KEY:
if (param != BD_VK_POPUP) {
_user_input(gc, param, cmds);
result = _user_input(gc, param, cmds);
break;
}
param = !gc->popup_visible;
/* fall thru (BD_VK_POPUP) */

case GC_CTRL_POPUP:
if (!gc->igs || !gc->igs->ics || gc->igs->ics->interactive_composition.ui_model != 1) {
if (gc->igs->ics->interactive_composition.ui_model != IG_UI_MODEL_POPUP) {
/* not pop-up menu */
break;
}
Expand All @@ -786,10 +837,6 @@ void gc_run(GRAPHICS_CONTROLLER *gc, gc_ctrl_e ctrl, uint32_t param, GC_NAV_CMDS
_render_page(gc, 0xffff, cmds);
break;

case GC_CTRL_RESET:
_gc_reset(gc);
break;

case GC_CTRL_IG_END:
_update_selected_button(gc);
_render_page(gc, 0xffff, cmds);
Expand All @@ -804,7 +851,14 @@ void gc_run(GRAPHICS_CONTROLLER *gc, gc_ctrl_e ctrl, uint32_t param, GC_NAV_CMDS
break;

case GC_CTRL_MOUSE_MOVE:
_mouse_move(gc, param >> 16, param & 0xffff, cmds);
return;
result = _mouse_move(gc, param >> 16, param & 0xffff, cmds);
break;
case GC_CTRL_RESET:
/* already handled */
break;
}

bd_mutex_unlock(&gc->mutex);

return result;
}
2 changes: 1 addition & 1 deletion mythtv/libs/libmythbluray/decoders/graphics_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ BD_PRIVATE void gc_decode_ts(GRAPHICS_CONTROLLER *p,
* run graphics controller
*/

BD_PRIVATE void gc_run(GRAPHICS_CONTROLLER *p,
BD_PRIVATE int gc_run(GRAPHICS_CONTROLLER *p,
/* in */ gc_ctrl_e msg, uint32_t param,
/* out */ GC_NAV_CMDS *cmds);

Expand Down
3 changes: 3 additions & 0 deletions mythtv/libs/libmythbluray/decoders/ig.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ typedef struct bd_ig_interactive_composition_s {

} BD_IG_INTERACTIVE_COMPOSITION;

#define IG_UI_MODEL_ALWAYS_ON 0
#define IG_UI_MODEL_POPUP 1

/*
* segment
*/
Expand Down