Blame player_wrappers/xine/input_bluray.c

Packit 5e46da
/*
Packit 5e46da
 * Copyright (C) 2000-2005 the xine project
Packit 5e46da
 *
Packit 5e46da
 * Copyright (C) 2009-2013 Petri Hintukainen <phintuka@users.sourceforge.net>
Packit 5e46da
 *
Packit 5e46da
 * This file is part of xine, a free video player.
Packit 5e46da
 *
Packit 5e46da
 * xine is free software; you can redistribute it and/or modify
Packit 5e46da
 * it under the terms of the GNU General Public License as published by
Packit 5e46da
 * the Free Software Foundation; either version 2 of the License, or
Packit 5e46da
 * (at your option) any later version.
Packit 5e46da
 *
Packit 5e46da
 * xine is distributed in the hope that it will be useful,
Packit 5e46da
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5e46da
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 5e46da
 * GNU General Public License for more details.
Packit 5e46da
 *
Packit 5e46da
 * You should have received a copy of the GNU General Public License
Packit 5e46da
 * along with this program; if not, write to the Free Software
Packit 5e46da
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
Packit 5e46da
 *
Packit 5e46da
 * Input plugin for BluRay discs / images
Packit 5e46da
 *
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
#ifdef HAVE_CONFIG_H
Packit 5e46da
#include "config.h"
Packit 5e46da
#endif
Packit 5e46da
Packit 5e46da
#include <stdio.h>
Packit 5e46da
#include <stdlib.h>
Packit 5e46da
#include <string.h>
Packit 5e46da
#include <errno.h>
Packit 5e46da
#include <pthread.h>
Packit 5e46da
Packit 5e46da
/* libbluray */
Packit 5e46da
#include <libbluray/bluray.h>
Packit 5e46da
#include <libbluray/bluray-version.h>
Packit 5e46da
#include <libbluray/keys.h>
Packit 5e46da
#include <libbluray/overlay.h>
Packit 5e46da
#include <libbluray/meta_data.h>
Packit 5e46da
Packit 5e46da
/* xine */
Packit 5e46da
Packit 5e46da
#define LOG_MODULE "input_bluray"
Packit 5e46da
#define LOG_VERBOSE
Packit 5e46da
Packit 5e46da
#define LOG
Packit 5e46da
Packit 5e46da
#define LOGMSG(x...)  xine_log (this->stream->xine, XINE_LOG_MSG, "input_bluray: " x);
Packit 5e46da
Packit 5e46da
#define XINE_ENGINE_INTERNAL  // stream->demux_plugin
Packit 5e46da
Packit 5e46da
#ifdef HAVE_CONFIG_H
Packit 5e46da
# include "xine_internal.h"
Packit 5e46da
# include "input_plugin.h"
Packit 5e46da
#else
Packit 5e46da
# include <xine/xine_internal.h>
Packit 5e46da
# include <xine/input_plugin.h>
Packit 5e46da
#endif
Packit 5e46da
Packit 5e46da
#ifndef XINE_VERSION_CODE
Packit 5e46da
# error XINE_VERSION_CODE undefined !
Packit 5e46da
#endif
Packit 5e46da
Packit 5e46da
#ifndef EXPORTED
Packit 5e46da
#  define EXPORTED __attribute__((visibility("default")))
Packit 5e46da
#endif
Packit 5e46da
Packit 5e46da
#ifndef MIN
Packit 5e46da
# define MIN(a,b) ((a)<(b)?(a):(b))
Packit 5e46da
#endif
Packit 5e46da
#ifndef MAX
Packit 5e46da
# define MAX(a,b) ((a)>(b)?(a):(b))
Packit 5e46da
#endif
Packit 5e46da
Packit 5e46da
#define ALIGNED_UNIT_SIZE 6144
Packit 5e46da
#define PKT_SIZE          192
Packit 5e46da
#define TICKS_IN_MS       45
Packit 5e46da
Packit 5e46da
#define MIN_TITLE_LENGTH  180
Packit 5e46da
Packit 5e46da
typedef struct {
Packit 5e46da
Packit 5e46da
  input_class_t   input_class;
Packit 5e46da
Packit 5e46da
  xine_t         *xine;
Packit 5e46da
Packit 5e46da
  /* config */
Packit 5e46da
  char           *mountpoint;
Packit 5e46da
  char           *language;
Packit 5e46da
  char           *country;
Packit 5e46da
  int             region;
Packit 5e46da
  int             parental;
Packit 5e46da
} bluray_input_class_t;
Packit 5e46da
Packit 5e46da
typedef struct {
Packit 5e46da
  BD_ARGB_BUFFER   buf;
Packit 5e46da
  pthread_mutex_t  buf_lock;
Packit 5e46da
} XINE_BD_ARGB_BUFFER;
Packit 5e46da
Packit 5e46da
static void osd_buf_lock(BD_ARGB_BUFFER *buf_gen)
Packit 5e46da
{
Packit 5e46da
  XINE_BD_ARGB_BUFFER *buf = (XINE_BD_ARGB_BUFFER*)buf_gen;
Packit 5e46da
  pthread_mutex_lock(&buf->buf_lock);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void osd_buf_unlock(BD_ARGB_BUFFER *buf_gen)
Packit 5e46da
{
Packit 5e46da
  XINE_BD_ARGB_BUFFER *buf = (XINE_BD_ARGB_BUFFER*)buf_gen;
Packit 5e46da
  pthread_mutex_unlock(&buf->buf_lock);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void osd_buf_init(XINE_BD_ARGB_BUFFER *buf)
Packit 5e46da
{
Packit 5e46da
  buf->buf.lock   = osd_buf_lock;
Packit 5e46da
  buf->buf.unlock = osd_buf_unlock;
Packit 5e46da
  pthread_mutex_init(&buf->buf_lock, NULL);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void osd_buf_destroy(XINE_BD_ARGB_BUFFER *buf)
Packit 5e46da
{
Packit 5e46da
  if (buf->buf.lock) {
Packit 5e46da
    buf->buf.lock   = NULL;
Packit 5e46da
    buf->buf.unlock = NULL;
Packit 5e46da
    pthread_mutex_destroy(&buf->buf_lock);
Packit 5e46da
  }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
typedef struct {
Packit 5e46da
  input_plugin_t        input_plugin;
Packit 5e46da
Packit 5e46da
  xine_stream_t        *stream;
Packit 5e46da
  xine_event_queue_t   *event_queue;
Packit 5e46da
  xine_osd_t           *osd[2];
Packit 5e46da
  XINE_BD_ARGB_BUFFER   osd_buf;
Packit 5e46da
Packit 5e46da
  bluray_input_class_t *class;
Packit 5e46da
Packit 5e46da
  char                 *mrl;
Packit 5e46da
  char                 *disc_root;
Packit 5e46da
  char                 *disc_name;
Packit 5e46da
Packit 5e46da
  BLURAY               *bdh;
Packit 5e46da
Packit 5e46da
  const BLURAY_DISC_INFO *disc_info;
Packit 5e46da
  const META_DL          *meta_dl; /* disc library meta data */
Packit 5e46da
Packit 5e46da
  int                num_title_idx;     /* number of relevant playlists */
Packit 5e46da
  int                current_title_idx;
Packit 5e46da
  int                num_titles;        /* navigation mode, number of titles in disc index */
Packit 5e46da
  int                current_title;     /* navigation mode, title from disc index */
Packit 5e46da
  BLURAY_TITLE_INFO *title_info;
Packit 5e46da
  pthread_mutex_t    title_info_mutex;  /* lock this when accessing title_info outside of input/demux thread */
Packit 5e46da
  unsigned int       current_clip;
Packit 5e46da
  time_t             still_end_time;
Packit 5e46da
  int                pg_stream;
Packit 5e46da
Packit 5e46da
  uint8_t            nav_mode : 1;
Packit 5e46da
  uint8_t            error : 1;
Packit 5e46da
  uint8_t            menu_open : 1;
Packit 5e46da
  uint8_t            stream_flushed : 1;
Packit 5e46da
  uint8_t            demux_action_req : 1;
Packit 5e46da
  uint8_t            end_of_title : 1;
Packit 5e46da
  uint8_t            pg_enable : 1;
Packit 5e46da
  uint8_t            has_video : 1;
Packit 5e46da
  int                mouse_inside_button;
Packit 5e46da
} bluray_input_plugin_t;
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * overlay
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
#define PALETTE_INDEX_BACKGROUND 0xff
Packit 5e46da
Packit 5e46da
static void send_num_buttons(bluray_input_plugin_t *this, int n)
Packit 5e46da
{
Packit 5e46da
  xine_event_t   event;
Packit 5e46da
  xine_ui_data_t data;
Packit 5e46da
Packit 5e46da
  event.type = XINE_EVENT_UI_NUM_BUTTONS;
Packit 5e46da
  event.data = &dat;;
Packit 5e46da
  event.data_length = sizeof(data);
Packit 5e46da
  data.num_buttons = n;
Packit 5e46da
Packit 5e46da
  xine_event_send(this->stream, &event);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void clear_overlay(xine_osd_t *osd)
Packit 5e46da
{
Packit 5e46da
  /* palette entry 0xff is background --> can't use xine_osd_clear(). */
Packit 5e46da
  memset(osd->osd.area, PALETTE_INDEX_BACKGROUND, osd->osd.width * osd->osd.height);
Packit 5e46da
  osd->osd.x1 = osd->osd.width;
Packit 5e46da
  osd->osd.y1 = osd->osd.height;
Packit 5e46da
  osd->osd.x2 = 0;
Packit 5e46da
  osd->osd.y2 = 0;
Packit 5e46da
  osd->osd.area_touched = 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void close_overlay(bluray_input_plugin_t *this, int plane)
Packit 5e46da
{
Packit 5e46da
  if (plane < 0) {
Packit 5e46da
    close_overlay(this, 0);
Packit 5e46da
    close_overlay(this, 1);
Packit 5e46da
    return;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  if (plane < 2 && this->osd[plane]) {
Packit 5e46da
    xine_osd_free(this->osd[plane]);
Packit 5e46da
    this->osd[plane] = NULL;
Packit 5e46da
    free(this->osd_buf.buf.buf[plane]);
Packit 5e46da
    this->osd_buf.buf.buf[plane] = NULL;
Packit 5e46da
  }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void open_overlay(bluray_input_plugin_t *this, int plane, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
Packit 5e46da
{
Packit 5e46da
  if (this->osd[plane]) {
Packit 5e46da
    close_overlay(this, plane);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  this->osd[plane] = xine_osd_new(this->stream, x, y, w, h);
Packit 5e46da
Packit 5e46da
  if (xine_osd_get_capabilities(this->osd[plane]) & XINE_OSD_CAP_ARGB_LAYER) {
Packit 5e46da
    this->osd_buf.buf.width = w;
Packit 5e46da
    this->osd_buf.buf.height = h;
Packit 5e46da
    this->osd_buf.buf.buf[plane] = calloc(sizeof(uint32_t), w * h);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  clear_overlay(this->osd[plane]);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static xine_osd_t *get_overlay(bluray_input_plugin_t *this, int plane)
Packit 5e46da
{
Packit 5e46da
  if (!this->osd[plane]) {
Packit 5e46da
    open_overlay(this, plane, 0, 0, 1920, 1080);
Packit 5e46da
  }
Packit 5e46da
  if (!this->pg_enable) {
Packit 5e46da
    _x_select_spu_channel(this->stream, -1);
Packit 5e46da
  }
Packit 5e46da
  this->stream->video_out->enable_ovl(this->stream->video_out, 1);
Packit 5e46da
  return this->osd[plane];
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void draw_bitmap(xine_osd_t *osd, const BD_OVERLAY * const ov)
Packit 5e46da
{
Packit 5e46da
  unsigned i;
Packit 5e46da
Packit 5e46da
  /* convert and set palette */
Packit 5e46da
  if (ov->palette) {
Packit 5e46da
    uint32_t color[256];
Packit 5e46da
    uint8_t  trans[256];
Packit 5e46da
    for(i = 0; i < 256; i++) {
Packit 5e46da
      trans[i] = ov->palette[i].T;
Packit 5e46da
      color[i] = (ov->palette[i].Y << 16) | (ov->palette[i].Cr << 8) | ov->palette[i].Cb;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    xine_osd_set_palette(osd, color, trans);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  /* uncompress and draw bitmap */
Packit 5e46da
  if (ov->img) {
Packit 5e46da
    const BD_PG_RLE_ELEM *rlep = ov->img;
Packit 5e46da
    uint8_t *img = malloc(ov->w * ov->h);
Packit 5e46da
    unsigned pixels = ov->w * ov->h;
Packit 5e46da
Packit 5e46da
    for (i = 0; i < pixels; i += rlep->len, rlep++) {
Packit 5e46da
      memset(img + i, rlep->color, rlep->len);
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    xine_osd_draw_bitmap(osd, img, ov->x, ov->y, ov->w, ov->h, NULL);
Packit 5e46da
Packit 5e46da
    free(img);
Packit 5e46da
  }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void overlay_proc(void *this_gen, const BD_OVERLAY * const ov)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
  xine_osd_t *osd;
Packit 5e46da
  int64_t vpts;
Packit 5e46da
Packit 5e46da
  if (!this) {
Packit 5e46da
    return;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  if (!ov) {
Packit 5e46da
    /* hide OSD */
Packit 5e46da
    close_overlay(this, -1);
Packit 5e46da
    return;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  if (ov->plane > 1) {
Packit 5e46da
    return;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  switch (ov->cmd) {
Packit 5e46da
    case BD_OVERLAY_INIT:    /* init overlay plane. Size of full plane in x,y,w,h */
Packit 5e46da
      open_overlay(this, ov->plane, ov->x, ov->y, ov->w, ov->h);
Packit 5e46da
      return;
Packit 5e46da
    case BD_OVERLAY_CLOSE:   /* close overlay */
Packit 5e46da
      close_overlay(this, ov->plane);
Packit 5e46da
      return;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  osd = get_overlay(this, ov->plane);
Packit 5e46da
  vpts = 0;
Packit 5e46da
  if (ov->pts > 0) {
Packit 5e46da
    vpts = this->stream->metronom->got_spu_packet (this->stream->metronom, ov->pts);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  switch (ov->cmd) {
Packit 5e46da
    case BD_OVERLAY_DRAW:    /* draw bitmap (x,y,w,h,img,palette) */
Packit 5e46da
      draw_bitmap(osd, ov);
Packit 5e46da
      return;
Packit 5e46da
Packit 5e46da
    case BD_OVERLAY_WIPE:    /* clear area (x,y,w,h) */
Packit 5e46da
      xine_osd_draw_rect(osd, ov->x, ov->y, ov->x + ov->w - 1, ov->y + ov->h - 1, PALETTE_INDEX_BACKGROUND, 1);
Packit 5e46da
      return;
Packit 5e46da
Packit 5e46da
    case BD_OVERLAY_CLEAR:   /* clear plane */
Packit 5e46da
      clear_overlay(osd);
Packit 5e46da
      return;
Packit 5e46da
Packit 5e46da
    case BD_OVERLAY_HIDE:
Packit 5e46da
      osd->osd.area_touched = 0; /* will be hiden at next commit time */
Packit 5e46da
      break;
Packit 5e46da
Packit 5e46da
    case BD_OVERLAY_FLUSH:   /* all changes have been done, flush overlay to display at given pts */
Packit 5e46da
      if (!osd->osd.area_touched) {
Packit 5e46da
        xine_osd_hide(osd, vpts);
Packit 5e46da
      } else {
Packit 5e46da
        xine_osd_show(osd, vpts);
Packit 5e46da
      }
Packit 5e46da
      return;
Packit 5e46da
Packit 5e46da
    default:
Packit 5e46da
      LOGMSG("unknown overlay command %d", ov->cmd);
Packit 5e46da
      return;
Packit 5e46da
  }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void argb_overlay_proc(void *this_gen, const BD_ARGB_OVERLAY * const ov)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
  xine_osd_t *osd;
Packit 5e46da
  int64_t vpts;
Packit 5e46da
Packit 5e46da
  if (!this) {
Packit 5e46da
    return;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  if (!ov) {
Packit 5e46da
    /* hide OSD */
Packit 5e46da
    close_overlay(this, -1);
Packit 5e46da
    return;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  vpts = 0;
Packit 5e46da
  if (ov->pts > 0) {
Packit 5e46da
    vpts = this->stream->metronom->got_spu_packet (this->stream->metronom, ov->pts);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  switch (ov->cmd) {
Packit 5e46da
    case BD_ARGB_OVERLAY_INIT:
Packit 5e46da
      open_overlay(this, ov->plane, 0, 0, ov->w, ov->h);
Packit 5e46da
      return;
Packit 5e46da
    case BD_ARGB_OVERLAY_CLOSE:
Packit 5e46da
      close_overlay(this, ov->plane);
Packit 5e46da
      return;
Packit 5e46da
    case BD_ARGB_OVERLAY_DRAW:
Packit 5e46da
      /* nothing to do */
Packit 5e46da
      return;
Packit 5e46da
Packit 5e46da
    case BD_ARGB_OVERLAY_FLUSH:
Packit 5e46da
      osd = get_overlay(this, ov->plane);
Packit 5e46da
      xine_osd_set_argb_buffer(osd, this->osd_buf.buf.buf[ov->plane],
Packit 5e46da
                               this->osd_buf.buf.dirty[ov->plane].x0,
Packit 5e46da
                               this->osd_buf.buf.dirty[ov->plane].y0,
Packit 5e46da
                               this->osd_buf.buf.dirty[ov->plane].x1 - this->osd_buf.buf.dirty[ov->plane].x0 + 1,
Packit 5e46da
                               this->osd_buf.buf.dirty[ov->plane].y1 - this->osd_buf.buf.dirty[ov->plane].y0 + 1);
Packit 5e46da
Packit 5e46da
      xine_osd_show(osd, vpts);
Packit 5e46da
      return;
Packit 5e46da
Packit 5e46da
   default:
Packit 5e46da
      lprintf("unknown ARGB overlay command %d\n", ov->cmd);
Packit 5e46da
      return;
Packit 5e46da
  }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * stream info
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
static void update_stream_info(bluray_input_plugin_t *this)
Packit 5e46da
{
Packit 5e46da
  if (this->title_info) {
Packit 5e46da
    /* set stream info */
Packit 5e46da
    _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_COUNT,    this->title_info->angle_count);
Packit 5e46da
    _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER,   bd_get_current_angle(this->bdh));
Packit 5e46da
    _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_CHAPTERS,       this->title_info->chapter_count > 0);
Packit 5e46da
    _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_COUNT,  this->title_info->chapter_count);
Packit 5e46da
    _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, bd_get_current_chapter(this->bdh) + 1);
Packit 5e46da
  }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void update_title_name(bluray_input_plugin_t *this)
Packit 5e46da
{
Packit 5e46da
  char           title_name[64] = "";
Packit 5e46da
  xine_ui_data_t udata;
Packit 5e46da
  xine_event_t   uevent = {
Packit 5e46da
    .type        = XINE_EVENT_UI_SET_TITLE,
Packit 5e46da
    .stream      = this->stream,
Packit 5e46da
    .data        = &udata,
Packit 5e46da
    .data_length = sizeof(udata)
Packit 5e46da
  };
Packit 5e46da
Packit 5e46da
  /* check disc library metadata */
Packit 5e46da
  if (this->meta_dl) {
Packit 5e46da
    unsigned i;
Packit 5e46da
    for (i = 0; i < this->meta_dl->toc_count; i++)
Packit 5e46da
      if (this->meta_dl->toc_entries[i].title_number == (unsigned)this->current_title)
Packit 5e46da
        if (this->meta_dl->toc_entries[i].title_name)
Packit 5e46da
          if (strlen(this->meta_dl->toc_entries[i].title_name) > 2)
Packit 5e46da
            strncpy(title_name, this->meta_dl->toc_entries[i].title_name, sizeof(title_name));
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  /* title name */
Packit 5e46da
  if (title_name[0]) {
Packit 5e46da
  } else if (this->current_title == BLURAY_TITLE_TOP_MENU) {
Packit 5e46da
    strcpy(title_name, "Top Menu");
Packit 5e46da
  } else if (this->current_title == BLURAY_TITLE_FIRST_PLAY) {
Packit 5e46da
    strcpy(title_name, "First Play");
Packit 5e46da
  } else if (this->nav_mode) {
Packit 5e46da
    snprintf(title_name, sizeof(title_name), "Title %d/%d (PL %d/%d)",
Packit 5e46da
             this->current_title, this->num_titles,
Packit 5e46da
             this->current_title_idx + 1, this->num_title_idx);
Packit 5e46da
  } else {
Packit 5e46da
    snprintf(title_name, sizeof(title_name), "Title %d/%d",
Packit 5e46da
             this->current_title_idx + 1, this->num_title_idx);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  /* disc name */
Packit 5e46da
  if (this->disc_name && this->disc_name[0]) {
Packit 5e46da
    udata.str_len = snprintf(udata.str, sizeof(udata.str), "%s, %s",
Packit 5e46da
                             this->disc_name, title_name);
Packit 5e46da
  } else {
Packit 5e46da
    udata.str_len = snprintf(udata.str, sizeof(udata.str), "%s",
Packit 5e46da
                             title_name);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, udata.str);
Packit 5e46da
Packit 5e46da
  xine_event_send(this->stream, &uevent);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void update_title_info(bluray_input_plugin_t *this, int playlist_id)
Packit 5e46da
{
Packit 5e46da
  /* update title_info */
Packit 5e46da
Packit 5e46da
  pthread_mutex_lock(&this->title_info_mutex);
Packit 5e46da
Packit 5e46da
  if (this->title_info)
Packit 5e46da
    bd_free_title_info(this->title_info);
Packit 5e46da
Packit 5e46da
  if (playlist_id < 0)
Packit 5e46da
    this->title_info = bd_get_title_info(this->bdh, this->current_title_idx, 0);
Packit 5e46da
  else
Packit 5e46da
    this->title_info = bd_get_playlist_info(this->bdh, playlist_id, 0);
Packit 5e46da
Packit 5e46da
  pthread_mutex_unlock(&this->title_info_mutex);
Packit 5e46da
Packit 5e46da
  if (!this->title_info) {
Packit 5e46da
    LOGMSG("bd_get_title_info(%d) failed\n", this->current_title_idx);
Packit 5e46da
    return;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  /* calculate and set stream rate */
Packit 5e46da
Packit 5e46da
  uint64_t rate = bd_get_title_size(this->bdh) * UINT64_C(8) // bits
Packit 5e46da
                  * INT64_C(90000)
Packit 5e46da
                  / (uint64_t)(this->title_info->duration);
Packit 5e46da
  _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, rate);
Packit 5e46da
Packit 5e46da
  /* set stream info */
Packit 5e46da
Packit 5e46da
  if (this->nav_mode) {
Packit 5e46da
    _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_COUNT,  this->num_titles);
Packit 5e46da
    _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_NUMBER, this->current_title);
Packit 5e46da
  } else {
Packit 5e46da
    _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_COUNT,  this->num_title_idx);
Packit 5e46da
    _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_NUMBER, this->current_title_idx + 1);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  update_stream_info(this);
Packit 5e46da
Packit 5e46da
  /* set title name */
Packit 5e46da
  update_title_name(this);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * libbluray event handling
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
static void stream_flush(bluray_input_plugin_t *this)
Packit 5e46da
{
Packit 5e46da
  if (this->stream_flushed || !this->stream)
Packit 5e46da
    return;
Packit 5e46da
Packit 5e46da
  lprintf("Stream flush\n");
Packit 5e46da
Packit 5e46da
  this->stream_flushed = 1;
Packit 5e46da
Packit 5e46da
  xine_event_t event = {
Packit 5e46da
    .type        = XINE_EVENT_END_OF_CLIP,
Packit 5e46da
    .stream      = this->stream,
Packit 5e46da
    .data        = NULL,
Packit 5e46da
    .data_length = 0,
Packit 5e46da
  };
Packit 5e46da
  xine_event_send (this->stream, &event);
Packit 5e46da
Packit 5e46da
  this->demux_action_req = 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void stream_reset(bluray_input_plugin_t *this)
Packit 5e46da
{
Packit 5e46da
  if (!this || !this->stream)
Packit 5e46da
    return;
Packit 5e46da
Packit 5e46da
  lprintf("Stream reset\n");
Packit 5e46da
Packit 5e46da
  xine_event_t event = {
Packit 5e46da
    .type        = XINE_EVENT_PIDS_CHANGE,
Packit 5e46da
    .stream      = this->stream,
Packit 5e46da
    .data        = NULL,
Packit 5e46da
    .data_length = 0,
Packit 5e46da
  };
Packit 5e46da
Packit 5e46da
  if (!this->end_of_title) {
Packit 5e46da
    _x_demux_flush_engine(this->stream);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  xine_event_send (this->stream, &event);
Packit 5e46da
Packit 5e46da
  this->demux_action_req = 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void wait_secs(bluray_input_plugin_t *this, unsigned seconds)
Packit 5e46da
{
Packit 5e46da
  stream_flush(this);
Packit 5e46da
Packit 5e46da
  if (this->still_end_time) {
Packit 5e46da
    if (time(NULL) >= this->still_end_time) {
Packit 5e46da
      lprintf("pause end\n");
Packit 5e46da
      this->still_end_time = 0;
Packit 5e46da
      bd_read_skip_still(this->bdh);
Packit 5e46da
      stream_reset(this);
Packit 5e46da
      return;
Packit 5e46da
    }
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  else if (seconds) {
Packit 5e46da
    if (seconds > 300) {
Packit 5e46da
      seconds = 300;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    lprintf("still image, pause for %d seconds\n", seconds);
Packit 5e46da
    this->still_end_time = time(NULL) + seconds;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  xine_usec_sleep(40*1000);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void update_spu_channel(bluray_input_plugin_t *this, int channel)
Packit 5e46da
{
Packit 5e46da
  if (this->stream->video_fifo) {
Packit 5e46da
    buf_element_t *buf = this->stream->video_fifo->buffer_pool_alloc(this->stream->video_fifo);
Packit 5e46da
    buf->type = BUF_CONTROL_SPU_CHANNEL;
Packit 5e46da
    buf->decoder_info[0] = channel;
Packit 5e46da
    buf->decoder_info[1] = channel;
Packit 5e46da
    buf->decoder_info[2] = channel;
Packit 5e46da
Packit 5e46da
    this->stream->video_fifo->put(this->stream->video_fifo, buf);
Packit 5e46da
  }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void update_audio_channel(bluray_input_plugin_t *this, int channel)
Packit 5e46da
{
Packit 5e46da
  if (this->stream->audio_fifo) {
Packit 5e46da
    buf_element_t *buf = this->stream->audio_fifo->buffer_pool_alloc(this->stream->audio_fifo);
Packit 5e46da
    buf->type = BUF_CONTROL_AUDIO_CHANNEL;
Packit 5e46da
    buf->decoder_info[0] = channel;
Packit 5e46da
Packit 5e46da
    this->stream->audio_fifo->put(this->stream->audio_fifo, buf);
Packit 5e46da
  }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void handle_libbluray_event(bluray_input_plugin_t *this, BD_EVENT ev)
Packit 5e46da
{
Packit 5e46da
    switch ((bd_event_e)ev.event) {
Packit 5e46da
Packit 5e46da
      case BD_EVENT_ERROR:
Packit 5e46da
        lprintf("BD_EVENT_ERROR\n");
Packit 5e46da
        _x_message (this->stream, XINE_MSG_GENERAL_WARNING,
Packit 5e46da
                    "Error playing BluRay disc", NULL);
Packit 5e46da
        this->error = 1;
Packit 5e46da
        return;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_READ_ERROR:
Packit 5e46da
        LOGMSG("m2ts file read error");
Packit 5e46da
        /*stream_flush(this); leave error detection and handling for upper layer */
Packit 5e46da
        return;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_ENCRYPTED:
Packit 5e46da
        lprintf("BD_EVENT_ENCRYPTED\n");
Packit 5e46da
        _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE,
Packit 5e46da
                    "Media stream scrambled/encrypted", NULL);
Packit 5e46da
        this->error = 1;
Packit 5e46da
        return;
Packit 5e46da
Packit 5e46da
      /* playback control */
Packit 5e46da
Packit 5e46da
      case BD_EVENT_SEEK:
Packit 5e46da
        lprintf("BD_EVENT_SEEK\n");
Packit 5e46da
        this->still_end_time = 0;
Packit 5e46da
        stream_reset(this);
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_STILL_TIME:
Packit 5e46da
        lprintf("BD_EVENT_STILL_TIME %d\n", ev.param);
Packit 5e46da
        wait_secs(this, ev.param);
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_STILL:
Packit 5e46da
        lprintf("BD_EVENT_STILL %d\n", ev.param);
Packit 5e46da
        int paused = _x_get_fine_speed(this->stream) == XINE_SPEED_PAUSE;
Packit 5e46da
        if (paused != ev.param) {
Packit 5e46da
          _x_set_fine_speed(this->stream, ev.param ? XINE_SPEED_PAUSE : XINE_SPEED_NORMAL);
Packit 5e46da
        }
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_IDLE:
Packit 5e46da
        xine_usec_sleep(10000);
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      /* playback position */
Packit 5e46da
Packit 5e46da
      case BD_EVENT_ANGLE:
Packit 5e46da
        lprintf("BD_EVENT_ANGLE_NUMBER %d\n", ev.param);
Packit 5e46da
        _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, ev.param);
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_END_OF_TITLE:
Packit 5e46da
        lprintf("BD_EVENT_END_OF_TITLE\n");
Packit 5e46da
        stream_flush(this);
Packit 5e46da
        this->end_of_title = 1;
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_TITLE:
Packit 5e46da
        this->current_title = ev.param;
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_PLAYLIST:
Packit 5e46da
        lprintf("BD_EVENT_PLAYLIST %d\n", ev.param);
Packit 5e46da
        this->current_title_idx = bd_get_current_title(this->bdh);
Packit 5e46da
        this->current_clip = 0;
Packit 5e46da
        update_title_info(this, ev.param);
Packit 5e46da
        stream_reset(this);
Packit 5e46da
        this->end_of_title = 0;
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_PLAYITEM:
Packit 5e46da
        lprintf("BD_EVENT_PLAYITEM %d\n", ev.param);
Packit 5e46da
        this->current_clip = ev.param;
Packit 5e46da
        this->still_end_time = 0;
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_CHAPTER:
Packit 5e46da
        lprintf("BD_EVENT_CHAPTER %d\n", ev.param);
Packit 5e46da
        _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, ev.param);
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      /* stream selection */
Packit 5e46da
Packit 5e46da
      case BD_EVENT_AUDIO_STREAM:
Packit 5e46da
        lprintf("BD_EVENT_AUDIO_STREAM %d\n", ev.param);
Packit 5e46da
        if (ev.param < 32) {
Packit 5e46da
          update_audio_channel(this, ev.param - 1);
Packit 5e46da
        } else {
Packit 5e46da
          update_audio_channel(this, 0);
Packit 5e46da
        }
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_PG_TEXTST:
Packit 5e46da
        lprintf("BD_EVENT_PG_TEXTST %s\n", ev.param ? "ON" : "OFF");
Packit 5e46da
        this->pg_enable = !!ev.param;
Packit 5e46da
        update_spu_channel(this, this->pg_enable ? this->pg_stream : -1);
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_PG_TEXTST_STREAM:
Packit 5e46da
        lprintf("BD_EVENT_PG_TEXTST_STREAM %d\n", ev.param);
Packit 5e46da
        if (ev.param < 64) {
Packit 5e46da
          this->pg_stream = ev.param - 1;
Packit 5e46da
        } else {
Packit 5e46da
          this->pg_stream = -1;
Packit 5e46da
        }
Packit 5e46da
        if (this->pg_enable) {
Packit 5e46da
          update_spu_channel(this, this->pg_stream);
Packit 5e46da
        }
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_MENU:
Packit 5e46da
        this->menu_open = !!ev.param;
Packit 5e46da
        send_num_buttons(this, ev.param);
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case BD_EVENT_IG_STREAM:
Packit 5e46da
      case BD_EVENT_SECONDARY_AUDIO:
Packit 5e46da
      case BD_EVENT_SECONDARY_AUDIO_STREAM:
Packit 5e46da
      case BD_EVENT_SECONDARY_VIDEO:
Packit 5e46da
      case BD_EVENT_SECONDARY_VIDEO_SIZE:
Packit 5e46da
      case BD_EVENT_SECONDARY_VIDEO_STREAM:
Packit 5e46da
Packit 5e46da
      case BD_EVENT_NONE:
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      default:
Packit 5e46da
        LOGMSG("unhandled libbluray event %d [param %d]\n", ev.event, ev.param);
Packit 5e46da
        break;
Packit 5e46da
    }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void handle_libbluray_events(bluray_input_plugin_t *this)
Packit 5e46da
{
Packit 5e46da
  BD_EVENT ev;
Packit 5e46da
  while (bd_get_event(this->bdh, &ev)) {
Packit 5e46da
    handle_libbluray_event(this, ev);
Packit 5e46da
    if (this->error || ev.event == BD_EVENT_NONE || ev.event == BD_EVENT_ERROR)
Packit 5e46da
      break;
Packit 5e46da
  }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * xine event handling
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
static int open_title (bluray_input_plugin_t *this, int title_idx)
Packit 5e46da
{
Packit 5e46da
  if (bd_select_title(this->bdh, title_idx) <= 0) {
Packit 5e46da
    LOGMSG("bd_select_title(%d) failed\n", title_idx);
Packit 5e46da
    return 0;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  this->current_title_idx = title_idx;
Packit 5e46da
Packit 5e46da
  update_title_info(this, -1);
Packit 5e46da
Packit 5e46da
  return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void send_mouse_enter_leave_event(bluray_input_plugin_t *this, int direction)
Packit 5e46da
{
Packit 5e46da
  if (direction != this->mouse_inside_button) {
Packit 5e46da
    xine_event_t        event;
Packit 5e46da
    xine_spu_button_t   spu_event;
Packit 5e46da
Packit 5e46da
    spu_event.direction = direction;
Packit 5e46da
    spu_event.button    = 1;
Packit 5e46da
Packit 5e46da
    event.type        = XINE_EVENT_SPU_BUTTON;
Packit 5e46da
    event.stream      = this->stream;
Packit 5e46da
    event.data        = &spu_event;
Packit 5e46da
    event.data_length = sizeof(spu_event);
Packit 5e46da
    xine_event_send(this->stream, &event);
Packit 5e46da
Packit 5e46da
    this->mouse_inside_button = direction;
Packit 5e46da
  }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void handle_events(bluray_input_plugin_t *this)
Packit 5e46da
{
Packit 5e46da
  xine_event_t *event;
Packit 5e46da
Packit 5e46da
  if (!this->event_queue)
Packit 5e46da
    return;
Packit 5e46da
Packit 5e46da
  while (NULL != (event = xine_event_get(this->event_queue))) {
Packit 5e46da
Packit 5e46da
    if (!this->bdh || !this->title_info) {
Packit 5e46da
      xine_event_free(event);
Packit 5e46da
      return;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    int64_t pts = xine_get_current_vpts(this->stream) -
Packit 5e46da
      this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET);
Packit 5e46da
Packit 5e46da
    if (this->menu_open) {
Packit 5e46da
      switch (event->type) {
Packit 5e46da
        case XINE_EVENT_INPUT_LEFT:  bd_user_input(this->bdh, pts, BD_VK_LEFT);  break;
Packit 5e46da
        case XINE_EVENT_INPUT_RIGHT: bd_user_input(this->bdh, pts, BD_VK_RIGHT); break;
Packit 5e46da
      }
Packit 5e46da
    } else {
Packit 5e46da
      switch (event->type) {
Packit 5e46da
Packit 5e46da
        case XINE_EVENT_INPUT_LEFT:
Packit 5e46da
          lprintf("XINE_EVENT_INPUT_LEFT: previous title\n");
Packit 5e46da
          if (!this->nav_mode) {
Packit 5e46da
            open_title(this, MAX(0, this->current_title_idx - 1));
Packit 5e46da
          } else {
Packit 5e46da
            bd_play_title(this->bdh, MAX(1, this->current_title - 1));
Packit 5e46da
          }
Packit 5e46da
          stream_reset(this);
Packit 5e46da
          break;
Packit 5e46da
Packit 5e46da
        case XINE_EVENT_INPUT_RIGHT:
Packit 5e46da
          lprintf("XINE_EVENT_INPUT_RIGHT: next title\n");
Packit 5e46da
          if (!this->nav_mode) {
Packit 5e46da
            open_title(this, MIN(this->num_title_idx - 1, this->current_title_idx + 1));
Packit 5e46da
          } else {
Packit 5e46da
            bd_play_title(this->bdh, MIN(this->num_titles, this->current_title + 1));
Packit 5e46da
          }
Packit 5e46da
          stream_reset(this);
Packit 5e46da
          break;
Packit 5e46da
      }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    switch (event->type) {
Packit 5e46da
Packit 5e46da
      case XINE_EVENT_INPUT_MOUSE_BUTTON: {
Packit 5e46da
        xine_input_data_t *input = event->data;
Packit 5e46da
        lprintf("mouse click: button %d at (%d,%d)\n", input->button, input->x, input->y);
Packit 5e46da
        if (input->button == 1) {
Packit 5e46da
          bd_mouse_select(this->bdh, pts, input->x, input->y);
Packit 5e46da
          bd_user_input(this->bdh, pts, BD_VK_MOUSE_ACTIVATE);
Packit 5e46da
          send_mouse_enter_leave_event(this, 0);
Packit 5e46da
        }
Packit 5e46da
        break;
Packit 5e46da
      }
Packit 5e46da
Packit 5e46da
      case XINE_EVENT_INPUT_MOUSE_MOVE: {
Packit 5e46da
        xine_input_data_t *input = event->data;
Packit 5e46da
        if (bd_mouse_select(this->bdh, pts, input->x, input->y) > 0) {
Packit 5e46da
          send_mouse_enter_leave_event(this, 1);
Packit 5e46da
        } else {
Packit 5e46da
          send_mouse_enter_leave_event(this, 0);
Packit 5e46da
        }
Packit 5e46da
        break;
Packit 5e46da
      }
Packit 5e46da
Packit 5e46da
      case XINE_EVENT_INPUT_MENU1:
Packit 5e46da
        if (!this->disc_info->top_menu_supported) {
Packit 5e46da
          _x_message (this->stream, XINE_MSG_GENERAL_WARNING,
Packit 5e46da
                      "Can't open Top Menu",
Packit 5e46da
                      "Top Menu title not supported", NULL);
Packit 5e46da
        }
Packit 5e46da
        bd_menu_call(this->bdh, pts);
Packit 5e46da
        break;
Packit 5e46da
Packit 5e46da
      case XINE_EVENT_INPUT_MENU2:     bd_user_input(this->bdh, pts, BD_VK_POPUP); break;
Packit 5e46da
      case XINE_EVENT_INPUT_UP:        bd_user_input(this->bdh, pts, BD_VK_UP);    break;
Packit 5e46da
      case XINE_EVENT_INPUT_DOWN:      bd_user_input(this->bdh, pts, BD_VK_DOWN);  break;
Packit 5e46da
      case XINE_EVENT_INPUT_SELECT:    bd_user_input(this->bdh, pts, BD_VK_ENTER); break;
Packit 5e46da
      case XINE_EVENT_INPUT_NUMBER_0:  bd_user_input(this->bdh, pts, BD_VK_0); break;
Packit 5e46da
      case XINE_EVENT_INPUT_NUMBER_1:  bd_user_input(this->bdh, pts, BD_VK_1); break;
Packit 5e46da
      case XINE_EVENT_INPUT_NUMBER_2:  bd_user_input(this->bdh, pts, BD_VK_2); break;
Packit 5e46da
      case XINE_EVENT_INPUT_NUMBER_3:  bd_user_input(this->bdh, pts, BD_VK_3); break;
Packit 5e46da
      case XINE_EVENT_INPUT_NUMBER_4:  bd_user_input(this->bdh, pts, BD_VK_4); break;
Packit 5e46da
      case XINE_EVENT_INPUT_NUMBER_5:  bd_user_input(this->bdh, pts, BD_VK_5); break;
Packit 5e46da
      case XINE_EVENT_INPUT_NUMBER_6:  bd_user_input(this->bdh, pts, BD_VK_6); break;
Packit 5e46da
      case XINE_EVENT_INPUT_NUMBER_7:  bd_user_input(this->bdh, pts, BD_VK_7); break;
Packit 5e46da
      case XINE_EVENT_INPUT_NUMBER_8:  bd_user_input(this->bdh, pts, BD_VK_8); break;
Packit 5e46da
      case XINE_EVENT_INPUT_NUMBER_9:  bd_user_input(this->bdh, pts, BD_VK_9); break;
Packit 5e46da
Packit 5e46da
      case XINE_EVENT_INPUT_NEXT: {
Packit 5e46da
        cfg_entry_t* entry = this->class->xine->config->lookup_entry(this->class->xine->config,
Packit 5e46da
                                                                     "media.bluray.skip_behaviour");
Packit 5e46da
        switch (entry->num_value) {
Packit 5e46da
          case 0: /* skip by chapter */
Packit 5e46da
            bd_seek_chapter(this->bdh, bd_get_current_chapter(this->bdh) + 1);
Packit 5e46da
            update_stream_info(this);
Packit 5e46da
            break;
Packit 5e46da
          case 1: /* skip by title */
Packit 5e46da
            if (!this->nav_mode) {
Packit 5e46da
              open_title(this, MIN(this->num_title_idx - 1, this->current_title_idx + 1));
Packit 5e46da
            } else {
Packit 5e46da
              bd_play_title(this->bdh, MIN(this->num_titles, this->current_title + 1));
Packit 5e46da
            }
Packit 5e46da
            break;
Packit 5e46da
        }
Packit 5e46da
        stream_reset(this);
Packit 5e46da
        break;
Packit 5e46da
      }
Packit 5e46da
Packit 5e46da
      case XINE_EVENT_INPUT_PREVIOUS: {
Packit 5e46da
        cfg_entry_t* entry = this->class->xine->config->lookup_entry(this->class->xine->config,
Packit 5e46da
                                                                     "media.bluray.skip_behaviour");
Packit 5e46da
        switch (entry->num_value) {
Packit 5e46da
          case 0: /* skip by chapter */
Packit 5e46da
            bd_seek_chapter(this->bdh, MAX(0, ((int)bd_get_current_chapter(this->bdh)) - 1));
Packit 5e46da
            update_stream_info(this);
Packit 5e46da
            break;
Packit 5e46da
          case 1: /* skip by title */
Packit 5e46da
            if (!this->nav_mode) {
Packit 5e46da
              open_title(this, MAX(0, this->current_title_idx - 1));
Packit 5e46da
            } else {
Packit 5e46da
              bd_play_title(this->bdh, MAX(1, this->current_title - 1));
Packit 5e46da
            }
Packit 5e46da
            break;
Packit 5e46da
        }
Packit 5e46da
        stream_reset(this);
Packit 5e46da
        break;
Packit 5e46da
      }
Packit 5e46da
Packit 5e46da
      case XINE_EVENT_INPUT_ANGLE_NEXT: {
Packit 5e46da
        unsigned curr_angle = bd_get_current_angle(this->bdh);
Packit 5e46da
        unsigned angle      = MIN(8, curr_angle + 1);
Packit 5e46da
        lprintf("XINE_EVENT_INPUT_ANGLE_NEXT: set angle %d --> %d\n", curr_angle, angle);
Packit 5e46da
        bd_seamless_angle_change(this->bdh, angle);
Packit 5e46da
        _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, bd_get_current_angle(this->bdh));
Packit 5e46da
        break;
Packit 5e46da
      }
Packit 5e46da
Packit 5e46da
      case XINE_EVENT_INPUT_ANGLE_PREVIOUS: {
Packit 5e46da
        unsigned curr_angle = bd_get_current_angle(this->bdh);
Packit 5e46da
        unsigned angle      = curr_angle ? curr_angle - 1 : 0;
Packit 5e46da
        lprintf("XINE_EVENT_INPUT_ANGLE_PREVIOUS: set angle %d --> %d\n", curr_angle, angle);
Packit 5e46da
        bd_seamless_angle_change(this->bdh, angle);
Packit 5e46da
        _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, bd_get_current_angle(this->bdh));
Packit 5e46da
        break;
Packit 5e46da
      }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    xine_event_free(event);
Packit 5e46da
  }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * xine plugin interface
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
static uint32_t bluray_plugin_get_capabilities (input_plugin_t *this_gen)
Packit 5e46da
{
Packit 5e46da
  return INPUT_CAP_SEEKABLE  |
Packit 5e46da
         INPUT_CAP_BLOCK     |
Packit 5e46da
         INPUT_CAP_AUDIOLANG |
Packit 5e46da
         INPUT_CAP_SPULANG   |
Packit 5e46da
         INPUT_CAP_CHAPTERS;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
#define CHECK_READ_INTERRUPT               \
Packit 5e46da
  do {                                     \
Packit 5e46da
    if (this->demux_action_req) {          \
Packit 5e46da
      this->demux_action_req = 0;          \
Packit 5e46da
      errno = EAGAIN;                      \
Packit 5e46da
      return -1;                           \
Packit 5e46da
    }                                      \
Packit 5e46da
    if (_x_action_pending(this->stream)) { \
Packit 5e46da
      errno = EINTR;                       \
Packit 5e46da
      return -1;                           \
Packit 5e46da
    }                                      \
Packit 5e46da
  } while (0)
Packit 5e46da
Packit 5e46da
static off_t bluray_plugin_read (input_plugin_t *this_gen, void *buf, off_t len)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
  off_t result;
Packit 5e46da
Packit 5e46da
  if (!this || !this->bdh || len < 0 || this->error)
Packit 5e46da
    return -1;
Packit 5e46da
Packit 5e46da
  if (!this->has_video) {
Packit 5e46da
    vo_frame_t *img    = NULL;
Packit 5e46da
    this->class->xine->port_ticket->acquire (this->class->xine->port_ticket, 1);
Packit 5e46da
    img = this->stream->video_out->get_frame (this->stream->video_out,
Packit 5e46da
                                              1920, 1080, 16.0/9.0,
Packit 5e46da
                                              XINE_IMGFMT_YV12, VO_BOTH_FIELDS);
Packit 5e46da
    this->class->xine->port_ticket->release (this->class->xine->port_ticket, 1);
Packit 5e46da
Packit 5e46da
    if (img) {
Packit 5e46da
      if (img->format == XINE_IMGFMT_YV12 && img->base[0] && img->base[1] && img->base[2]) {
Packit 5e46da
        memset(img->base[0], 0x00, img->pitches[0] * img->height);
Packit 5e46da
        memset(img->base[1], 0x80, img->pitches[1] * img->height / 2);
Packit 5e46da
        memset(img->base[2], 0x80, img->pitches[2] * img->height / 2);
Packit 5e46da
        img->duration  = 0;
Packit 5e46da
        img->pts       = 0;
Packit 5e46da
        img->bad_frame = 0;
Packit 5e46da
        img->draw(img, this->stream);
Packit 5e46da
      }
Packit 5e46da
      img->free(img);
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    this->has_video = 1;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  handle_events(this);
Packit 5e46da
  CHECK_READ_INTERRUPT;
Packit 5e46da
Packit 5e46da
  if (this->nav_mode) {
Packit 5e46da
    do {
Packit 5e46da
      BD_EVENT ev;
Packit 5e46da
      result = bd_read_ext (this->bdh, (unsigned char *)buf, len, &ev;;
Packit 5e46da
      handle_libbluray_event(this, ev);
Packit 5e46da
      CHECK_READ_INTERRUPT;
Packit 5e46da
Packit 5e46da
      if (result == 0) {
Packit 5e46da
        handle_events(this);
Packit 5e46da
        CHECK_READ_INTERRUPT;
Packit 5e46da
      }
Packit 5e46da
    } while (!this->error && result == 0);
Packit 5e46da
Packit 5e46da
  } else {
Packit 5e46da
    result = bd_read (this->bdh, (unsigned char *)buf, len);
Packit 5e46da
    handle_libbluray_events(this);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  if (result < 0) {
Packit 5e46da
    LOGMSG("bd_read() failed: %s (%d of %d)\n", strerror(errno), (int)result, (int)len);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  if (result > 0) {
Packit 5e46da
    this->stream_flushed = 0;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  return result;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static buf_element_t *bluray_plugin_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t todo)
Packit 5e46da
{
Packit 5e46da
  buf_element_t *buf = fifo->buffer_pool_alloc (fifo);
Packit 5e46da
Packit 5e46da
  if (todo > (off_t)buf->max_size)
Packit 5e46da
    todo = buf->max_size;
Packit 5e46da
Packit 5e46da
  if (todo > ALIGNED_UNIT_SIZE)
Packit 5e46da
    todo = ALIGNED_UNIT_SIZE;
Packit 5e46da
Packit 5e46da
  if (todo > 0) {
Packit 5e46da
    bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
Packit 5e46da
    buf->size = bluray_plugin_read(this_gen, (char*)buf->mem, todo);
Packit 5e46da
    buf->type = BUF_DEMUX_BLOCK;
Packit 5e46da
Packit 5e46da
    if (buf->size > 0) {
Packit 5e46da
      buf->extra_info->input_time = 0;
Packit 5e46da
      buf->extra_info->total_time = this->title_info->duration / 90000;
Packit 5e46da
      return buf;
Packit 5e46da
    }
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  buf->free_buffer (buf);
Packit 5e46da
  return NULL;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static off_t bluray_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
Packit 5e46da
  if (!this || !this->bdh)
Packit 5e46da
    return -1;
Packit 5e46da
  if (this->still_end_time)
Packit 5e46da
    return offset;
Packit 5e46da
Packit 5e46da
  /* convert relative seeks to absolute */
Packit 5e46da
Packit 5e46da
  if (origin == SEEK_CUR) {
Packit 5e46da
    offset = bd_tell(this->bdh) + offset;
Packit 5e46da
  }
Packit 5e46da
  else if (origin == SEEK_END) {
Packit 5e46da
    if (offset < (off_t)bd_get_title_size(this->bdh))
Packit 5e46da
      offset = bd_get_title_size(this->bdh) - offset;
Packit 5e46da
    else
Packit 5e46da
      offset = 0;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  lprintf("bluray_plugin_seek() seeking to %lld\n", (long long)offset);
Packit 5e46da
Packit 5e46da
  return bd_seek (this->bdh, offset);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static off_t bluray_plugin_seek_time (input_plugin_t *this_gen, int time_offset, int origin)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
Packit 5e46da
  if (!this || !this->bdh)
Packit 5e46da
    return -1;
Packit 5e46da
Packit 5e46da
  if (this->still_end_time)
Packit 5e46da
    return bd_tell(this->bdh);
Packit 5e46da
Packit 5e46da
  /* convert relative seeks to absolute */
Packit 5e46da
Packit 5e46da
  if (origin == SEEK_CUR) {
Packit 5e46da
    time_offset += this_gen->get_current_time(this_gen);
Packit 5e46da
  }
Packit 5e46da
  else if (origin == SEEK_END) {
Packit 5e46da
Packit 5e46da
    pthread_mutex_lock(&this->title_info_mutex);
Packit 5e46da
Packit 5e46da
    if (!this->title_info) {
Packit 5e46da
      pthread_mutex_unlock(&this->title_info_mutex);
Packit 5e46da
      return -1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    int duration = this->title_info->duration / 90;
Packit 5e46da
    if (time_offset < duration)
Packit 5e46da
      time_offset = duration - time_offset;
Packit 5e46da
    else
Packit 5e46da
      time_offset = 0;
Packit 5e46da
Packit 5e46da
    pthread_mutex_unlock(&this->title_info_mutex);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  lprintf("bluray_plugin_seek_time() seeking to %d.%03ds\n", time_offset / 1000, time_offset % 1000);
Packit 5e46da
Packit 5e46da
  return bd_seek_time(this->bdh, time_offset * INT64_C(90));
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static off_t bluray_plugin_get_current_pos (input_plugin_t *this_gen)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
Packit 5e46da
  return this->bdh ? bd_tell(this->bdh) : 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int bluray_plugin_get_current_time (input_plugin_t *this_gen)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
Packit 5e46da
  return this->bdh ? (int)(bd_tell_time(this->bdh) / UINT64_C(90)) : -1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static off_t bluray_plugin_get_length (input_plugin_t *this_gen)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
Packit 5e46da
  return this->bdh ? (off_t)bd_get_title_size(this->bdh) : (off_t)-1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static uint32_t bluray_plugin_get_blocksize (input_plugin_t *this_gen)
Packit 5e46da
{
Packit 5e46da
  (void)this_gen;
Packit 5e46da
Packit 5e46da
  return ALIGNED_UNIT_SIZE;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static const char* bluray_plugin_get_mrl (input_plugin_t *this_gen)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
Packit 5e46da
  return this->mrl;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int get_optional_data_impl (bluray_input_plugin_t *this, void *data, int data_type)
Packit 5e46da
{
Packit 5e46da
  unsigned int current_clip = this->current_clip;
Packit 5e46da
Packit 5e46da
  switch (data_type) {
Packit 5e46da
    case INPUT_OPTIONAL_DATA_DEMUXER:
Packit 5e46da
      *(const char **)data = "mpeg-ts";
Packit 5e46da
      return INPUT_OPTIONAL_SUCCESS;
Packit 5e46da
Packit 5e46da
    /*
Packit 5e46da
     * audio track language:
Packit 5e46da
     * - channel number can be mpeg-ts PID (0x1100 ... 0x11ff)
Packit 5e46da
     */
Packit 5e46da
    case INPUT_OPTIONAL_DATA_AUDIOLANG:
Packit 5e46da
      if (this->title_info && this->title_info->clip_count < current_clip) {
Packit 5e46da
        int               channel = *((int *)data);
Packit 5e46da
        BLURAY_CLIP_INFO *clip    = &this->title_info->clips[current_clip];
Packit 5e46da
Packit 5e46da
        if (channel >= 0 && channel < clip->audio_stream_count) {
Packit 5e46da
          memcpy(data, clip->audio_streams[channel].lang, 4);
Packit 5e46da
          lprintf("INPUT_OPTIONAL_DATA_AUDIOLANG: %02d [pid 0x%04x]: %s\n",
Packit 5e46da
                  channel, clip->audio_streams[channel].pid, clip->audio_streams[channel].lang);
Packit 5e46da
Packit 5e46da
          return INPUT_OPTIONAL_SUCCESS;
Packit 5e46da
        }
Packit 5e46da
        /* search by pid */
Packit 5e46da
        int i;
Packit 5e46da
        for (i = 0; i < clip->audio_stream_count; i++) {
Packit 5e46da
          if (channel == clip->audio_streams[i].pid) {
Packit 5e46da
            memcpy(data, clip->audio_streams[i].lang, 4);
Packit 5e46da
            lprintf("INPUT_OPTIONAL_DATA_AUDIOLANG: pid 0x%04x -> ch %d: %s\n",
Packit 5e46da
                    channel, i, clip->audio_streams[i].lang);
Packit 5e46da
Packit 5e46da
            return INPUT_OPTIONAL_SUCCESS;
Packit 5e46da
          }
Packit 5e46da
        }
Packit 5e46da
      }
Packit 5e46da
      return INPUT_OPTIONAL_UNSUPPORTED;
Packit 5e46da
Packit 5e46da
    /*
Packit 5e46da
     * SPU track language:
Packit 5e46da
     * - channel number can be mpeg-ts PID (0x1200 ... 0x12ff)
Packit 5e46da
     */
Packit 5e46da
    case INPUT_OPTIONAL_DATA_SPULANG:
Packit 5e46da
      if (this->title_info && this->title_info->clip_count < current_clip) {
Packit 5e46da
        int               channel = *((int *)data);
Packit 5e46da
        BLURAY_CLIP_INFO *clip    = &this->title_info->clips[current_clip];
Packit 5e46da
Packit 5e46da
        if (channel >= 0 && channel < clip->pg_stream_count) {
Packit 5e46da
          memcpy(data, clip->pg_streams[channel].lang, 4);
Packit 5e46da
          lprintf("INPUT_OPTIONAL_DATA_SPULANG: %02d [pid 0x%04x]: %s\n",
Packit 5e46da
                  channel, clip->pg_streams[channel].pid, clip->pg_streams[channel].lang);
Packit 5e46da
Packit 5e46da
          return INPUT_OPTIONAL_SUCCESS;
Packit 5e46da
        }
Packit 5e46da
        /* search by pid */
Packit 5e46da
        int i;
Packit 5e46da
        for (i = 0; i < clip->pg_stream_count; i++) {
Packit 5e46da
          if (channel == clip->pg_streams[i].pid) {
Packit 5e46da
            memcpy(data, clip->pg_streams[i].lang, 4);
Packit 5e46da
            lprintf("INPUT_OPTIONAL_DATA_SPULANG: pid 0x%04x -> ch %d: %s\n",
Packit 5e46da
                    channel, i, clip->pg_streams[i].lang);
Packit 5e46da
Packit 5e46da
            return INPUT_OPTIONAL_SUCCESS;
Packit 5e46da
          }
Packit 5e46da
        }
Packit 5e46da
      }
Packit 5e46da
      return INPUT_OPTIONAL_UNSUPPORTED;
Packit 5e46da
Packit 5e46da
    default:
Packit 5e46da
      return INPUT_OPTIONAL_UNSUPPORTED;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
  return INPUT_OPTIONAL_UNSUPPORTED;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int bluray_plugin_get_optional_data (input_plugin_t *this_gen, void *data, int data_type)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
  int r = INPUT_OPTIONAL_UNSUPPORTED;
Packit 5e46da
Packit 5e46da
  if (this && this->stream && data) {
Packit 5e46da
    pthread_mutex_lock(&this->title_info_mutex);
Packit 5e46da
    r = get_optional_data_impl(this, data, data_type);
Packit 5e46da
    pthread_mutex_unlock(&this->title_info_mutex);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  return r;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void bluray_plugin_dispose (input_plugin_t *this_gen)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
Packit 5e46da
  if (this->bdh) {
Packit 5e46da
    bd_register_argb_overlay_proc(this->bdh, NULL, NULL, NULL);
Packit 5e46da
    bd_register_overlay_proc(this->bdh, NULL, NULL);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  close_overlay(this, -1);
Packit 5e46da
Packit 5e46da
  if (this->event_queue)
Packit 5e46da
    xine_event_dispose_queue(this->event_queue);
Packit 5e46da
Packit 5e46da
  pthread_mutex_lock(&this->title_info_mutex);
Packit 5e46da
  if (this->title_info)
Packit 5e46da
    bd_free_title_info(this->title_info);
Packit 5e46da
  this->title_info = NULL;
Packit 5e46da
  pthread_mutex_unlock(&this->title_info_mutex);
Packit 5e46da
Packit 5e46da
  pthread_mutex_destroy(&this->title_info_mutex);
Packit 5e46da
Packit 5e46da
  if (this->bdh)
Packit 5e46da
    bd_close(this->bdh);
Packit 5e46da
Packit 5e46da
  osd_buf_destroy(&this->osd_buf);
Packit 5e46da
Packit 5e46da
  free (this->mrl);
Packit 5e46da
  free (this->disc_root);
Packit 5e46da
  free (this->disc_name);
Packit 5e46da
Packit 5e46da
  free (this);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int parse_mrl(const char *mrl_in, char **path, int *title, int *chapter)
Packit 5e46da
{
Packit 5e46da
  int skip = 0;
Packit 5e46da
Packit 5e46da
  if (!strncasecmp(mrl_in, "bluray:", 7))
Packit 5e46da
    skip = 7;
Packit 5e46da
  else if (!strncasecmp(mrl_in, "bd:", 3))
Packit 5e46da
    skip = 3;
Packit 5e46da
  else
Packit 5e46da
    return -1;
Packit 5e46da
Packit 5e46da
  char *mrl = strdup(mrl_in + skip);
Packit 5e46da
Packit 5e46da
  /* title[.chapter] given ? parse and drop it */
Packit 5e46da
  if (mrl[strlen(mrl)-1] != '/') {
Packit 5e46da
    char *end = strrchr(mrl, '/');
Packit 5e46da
    if (end && end[1]) {
Packit 5e46da
      if (sscanf(end, "/%d.%d", title, chapter) < 1)
Packit 5e46da
        *title = -1;
Packit 5e46da
      else
Packit 5e46da
        *end = 0;
Packit 5e46da
    }
Packit 5e46da
  }
Packit 5e46da
  lprintf(" -> title %d, chapter %d, mrl \'%s\'\n", *title, *chapter, mrl);
Packit 5e46da
Packit 5e46da
  if ((mrl[0] == 0) ||
Packit 5e46da
      (mrl[1] == 0 && mrl[0] == '/') ||
Packit 5e46da
      (mrl[2] == 0 && mrl[1] == '/' && mrl[0] == '/') ||
Packit 5e46da
      (mrl[3] == 0 && mrl[2] == '/' && mrl[1] == '/' && mrl[0] == '/')){
Packit 5e46da
Packit 5e46da
    /* default device */
Packit 5e46da
    *path = NULL;
Packit 5e46da
Packit 5e46da
  } else if (*mrl == '/') {
Packit 5e46da
Packit 5e46da
    /* strip extra slashes */
Packit 5e46da
    char *start = mrl;
Packit 5e46da
    while (start[0] == '/' && start[1] == '/')
Packit 5e46da
      start++;
Packit 5e46da
Packit 5e46da
    *path = strdup(start);
Packit 5e46da
Packit 5e46da
    _x_mrl_unescape(*path);
Packit 5e46da
Packit 5e46da
    lprintf("non-defaut mount point \'%s\'\n", *path);
Packit 5e46da
Packit 5e46da
  } else {
Packit 5e46da
    lprintf("invalid mrl \'%s\'\n", mrl_in);
Packit 5e46da
    free(mrl);
Packit 5e46da
    return 0;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  free(mrl);
Packit 5e46da
Packit 5e46da
  return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int get_disc_info(bluray_input_plugin_t *this)
Packit 5e46da
{
Packit 5e46da
  const BLURAY_DISC_INFO *disc_info;
Packit 5e46da
Packit 5e46da
  disc_info = bd_get_disc_info(this->bdh);
Packit 5e46da
Packit 5e46da
  if (!disc_info) {
Packit 5e46da
    LOGMSG("bd_get_disc_info() failed\n");
Packit 5e46da
    return -1;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  if (!disc_info->bluray_detected) {
Packit 5e46da
    LOGMSG("bd_get_disc_info(): BluRay not detected\n");
Packit 5e46da
    this->nav_mode = 0;
Packit 5e46da
    return 0;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  if (disc_info->aacs_detected && !disc_info->aacs_handled) {
Packit 5e46da
    if (!disc_info->libaacs_detected)
Packit 5e46da
      _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE,
Packit 5e46da
                  "Media stream scrambled/encrypted with AACS",
Packit 5e46da
                  "libaacs not installed", NULL);
Packit 5e46da
    else
Packit 5e46da
      _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE,
Packit 5e46da
                  "Media stream scrambled/encrypted with AACS", NULL);
Packit 5e46da
    return -1;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  if (disc_info->bdplus_detected && !disc_info->bdplus_handled) {
Packit 5e46da
    if (!disc_info->libbdplus_detected)
Packit 5e46da
      _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE,
Packit 5e46da
                  "Media scrambled/encrypted with BD+",
Packit 5e46da
                  "libbdplus not installed.", NULL);
Packit 5e46da
    else
Packit 5e46da
      _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE,
Packit 5e46da
                  "Media stream scrambled/encrypted with BD+", NULL);
Packit 5e46da
    return -1;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
#if 0
Packit 5e46da
  if (this->nav_mode && !disc_info->first_play_supported) {
Packit 5e46da
    _x_message (this->stream, XINE_MSG_GENERAL_WARNING,
Packit 5e46da
                "Can't play disc using menus",
Packit 5e46da
                "First Play title not supported", NULL);
Packit 5e46da
    this->nav_mode = 0;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  if (this->nav_mode && disc_info->num_unsupported_titles > 0) {
Packit 5e46da
    _x_message (this->stream, XINE_MSG_GENERAL_WARNING,
Packit 5e46da
                "Unsupported titles found",
Packit 5e46da
                "Some titles can't be played in navigation mode", NULL);
Packit 5e46da
  }
Packit 5e46da
#endif
Packit 5e46da
  this->num_titles = disc_info->num_hdmv_titles + disc_info->num_bdj_titles;
Packit 5e46da
  this->disc_info  = disc_info;
Packit 5e46da
Packit 5e46da
  return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int bluray_plugin_open (input_plugin_t *this_gen)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this    = (bluray_input_plugin_t *) this_gen;
Packit 5e46da
  int                    title   = -1;
Packit 5e46da
  int                    chapter = 0;
Packit 5e46da
Packit 5e46da
  lprintf("bluray_plugin_open\n");
Packit 5e46da
Packit 5e46da
  /* validate and parse mrl */
Packit 5e46da
  if (!parse_mrl(this->mrl, &this->disc_root, &title, &chapter))
Packit 5e46da
    return -1;
Packit 5e46da
Packit 5e46da
  if (!strncasecmp(this->mrl, "bd:", 3))
Packit 5e46da
    this->nav_mode = 1;
Packit 5e46da
Packit 5e46da
  if (!this->disc_root)
Packit 5e46da
    this->disc_root = strdup(this->class->mountpoint);
Packit 5e46da
Packit 5e46da
  /* open libbluray */
Packit 5e46da
Packit 5e46da
  if (! (this->bdh = bd_open (this->disc_root, NULL))) {
Packit 5e46da
    LOGMSG("bd_open(\'%s\') failed: %s\n", this->disc_root, strerror(errno));
Packit 5e46da
    return -1;
Packit 5e46da
  }
Packit 5e46da
  lprintf("bd_open(\'%s\') OK\n", this->disc_root);
Packit 5e46da
Packit 5e46da
  if (get_disc_info(this) < 0) {
Packit 5e46da
    return -1;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  /* load title list */
Packit 5e46da
Packit 5e46da
  this->num_title_idx = bd_get_titles(this->bdh, TITLES_RELEVANT, MIN_TITLE_LENGTH);
Packit 5e46da
  LOGMSG("%d titles\n", this->num_title_idx);
Packit 5e46da
Packit 5e46da
  if (this->num_title_idx < 1)
Packit 5e46da
    return -1;
Packit 5e46da
Packit 5e46da
  /* select title */
Packit 5e46da
Packit 5e46da
  /* if title was not in mrl, guess the main title */
Packit 5e46da
  if (title < 0) {
Packit 5e46da
    uint64_t duration = 0;
Packit 5e46da
    int i, playlist = 99999;
Packit 5e46da
    for (i = 0; i < this->num_title_idx; i++) {
Packit 5e46da
      BLURAY_TITLE_INFO *info = bd_get_title_info(this->bdh, i, 0);
Packit 5e46da
      if (info->duration > duration) {
Packit 5e46da
        title    = i;
Packit 5e46da
        duration = info->duration;
Packit 5e46da
        playlist = info->playlist;
Packit 5e46da
      }
Packit 5e46da
      bd_free_title_info(info);
Packit 5e46da
    }
Packit 5e46da
    lprintf("main title: %d (%05d.mpls)\n", title, playlist);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  /* update player settings */
Packit 5e46da
Packit 5e46da
  bd_set_player_setting    (this->bdh, BLURAY_PLAYER_SETTING_REGION_CODE,  this->class->region);
Packit 5e46da
  bd_set_player_setting    (this->bdh, BLURAY_PLAYER_SETTING_PARENTAL,     this->class->parental);
Packit 5e46da
  bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_AUDIO_LANG,   this->class->language);
Packit 5e46da
  bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_PG_LANG,      this->class->language);
Packit 5e46da
  bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_MENU_LANG,    this->class->language);
Packit 5e46da
  bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_COUNTRY_CODE, this->class->country);
Packit 5e46da
Packit 5e46da
  /* init event queue */
Packit 5e46da
  bd_get_event(this->bdh, NULL);
Packit 5e46da
Packit 5e46da
  /* get disc name */
Packit 5e46da
Packit 5e46da
  this->meta_dl = bd_get_meta(this->bdh);
Packit 5e46da
Packit 5e46da
  if (this->meta_dl && this->meta_dl->di_name && strlen(this->meta_dl->di_name) > 1) {
Packit 5e46da
    this->disc_name = strdup(this->meta_dl->di_name);
Packit 5e46da
  }
Packit 5e46da
  else if (strcmp(this->disc_root, this->class->mountpoint)) {
Packit 5e46da
    char *t = strrchr(this->disc_root, '/');
Packit 5e46da
    if (!t[1])
Packit 5e46da
      while (t > this->disc_root && t[-1] != '/') t--;
Packit 5e46da
    else
Packit 5e46da
      while (t[0] == '/') t++;
Packit 5e46da
    this->disc_name = strdup(t);
Packit 5e46da
    char *end = this->disc_name + strlen(this->disc_name) - 1;
Packit 5e46da
    if (*end ==  '/')
Packit 5e46da
      *end = 0;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  /* register overlay (graphics) handler */
Packit 5e46da
Packit 5e46da
  if (this->stream->video_out->get_capabilities(this->stream->video_out) & VO_CAP_ARGB_LAYER_OVERLAY) {
Packit 5e46da
fprintf(stderr, "argb overlays\n");
Packit 5e46da
    osd_buf_init(&this->osd_buf);
Packit 5e46da
    bd_register_argb_overlay_proc(this->bdh, this, argb_overlay_proc, &this->osd_buf.buf);
Packit 5e46da
  } else {
Packit 5e46da
    fprintf(stderr, "no argb overlay support. NO BD-J.\n");
Packit 5e46da
  }
Packit 5e46da
  bd_register_overlay_proc(this->bdh, this, overlay_proc);
Packit 5e46da
Packit 5e46da
  /* open */
Packit 5e46da
  this->current_title = -1;
Packit 5e46da
  this->current_title_idx = -1;
Packit 5e46da
Packit 5e46da
  if (this->nav_mode) {
Packit 5e46da
    if (bd_play(this->bdh) <= 0) {
Packit 5e46da
      LOGMSG("bd_play() failed\n");
Packit 5e46da
      return -1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
  } else {
Packit 5e46da
    if (open_title(this, title) <= 0 &&
Packit 5e46da
        open_title(this, 0) <= 0)
Packit 5e46da
      return -1;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  /* jump to chapter */
Packit 5e46da
Packit 5e46da
  if (chapter > 0) {
Packit 5e46da
    chapter = MAX(0, MIN((int)this->title_info->chapter_count, chapter) - 1);
Packit 5e46da
    bd_seek_chapter(this->bdh, chapter);
Packit 5e46da
    _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, chapter + 1);
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static input_plugin_t *bluray_class_get_instance (input_class_t *cls_gen, xine_stream_t *stream,
Packit 5e46da
                                                  const char *mrl)
Packit 5e46da
{
Packit 5e46da
  bluray_input_plugin_t *this;
Packit 5e46da
Packit 5e46da
  lprintf("bluray_class_get_instance\n");
Packit 5e46da
Packit 5e46da
  if (strncasecmp(mrl, "bluray:", 7) && strncasecmp(mrl, "bd:", 3))
Packit 5e46da
    return NULL;
Packit 5e46da
Packit 5e46da
  this = (bluray_input_plugin_t *) calloc(1, sizeof (bluray_input_plugin_t));
Packit 5e46da
Packit 5e46da
  this->stream = stream;
Packit 5e46da
  this->class  = (bluray_input_class_t*)cls_gen;
Packit 5e46da
  this->mrl    = strdup(mrl);
Packit 5e46da
Packit 5e46da
  this->input_plugin.open               = bluray_plugin_open;
Packit 5e46da
  this->input_plugin.get_capabilities   = bluray_plugin_get_capabilities;
Packit 5e46da
  this->input_plugin.read               = bluray_plugin_read;
Packit 5e46da
  this->input_plugin.read_block         = bluray_plugin_read_block;
Packit 5e46da
  this->input_plugin.seek               = bluray_plugin_seek;
Packit 5e46da
  this->input_plugin.seek_time          = bluray_plugin_seek_time;
Packit 5e46da
  this->input_plugin.get_current_pos    = bluray_plugin_get_current_pos;
Packit 5e46da
  this->input_plugin.get_current_time   = bluray_plugin_get_current_time;
Packit 5e46da
  this->input_plugin.get_length         = bluray_plugin_get_length;
Packit 5e46da
  this->input_plugin.get_blocksize      = bluray_plugin_get_blocksize;
Packit 5e46da
  this->input_plugin.get_mrl            = bluray_plugin_get_mrl;
Packit 5e46da
  this->input_plugin.get_optional_data  = bluray_plugin_get_optional_data;
Packit 5e46da
  this->input_plugin.dispose            = bluray_plugin_dispose;
Packit 5e46da
  this->input_plugin.input_class        = cls_gen;
Packit 5e46da
Packit 5e46da
  this->event_queue = xine_event_new_queue (this->stream);
Packit 5e46da
Packit 5e46da
  pthread_mutex_init(&this->title_info_mutex, NULL);
Packit 5e46da
Packit 5e46da
  this->pg_stream = -1;
Packit 5e46da
Packit 5e46da
  return &this->input_plugin;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * plugin class
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
static void mountpoint_change_cb(void *data, xine_cfg_entry_t *cfg)
Packit 5e46da
{
Packit 5e46da
  bluray_input_class_t *this = (bluray_input_class_t *) data;
Packit 5e46da
Packit 5e46da
  this->mountpoint = cfg->str_value;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void language_change_cb(void *data, xine_cfg_entry_t *cfg)
Packit 5e46da
{
Packit 5e46da
  bluray_input_class_t *this = (bluray_input_class_t *) data;
Packit 5e46da
Packit 5e46da
  this->language = cfg->str_value;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void country_change_cb(void *data, xine_cfg_entry_t *cfg)
Packit 5e46da
{
Packit 5e46da
  bluray_input_class_t *this = (bluray_input_class_t *) data;
Packit 5e46da
Packit 5e46da
  this->country = cfg->str_value;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void region_change_cb(void *data, xine_cfg_entry_t *cfg)
Packit 5e46da
{
Packit 5e46da
  bluray_input_class_t *this = (bluray_input_class_t *) data;
Packit 5e46da
Packit 5e46da
  this->region = cfg->num_value;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void parental_change_cb(void *data, xine_cfg_entry_t *cfg)
Packit 5e46da
{
Packit 5e46da
  bluray_input_class_t *this = (bluray_input_class_t *) data;
Packit 5e46da
Packit 5e46da
  this->parental = cfg->num_value;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static const char * const *bluray_class_get_autoplay_list (input_class_t *this_gen, int *num_files)
Packit 5e46da
{
Packit 5e46da
  (void)this_gen;
Packit 5e46da
Packit 5e46da
  static char *autoplay_list[] = { "bluray:/", NULL };
Packit 5e46da
Packit 5e46da
  *num_files = 1;
Packit 5e46da
Packit 5e46da
  return (const char * const *)autoplay_list;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int bluray_class_eject_media (input_class_t *this_gen)
Packit 5e46da
{
Packit 5e46da
  return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void bluray_class_dispose (input_class_t *this_gen)
Packit 5e46da
{
Packit 5e46da
  bluray_input_class_t *this   = (bluray_input_class_t *) this_gen;
Packit 5e46da
  config_values_t      *config = this->xine->config;
Packit 5e46da
Packit 5e46da
  config->unregister_callback(config, "media.bluray.mountpoint");
Packit 5e46da
  config->unregister_callback(config, "media.bluray.region");
Packit 5e46da
  config->unregister_callback(config, "media.bluray.language");
Packit 5e46da
  config->unregister_callback(config, "media.bluray.country");
Packit 5e46da
  config->unregister_callback(config, "media.bluray.parental");
Packit 5e46da
Packit 5e46da
  free (this);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void *bluray_init_plugin (xine_t *xine, void *data)
Packit 5e46da
{
Packit 5e46da
  (void)data;
Packit 5e46da
Packit 5e46da
  static char *skip_modes[] = {"skip chapter", "skip title", NULL};
Packit 5e46da
Packit 5e46da
  config_values_t      *config = xine->config;
Packit 5e46da
  bluray_input_class_t *this   = (bluray_input_class_t *) calloc(1, sizeof (bluray_input_class_t));
Packit 5e46da
Packit 5e46da
  this->xine = xine;
Packit 5e46da
Packit 5e46da
  this->input_class.get_instance       = bluray_class_get_instance;
Packit 5e46da
  this->input_class.identifier         = "bluray";
Packit 5e46da
  this->input_class.description        = _("BluRay input plugin");
Packit 5e46da
  this->input_class.get_dir            = NULL;
Packit 5e46da
  this->input_class.get_autoplay_list  = bluray_class_get_autoplay_list;
Packit 5e46da
  this->input_class.dispose            = bluray_class_dispose;
Packit 5e46da
  this->input_class.eject_media        = bluray_class_eject_media;
Packit 5e46da
Packit 5e46da
  this->mountpoint = config->register_filename(config, "media.bluray.mountpoint",
Packit 5e46da
                                               "/mnt/bluray", XINE_CONFIG_STRING_IS_DIRECTORY_NAME,
Packit 5e46da
                                               _("BluRay mount point"),
Packit 5e46da
                                               _("Default mount location for BluRay discs."),
Packit 5e46da
                                               0, mountpoint_change_cb, (void *) this);
Packit 5e46da
Packit 5e46da
  /* Player settings */
Packit 5e46da
  this->language =
Packit 5e46da
    config->register_string(config, "media.bluray.language",
Packit 5e46da
                            "eng",
Packit 5e46da
                            _("default language for BluRay playback"),
Packit 5e46da
                            _("xine tries to use this language as a default for BluRay playback. "
Packit 5e46da
                              "As far as the BluRay supports it, menus and audio tracks will be presented "
Packit 5e46da
                              "in this language.\nThe value must be a three character"
Packit 5e46da
                              "ISO639-2 language code."),
Packit 5e46da
                            0, language_change_cb, this);
Packit 5e46da
  this->country =
Packit 5e46da
    config->register_string(config, "media.bluray.country",
Packit 5e46da
                            "en",
Packit 5e46da
                            _("BluRay player country code"),
Packit 5e46da
                            _("The value must be a two character ISO3166-1 country code."),
Packit 5e46da
                            0, country_change_cb, this);
Packit 5e46da
  this->region =
Packit 5e46da
    config->register_num(config, "media.bluray.region",
Packit 5e46da
                         7,
Packit 5e46da
                         _("BluRay player region code (1=A, 2=B, 4=C)"),
Packit 5e46da
                         _("This only needs to be changed if your BluRay jumps to a screen "
Packit 5e46da
                           "complaining about a wrong region code. It has nothing to do with "
Packit 5e46da
                           "the region code set in BluRay drives, this is purely software."),
Packit 5e46da
                         0, region_change_cb, this);
Packit 5e46da
  this->parental =
Packit 5e46da
    config->register_num(config, "media.bluray.parental",
Packit 5e46da
                         99,
Packit 5e46da
                         _("parental control age limit (1-99)"),
Packit 5e46da
                         _("Prevents playback of BluRay titles where parental "
Packit 5e46da
                           "control age limit is higher than this limit"),
Packit 5e46da
                         0, parental_change_cb, this);
Packit 5e46da
Packit 5e46da
  /* */
Packit 5e46da
  config->register_enum(config, "media.bluray.skip_behaviour", 0,
Packit 5e46da
                        skip_modes,
Packit 5e46da
                        _("unit for the skip action"),
Packit 5e46da
                        _("You can configure the behaviour when issuing a skip command (using the skip "
Packit 5e46da
                          "buttons for example)."),
Packit 5e46da
                        20, NULL, NULL);
Packit 5e46da
Packit 5e46da
  return this;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static const char * const *bd_class_get_autoplay_list (input_class_t *this_gen, int *num_files)
Packit 5e46da
{
Packit 5e46da
  static const char * const autoplay_list[] = { "bd:/", NULL };
Packit 5e46da
Packit 5e46da
  *num_files = 1;
Packit 5e46da
Packit 5e46da
  return autoplay_list;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void *bd_init_plugin (xine_t *xine, void *data)
Packit 5e46da
{
Packit 5e46da
  bluray_input_class_t *this = bluray_init_plugin(xine, data);
Packit 5e46da
Packit 5e46da
  if (this) {
Packit 5e46da
    this->input_class.identifier  = "bluray";
Packit 5e46da
    this->input_class.description = _("BluRay input plugin (using menus)");
Packit 5e46da
Packit 5e46da
    this->input_class.get_dir            = NULL;
Packit 5e46da
    this->input_class.get_autoplay_list  = bd_class_get_autoplay_list;
Packit 5e46da
  }
Packit 5e46da
Packit 5e46da
  return this;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * exported plugin catalog entry
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
const plugin_info_t xine_plugin_info[] EXPORTED = {
Packit 5e46da
  /* type, API, "name", version, special_info, init_function */
Packit 5e46da
  { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, INPUT_PLUGIN_IFACE_VERSION, "BLURAY", XINE_VERSION_CODE, NULL, bluray_init_plugin },
Packit 5e46da
  { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, INPUT_PLUGIN_IFACE_VERSION, "BD",     XINE_VERSION_CODE, NULL, bd_init_plugin },
Packit 5e46da
  { PLUGIN_NONE, 0, "", 0, NULL, NULL }
Packit 5e46da
};