]> git.sesse.net Git - vlc/blob - modules/access/bluray.c
Bluray: correctly select the main title
[vlc] / modules / access / bluray.c
1 /*****************************************************************************
2  * bluray.c: Blu-ray disc support plugin
3  *****************************************************************************
4  * Copyright (C) 2010 VideoLAN, VLC authors and libbluray AUTHORS
5  *
6  * This program 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.
10  *
11  * This program 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.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #ifdef HAVE_SYS_STAT_H
26 #   include <sys/stat.h>
27 #endif
28
29 #include <assert.h>
30 #include <limits.h>
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_access.h>
35 #include <vlc_messages.h>
36
37 #include <libbluray/bluray.h>
38
39 /*****************************************************************************
40  * Module descriptor
41  *****************************************************************************/
42 #define CACHING_TEXT N_("Caching value in ms")
43 #define CACHING_LONGTEXT N_( "Caching value for BDs. This "\
44                              "value should be set in milliseconds." )
45
46 /* Callbacks */
47 static int  blurayOpen ( vlc_object_t * );
48 static void blurayClose( vlc_object_t * );
49
50 vlc_module_begin ()
51     set_shortname( N_("BluRay") )
52     set_description( N_("Blu-Ray Disc support (libbluray)") )
53
54     set_category( CAT_INPUT )
55     set_subcategory( SUBCAT_INPUT_ACCESS )
56     set_capability( "access", 60 )
57
58     add_integer( "bluray-caching", 1000, NULL,
59         CACHING_TEXT, CACHING_LONGTEXT, true )
60
61     add_shortcut( "bluray" )
62     add_shortcut( "file" )
63
64     set_callbacks( blurayOpen, blurayClose )
65 vlc_module_end ()
66
67 /*****************************************************************************
68  * Local prototypes
69  *****************************************************************************/
70
71 struct access_sys_t
72 {
73     BLURAY *bluray; /* */
74     int i_bd_delay;
75 };
76
77 static ssize_t blurayRead   (access_t *, uint8_t *, size_t);
78 static int     bluraySeek   (access_t *, uint64_t);
79 static int     blurayControl(access_t *, int, va_list);
80 static int     bluraySetTitle(access_t *p_access, int i_tile);
81
82 /*****************************************************************************
83  * blurayOpen: module init function
84  *****************************************************************************/
85 static int blurayOpen( vlc_object_t *object )
86 {
87     access_t *p_access = (access_t*)object;
88
89     access_sys_t *p_sys;
90     char *pos_title;
91     int i_title = -1;
92     char bd_path[PATH_MAX];
93
94     if( strcmp( p_access->psz_access, "bluray" ) ) {
95         // TODO BDMV support, once we figure out what to do in libbluray
96         return VLC_EGENERIC;
97     }
98
99     /* init access fields */
100     access_InitFields(p_access);
101
102     /* register callback function for communication */
103     ACCESS_SET_CALLBACKS(blurayRead, NULL, blurayControl, bluraySeek);
104
105     p_access->p_sys = p_sys = malloc(sizeof(access_sys_t));
106     if (unlikely(!p_sys)) {
107         return VLC_ENOMEM;
108     }
109
110     /* store current bd_path */
111     strncpy(bd_path, p_access->psz_location, sizeof(bd_path));
112     bd_path[PATH_MAX - 1] = '\0';
113
114     if ( (pos_title = strrchr(bd_path, ':')) ) {
115         /* found character ':' for title information */
116         *(pos_title++) = '\0';
117         i_title = atoi(pos_title);
118     }
119
120     p_sys->bluray = bd_open(bd_path, NULL);
121     if ( !p_sys->bluray ) {
122         free(p_sys);
123         return VLC_EGENERIC;
124     }
125
126     /* set start title number */
127     if ( bluraySetTitle(p_access, i_title) != VLC_SUCCESS ) {
128         blurayClose(object);
129         return VLC_EGENERIC;
130     }
131
132     p_sys->i_bd_delay = var_InheritInteger(p_access, "bluray-caching");
133
134     return VLC_SUCCESS;
135 }
136
137
138 /*****************************************************************************
139  * blurayClose: module destroy function
140  *****************************************************************************/
141 static void blurayClose( vlc_object_t *object )
142 {
143     access_t *p_access = (access_t*)object;
144     access_sys_t *p_sys = p_access->p_sys;
145
146     /* bd_close( NULL ) can crash */
147     assert(p_sys->bluray);
148     bd_close(p_sys->bluray);
149     free(p_sys);
150 }
151
152
153 /*****************************************************************************
154  * bluraySetTitle: select new BD title
155  *****************************************************************************/
156 static int bluraySetTitle(access_t *p_access, int i_title)
157 {
158     access_sys_t *p_sys = p_access->p_sys;
159
160     unsigned int i_nb_titles = bd_get_titles(p_sys->bluray, TITLES_RELEVANT);
161
162     /* Looking for the main title, ie the longest duration */
163     if (i_title == -1) {
164         uint64_t duration=0;
165         for (unsigned int i = 0; i < i_nb_titles; i++) {
166             BLURAY_TITLE_INFO *info = bd_get_title_info(p_sys->bluray, i);
167             if (info->duration > duration) {
168                 i_title = i;
169                 duration = info->duration;
170             }
171         }
172     }
173
174     /* Select Blu-Ray title */
175     if ( bd_select_title(p_access->p_sys->bluray, i_title) == 0 ) {
176         msg_Err( p_access, "cannot select bd title '%d'", p_access->info.i_title);
177         return VLC_EGENERIC;
178     }
179
180     /* read title length and init some values */
181     p_access->info.i_title = i_title;
182     p_access->info.i_size  = bd_get_title_size(p_sys->bluray);
183     p_access->info.i_pos   = 0;
184     p_access->info.b_eof   = false;
185     p_access->info.i_seekpoint = 0;
186
187     return VLC_SUCCESS;
188 }
189
190
191 /*****************************************************************************
192  * blurayControl: handle the controls
193  *****************************************************************************/
194 static int blurayControl(access_t *p_access, int query, va_list args)
195 {
196     access_sys_t *p_sys = p_access->p_sys;
197     bool     *pb_bool;
198     int64_t  *pi_64;
199
200     switch (query) {
201         case ACCESS_CAN_SEEK:
202         case ACCESS_CAN_FASTSEEK:
203         case ACCESS_CAN_PAUSE:
204         case ACCESS_CAN_CONTROL_PACE:
205              pb_bool = (bool*)va_arg( args, bool * );
206              *pb_bool = true;
207              break;
208
209         case ACCESS_GET_PTS_DELAY:
210             pi_64 = (int64_t*)va_arg( args, int64_t * );
211             *pi_64 = p_sys->i_bd_delay;
212             break;
213
214         case ACCESS_SET_PAUSE_STATE:
215             /* Nothing to do */
216             break;
217
218         case ACCESS_SET_TITLE:
219         {
220             int i_title = (int)va_arg( args, int );
221             if( bluraySetTitle( p_access, i_title ) != VLC_SUCCESS )
222                 return VLC_EGENERIC;
223             break;
224         }
225         case ACCESS_SET_SEEKPOINT:
226         {
227             int i_chapter = (int)va_arg( args, int );
228             bd_seek_chapter( p_sys->bluray, i_chapter );
229             break;
230         }
231         case ACCESS_GET_META:
232         case ACCESS_GET_TITLE_INFO:
233         case ACCESS_SET_PRIVATE_ID_STATE:
234         case ACCESS_GET_CONTENT_TYPE:
235             return VLC_EGENERIC;
236
237         default:
238             msg_Warn( p_access, "unimplemented query (%d) in control", query );
239             return VLC_EGENERIC;
240     }
241
242     return VLC_SUCCESS;
243 }
244
245
246 /*****************************************************************************
247  * bluraySeek: seek to the given position
248  *****************************************************************************/
249 static int bluraySeek(access_t *p_access, uint64_t position)
250 {
251     access_sys_t *p_sys = p_access->p_sys;
252
253     p_access->info.i_pos = bd_seek(p_sys->bluray, position);
254     p_access->info.b_eof = false;
255
256     return VLC_SUCCESS;
257 }
258
259
260 /*****************************************************************************
261  * blurayRead: read BD data into buffer
262  *****************************************************************************/
263 static ssize_t blurayRead(access_t *p_access, uint8_t *data, size_t size)
264 {
265     access_sys_t *p_sys = p_access->p_sys;
266     int nread;
267
268     if (p_access->info.b_eof) {
269         return 0;
270     }
271
272     /* read data into buffer with given length */
273     nread = bd_read(p_sys->bluray, data, size);
274
275     if( nread == 0 ) {
276         p_access->info.b_eof = true;
277     }
278     else if( nread > 0 ) {
279         p_access->info.i_pos += nread;
280     }
281
282     return nread;
283 }
284