2
* Blu-ray stream playback
3
* by cRTrn13 <crtrn13-at-gmail.com> 2009
5
* This file is part of MPlayer.
7
* MPlayer is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* MPlayer is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License along
18
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
19
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25
#include "libavutil/common.h"
26
#include "libavutil/aes.h"
27
#include "libavutil/sha.h"
28
#include "libmpdemux/demuxer.h"
29
#include "libavutil/intreadwrite.h"
34
#include "stream_bd.h"
36
static const int BD_UNIT_SIZE = 6144;
37
static const char BD_UKF_PATH[] = "%s/AACS/Unit_Key_RO.inf";
38
static const char BD_M2TS_PATH[] = "%s/BDMV/STREAM/%05d.m2ts";
39
static const char BD_CLIPINF_PATH[] = "%s/BDMV/CLIPINF/%05d.clpi";
41
static const char DEFAULT_BD_DEVICE[] = "/mnt/bd";
43
static const struct stream_priv_s {
46
} stream_priv_dflts = {
51
// Format: bd://[title][</mntlocation>]
52
// --> e.g.: bd://117/media/THE_MUMMY/
54
// instead of directly, mount location can also be gotten through -dvd-device
55
#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
56
static const m_option_t stream_opts_fields[] = {
57
{ "hostname", ST_OFF(title), CONF_TYPE_INT, M_OPT_RANGE, 0, 99999, NULL},
58
{ "filename", ST_OFF(device), CONF_TYPE_STRING, 0, 0 ,0, NULL},
59
{ NULL, NULL, 0, 0, 0, 0, NULL }
62
static const struct m_struct_st stream_opts = {
64
sizeof(struct stream_priv_s),
74
static const key BD_CBC_IV = {
76
0x0b, 0xa0, 0xf8, 0xdd, 0xfe, 0xa6, 0x1f, 0xb3,
77
0xd8, 0xdf, 0x9f, 0x56, 0x6a, 0x05, 0x0f, 0x78
86
// This is just a guess
87
#define LANG_NAME_LEN 20
92
char lang_name[LANG_NAME_LEN + 1];
100
stream_t *title_file;
101
struct AVAES *aescbc;
102
struct AVAES *aeseed;
106
struct lang_map *lang_maps;
109
static void bd_stream_close(stream_t *s)
111
struct bd_priv *bd = s->priv;
112
free_stream(bd->title_file);
119
static int bd_stream_seek(stream_t *s, off_t pos)
121
struct bd_priv *bd = s->priv;
123
// must seek to start of unit
124
pos -= pos % BD_UNIT_SIZE;
125
if (!stream_seek(bd->title_file, pos)) {
136
#define ID_STR_LEN 41
137
static void id2str(const uint8_t *id, int idlen, char dst[ID_STR_LEN])
140
idlen = FFMIN(idlen, 20);
141
for (i = 0; i < idlen; i++)
142
snprintf(dst + 2*i, 3, "%02"PRIX8, id[i]);
145
static int find_vuk(struct bd_priv *bd, const uint8_t discid[20])
148
char filename[PATH_MAX];
152
char idstr[ID_STR_LEN];
154
// look up discid in KEYDB.cfg to get VUK
155
home = getenv("HOME");
156
snprintf(filename, sizeof(filename), "%s/.dvdcss/KEYDB.cfg", home);
157
file = open_stream(filename, NULL, NULL);
159
mp_msg(MSGT_OPEN,MSGL_ERR,
160
"Cannot open VUK database file %s\n", filename);
163
id2str(discid, 20, idstr);
164
while (stream_read_line(file, line, sizeof(line), 0)) {
167
// file is built up this way:
168
// DISCID = title | V | VUK
170
// DISCID = title | key-pair
171
// key-pair = V | VUK
175
// can be followed by ; and comment
177
if (strncasecmp(line, idstr, 40))
179
mp_msg(MSGT_OPEN, MSGL_V, "KeyDB found Entry for DiscID:\n%s\n", line);
181
vst = strstr(line, "| V |");
185
while (isspace(*vst)) vst++;
186
if (sscanf(vst, "%16"SCNx64, &bd->vuk.u64[0]) != 1)
188
if (sscanf(vst + 16, "%16"SCNx64, &bd->vuk.u64[1]) != 1)
190
bd->vuk.u64[0] = av_be2ne64(bd->vuk.u64[0]);
191
bd->vuk.u64[1] = av_be2ne64(bd->vuk.u64[1]);
198
static int bd_get_uks(struct bd_priv *bd)
207
char filename[PATH_MAX];
209
char idstr[ID_STR_LEN];
211
snprintf(filename, sizeof(filename), BD_UKF_PATH, bd->device);
212
file = open_stream(filename, NULL, NULL);
214
mp_msg(MSGT_OPEN, MSGL_ERR,
215
"Cannot open file %s to get UK and DiscID\n", filename);
218
file_size = file->end_pos;
219
if (file_size <= 0 || file_size > 10 * 1024* 1024) {
220
mp_msg(MSGT_OPEN, MSGL_ERR, "File %s too large\n", filename);
224
buf = av_malloc(file_size);
225
stream_read(file, buf, file_size);
228
// get discid from file
229
asha = av_malloc(av_sha_size);
230
av_sha_init(asha, 160);
231
av_sha_update(asha, buf, file_size);
232
av_sha_final(asha, discid);
235
if (!find_vuk(bd, discid)) {
236
id2str(discid, 20, idstr);
237
mp_msg(MSGT_OPEN, MSGL_ERR,
238
"No Volume Unique Key (VUK) found for this Disc: %s\n", idstr);
244
if (pos < file_size) {
245
int key_pos = pos + 48;
246
int max_count = (file_size - key_pos - 16) / 48;
247
bd->uks.count = AV_RB16(&buf[pos]);
248
if (max_count < bd->uks.count) {
249
mp_msg(MSGT_OPEN, MSGL_ERR,
250
"File to small for key count %i, using %i\n",
251
bd->uks.count, max_count);
252
bd->uks.count = max_count;
254
bd->uks.keys = calloc(bd->uks.count, sizeof(key));
256
a = av_malloc(av_aes_size);
257
av_aes_init(a, bd->vuk.u8, 128, 1);
259
id2str(discid, 20, idstr);
260
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_BD_DISCID=%s\n", idstr);
261
id2str(bd->vuk.u8, 16, idstr);
262
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_BD_VUK=%s\n", idstr);
264
for (i = 0; i < bd->uks.count; i++) {
265
av_aes_crypt(a, bd->uks.keys[i].u8, &buf[key_pos], 1, NULL, 1); // decrypt unit key
276
// NOTE: we assume buf is sufficiently aligned to 64 bit read/writes
277
static off_t bd_read(struct bd_priv *bd, uint8_t *buf, int len)
280
int unit_offset = bd->pos % BD_UNIT_SIZE;
285
read_len = stream_read(bd->title_file, buf, len);
290
int decrypt_len = FFMIN(len, BD_UNIT_SIZE - unit_offset);
291
av_aes_crypt(bd->aescbc, buf, buf, decrypt_len / 16, bd->iv.u8, 1);
296
int decrypt_len = FFMIN(len, BD_UNIT_SIZE);
297
// reset aes context as at start of unit
301
// perform encryption of first 16 bytes of unit (seed)
302
av_aes_crypt(bd->aeseed, enc_seed.u8, buf, 1, NULL, 0);
305
enc_seed.u64[0] ^= AV_RN64A(buf);
306
enc_seed.u64[1] ^= AV_RN64A(buf + 8);
308
// set uk AES-CBC key from enc_seed and BD_CBC_IV
309
av_aes_init(bd->aescbc, enc_seed.u8, 128, 1);
312
av_aes_crypt(bd->aescbc, &buf[16], &buf[16],
313
(decrypt_len - 16) / 16, bd->iv.u8, 1);
323
static int bd_stream_fill_buffer(stream_t *s, char *buf, int len)
326
struct bd_priv *bd = s->priv;
328
read_len = bd_read(bd, buf, len);
335
static int is_video_type(int type)
349
static int is_audio_type(int type)
366
static int is_sub_type(int type)
375
const char *bd_lang_from_id(stream_t *s, int id)
377
struct bd_priv *bd = s->priv;
379
for (i = 0; i < bd->nr_lang_maps; i++) {
380
if (bd->lang_maps[i].id == id)
381
return bd->lang_maps[i].lang_name;
386
int bd_aid_from_lang(stream_t *s, const char *lang)
388
struct bd_priv *bd = s->priv;
390
for (i = 0; i < bd->nr_lang_maps; i++) {
391
if (is_audio_type(bd->lang_maps[i].type) &&
392
strstr(bd->lang_maps[i].lang_name, lang))
393
return bd->lang_maps[i].id;
398
int bd_sid_from_lang(stream_t *s, const char *lang)
400
struct bd_priv *bd = s->priv;
402
for (i = 0; i < bd->nr_lang_maps; i++) {
403
if (is_sub_type(bd->lang_maps[i].type) &&
404
strstr(bd->lang_maps[i].lang_name, lang))
405
return bd->lang_maps[i].id;
410
static void get_clipinf(struct bd_priv *bd)
413
int langmap_offset, index_offset, end_offset;
414
char filename[PATH_MAX];
417
snprintf(filename, sizeof(filename), BD_CLIPINF_PATH, bd->device, bd->title);
418
file = open_stream(filename, NULL, NULL);
420
mp_msg(MSGT_OPEN, MSGL_ERR, "Cannot open clipinf %s\n", filename);
423
if (stream_read_qword(file) != AV_RB64("HDMV0200")) {
424
mp_msg(MSGT_OPEN, MSGL_ERR, "Unknown clipinf format\n");
427
stream_read_dword(file); // unknown offset
428
langmap_offset = stream_read_dword(file);
429
index_offset = stream_read_dword(file);
430
end_offset = stream_read_dword(file);
432
// read language <-> stream id mappings
433
stream_seek(file, langmap_offset);
434
stream_read_dword(file); // size
435
stream_skip(file, 8); // unknown
436
bd->nr_lang_maps = stream_read_char(file); // number of entries
437
stream_read_char(file); // unknown
439
bd->lang_maps = calloc(bd->nr_lang_maps, sizeof(*bd->lang_maps));
440
for (i = 0; i < bd->nr_lang_maps; i++) {
442
bd->lang_maps[i].id = stream_read_word(file);
443
stream_read_char(file); // unknown
444
type = stream_read_char(file);
445
if (!is_video_type(type) && !is_audio_type(type) && !is_sub_type(type))
446
mp_msg(MSGT_OPEN, MSGL_WARN, "Unknown type %x in clipinf\n", type);
447
bd->lang_maps[i].type = type;
448
stream_read(file, bd->lang_maps[i].lang_name, LANG_NAME_LEN);
454
static int bd_stream_open(stream_t *s, int mode, void* opts, int* file_format)
456
char filename[PATH_MAX];
458
struct stream_priv_s* p = opts;
459
struct bd_priv *bd = calloc(1, sizeof(*bd));
462
bd->device = p->device;
463
else if (bluray_device)
464
bd->device = bluray_device;
466
bd->device = DEFAULT_BD_DEVICE;
468
s->sector_size = BD_UNIT_SIZE;
469
s->read_chunk = 32 * BD_UNIT_SIZE;
470
s->flags = STREAM_READ | MP_STREAM_SEEK;
471
s->fill_buffer = bd_stream_fill_buffer;
472
s->seek = bd_stream_seek;
473
s->close = bd_stream_close;
476
s->type = STREAMTYPE_BD;
477
s->url = strdup("bd://");
480
bd->title = p->title;
482
// get and decrypt unit keys
486
bd->aescbc = av_malloc(av_aes_size);
487
bd->aeseed = av_malloc(av_aes_size);
489
// set up AES key from uk
490
av_aes_init(bd->aeseed, bd->uks.keys[0].u8, 128, 0);
492
snprintf(filename, sizeof(filename), BD_M2TS_PATH, bd->device, bd->title);
493
mp_msg(MSGT_OPEN, MSGL_STATUS, "Opening %s\n", filename);
494
bd->title_file = open_stream(filename, NULL, NULL);
497
s->end_pos = bd->title_file->end_pos;
504
const stream_info_t stream_info_bd = {