FFmpeg
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
bluray.c
Go to the documentation of this file.
1 /*
2  * BluRay (libbluray) protocol
3  *
4  * Copyright (c) 2012 Petri Hintukainen <phintuka <at> users.sourceforge.net>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include <libbluray/bluray.h>
24 
25 #include "libavutil/avstring.h"
26 #include "libavformat/avformat.h"
27 #include "libavformat/url.h"
28 #include "libavutil/opt.h"
29 
30 #define BLURAY_PROTO_PREFIX "bluray:"
31 #define MIN_PLAYLIST_LENGTH 180 /* 3 min */
32 
33 typedef struct {
34  const AVClass *class;
35 
36  BLURAY *bd;
37 
38  int playlist;
39  int angle;
40  int chapter;
41  /*int region;*/
43 
44 #define OFFSET(x) offsetof(BlurayContext, x)
45 static const AVOption options[] = {
46 {"playlist", "", OFFSET(playlist), AV_OPT_TYPE_INT, { .i64=-1 }, -1, 99999, AV_OPT_FLAG_DECODING_PARAM },
47 {"angle", "", OFFSET(angle), AV_OPT_TYPE_INT, { .i64=0 }, 0, 0xfe, AV_OPT_FLAG_DECODING_PARAM },
48 {"chapter", "", OFFSET(chapter), AV_OPT_TYPE_INT, { .i64=1 }, 1, 0xfffe, AV_OPT_FLAG_DECODING_PARAM },
49 /*{"region", "bluray player region code (1 = region A, 2 = region B, 4 = region C)", OFFSET(region), AV_OPT_TYPE_INT, { .i64=0 }, 0, 3, AV_OPT_FLAG_DECODING_PARAM },*/
50 {NULL}
51 };
52 
53 static const AVClass bluray_context_class = {
54  .class_name = "bluray",
55  .item_name = av_default_item_name,
56  .option = options,
57  .version = LIBAVUTIL_VERSION_INT,
58 };
59 
60 
62 {
63  BlurayContext *bd = h->priv_data;
64  const BLURAY_DISC_INFO *disc_info;
65 
66  disc_info = bd_get_disc_info(bd->bd);
67  if (!disc_info) {
68  av_log(h, AV_LOG_ERROR, "bd_get_disc_info() failed\n");
69  return -1;
70  }
71 
72  if (!disc_info->bluray_detected) {
73  av_log(h, AV_LOG_ERROR, "BluRay disc not detected\n");
74  return -1;
75  }
76 
77  /* AACS */
78  if (disc_info->aacs_detected && !disc_info->aacs_handled) {
79  if (!disc_info->libaacs_detected) {
81  "Media stream encrypted with AACS, install and configure libaacs\n");
82  } else {
83  av_log(h, AV_LOG_ERROR, "Your libaacs can't decrypt this media\n");
84  }
85  return -1;
86  }
87 
88  /* BD+ */
89  if (disc_info->bdplus_detected && !disc_info->bdplus_handled) {
90  /*
91  if (!disc_info->libbdplus_detected) {
92  av_log(h, AV_LOG_ERROR,
93  "Media stream encrypted with BD+, install and configure libbdplus");
94  } else {
95  */
96  av_log(h, AV_LOG_ERROR, "Unable to decrypt BD+ encrypted media\n");
97  /*}*/
98  return -1;
99  }
100 
101  return 0;
102 }
103 
104 static int bluray_close(URLContext *h)
105 {
106  BlurayContext *bd = h->priv_data;
107  if (bd->bd) {
108  bd_close(bd->bd);
109  }
110 
111  return 0;
112 }
113 
114 static int bluray_open(URLContext *h, const char *path, int flags)
115 {
116  BlurayContext *bd = h->priv_data;
117  int num_title_idx;
118  const char *diskname = path;
119 
120  av_strstart(path, BLURAY_PROTO_PREFIX, &diskname);
121 
122  bd->bd = bd_open(diskname, NULL);
123  if (!bd->bd) {
124  av_log(h, AV_LOG_ERROR, "bd_open() failed\n");
125  return AVERROR(EIO);
126  }
127 
128  /* check if disc can be played */
129  if (check_disc_info(h) < 0) {
130  return AVERROR(EIO);
131  }
132 
133  /* setup player registers */
134  /* region code has no effect without menus
135  if (bd->region > 0 && bd->region < 5) {
136  av_log(h, AV_LOG_INFO, "setting region code to %d (%c)\n", bd->region, 'A' + (bd->region - 1));
137  bd_set_player_setting(bd->bd, BLURAY_PLAYER_SETTING_REGION_CODE, bd->region);
138  }
139  */
140 
141  /* load title list */
142  num_title_idx = bd_get_titles(bd->bd, TITLES_RELEVANT, MIN_PLAYLIST_LENGTH);
143  av_log(h, AV_LOG_INFO, "%d usable playlists:\n", num_title_idx);
144  if (num_title_idx < 1) {
145  return AVERROR(EIO);
146  }
147 
148  /* if playlist was not given, select longest playlist */
149  if (bd->playlist < 0) {
150  uint64_t duration = 0;
151  int i;
152  for (i = 0; i < num_title_idx; i++) {
153  BLURAY_TITLE_INFO *info = bd_get_title_info(bd->bd, i, 0);
154 
155  av_log(h, AV_LOG_INFO, "playlist %05d.mpls (%d:%02d:%02d)\n",
156  info->playlist,
157  ((int)(info->duration / 90000) / 3600),
158  ((int)(info->duration / 90000) % 3600) / 60,
159  ((int)(info->duration / 90000) % 60));
160 
161  if (info->duration > duration) {
162  bd->playlist = info->playlist;
163  duration = info->duration;
164  }
165 
166  bd_free_title_info(info);
167  }
168  av_log(h, AV_LOG_INFO, "selected %05d.mpls\n", bd->playlist);
169  }
170 
171  /* select playlist */
172  if (bd_select_playlist(bd->bd, bd->playlist) <= 0) {
173  av_log(h, AV_LOG_ERROR, "bd_select_playlist(%05d.mpls) failed\n", bd->playlist);
174  return AVERROR(EIO);
175  }
176 
177  /* select angle */
178  if (bd->angle >= 0) {
179  bd_select_angle(bd->bd, bd->angle);
180  }
181 
182  /* select chapter */
183  if (bd->chapter > 1) {
184  bd_seek_chapter(bd->bd, bd->chapter - 1);
185  }
186 
187  return 0;
188 }
189 
190 static int bluray_read(URLContext *h, unsigned char *buf, int size)
191 {
192  BlurayContext *bd = h->priv_data;
193  int len;
194 
195  if (!bd || !bd->bd) {
196  return AVERROR(EFAULT);
197  }
198 
199  len = bd_read(bd->bd, buf, size);
200 
201  return len;
202 }
203 
204 static int64_t bluray_seek(URLContext *h, int64_t pos, int whence)
205 {
206  BlurayContext *bd = h->priv_data;
207 
208  if (!bd || !bd->bd) {
209  return AVERROR(EFAULT);
210  }
211 
212  switch (whence) {
213  case SEEK_SET:
214  case SEEK_CUR:
215  case SEEK_END:
216  return bd_seek(bd->bd, pos);
217 
218  case AVSEEK_SIZE:
219  return bd_get_title_size(bd->bd);
220  }
221 
222  av_log(h, AV_LOG_ERROR, "Unsupported whence operation %d\n", whence);
223  return AVERROR(EINVAL);
224 }
225 
226 
228  .name = "bluray",
229  .url_close = bluray_close,
230  .url_open = bluray_open,
231  .url_read = bluray_read,
232  .url_seek = bluray_seek,
233  .priv_data_size = sizeof(BlurayContext),
234  .priv_data_class = &bluray_context_class,
235 };