2 * Copyright (C) 2010 Benjamin Zores <ben@geexbox.org>
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * Blu-ray parser/reader using libbluray
23 * Use 'git clone git://git.videolan.org/libbluray' to get it.
26 * - Add libbdnav support for menus navigation
27 * - Add AACS/BD+ protection detection
28 * - Add descrambled keys database support (KEYDB.cfg)
32 #include <libbluray/bluray.h>
35 #include "libavutil/common.h"
36 #include "libmpdemux/demuxer.h"
42 #define BLURAY_SECTOR_SIZE 6144
44 #define BLURAY_DEFAULT_ANGLE 0
45 #define BLURAY_DEFAULT_CHAPTER 0
46 #define BLURAY_DEFAULT_TITLE 0
48 char *bluray_device
= NULL
;
50 int bluray_chapter
= 0;
52 struct bluray_priv_s
{
59 static struct stream_priv_s
{
62 } bluray_stream_priv_dflts
= {
67 #define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
68 static const m_option_t bluray_stream_opts_fields
[] = {
69 { "hostname", ST_OFF(title
), CONF_TYPE_INT
, M_OPT_RANGE
, 0, 99999, NULL
},
70 { "filename", ST_OFF(device
), CONF_TYPE_STRING
, 0, 0 ,0, NULL
},
71 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
74 static const struct m_struct_st bluray_stream_opts
= {
76 sizeof(struct stream_priv_s
),
77 &bluray_stream_priv_dflts
,
78 bluray_stream_opts_fields
81 static void bluray_stream_close(stream_t
*s
)
83 struct bluray_priv_s
*b
= s
->priv
;
90 static int bluray_stream_seek(stream_t
*s
, off_t pos
)
92 struct bluray_priv_s
*b
= s
->priv
;
95 p
= bd_seek(b
->bd
, pos
);
103 static int bluray_stream_fill_buffer(stream_t
*s
, char *buf
, int len
)
105 struct bluray_priv_s
*b
= s
->priv
;
107 return bd_read(b
->bd
, buf
, len
);
110 static int bluray_stream_control(stream_t
*s
, int cmd
, void *arg
)
112 struct bluray_priv_s
*b
= s
->priv
;
116 case STREAM_CTRL_GET_NUM_CHAPTERS
: {
117 BLURAY_TITLE_INFO
*ti
;
119 ti
= bd_get_title_info(b
->bd
, b
->current_title
);
121 return STREAM_UNSUPPORTED
;
123 *((unsigned int *) arg
) = ti
->chapter_count
;
124 bd_free_title_info(ti
);
129 case STREAM_CTRL_GET_CURRENT_CHAPTER
: {
130 *((unsigned int *) arg
) = b
->current_chapter
;
134 case STREAM_CTRL_SEEK_TO_CHAPTER
: {
135 BLURAY_TITLE_INFO
*ti
;
136 int chapter
= *((unsigned int *) arg
);
140 ti
= bd_get_title_info(b
->bd
, b
->current_title
);
142 return STREAM_UNSUPPORTED
;
144 if (chapter
< 0 || chapter
> ti
->chapter_count
) {
145 bd_free_title_info(ti
);
146 return STREAM_UNSUPPORTED
;
149 pos
= bd_chapter_pos(b
->bd
, chapter
);
150 r
= bluray_stream_seek(s
, pos
);
151 bd_free_title_info(ti
);
153 return r
? 1 : STREAM_UNSUPPORTED
;
156 case STREAM_CTRL_GET_NUM_ANGLES
: {
157 BLURAY_TITLE_INFO
*ti
;
159 ti
= bd_get_title_info(b
->bd
, b
->current_title
);
161 return STREAM_UNSUPPORTED
;
163 *((int *) arg
) = ti
->angle_count
;
164 bd_free_title_info(ti
);
169 case STREAM_CTRL_GET_ANGLE
: {
170 *((int *) arg
) = b
->current_angle
;
174 case STREAM_CTRL_SET_ANGLE
: {
175 BLURAY_TITLE_INFO
*ti
;
176 int angle
= *((int *) arg
);
178 ti
= bd_get_title_info(b
->bd
, b
->current_title
);
180 return STREAM_UNSUPPORTED
;
182 if (angle
< 0 || angle
> ti
->angle_count
) {
183 bd_free_title_info(ti
);
184 return STREAM_UNSUPPORTED
;
187 b
->current_angle
= angle
;
188 bd_seamless_angle_change(b
->bd
, angle
);
189 bd_free_title_info(ti
);
198 return STREAM_UNSUPPORTED
;
201 static int bluray_stream_open(stream_t
*s
, int mode
,
202 void *opts
, int *file_format
)
204 struct stream_priv_s
*p
= opts
;
205 struct bluray_priv_s
*b
;
207 BLURAY_TITLE_INFO
*info
= NULL
;
210 int title
, title_guess
, title_count
;
213 unsigned int chapter
= 0, angle
= 0;
214 uint64_t max_duration
= 0;
215 int64_t chapter_pos
= 0;
220 /* find the requested device */
223 else if (bluray_device
)
224 device
= bluray_device
;
227 mp_tmsg(MSGT_OPEN
, MSGL_ERR
,
228 "No Blu-ray device/location was specified ...\n");
229 return STREAM_UNSUPPORTED
;
233 bd
= bd_open(device
, NULL
);
235 mp_tmsg(MSGT_OPEN
, MSGL_ERR
, "Couldn't open Blu-ray device: %s\n",
237 return STREAM_UNSUPPORTED
;
240 /* check for available titles on disc */
241 title_count
= bd_get_titles(bd
, TITLES_RELEVANT
);
242 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_BLURAY_TITLES=%d\n", title_count
);
244 mp_msg(MSGT_OPEN
, MSGL_ERR
,
245 "Can't find any Blu-ray-compatible title here.\n");
247 return STREAM_UNSUPPORTED
;
250 /* parse titles information */
251 title_guess
= BLURAY_DEFAULT_TITLE
;
252 for (i
= 0; i
< title_count
; i
++) {
253 BLURAY_TITLE_INFO
*ti
;
256 ti
= bd_get_title_info(bd
, i
);
260 sec
= ti
->duration
/ 90000;
261 msec
= (ti
->duration
- sec
) % 1000;
263 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
,
264 "ID_BLURAY_TITLE_%d_CHAPTERS=%d\n", i
+ 1, ti
->chapter_count
);
265 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
,
266 "ID_BLURAY_TITLE_%d_ANGLE=%d\n", i
+ 1, ti
->angle_count
);
267 mp_msg(MSGT_IDENTIFY
, MSGL_V
,
268 "ID_BLURAY_TITLE_%d_LENGTH=%d.%03d\n", i
+ 1, sec
, msec
);
270 /* try to guess which title may contain the main movie */
271 if (ti
->duration
> max_duration
) {
272 max_duration
= ti
->duration
;
276 bd_free_title_info(ti
);
279 /* Select current title */
280 title
= p
->title
? p
->title
- 1: title_guess
;
281 title
= FFMIN(title
, title_count
- 1);
283 bd_select_title(bd
, title
);
285 title_size
= bd_get_title_size(bd
);
286 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
,
287 "ID_BLURAY_CURRENT_TITLE=%d\n", title
+ 1);
289 /* Get current title information */
290 info
= bd_get_title_info(bd
, title
);
295 chapter
= bluray_chapter
? bluray_chapter
: BLURAY_DEFAULT_CHAPTER
;
296 chapter
= FFMIN(chapter
, info
->chapter_count
);
299 chapter_pos
= bd_chapter_pos(bd
, chapter
);
301 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
,
302 "ID_BLURAY_CURRENT_CHAPTER=%d\n", chapter
+ 1);
305 angle
= bluray_angle
? bluray_angle
: BLURAY_DEFAULT_ANGLE
;
306 angle
= FFMIN(angle
, info
->angle_count
);
309 bd_select_angle(bd
, angle
);
311 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_BLURAY_CURRENT_ANGLE=%d\n", angle
+ 1);
313 bd_free_title_info(info
);
316 s
->fill_buffer
= bluray_stream_fill_buffer
;
317 s
->seek
= bluray_stream_seek
;
318 s
->close
= bluray_stream_close
;
319 s
->control
= bluray_stream_control
;
321 b
= calloc(1, sizeof(struct bluray_priv_s
));
323 b
->current_angle
= angle
;
324 b
->current_chapter
= chapter
;
325 b
->current_title
= title
;
327 s
->start_pos
= chapter_pos
;
328 s
->end_pos
= title_size
;
329 s
->sector_size
= BLURAY_SECTOR_SIZE
;
330 s
->flags
= mode
| MP_STREAM_SEEK
;
332 s
->type
= STREAMTYPE_BLURAY
;
333 s
->url
= strdup("br://");
335 mp_tmsg(MSGT_OPEN
, MSGL_V
, "Blu-ray successfully opened.\n");
340 const stream_info_t stream_info_bluray
= {
344 "Play Blu-ray discs through external libbluray",
346 { "br", "bluray", NULL
},