2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #define FIRST_AC3_AID 128
33 #define FIRST_DTS_AID 136
34 #define FIRST_MPG_AID 0
35 #define FIRST_PCM_AID 160
41 #include "stream_dvd.h"
42 #include "stream_dvd_common.h"
43 #include "libmpdemux/demuxer.h"
45 static char* dvd_device_current
;
48 #define LIBDVDREAD_VERSION(maj,min,micro) ((maj)*10000 + (min)*100 + (micro))
50 * Try to autodetect the libdvd-0.9.0 library
51 * (0.9.0 removed the <dvdread/dvd_udf.h> header, and moved the two defines
52 * DVD_VIDEO_LB_LEN and MAX_UDF_FILE_NAME_LEN from it to
53 * <dvdread/dvd_reader.h>)
55 #ifndef DVDREAD_VERSION
56 #if defined(DVD_VIDEO_LB_LEN) && defined(MAX_UDF_FILE_NAME_LEN)
57 #define DVDREAD_VERSION LIBDVDREAD_VERSION(0,9,0)
59 #define DVDREAD_VERSION LIBDVDREAD_VERSION(0,8,0)
64 static struct stream_priv_s
{
67 } stream_priv_dflts
= {
72 #define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
74 static const m_option_t stream_opts_fields
[] = {
75 { "hostname", ST_OFF(title
), CONF_TYPE_INT
, M_OPT_RANGE
, 1, 99, NULL
},
76 { "filename", ST_OFF(device
), CONF_TYPE_STRING
, 0, 0 ,0, NULL
},
77 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
79 static const struct m_struct_st stream_opts
= {
81 sizeof(struct stream_priv_s
),
86 int dvd_chapter_from_cell(dvd_priv_t
* dvd
,int title
,int cell
)
92 if(title
< 0 || cell
< 0){
95 /* for most DVD's chapter == cell */
96 /* but there are more complecated cases... */
97 if(chapter
>= dvd
->vmg_file
->tt_srpt
->title
[title
].nr_of_ptts
) {
98 chapter
= dvd
->vmg_file
->tt_srpt
->title
[title
].nr_of_ptts
-1;
100 title
= dvd
->tt_srpt
->title
[title
].vts_ttn
-1;
101 ptt
= dvd
->vts_file
->vts_ptt_srpt
->title
[title
].ptt
;
102 while(chapter
>= 0) {
103 pgc_id
= ptt
[chapter
].pgcn
;
104 pgn
= ptt
[chapter
].pgn
;
105 cur_pgc
= dvd
->vts_file
->vts_pgcit
->pgci_srp
[pgc_id
-1].pgc
;
106 if(cell
>= cur_pgc
->program_map
[pgn
-1]-1) {
111 /* didn't find a chapter ??? */
115 int dvd_lang_from_aid(stream_t
*stream
, int id
) {
118 if (!stream
) return 0;
121 for(i
=0;i
<d
->nr_of_channels
;i
++) {
122 if(d
->audio_streams
[i
].id
==id
)
123 return d
->audio_streams
[i
].language
;
128 int dvd_aid_from_lang(stream_t
*stream
, char **lang
) {
129 dvd_priv_t
*d
=stream
->priv
;
131 for (int n
= 0; lang
[n
]; n
++) {
132 code
= lang
[n
][1] | (lang
[n
][0] << 8);
133 for(i
=0;i
<d
->nr_of_channels
;i
++) {
134 if(d
->audio_streams
[i
].language
==code
) {
135 mp_tmsg(MSGT_OPEN
,MSGL_INFO
,"Selected DVD audio channel: %d language: %c%c\n",
136 d
->audio_streams
[i
].id
, lang
[n
][0], lang
[n
][1]);
137 return d
->audio_streams
[i
].id
;
139 //printf("%X != %X (%c%c)\n",code,d->audio_streams[i].language,lang[0],lang[1]);
142 mp_tmsg(MSGT_OPEN
,MSGL_WARN
,"No matching DVD audio language found!\n");
146 int dvd_number_of_subs(stream_t
*stream
) {
150 if (!stream
) return -1;
153 for (i
= 0; i
< d
->nr_of_subtitles
; i
++)
154 if (d
->subtitles
[i
].id
> maxid
) maxid
= d
->subtitles
[i
].id
;
158 int dvd_lang_from_sid(stream_t
*stream
, int id
) {
161 if (!stream
) return 0;
164 for (i
= 0; i
< d
->nr_of_subtitles
; i
++)
165 if (d
->subtitles
[i
].id
== id
&& d
->subtitles
[i
].language
) return d
->subtitles
[i
].language
;
169 int dvd_sid_from_lang(stream_t
*stream
, char **lang
) {
170 dvd_priv_t
*d
=stream
->priv
;
172 for (int n
= 0; lang
[n
]; n
++) {
173 code
= lang
[n
][1] | (lang
[n
][0] << 8);
174 for(i
=0;i
<d
->nr_of_subtitles
;i
++) {
175 if(d
->subtitles
[i
].language
==code
) {
176 mp_tmsg(MSGT_OPEN
,MSGL_INFO
,"Selected DVD subtitle channel: %d language: %c%c\n", i
, lang
[n
][0], lang
[n
][1]);
177 return d
->subtitles
[i
].id
;
181 mp_tmsg(MSGT_OPEN
,MSGL_WARN
,"No matching DVD subtitle language found!\n");
185 static int dvd_next_cell(dvd_priv_t
*d
) {
186 int next_cell
=d
->cur_cell
;
188 mp_msg(MSGT_DVD
,MSGL_DBG2
, "dvd_next_cell: next1=0x%X \n",next_cell
);
189 if( d
->cur_pgc
->cell_playback
[ next_cell
].block_type
== BLOCK_TYPE_ANGLE_BLOCK
) {
190 while(next_cell
<d
->last_cell
) {
191 if( d
->cur_pgc
->cell_playback
[next_cell
].block_mode
== BLOCK_MODE_LAST_CELL
)
196 mp_msg(MSGT_DVD
,MSGL_DBG2
, "dvd_next_cell: next2=0x%X \n",next_cell
);
199 if(next_cell
>=d
->last_cell
)
201 if(d
->cur_pgc
->cell_playback
[next_cell
].block_type
== BLOCK_TYPE_ANGLE_BLOCK
) {
202 next_cell
+=dvd_angle
;
203 if(next_cell
>=d
->last_cell
)
206 mp_msg(MSGT_DVD
,MSGL_DBG2
, "dvd_next_cell: next3=0x%X \n",next_cell
);
210 static int dvd_read_sector(dvd_priv_t
*d
, unsigned char *data
)
214 if(d
->packs_left
==0) {
216 * If we're not at the end of this cell, we can determine the next
217 * VOBU to display using the VOBU_SRI information section of the
218 * DSI. Using this value correctly follows the current angle,
219 * avoiding the doubled scenes in The Matrix, and makes our life
222 * Otherwise, we set our next address past the end of this cell to
223 * force the code above to go to the next cell in the program.
225 if(d
->dsi_pack
.vobu_sri
.next_vobu
!= SRI_END_OF_CELL
) {
226 d
->cur_pack
= d
->dsi_pack
.dsi_gi
.nv_pck_lbn
+ ( d
->dsi_pack
.vobu_sri
.next_vobu
& 0x7fffffff );
227 mp_msg(MSGT_DVD
,MSGL_DBG2
, "Navi new pos=0x%X \n",d
->cur_pack
);
229 // end of cell! find next cell!
230 mp_msg(MSGT_DVD
,MSGL_V
, "--- END OF CELL !!! ---\n");
231 d
->cur_pack
=d
->cell_last_pack
+1;
236 if(d
->cur_pack
>d
->cell_last_pack
) {
238 int next
=dvd_next_cell(d
);
241 // if( d->cur_pgc->cell_playback[d->cur_cell].block_type
242 // == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle;
243 d
->cur_pack
= d
->cur_pgc
->cell_playback
[ d
->cur_cell
].first_sector
;
244 d
->cell_last_pack
=d
->cur_pgc
->cell_playback
[ d
->cur_cell
].last_sector
;
245 mp_msg(MSGT_DVD
,MSGL_V
, "DVD next cell: %d pack: 0x%X-0x%X \n",d
->cur_cell
,d
->cur_pack
,d
->cell_last_pack
);
250 len
= DVDReadBlocks(d
->title
, d
->cur_pack
, 1, data
);
251 // only == 0 should indicate an error, but some dvdread version are buggy when used with dvdcss
252 if(len
<= 0) return -1; //error
254 if(data
[38]==0 && data
[39]==0 && data
[40]==1 && data
[41]==0xBF &&
255 data
[1024]==0 && data
[1025]==0 && data
[1026]==1 && data
[1027]==0xBF) {
256 // found a Navi packet!!!
257 #if DVDREAD_VERSION >= LIBDVDREAD_VERSION(0,9,0)
258 navRead_DSI(&d
->dsi_pack
, &(data
[ DSI_START_BYTE
]));
260 navRead_DSI(&d
->dsi_pack
, &(data
[ DSI_START_BYTE
]), sizeof(dsi_t
));
262 if(d
->cur_pack
!= d
->dsi_pack
.dsi_gi
.nv_pck_lbn
) {
263 mp_msg(MSGT_DVD
,MSGL_V
, "Invalid NAVI packet! lba=0x%X navi=0x%X \n",
264 d
->cur_pack
,d
->dsi_pack
.dsi_gi
.nv_pck_lbn
);
267 d
->packs_left
= d
->dsi_pack
.dsi_gi
.vobu_ea
;
268 mp_msg(MSGT_DVD
,MSGL_DBG2
, "Found NAVI packet! lba=0x%X len=%d \n",d
->cur_pack
,d
->packs_left
);
269 //navPrint_DSI(&d->dsi_pack);
270 mp_msg(MSGT_DVD
,MSGL_DBG3
,"\r### CELL %d: Navi: %d/%d IFO: %d/%d \n",d
->cur_cell
,
271 d
->dsi_pack
.dsi_gi
.vobu_c_idn
,d
->dsi_pack
.dsi_gi
.vobu_vob_idn
,
272 d
->cur_pgc
->cell_position
[d
->cur_cell
].cell_nr
,
273 d
->cur_pgc
->cell_position
[d
->cur_cell
].vob_id_nr
);
277 #if defined(__GNUC__) && ( defined(__sparc__) || defined(hpux) )
278 // workaround for a bug in the sparc/hpux version of gcc 2.95.X ... 3.2,
279 // it generates incorrect code for unaligned access to a packed
280 // structure member, resulting in an mplayer crash with a SIGBUS
283 // See also gcc problem report PR c/7847:
284 // http://gcc.gnu.org/cgi-bin/gnatsweb.pl?database=gcc&cmd=view+audit-trail&pr=7847
285 for(i
=0;i
<9;i
++) { // check if all values zero:
286 __typeof__(d
->dsi_pack
.sml_agli
.data
[i
].address
) tmp_addr
;
287 memcpy(&tmp_addr
,&d
->dsi_pack
.sml_agli
.data
[i
].address
,sizeof(tmp_addr
));
288 if((skip
=tmp_addr
)!=0) break;
291 for(i
=0;i
<9;i
++) // check if all values zero:
292 if((skip
=d
->dsi_pack
.sml_agli
.data
[i
].address
)!=0) break;
294 if(skip
&& skip
!=0x7fffffff) {
295 // sml_agli table has valid data (at least one non-zero):
296 d
->cur_pack
=d
->dsi_pack
.dsi_gi
.nv_pck_lbn
+
297 d
->dsi_pack
.sml_agli
.data
[dvd_angle
].address
;
300 mp_msg(MSGT_DVD
,MSGL_V
, "Angle-seek synced using sml_agli map! new_lba=0x%X \n",d
->cur_pack
);
302 // check if we're in the right cell, jump otherwise:
303 if( (d
->dsi_pack
.dsi_gi
.vobu_c_idn
==d
->cur_pgc
->cell_position
[d
->cur_cell
].cell_nr
) &&
304 (d
->dsi_pack
.dsi_gi
.vobu_vob_idn
==d
->cur_pgc
->cell_position
[d
->cur_cell
].vob_id_nr
) ){
306 mp_msg(MSGT_DVD
,MSGL_V
, "Angle-seek synced by cell/vob IDN search! \n");
308 // wrong angle, skip this vobu:
309 d
->cur_pack
=d
->dsi_pack
.dsi_gi
.nv_pck_lbn
+
310 d
->dsi_pack
.dsi_gi
.vobu_ea
;
311 d
->angle_seek
=2; // DEBUG
321 if(d
->packs_left
>=0) --d
->packs_left
;
324 if(d
->angle_seek
==2) mp_msg(MSGT_DVD
,MSGL_V
, "!!! warning! reading packet while angle_seek !!!\n");
325 goto read_next
; // searching for Navi packet
328 return d
->cur_pack
-1;
331 static void dvd_seek(dvd_priv_t
*d
, int pos
)
336 // check if we stay in current cell (speedup things, and avoid angle skip)
337 if(d
->cur_pack
>d
->cell_last_pack
||
338 d
->cur_pack
<d
->cur_pgc
->cell_playback
[ d
->cur_cell
].first_sector
) {
340 // ok, cell change, find the right cell!
341 cell_playback_t
*cell
;
342 for(d
->cur_cell
=0; d
->cur_cell
< d
->cur_pgc
->nr_of_cells
; d
->cur_cell
++) {
343 cell
= &(d
->cur_pgc
->cell_playback
[d
->cur_cell
]);
344 if(cell
->block_type
== BLOCK_TYPE_ANGLE_BLOCK
&& cell
->block_mode
!= BLOCK_MODE_FIRST_CELL
)
346 d
->cell_last_pack
=cell
->last_sector
;
347 if(d
->cur_pack
<cell
->first_sector
) {
348 d
->cur_pack
=cell
->first_sector
;
351 if(d
->cur_pack
<=d
->cell_last_pack
) break; // ok, we find it! :)
355 mp_msg(MSGT_DVD
,MSGL_V
, "DVD Seek! lba=0x%X cell=%d packs: 0x%X-0x%X \n",
356 d
->cur_pack
,d
->cur_cell
,d
->cur_pgc
->cell_playback
[ d
->cur_cell
].first_sector
,d
->cell_last_pack
);
358 // if we're in interleaved multi-angle cell, find the right angle chain!
359 // (read Navi block, and use the seamless angle jump table)
363 static void dvd_close(dvd_priv_t
*d
)
365 ifoClose(d
->vts_file
);
366 ifoClose(d
->vmg_file
);
367 DVDCloseFile(d
->title
);
369 dvd_set_speed(dvd_device_current
, -1); /* -1 => restore default */
372 static int fill_buffer(stream_t
*s
, char *buf
, int len
)
377 pos
= dvd_read_sector(s
->priv
, buf
);
380 s
->pos
= 2048*(pos
- 1);
381 return 2048; // full sector
384 static int seek(stream_t
*s
, off_t newpos
) {
385 s
->pos
=newpos
; // real seek
386 dvd_seek(s
->priv
,s
->pos
/2048);
390 static void stream_dvd_close(stream_t
*s
) {
394 static int mp_get_titleset_length(ifo_handle_t
*vts_file
, tt_srpt_t
*tt_srpt
, int title_no
)
396 int vts_ttn
; ///< title number within video title set
397 int pgc_no
; ///< program chain number
398 int msec
; ///< time length in milliseconds
401 if(!vts_file
|| !tt_srpt
)
404 if(vts_file
->vtsi_mat
&& vts_file
->vts_pgcit
)
406 vts_ttn
= tt_srpt
->title
[title_no
].vts_ttn
- 1;
407 pgc_no
= vts_file
->vts_ptt_srpt
->title
[vts_ttn
].ptt
[0].pgcn
- 1;
408 msec
= mp_dvdtimetomsec(&vts_file
->vts_pgcit
->pgci_srp
[pgc_no
].pgc
->playback_time
);
414 static int mp_describe_titleset(dvd_reader_t
*dvd
, tt_srpt_t
*tt_srpt
, int vts_no
)
416 ifo_handle_t
*vts_file
;
417 int title_no
, msec
=0;
419 vts_file
= ifoOpen(dvd
, vts_no
);
423 if(!vts_file
->vtsi_mat
|| !vts_file
->vts_pgcit
)
429 for(title_no
= 0; title_no
< tt_srpt
->nr_of_srpts
; title_no
++)
431 if (tt_srpt
->title
[title_no
].title_set_nr
!= vts_no
)
433 msec
= mp_get_titleset_length(vts_file
, tt_srpt
, title_no
);
434 mp_msg(MSGT_IDENTIFY
, MSGL_V
, "ID_DVD_TITLE_%d_LENGTH=%d.%03d\n", title_no
+ 1, msec
/ 1000, msec
% 1000);
440 static int get_num_chapter(ifo_handle_t
*vts_file
, tt_srpt_t
*tt_srpt
, int title_no
)
442 if(!vts_file
|| !tt_srpt
)
445 if(title_no
< 0 || title_no
>= tt_srpt
->nr_of_srpts
)
448 // map global title to vts title
449 title_no
= tt_srpt
->title
[title_no
].vts_ttn
- 1;
451 if(title_no
< 0 || title_no
>= vts_file
->vts_ptt_srpt
->nr_of_srpts
)
454 return vts_file
->vts_ptt_srpt
->title
[title_no
].nr_of_ptts
;
457 static int seek_to_chapter(stream_t
*stream
, ifo_handle_t
*vts_file
, tt_srpt_t
*tt_srpt
, int title_no
, int chapter
)
459 dvd_priv_t
*d
= stream
->priv
;
464 if(!vts_file
|| !tt_srpt
)
467 if(title_no
< 0 || title_no
>= tt_srpt
->nr_of_srpts
)
470 // map global title to vts title
471 title_no
= tt_srpt
->title
[title_no
].vts_ttn
- 1;
473 if(title_no
< 0 || title_no
>= vts_file
->vts_ptt_srpt
->nr_of_srpts
)
476 if(chapter
< 0 || chapter
> vts_file
->vts_ptt_srpt
->title
[title_no
].nr_of_ptts
-1) //no such chapter
479 ptt
= vts_file
->vts_ptt_srpt
->title
[title_no
].ptt
[chapter
];
480 pgc
= vts_file
->vts_pgcit
->pgci_srp
[ptt
.pgcn
-1].pgc
;
482 d
->cur_cell
= pgc
->program_map
[ptt
.pgn
- 1] - 1;
483 if(pgc
->cell_playback
[d
->cur_cell
].block_type
== BLOCK_TYPE_ANGLE_BLOCK
)
484 d
->cur_cell
+= dvd_angle
;
485 d
->cur_pack
= pgc
->cell_playback
[d
->cur_cell
].first_sector
;
486 d
->cell_last_pack
= pgc
->cell_playback
[d
->cur_cell
].last_sector
;
491 pos
= (off_t
) d
->cur_pack
* 2048;
492 mp_msg(MSGT_OPEN
,MSGL_V
,"\r\nSTREAM_DVD, seeked to chapter: %d, cell: %u, pos: %"PRIu64
"\n",
493 chapter
, d
->cur_pack
, pos
);
498 static void list_chapters(ifo_handle_t
*vts_file
, tt_srpt_t
*tt_srpt
, int title_no
)
500 unsigned int i
, cell
, last_cell
;
505 title_no
= tt_srpt
->title
[title_no
].vts_ttn
- 1;
506 if(vts_file
->vts_ptt_srpt
->title
[title_no
].nr_of_ptts
< 2)
508 ptt
= vts_file
->vts_ptt_srpt
->title
[title_no
].ptt
;
510 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "CHAPTERS: ");
511 for(i
=0; i
<vts_file
->vts_ptt_srpt
->title
[title_no
].nr_of_ptts
; i
++)
513 pgc
= vts_file
->vts_pgcit
->pgci_srp
[ptt
[i
].pgcn
-1].pgc
;
514 cell
= pgc
->program_map
[ptt
[i
].pgn
-1]; //here the cell is 1-based
515 if(ptt
[i
].pgn
<pgc
->nr_of_programs
)
516 last_cell
= pgc
->program_map
[ptt
[i
].pgn
];
519 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "%02d:%02d:%02d.%03d,", t
/3600000, (t
/60000)%60, (t
/1000)%60, t
%1000);
521 if(!(pgc
->cell_playback
[cell
-1].block_type
== BLOCK_TYPE_ANGLE_BLOCK
&&
522 pgc
->cell_playback
[cell
-1].block_mode
!= BLOCK_MODE_FIRST_CELL
)
524 t
+= mp_dvdtimetomsec(&pgc
->cell_playback
[cell
-1].playback_time
);
526 } while(cell
< last_cell
);
528 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "\n");
531 static double dvd_get_current_time(stream_t
*stream
, int cell
)
534 dvd_priv_t
*d
= stream
->priv
;
537 if(cell
< 0) cell
=d
->cur_cell
;
538 for(i
=0; i
<cell
; i
++) {
539 if(d
->cur_pgc
->cell_playback
[i
].block_type
== BLOCK_TYPE_ANGLE_BLOCK
&&
540 d
->cur_pgc
->cell_playback
[i
].block_mode
!= BLOCK_MODE_FIRST_CELL
543 tm
+= d
->cell_times_table
[i
];
545 tm
+= mp_dvdtimetomsec(&d
->dsi_pack
.dsi_gi
.c_eltm
);
547 return (double)tm
/1000.0;
550 static int dvd_seek_to_time(stream_t
*stream
, ifo_handle_t
*vts_file
, double sec
)
552 unsigned int i
, j
, k
, timeunit
, ac_time
, tmap_sector
=0, cell_sector
=0, vobu_sector
=0;
556 dvd_priv_t
*d
= stream
->priv
;
557 vts_tmapt_t
*vts_tmapt
= vts_file
->vts_tmapt
;
559 if(!vts_file
->vts_tmapt
|| sec
< 0)
562 duration
= (double) mp_get_titleset_length(d
->vts_file
, d
->tt_srpt
, d
->cur_title
-1) / 1000.0f
;
567 timeunit
= vts_tmapt
->tmap
[i
].tmu
;
568 for(j
= 0; j
< vts_tmapt
->tmap
[i
].nr_of_entries
; j
++) {
569 ac_time
= timeunit
* (j
+ 1);
572 tmap_sector
= vts_tmapt
->tmap
[i
].map_ent
[j
] & 0x7fffffff;
574 //search enclosing cell
575 for(i
=0; i
<d
->cur_pgc
->nr_of_cells
; i
++) {
576 if(tmap_sector
>= d
->cur_pgc
->cell_playback
[i
].first_sector
&& tmap_sector
<= d
->cur_pgc
->cell_playback
[i
].last_sector
) {
577 cell_sector
= d
->cur_pgc
->cell_playback
[i
].first_sector
;
582 pos
= ((off_t
)cell_sector
)<<11;
583 stream_seek(stream
, pos
);
585 stream_skip(stream
, 2048);
586 t
= mp_dvdtimetomsec(&d
->dsi_pack
.dsi_gi
.c_eltm
);
588 tm
= dvd_get_current_time(stream
, -1);
590 pos
= ((off_t
)tmap_sector
)<<11;
591 stream_seek(stream
, pos
);
592 //now get current time in terms of the cell+cell time offset
593 memset(&d
->dsi_pack
.dsi_gi
.c_eltm
, 0, sizeof(dvd_time_t
));
595 if(!stream_skip(stream
, 2048))
597 tm
= dvd_get_current_time(stream
, -1);
599 tmap_sector
= stream
->pos
>> 11;
601 //search closest VOBU sector
602 k
=(vts_file
->vts_vobu_admap
->last_byte
+ 1 - VOBU_ADMAP_SIZE
)/4; //entries in the vobu admap
604 if(vts_file
->vts_vobu_admap
->vobu_start_sectors
[i
] > tmap_sector
)
607 vobu_sector
= vts_file
->vts_vobu_admap
->vobu_start_sectors
[i
-1];
608 pos
= ((off_t
)vobu_sector
) << 11;
609 stream_seek(stream
, pos
);
614 static int control(stream_t
*stream
,int cmd
,void* arg
)
616 dvd_priv_t
*d
= stream
->priv
;
619 case STREAM_CTRL_GET_TIME_LENGTH
:
621 *((double *)arg
) = (double) mp_get_titleset_length(d
->vts_file
, d
->tt_srpt
, d
->cur_title
-1)/1000.0;
624 case STREAM_CTRL_GET_NUM_CHAPTERS
:
627 r
= get_num_chapter(d
->vts_file
, d
->tt_srpt
, d
->cur_title
-1);
628 if(! r
) return STREAM_UNSUPPORTED
;
629 *((unsigned int *)arg
) = r
;
632 case STREAM_CTRL_SEEK_TO_CHAPTER
:
635 r
= seek_to_chapter(stream
, d
->vts_file
, d
->tt_srpt
, d
->cur_title
-1, *((unsigned int *)arg
));
636 if(! r
) return STREAM_UNSUPPORTED
;
640 case STREAM_CTRL_GET_CURRENT_CHAPTER
:
642 *((unsigned int *)arg
) = dvd_chapter_from_cell(d
, d
->cur_title
-1, d
->cur_cell
);
645 case STREAM_CTRL_GET_CURRENT_TIME
:
648 tm
= dvd_get_current_time(stream
, -1);
650 *((double *)arg
) = tm
;
655 case STREAM_CTRL_SEEK_TO_TIME
:
657 if(dvd_seek_to_time(stream
, d
->vts_file
, *((double*)arg
)))
661 case STREAM_CTRL_GET_ASPECT_RATIO
:
663 *((double *)arg
) = !d
->vts_file
->vtsi_mat
->vts_video_attr
.display_aspect_ratio
? 4.0/3.0 : 16.0/9.0;
666 case STREAM_CTRL_GET_NUM_ANGLES
:
668 *((int *)arg
) = d
->vmg_file
->tt_srpt
->title
[dvd_title
].nr_of_angles
;
671 case STREAM_CTRL_GET_ANGLE
:
673 *((int *)arg
) = dvd_angle
+1;
676 case STREAM_CTRL_SET_ANGLE
:
678 int ang
= *((int *)arg
);
679 if(ang
>d
->vmg_file
->tt_srpt
->title
[dvd_title
].nr_of_angles
|| ang
<=0)
686 return STREAM_UNSUPPORTED
;
690 static int open_s(stream_t
*stream
,int mode
, void* opts
, int* file_format
) {
691 struct stream_priv_s
* p
= (struct stream_priv_s
*)opts
;
694 mp_msg(MSGT_OPEN
,MSGL_V
,"URL: %s\n", stream
->url
);
695 dvd_title
= p
->title
;
702 ifo_handle_t
*vmg_file
;
704 ifo_handle_t
*vts_file
;
710 dvd_device_current
= p
->device
;
712 dvd_device_current
= dvd_device
;
714 dvd_device_current
= DEFAULT_DVD_DEVICE
;
715 dvd_set_speed(dvd_device_current
, dvd_speed
);
716 #if defined(__APPLE__) || defined(__DARWIN__)
717 /* Dynamic DVD drive selection on Darwin */
718 if(!strcmp(dvd_device_current
, "/dev/rdiskN")) {
720 size_t len
= strlen(dvd_device_current
)+1;
721 char *temp_device
= malloc(len
);
723 for (i
= 1; i
< 10; i
++) {
724 snprintf(temp_device
, len
, "/dev/rdisk%d", i
);
725 dvd
= DVDOpen(temp_device
);
727 mp_tmsg(MSGT_OPEN
,MSGL_ERR
,"Couldn't open DVD device: %s (%s)\n",temp_device
, strerror(errno
));
729 #if DVDREAD_VERSION <= LIBDVDREAD_VERSION(0,9,4)
730 dvd_file_t
*dvdfile
= DVDOpenFile(dvd
,dvd_title
,DVD_READ_INFO_FILE
);
732 mp_tmsg(MSGT_OPEN
,MSGL_ERR
,"Couldn't open DVD device: %s (%s)\n",temp_device
, strerror(errno
));
736 DVDCloseFile(dvdfile
);
744 m_struct_free(&stream_opts
,opts
);
745 return STREAM_UNSUPPORTED
;
748 #endif /* defined(__APPLE__) || defined(__DARWIN__) */
750 dvd
= DVDOpen(dvd_device_current
);
752 mp_tmsg(MSGT_OPEN
,MSGL_ERR
,"Couldn't open DVD device: %s (%s)\n",dvd_device_current
, strerror(errno
));
753 m_struct_free(&stream_opts
,opts
);
754 return STREAM_UNSUPPORTED
;
758 mp_msg(MSGT_OPEN
,MSGL_V
,"Reading disc structure, please wait...\n");
761 * Load the video manager to find out the information about the titles on
764 vmg_file
= ifoOpen(dvd
, 0);
766 mp_tmsg(MSGT_OPEN
,MSGL_ERR
, "Can't open VMG info!\n");
768 m_struct_free(&stream_opts
,opts
);
769 return STREAM_UNSUPPORTED
;
771 tt_srpt
= vmg_file
->tt_srpt
;
772 if (mp_msg_test(MSGT_IDENTIFY
, MSGL_INFO
))
774 int title_no
; ///< title number
775 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_DVD_TITLES=%d\n", tt_srpt
->nr_of_srpts
);
776 for (title_no
= 0; title_no
< tt_srpt
->nr_of_srpts
; title_no
++)
778 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_DVD_TITLE_%d_CHAPTERS=%d\n", title_no
+ 1, tt_srpt
->title
[title_no
].nr_of_ptts
);
779 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_DVD_TITLE_%d_ANGLES=%d\n", title_no
+ 1, tt_srpt
->title
[title_no
].nr_of_angles
);
782 if (mp_msg_test(MSGT_IDENTIFY
, MSGL_V
))
785 unsigned char discid
[16]; ///< disk ID, a 128 bit MD5 sum
786 int vts_no
; ///< video title set number
787 for (vts_no
= 1; vts_no
<= vmg_file
->vts_atrt
->nr_of_vtss
; vts_no
++)
788 mp_describe_titleset(dvd
, tt_srpt
, vts_no
);
789 if (DVDDiscID(dvd
, discid
) >= 0)
792 mp_msg(MSGT_IDENTIFY
, MSGL_V
, "ID_DVD_DISC_ID=");
793 for (i
= 0; i
< 16; i
++)
794 mp_msg(MSGT_IDENTIFY
, MSGL_V
, "%02X", discid
[i
]);
795 mp_msg(MSGT_IDENTIFY
, MSGL_V
, "\n");
797 if (DVDUDFVolumeInfo(dvd
, volid
, sizeof(volid
), NULL
, 0) >= 0 || DVDISOVolumeInfo(dvd
, volid
, sizeof(volid
), NULL
, 0) >= 0)
798 mp_msg(MSGT_IDENTIFY
, MSGL_V
, "ID_DVD_VOLUME_ID=%s\n", volid
);
801 * Make sure our title number is valid.
803 mp_tmsg(MSGT_OPEN
,MSGL_STATUS
, "There are %d titles on this DVD.\n", tt_srpt
->nr_of_srpts
);
804 if(dvd_title
< 1 || dvd_title
> tt_srpt
->nr_of_srpts
) {
805 mp_tmsg(MSGT_OPEN
,MSGL_ERR
, "Invalid DVD title number: %d\n", dvd_title
);
806 ifoClose( vmg_file
);
808 m_struct_free(&stream_opts
,opts
);
809 return STREAM_UNSUPPORTED
;
811 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_DVD_CURRENT_TITLE=%d\n", dvd_title
);
812 --dvd_title
; // remap 1.. -> 0..
814 * Make sure the angle number is valid for this title.
816 mp_tmsg(MSGT_OPEN
,MSGL_STATUS
, "There are %d angles in this DVD title.\n", tt_srpt
->title
[dvd_title
].nr_of_angles
);
817 if(dvd_angle
<1 || dvd_angle
>tt_srpt
->title
[dvd_title
].nr_of_angles
) {
818 mp_tmsg(MSGT_OPEN
,MSGL_ERR
, "Invalid DVD angle number: %d\n", dvd_angle
);
821 --dvd_angle
; // remap 1.. -> 0..
823 ttn
= tt_srpt
->title
[dvd_title
].vts_ttn
- 1;
825 * Load the VTS information for the title set our title is in.
827 vts_file
= ifoOpen( dvd
, tt_srpt
->title
[dvd_title
].title_set_nr
);
829 mp_tmsg(MSGT_OPEN
,MSGL_ERR
, "Cannot open the IFO file for DVD title %d.\n", tt_srpt
->title
[dvd_title
].title_set_nr
);
833 * We've got enough info, time to open the title set data.
835 title
= DVDOpenFile(dvd
, tt_srpt
->title
[dvd_title
].title_set_nr
, DVD_READ_TITLE_VOBS
);
837 mp_tmsg(MSGT_OPEN
,MSGL_ERR
, "Cannot open title VOBS (VTS_%02d_1.VOB).\n", tt_srpt
->title
[dvd_title
].title_set_nr
);
838 ifoClose( vts_file
);
842 mp_msg(MSGT_OPEN
,MSGL_V
, "DVD successfully opened.\n");
844 d
=malloc(sizeof(dvd_priv_t
)); memset(d
,0,sizeof(dvd_priv_t
));
847 d
->vmg_file
=vmg_file
;
849 d
->vts_file
=vts_file
;
850 d
->cur_title
= dvd_title
+1;
852 pgc
= vts_file
->vts_pgcit
? vts_file
->vts_pgcit
->pgci_srp
[ttn
].pgc
: NULL
;
854 * Check number of audio channels and types
858 if(vts_file
->vts_pgcit
) {
861 if(pgc
->audio_control
[i
] & 0x8000) {
862 audio_attr_t
* audio
= &vts_file
->vtsi_mat
->vts_audio_attr
[i
];
864 char tmp
[] = "unknown";
865 stream_language_t
*audio_stream
= &d
->audio_streams
[d
->nr_of_channels
];
867 if(audio
->lang_type
== 1) {
868 language
=audio
->lang_code
;
870 tmp
[1]=language
&0xff;
874 audio_stream
->language
=language
;
875 audio_stream
->id
=pgc
->audio_control
[i
] >> 8 & 7;
876 switch(audio
->audio_format
) {
878 audio_stream
->id
+=FIRST_AC3_AID
;
881 audio_stream
->id
+=FIRST_DTS_AID
;
883 case 2: // mpeg layer 1/2/3
885 audio_stream
->id
+=FIRST_MPG_AID
;
888 audio_stream
->id
+=FIRST_PCM_AID
;
892 audio_stream
->type
=audio
->audio_format
;
893 // Pontscho: to my mind, tha channels:
896 audio_stream
->channels
=audio
->channels
;
897 mp_tmsg(MSGT_OPEN
,MSGL_STATUS
,"audio stream: %d format: %s (%s) language: %s aid: %d.\n",
899 dvd_audio_stream_types
[ audio
->audio_format
],
900 dvd_audio_stream_channels
[ audio
->channels
],
904 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_AUDIO_ID=%d\n", audio_stream
->id
);
905 if(language
&& tmp
[0])
906 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_AID_%d_LANG=%s\n", audio_stream
->id
, tmp
);
911 mp_tmsg(MSGT_OPEN
,MSGL_STATUS
,"number of audio channels on disk: %d.\n",d
->nr_of_channels
);
915 * Check number of subtitles and language
920 d
->nr_of_subtitles
=0;
922 if(pgc
->subp_control
[i
] & 0x80000000) {
923 subp_attr_t
* subtitle
= &vts_file
->vtsi_mat
->vts_subp_attr
[i
];
924 video_attr_t
*video
= &vts_file
->vtsi_mat
->vts_video_attr
;
926 char tmp
[] = "unknown";
927 stream_language_t
*sub_stream
= &d
->subtitles
[d
->nr_of_subtitles
];
929 if(subtitle
->type
== 1) {
930 language
=subtitle
->lang_code
;
932 tmp
[1]=language
&0xff;
936 sub_stream
->language
=language
;
937 sub_stream
->id
=d
->nr_of_subtitles
;
938 if(video
->display_aspect_ratio
== 0) /* 4:3 */
939 sub_stream
->id
= pgc
->subp_control
[i
] >> 24 & 31;
940 else if(video
->display_aspect_ratio
== 3) /* 16:9 */
941 sub_stream
->id
= pgc
->subp_control
[i
] >> 8 & 31;
943 mp_tmsg(MSGT_OPEN
,MSGL_STATUS
,"subtitle ( sid ): %d language: %s\n", sub_stream
->id
, tmp
);
944 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_SUBTITLE_ID=%d\n", sub_stream
->id
);
945 if(language
&& tmp
[0])
946 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_SID_%d_LANG=%s\n", sub_stream
->id
, tmp
);
947 d
->nr_of_subtitles
++;
949 mp_tmsg(MSGT_OPEN
,MSGL_STATUS
,"number of subtitles on disk: %d\n",d
->nr_of_subtitles
);
953 * Determine which program chain we want to watch. This is based on the
956 pgc_id
= vts_file
->vts_ptt_srpt
->title
[ttn
].ptt
[0].pgcn
; // local
957 pgn
= vts_file
->vts_ptt_srpt
->title
[ttn
].ptt
[0].pgn
; // local
958 d
->cur_pgc_idx
= pgc_id
-1;
959 d
->cur_pgc
= vts_file
->vts_pgcit
->pgci_srp
[pgc_id
-1].pgc
;
960 d
->cur_cell
= d
->cur_pgc
->program_map
[pgn
-1] - 1; // start playback here
961 d
->packs_left
=-1; // for Navi stuff
963 d
->last_cell
=d
->cur_pgc
->nr_of_cells
;
965 if(d
->cur_pgc
->cell_playback
[d
->cur_cell
].block_type
== BLOCK_TYPE_ANGLE_BLOCK
)
966 d
->cur_cell
+=dvd_angle
;
967 d
->cur_pack
= d
->cur_pgc
->cell_playback
[ d
->cur_cell
].first_sector
;
968 d
->cell_last_pack
=d
->cur_pgc
->cell_playback
[ d
->cur_cell
].last_sector
;
969 mp_msg(MSGT_DVD
,MSGL_V
, "DVD start cell: %d pack: 0x%X-0x%X \n",d
->cur_cell
,d
->cur_pack
,d
->cell_last_pack
);
971 //assign cell_times_table
972 d
->cell_times_table
= malloc(sizeof(unsigned int) * d
->cur_pgc
->nr_of_cells
);
973 if(d
->cell_times_table
== NULL
)
974 return STREAM_UNSUPPORTED
;
975 for(k
=0; k
<d
->cur_pgc
->nr_of_cells
; k
++)
976 d
->cell_times_table
[k
] = mp_dvdtimetomsec(&d
->cur_pgc
->cell_playback
[k
].playback_time
);
977 list_chapters(vts_file
,tt_srpt
,dvd_title
);
979 // ... (unimplemented)
981 stream
->type
= STREAMTYPE_DVD
;
982 stream
->sector_size
= 2048;
983 stream
->flags
= STREAM_READ
| MP_STREAM_SEEK
;
984 stream
->fill_buffer
= fill_buffer
;
986 stream
->control
= control
;
987 stream
->close
= stream_dvd_close
;
988 stream
->start_pos
= (off_t
)d
->cur_pack
*2048;
989 stream
->end_pos
= (off_t
)(d
->cur_pgc
->cell_playback
[d
->last_cell
-1].last_sector
)*2048;
990 *file_format
= DEMUXER_TYPE_MPEG_PS
;
991 mp_msg(MSGT_DVD
,MSGL_V
,"DVD start=%d end=%d \n",d
->cur_pack
,d
->cur_pgc
->cell_playback
[d
->last_cell
-1].last_sector
);
992 stream
->priv
= (void*)d
;
998 m_struct_free(&stream_opts
, opts
);
999 return STREAM_UNSUPPORTED
;
1001 mp_tmsg(MSGT_DVD
,MSGL_ERR
,"MPlayer was compiled without DVD support, exiting.\n");
1002 m_struct_free(&stream_opts
,opts
);
1003 return STREAM_UNSUPPORTED
;
1006 static int ifo_stream_open (stream_t
*stream
, int mode
, void *opts
, int *file_format
)
1009 struct stream_priv_s
*spriv
;
1010 int len
= strlen(stream
->url
);
1012 if (len
< 4 || strcasecmp (stream
->url
+ len
- 4, ".ifo"))
1013 return STREAM_UNSUPPORTED
;
1015 mp_msg(MSGT_DVD
, MSGL_INFO
, ".IFO detected. Redirecting to dvd://\n");
1017 filename
= strdup(basename(stream
->url
));
1019 spriv
=calloc(1, sizeof(struct stream_priv_s
));
1020 spriv
->device
= strdup(dirname(stream
->url
));
1021 if(!strncasecmp(filename
,"vts_",4))
1023 if(sscanf(filename
+3, "_%02d_", &spriv
->title
)!=1)
1030 stream
->url
=strdup("dvd://");
1032 return open_s(stream
, mode
, spriv
, file_format
);
1035 const stream_info_t stream_info_dvd
= {
1043 1 // Urls are an option string
1046 const stream_info_t stream_info_ifo
= {
1050 "Mostly used to play DVDs on disk through OSD Menu",
1052 { "file", "", NULL
},