[bluray] Initial support for menu's, no BD-J supported
authorelupus <elupus@xbmc.org>
Sat, 8 Oct 2011 13:18:49 +0000 (15:18 +0200)
committerelupus <elupus@xbmc.org>
Tue, 10 Apr 2012 22:06:23 +0000 (00:06 +0200)
Code will fall back to longest item if there is not first play
hdmv item. However it will still try menu's if there is only
some unnsupported BD-J titles. This could possible fail to
play if it switches into BD-J mode later in menu's.

Starting index.bdmv will still only play longest title,
to attempt playback with menu's, start the MovieObject.bdmv

lib/DllLibbluray.h
xbmc/cores/dvdplayer/DVDInputStreams/DVDFactoryInputStream.cpp
xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.cpp
xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamBluray.h
xbmc/cores/dvdplayer/DVDPlayer.cpp

index 30307ca..5111c53 100644 (file)
@@ -30,6 +30,8 @@ extern "C"
 #include <libbluray/bluray.h>
 #include <libbluray/filesystem.h>
 #include <libbluray/log_control.h>
+#include <libbluray/keys.h>
+#include <libbluray/overlay.h>
 }
 
 class DllLibblurayInterface
@@ -65,6 +67,16 @@ public:
   virtual void     bd_set_debug_mask(uint32_t mask)=0;
   virtual uint32_t bd_get_debug_mask(void)=0;
   virtual const BLURAY_DISC_INFO *bd_get_disc_info(BLURAY *bd)=0;
+
+  virtual int      bd_get_event                 (BLURAY *bd, BD_EVENT *event)=0;
+  virtual int      bd_play                      (BLURAY *bd)=0;
+  virtual int      bd_read_ext                  (BLURAY *bd, unsigned char *buf, int len, BD_EVENT *event)=0;
+  virtual int      bd_read_skip_still           (BLURAY *bd)=0;
+  virtual int      bd_user_input                (BLURAY *bd, int64_t pts, uint32_t key)=0;
+  virtual int      bd_set_player_setting        (BLURAY *bd, uint32_t idx, uint32_t value)=0;
+  virtual int      bd_set_player_setting_str    (BLURAY *bd, uint32_t idx, const char *s)=0;
+  virtual void     bd_register_overlay_proc     (BLURAY *bd, void *handle, bd_overlay_proc_f func)=0;
+  virtual int      bd_menu_call                 (BLURAY *bd, int64_t pts)=0;
 };
 
 class DllLibbluray : public DllDynamic, DllLibblurayInterface
@@ -100,6 +112,16 @@ class DllLibbluray : public DllDynamic, DllLibblurayInterface
   DEFINE_METHOD0(uint32_t,            bd_get_debug_mask)
   DEFINE_METHOD1(const BLURAY_DISC_INFO*, bd_get_disc_info,      (BLURAY *p1))
 
+  DEFINE_METHOD2(int,                 bd_get_event,              (BLURAY *p1, BD_EVENT *p2))
+  DEFINE_METHOD1(int,                 bd_play,                   (BLURAY *p1))
+  DEFINE_METHOD4(int,                 bd_read_ext,               (BLURAY *p1, unsigned char *p2, int p3, BD_EVENT *p4))
+  DEFINE_METHOD1(int,                 bd_read_skip_still,        (BLURAY *p1))
+  DEFINE_METHOD3(int,                 bd_user_input,             (BLURAY *p1, int64_t p2, uint32_t p3))
+  DEFINE_METHOD3(int,                 bd_set_player_setting,     (BLURAY *p1, uint32_t p2, uint32_t p3))
+  DEFINE_METHOD3(int,                 bd_set_player_setting_str, (BLURAY *p1, uint32_t p2, const char *p3))
+  DEFINE_METHOD3(void,                bd_register_overlay_proc,  (BLURAY *p1, void *p2, bd_overlay_proc_f p3))
+  DEFINE_METHOD2(int,                 bd_menu_call,              (BLURAY *p1, int64_t p2))
+
   BEGIN_METHOD_RESOLVE()
     RESOLVE_METHOD(bd_get_titles)
     RESOLVE_METHOD(bd_get_title_info)
@@ -129,6 +151,16 @@ class DllLibbluray : public DllDynamic, DllLibblurayInterface
     RESOLVE_METHOD(bd_set_debug_mask)
     RESOLVE_METHOD(bd_get_debug_mask)
     RESOLVE_METHOD(bd_get_disc_info)
+
+    RESOLVE_METHOD(bd_get_event)
+    RESOLVE_METHOD(bd_play)
+    RESOLVE_METHOD(bd_read_ext)
+    RESOLVE_METHOD(bd_read_skip_still)
+    RESOLVE_METHOD(bd_user_input)
+    RESOLVE_METHOD(bd_set_player_setting)
+    RESOLVE_METHOD(bd_set_player_setting_str)
+    RESOLVE_METHOD(bd_register_overlay_proc)
+    RESOLVE_METHOD(bd_menu_call)
   END_METHOD_RESOLVE()
 
 public:
index e4e7065..1fe8ae1 100644 (file)
@@ -54,7 +54,7 @@ CDVDInputStream* CDVDFactoryInputStream::CreateInputStream(IDVDPlayer* pPlayer,
   }
 #ifdef HAVE_LIBBLURAY
   else if (item.IsType(".bdmv") || item.IsType(".mpls") || content == "bluray/iso")
-    return new CDVDInputStreamBluray();
+    return new CDVDInputStreamBluray(pPlayer);
 #endif
   else if(file.substr(0, 6) == "rtp://"
        || file.substr(0, 7) == "rtsp://"
index 41e7818..ce871e4 100644 (file)
 #ifdef HAVE_LIBBLURAY
 
 #include "DVDInputStreamBluray.h"
+#include "IDVDPlayer.h"
+#include "DVDCodecs/Overlay/DVDOverlay.h"
+#include "DVDCodecs/Overlay/DVDOverlayImage.h"
+#include "settings/GUISettings.h"
+#include "LangInfo.h"
 #include "utils/log.h"
 #include "utils/URIUtils.h"
 #include "filesystem/File.h"
@@ -195,10 +200,17 @@ void DllLibbluray::bluray_logger(const char* msg)
   CLog::Log(LOGDEBUG, "CDVDInputStreamBluray::Logger - %s", msg);
 }
 
-CDVDInputStreamBluray::CDVDInputStreamBluray() :
+
+static void bluray_overlay_cb(void *this_gen, const BD_OVERLAY * ov)
+{
+  static_cast<CDVDInputStreamBluray*>(this_gen)->OverlayCallback(ov);
+}
+
+CDVDInputStreamBluray::CDVDInputStreamBluray(IDVDPlayer* player) :
   CDVDInputStream(DVDSTREAM_TYPE_BLURAY)
 {
   m_title = NULL;
+  m_clip  = 0;
   m_bd    = NULL;
   m_dll = new DllLibbluray;
   if (!m_dll->Load())
@@ -206,6 +218,8 @@ CDVDInputStreamBluray::CDVDInputStreamBluray() :
     delete m_dll;
     m_dll = NULL;
   }
+  m_content = "video/x-mpegts";
+  m_player  = player;
 }
 
 CDVDInputStreamBluray::~CDVDInputStreamBluray()
@@ -250,33 +264,15 @@ BLURAY_TITLE_INFO* CDVDInputStreamBluray::GetTitleFile(const std::string& filena
     return NULL;
   }
 
-  int titles = m_dll->bd_get_titles(m_bd, TITLES_ALL, 0);
-  if(titles < 0)
-  {
-    CLog::Log(LOGERROR, "get_playlist_title - unable to get list of titles");
-    return NULL;
-  }
-
-  BLURAY_TITLE_INFO *t;
-  for(int i=0; i < titles; i++)
-  {
-    t = m_dll->bd_get_title_info(m_bd, i, 0);
-    if(!t)
-    {
-      CLog::Log(LOGDEBUG, "get_playlist_title - unable to get title %d", i);
-      continue;
-    }
-    if(t->playlist == playlist)
-      return t;
-    m_dll->bd_free_title_info(t);
-  }
-
-  return NULL;
+  return m_dll->bd_get_playlist_info(m_bd, playlist, 0);
 }
 
 
 bool CDVDInputStreamBluray::Open(const char* strFile, const std::string& content)
 {
+  if(m_player == NULL)
+    return false;
+
   CStdString strPath;
   URIUtils::GetDirectory(strFile,strPath);
   URIUtils::RemoveSlashAtEnd(strPath);
@@ -299,7 +295,7 @@ bool CDVDInputStreamBluray::Open(const char* strFile, const std::string& content
   m_dll->bd_register_dir(DllLibbluray::dir_open);
   m_dll->bd_register_file(DllLibbluray::file_open);
   m_dll->bd_set_debug_handler(DllLibbluray::bluray_logger);
-  m_dll->bd_set_debug_mask(DBG_CRIT);
+  m_dll->bd_set_debug_mask(DBG_CRIT | DBG_BLURAY | DBG_NAV);
 
   CLog::Log(LOGDEBUG, "CDVDInputStreamBluray::Open - opening %s", strPath.c_str());
   m_bd = m_dll->bd_open(strPath.c_str(), NULL);
@@ -353,28 +349,76 @@ bool CDVDInputStreamBluray::Open(const char* strFile, const std::string& content
   CStdString filename = URIUtils::GetFileName(strFile);
   if(filename.Equals("index.bdmv"))
   {
+    m_navmode = false;
     m_title = GetTitleLongest();
   }
   else if(URIUtils::GetExtension(filename).Equals(".mpls"))
   {
+    m_navmode = false;
     m_title = GetTitleFile(filename);
   }
+  else if(filename.Equals("MovieObject.bdmv"))
+  {
+    m_navmode = true;
+    if (m_navmode && !disc_info->first_play_supported) {
+      CLog::Log(LOGERROR, "CDVDInputStreamBluray::Open - Can't play disc in HDMV navigation mode - First Play title not supported");
+      m_navmode = false;
+    }
+
+    if (m_navmode && disc_info->num_unsupported_titles > 0) {
+      CLog::Log(LOGERROR, "CDVDInputStreamBluray::Open - Unsupported titles found - Some titles can't be played in navigation mode");
+    }
+
+    if(!m_navmode)
+      m_title = GetTitleLongest();
+  }
   else
   {
     CLog::Log(LOGERROR, "CDVDInputStreamBluray::Open - unsupported bluray file selected %s", strPath.c_str());
     return false;
   }
 
-  if(!m_title)
+  if(m_navmode)
   {
-    CLog::Log(LOGERROR, "CDVDInputStreamBluray::Open - failed to get title info");
-    return false;
-  }
+    int region = g_guiSettings.GetInt("dvds.playerregion");
+    if(region == 0)
+    {
+      CLog::Log(LOGWARNING, "CDVDInputStreamBluray::Open - region dvd must be set in setting, assuming region 1");
+      region = 1;
+    }
+    m_dll->bd_set_player_setting    (m_bd, BLURAY_PLAYER_SETTING_REGION_CODE,  region);
+    m_dll->bd_set_player_setting    (m_bd, BLURAY_PLAYER_SETTING_PARENTAL,     0);
+    m_dll->bd_set_player_setting    (m_bd, BLURAY_PLAYER_SETTING_PLAYER_PROFILE, 0);
+    m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_AUDIO_LANG,   g_langInfo.GetDVDAudioLanguage().c_str());
+    m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_PG_LANG,      g_langInfo.GetDVDSubtitleLanguage().c_str());
+    m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_MENU_LANG,    g_langInfo.GetDVDMenuLanguage().c_str());
+    m_dll->bd_set_player_setting_str(m_bd, BLURAY_PLAYER_SETTING_COUNTRY_CODE, "us");
+    m_dll->bd_register_overlay_proc (m_bd, this, bluray_overlay_cb);
+
+    m_dll->bd_get_event(m_bd, NULL);
+
 
-  if(m_dll->bd_select_title(m_bd, m_title->idx) == 0 )
+    if(m_dll->bd_play(m_bd) <= 0)
+    {
+      CLog::Log(LOGERROR, "CDVDInputStreamBluray::Open - failed play disk %s", strPath.c_str());
+      return false;
+    }
+    m_hold = HOLD_DATA;
+    m_title_playing = false;
+  }
+  else
   {
-    CLog::Log(LOGERROR, "CDVDInputStreamBluray::Open - failed to select title %d", m_title->idx);
-    return false;
+    if(!m_title)
+    {
+      CLog::Log(LOGERROR, "CDVDInputStreamBluray::Open - failed to get title info");
+      return false;
+    }
+
+    if(m_dll->bd_select_playlist(m_bd, m_title->playlist) == 0 )
+    {
+      CLog::Log(LOGERROR, "CDVDInputStreamBluray::Open - failed to select title %d", m_title->idx);
+      return false;
+    }
   }
 
   return true;
@@ -385,17 +429,324 @@ void CDVDInputStreamBluray::Close()
 {
   if (!m_dll)
     return;
+  if(m_title)
+    m_dll->bd_free_title_info(m_title);
   if(m_bd)
+  {
+    m_dll->bd_register_overlay_proc(m_bd, NULL, NULL);
     m_dll->bd_close(m_bd);
+  }
   m_bd = NULL;
-  if(m_title)
-    m_dll->bd_free_title_info(m_title);
   m_title = NULL;
 }
 
 int CDVDInputStreamBluray::Read(BYTE* buf, int buf_size)
 {
-  return m_dll->bd_read(m_bd, buf, buf_size);
+  if(m_navmode)
+  {
+    int result = 0;
+    do {
+
+      if(m_hold == HOLD_HELD)
+        return 0;
+
+      if(m_hold == HOLD_SKIP)
+      {
+        /* m_event already holds data */
+        m_hold = HOLD_DATA;
+        result = 0;
+      }
+      else
+      {
+        result = m_dll->bd_read_ext (m_bd, buf, buf_size, &m_event);
+
+        if(m_hold == HOLD_NONE)
+        {
+          /* Check for holding events */
+          switch(m_event.event) {
+            case BD_EVENT_SEEK:
+            case BD_EVENT_TITLE:
+              if(m_title_playing)
+                m_player->OnDVDNavResult(NULL, 1);
+              m_hold = HOLD_HELD;
+              return result;
+
+            case BD_EVENT_PLAYLIST:
+            case BD_EVENT_PLAYITEM:
+              m_hold = HOLD_HELD;
+              return result;
+            default:
+              break;
+          }
+        }
+        if(result > 0)
+          m_hold = HOLD_NONE;
+      }
+      int pid = -1;
+      switch (m_event.event) {
+
+        case BD_EVENT_ERROR:
+          CLog::Log(LOGERROR, "CDVDInputStreamBluray - BD_EVENT_ERROR");
+          return -1;
+
+        case BD_EVENT_ENCRYPTED:
+          CLog::Log(LOGERROR, "CDVDInputStreamBluray - BD_EVENT_ENCRYPTED");
+          return -1;
+
+        /* playback control */
+
+        case BD_EVENT_SEEK:
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_SEEK");
+          break;
+
+        case BD_EVENT_STILL_TIME:
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_STILL_TIME %d", m_event.param);
+          return 0;
+
+        case BD_EVENT_STILL:
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_STILL %d", m_event.param);
+          break;
+
+        /* playback position */
+
+        case BD_EVENT_ANGLE:
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_ANGLE %d", m_event.param);
+          break;
+
+        case BD_EVENT_END_OF_TITLE:
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_END_OF_TITLE %d", m_event.param);
+          m_title_playing = false;
+          break;
+
+        case BD_EVENT_TITLE:
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_TITLE %d", m_event.param);
+          if(m_title)
+            m_dll->bd_free_title_info(m_title);
+          m_title = m_dll->bd_get_title_info(m_bd, m_event.param, 0);
+          m_title_playing = true;
+          break;
+
+        case BD_EVENT_PLAYLIST:
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_PLAYLIST %d", m_event.param);
+          if(m_title)
+            m_dll->bd_free_title_info(m_title);
+          m_title = m_dll->bd_get_playlist_info(m_bd, m_event.param, 0);
+          break;
+
+        case BD_EVENT_PLAYITEM:
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_PLAYITEM %d", m_event.param);
+          m_clip = m_event.param;
+          break;
+
+        case BD_EVENT_CHAPTER:
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_CHAPTER %d", m_event.param);
+          break;
+
+        /* stream selection */
+
+        case BD_EVENT_AUDIO_STREAM:
+          pid = -1;
+          if(m_title
+          && m_title->clip_count > m_clip
+          && m_title->clips[m_clip].audio_stream_count > (uint8_t)(m_event.param - 1))
+            pid = m_title->clips[m_clip].audio_streams[m_event.param-1].pid;
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_AUDIO_STREAM %d %d", m_event.param, pid);
+          m_player->OnDVDNavResult((void*)&pid, 2);
+          break;
+
+        case BD_EVENT_PG_TEXTST:
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_PG_TEXTST %d", m_event.param);
+          pid = m_event.param;
+          m_player->OnDVDNavResult((void*)&pid, 4);
+          break;
+
+        case BD_EVENT_PG_TEXTST_STREAM:
+          pid = -1;
+          if(m_title
+          && m_title->clip_count > m_clip
+          && m_title->clips[m_clip].pg_stream_count > (uint8_t)(m_event.param - 1))
+            pid = m_title->clips[m_clip].pg_streams[m_event.param-1].pid;
+          CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - BD_EVENT_PG_TEXTST_STREAM %d, %d", m_event.param, pid);
+          m_player->OnDVDNavResult((void*)&pid, 3);
+          break;
+
+        case BD_EVENT_IG_STREAM:
+        case BD_EVENT_SECONDARY_AUDIO:
+        case BD_EVENT_SECONDARY_AUDIO_STREAM:
+        case BD_EVENT_SECONDARY_VIDEO:
+        case BD_EVENT_SECONDARY_VIDEO_SIZE:
+        case BD_EVENT_SECONDARY_VIDEO_STREAM:
+
+        case BD_EVENT_NONE:
+          break;
+
+        default:
+          CLog::Log(LOGWARNING, "CDVDInputStreamBluray - unhandled libbluray event %d [param %d]", m_event.event, m_event.param);
+          break;
+      }
+
+    } while(result == 0);
+
+    return result;
+  }
+  else
+    return m_dll->bd_read(m_bd, buf, buf_size);
+}
+
+static uint8_t  clamp(double v)
+{
+  return (v) > 255.0 ? 255 : ((v) < 0.0 ? 0 : (uint8_t)(v+0.5f));
+}
+
+static uint32_t build_rgba(const BD_PG_PALETTE_ENTRY &e)
+{
+  double r = 1.164 * (e.Y - 16)                        + 1.596 * (e.Cr - 128);
+  double g = 1.164 * (e.Y - 16) - 0.391 * (e.Cb - 128) - 0.813 * (e.Cr - 128);
+  double b = 1.164 * (e.Y - 16) + 2.018 * (e.Cb - 128);
+  return (uint32_t)e.T      << PIXEL_ASHIFT
+       | (uint32_t)clamp(r) << PIXEL_RSHIFT
+       | (uint32_t)clamp(g) << PIXEL_GSHIFT
+       | (uint32_t)clamp(b) << PIXEL_BSHIFT;
+}
+
+void CDVDInputStreamBluray::OverlayCallback(const BD_OVERLAY * const ov)
+{
+
+  CDVDOverlayGroup* group   = new CDVDOverlayGroup();
+  group->bForced = true;
+
+  if(ov == NULL)
+  {
+    for(unsigned i = 0; i < 2; ++i)
+    {
+      for(std::vector<CDVDOverlayImage*>::iterator it = m_overlays[i].begin(); it != m_overlays[i].end(); ++it)
+        (*it)->Release();
+      m_overlays[i].clear();
+    }
+
+    m_player->OnDVDNavResult(group, 0);
+    return;
+  }
+
+  group->iPTSStartTime = ov->pts;
+  group->iPTSStopTime  = 0;
+
+  if (ov->plane > 1)
+  {
+    CLog::Log(LOGWARNING, "CDVDInputStreamBluray - Ignoring overlay with multiple planes");
+    group->Release();
+    return;
+  }
+
+  std::vector<CDVDOverlayImage*>& plane(m_overlays[ov->plane]);
+
+  /* fixup existing overlays */
+  for(std::vector<CDVDOverlayImage*>::iterator it = plane.begin(); it != plane.end();)
+  {
+    /* if it's fully outside we are done */
+    if(ov->x + ov->w <= (*it)->x
+    || ov->x         >= (*it)->x + (*it)->width
+    || ov->y + ov->h <= (*it)->y
+    || ov->y         >= (*it)->y + (*it)->height)
+    {
+      ++it;
+      continue;
+    }
+
+    int y1 = std::max<int>((*it)->y                , ov->y);
+    int y2 = std::min<int>((*it)->y + (*it)->height, ov->y + ov->h);
+    int x1 = std::max<int>((*it)->x                , ov->x);
+    int x2 = std::min<int>((*it)->x + (*it)->width , ov->x + ov->w);
+
+    /* if all should be cleared, delete */
+    if(x1 == (*it)->x
+    && x2 == (*it)->x + (*it)->width
+    && y1 == (*it)->y
+    && y2 == (*it)->y + (*it)->height)
+    {
+      CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - Delete(%d) %d-%dx%d-%d", ov->plane, x1, x2, y1, y2);
+      it = plane.erase(it);
+      continue;
+    }
+#if(1)
+    CLog::Log(LOGDEBUG, "CDVDInputStreamBluray - Clearing(%d) %d-%dx%d-%d", ov->plane, x1, x2, y1, y2);
+
+    /* replace overlay with a new copy*/
+    CDVDOverlayImage* overlay = new CDVDOverlayImage(*(*it));
+    (*it)->Release();
+    (*it) = overlay;
+
+    /* any old hw overlay must be released */
+    SAFE_RELEASE(overlay->m_overlay);
+
+    /* clear out overlap */
+    y1 -= overlay->y;
+    y2 -= overlay->y;
+    x1 -= overlay->x;
+    x2 -= overlay->x;
+
+    /* find fully transparent */
+    int transp = 0;
+    for(; transp < overlay->palette_colors; ++transp)
+    {
+      if(((overlay->palette[transp] >> PIXEL_ASHIFT) & 0xff) == 0)
+        break;
+    }
+
+    if(transp == overlay->palette_colors)
+    {
+      CLog::Log(LOGERROR, "CDVDInputStreamBluray - failed to find transparent color");
+      continue;
+    }
+
+    for(int y = y1; y < y2; ++y)
+    {
+      BYTE* line = overlay->data + y * overlay->linesize;
+      for(int x = x1; x < x2; ++x)
+        line[x] = transp;
+    }
+    ++it;
+#endif
+  }
+
+
+  /* uncompress and draw bitmap */
+  if (ov->img)
+  {
+    CDVDOverlayImage* overlay = new CDVDOverlayImage();
+
+    if (ov->palette)
+    {
+      overlay->palette_colors = 256;
+      overlay->palette        = (uint32_t*)calloc(overlay->palette_colors, 4);
+
+      for(unsigned i = 0; i < 256; i++)
+        overlay->palette[i] = build_rgba(ov->palette[i]);
+    }
+
+    const BD_PG_RLE_ELEM *rlep = ov->img;
+    uint8_t *img = (uint8_t*) malloc(ov->w * ov->h);
+    unsigned pixels = ov->w * ov->h;
+
+    for (unsigned i = 0; i < pixels; i += rlep->len, rlep++) {
+      memset(img + i, rlep->color, rlep->len);
+    }
+
+    overlay->data     = img;
+    overlay->linesize = ov->w;
+    overlay->x        = ov->x;
+    overlay->y        = ov->y;
+    overlay->height   = ov->h;
+    overlay->width    = ov->w;
+    plane.push_back(overlay);
+  }
+
+  for(unsigned i = 0; i < 2; ++i)
+  {
+    for(std::vector<CDVDOverlayImage*>::iterator it = m_overlays[i].begin(); it != m_overlays[i].end(); ++it)
+      group->m_overlays.push_back((*it)->Acquire());
+  }
+  m_player->OnDVDNavResult(group, 0);
 }
 
 int CDVDInputStreamBluray::GetTotalTime()
@@ -499,10 +850,10 @@ static bool find_stream(int pid, BLURAY_STREAM_INFO *info, int count, char* lang
 
 void CDVDInputStreamBluray::GetStreamInfo(int pid, char* language)
 {
-  if(m_title->clip_count == 0)
+  if(!m_title || m_clip >= m_title->clip_count)
     return;
 
-  BLURAY_CLIP_INFO *clip = m_title->clips;
+  BLURAY_CLIP_INFO *clip = m_title->clips+m_clip;
 
   if(find_stream(pid, clip->audio_streams, clip->audio_stream_count, language))
     return;
@@ -514,4 +865,56 @@ void CDVDInputStreamBluray::GetStreamInfo(int pid, char* language)
     return;
 }
 
+CDVDInputStream::ENextStream CDVDInputStreamBluray::NextStream()
+{
+  if(!m_navmode)
+    return NEXTSTREAM_NONE;
+
+  if(m_hold == HOLD_HELD)
+  {
+    m_hold = HOLD_SKIP;
+    return NEXTSTREAM_OPEN;
+  }
+  if(m_hold == HOLD_NONE)
+  {
+    m_hold = HOLD_DATA;
+    m_dll->bd_read_skip_still(m_bd);
+  }
+  return NEXTSTREAM_RETRY;
+}
+
+void CDVDInputStreamBluray::UserInput(bd_vk_key_e vk)
+{
+  if(m_bd == NULL || !m_navmode)
+    return;
+  m_dll->bd_user_input(m_bd, -1, vk);
+}
+
+void CDVDInputStreamBluray::OnMenu()
+{
+  if(m_bd == NULL || !m_navmode)
+    return;
+
+  if(m_dll->bd_user_input(m_bd, -1, BD_VK_POPUP) >= 0)
+    return;
+  CLog::Log(LOGDEBUG, "CDVDInputStreamBluray::OnMenu - popup failed, trying root");
+
+  if(m_dll->bd_user_input(m_bd, -1, BD_VK_ROOT_MENU) >= 0)
+    return;
+
+  CLog::Log(LOGDEBUG, "CDVDInputStreamBluray::OnMenu - root failed, trying explicit");
+  if(m_dll->bd_menu_call(m_bd, -1) >= 0)
+    return;
+  CLog::Log(LOGDEBUG, "CDVDInputStreamBluray::OnMenu - root failed");
+}
+
+bool CDVDInputStreamBluray::IsInMenu()
+{
+  if(m_bd == NULL || !m_navmode)
+    return false;
+  if(m_overlays[BD_OVERLAY_IG].size() > 0)
+    return true;
+  return false;
+}
+
 #endif
index 1d11ea2..dc0ffa9 100644 (file)
 
 #include "DVDInputStream.h"
 
+
+extern "C"
+{
+#include <libbluray/bluray.h>
+#include <libbluray/keys.h>
+#include <libbluray/overlay.h>
+}
+
+class CDVDOverlayImage;
 class DllLibbluray;
-typedef struct bluray BLURAY;
-typedef struct bd_title_info BLURAY_TITLE_INFO;
+class IDVDPlayer;
 
 class CDVDInputStreamBluray 
   : public CDVDInputStream
   , public CDVDInputStream::IDisplayTime
   , public CDVDInputStream::IChapter
   , public CDVDInputStream::ISeekTime
+  , public CDVDInputStream::IMenus
 {
 public:
-  CDVDInputStreamBluray();
+  CDVDInputStreamBluray(IDVDPlayer* player);
   virtual ~CDVDInputStreamBluray();
   virtual bool Open(const char* strFile, const std::string &content);
   virtual void Close();
@@ -44,6 +53,36 @@ public:
   virtual bool IsEOF();
   virtual __int64 GetLength();
   virtual int GetBlockSize() { return 6144; }
+  virtual ENextStream NextStream();
+
+
+  /* IMenus */
+  virtual void ActivateButton()          { UserInput(BD_VK_ENTER); }
+  virtual void SelectButton(int iButton)
+  {
+    if(iButton < 10)
+      UserInput((bd_vk_key_e)(BD_VK_0 + iButton));
+  }
+  virtual int  GetCurrentButton()        { return 0; }
+  virtual int  GetTotalButtons()         { return 0; }
+  virtual void OnUp()                    { UserInput(BD_VK_UP); }
+  virtual void OnDown()                  { UserInput(BD_VK_DOWN); }
+  virtual void OnLeft()                  { UserInput(BD_VK_LEFT); }
+  virtual void OnRight()                 { UserInput(BD_VK_RIGHT); }
+  virtual void OnMenu();
+  virtual void OnBack()
+  {
+    if(IsInMenu())
+      OnMenu();
+  }
+  virtual void OnNext()                  {}
+  virtual void OnPrevious()              {}
+  virtual bool IsInMenu();
+  virtual bool OnMouseMove(const CPoint &point)  { return false; }
+  virtual bool OnMouseClick(const CPoint &point) { return false; }
+  virtual double GetTimeStampCorrection()        { return 0.0; }
+
+  void UserInput(bd_vk_key_e vk);
 
   int GetChapter();
   int GetChapterCount();
@@ -56,11 +95,25 @@ public:
 
   void GetStreamInfo(int pid, char* language);
 
+  void OverlayCallback(const BD_OVERLAY * const);
+
   BLURAY_TITLE_INFO* GetTitleLongest();
   BLURAY_TITLE_INFO* GetTitleFile(const std::string& name);
 
 protected:
+  IDVDPlayer*   m_player;
   DllLibbluray *m_dll;
   BLURAY* m_bd;
   BLURAY_TITLE_INFO* m_title;
+  bool               m_title_playing;
+  uint32_t           m_clip;
+  bool m_navmode;
+  std::vector<CDVDOverlayImage*> m_overlays[2];
+  enum EHoldState {
+    HOLD_NONE = 0,
+    HOLD_HELD,
+    HOLD_SKIP,
+    HOLD_DATA,
+  } m_hold;
+  BD_EVENT m_event;
 };
index 19beafa..9c9fbac 100644 (file)
@@ -855,7 +855,8 @@ bool CDVDPlayer::IsBetterStream(CCurrentStream& current, CDemuxStream* stream)
   if(m_PlayerOptions.video_only && current.type != STREAM_VIDEO)
     return false;
 
-  if (m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
+  if (m_pInputStream && ( m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)
+                       || m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY) ) )
   {
     int source_type;
 
@@ -3064,6 +3065,22 @@ void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate)
 // since we call ffmpeg functions to decode, this is being called in the same thread as ::Process() is
 int CDVDPlayer::OnDVDNavResult(void* pData, int iMessage)
 {
+  if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_BLURAY))
+  {
+    if(iMessage == 0)
+      m_overlayContainer.Add((CDVDOverlay*)pData);
+    else if(iMessage == 1)
+      m_messenger.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH));
+    else if(iMessage == 2)
+      m_dvd.iSelectedAudioStream = *(int*)pData;
+    else if(iMessage == 3)
+      m_dvd.iSelectedSPUStream   = *(int*)pData;
+    else if(iMessage == 4)
+      m_dvdPlayerVideo.EnableSubtitle(*(int*)pData ? true: false);
+
+    return 0;
+  }
+
   if (m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD))
   {
     CDVDInputStreamNavigator* pStream = (CDVDInputStreamNavigator*)m_pInputStream;