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