Remove the file:// URI decode hack
[vlc/asuraparaju-public.git] / modules / access / bd / bd.c
blob20b78b06f1f4d51155344851812802b8dea192eb
1 /*****************************************************************************
2 * bd.c: BluRay Disc support (uncrypted)
3 *****************************************************************************
4 * Copyright (C) 2009 the VideoLAN team
5 * $Id$
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #ifdef HAVE_SYS_STAT_H
33 # include <sys/stat.h>
34 #endif
35 #include <limits.h>
37 #include <vlc_common.h>
38 #include <vlc_plugin.h>
39 #include <vlc_input.h>
40 #include <vlc_access.h>
41 #include <vlc_demux.h>
42 #include <vlc_fs.h>
43 #include <vlc_bits.h>
44 #include <assert.h>
46 #include "mpls.h"
47 #include "clpi.h"
49 /*****************************************************************************
50 * Module descriptor
51 *****************************************************************************/
52 #define CACHING_TEXT N_("Caching value in ms")
53 #define CACHING_LONGTEXT N_( \
54 "Caching value for BDs. This "\
55 "value should be set in milliseconds." )
57 static int Open ( vlc_object_t * );
58 static void Close( vlc_object_t * );
60 vlc_module_begin ()
61 set_shortname( N_("BD") )
62 set_description( N_("Blu-Ray Disc Input") )
63 set_category( CAT_INPUT )
64 set_subcategory( SUBCAT_INPUT_ACCESS )
65 add_integer( "bd-caching", DEFAULT_PTS_DELAY / 1000, NULL,
66 CACHING_TEXT, CACHING_LONGTEXT, true )
67 set_capability( "access_demux", 60 )
68 add_shortcut( "bd" )
69 add_shortcut( "file" )
70 set_callbacks( Open, Close )
71 vlc_module_end ()
73 /*****************************************************************************
74 * Documentation
75 * I have used:
76 * - http://www.stebbins.biz/source/bdtools.tgz
77 * - hdcookbook java code
78 * - BDInfo source code
79 *****************************************************************************/
81 /*****************************************************************************
82 * Local prototypes
83 *****************************************************************************/
84 struct demux_sys_t
86 char *psz_base;
87 bool b_shortname;
89 /* */
90 int i_mpls;
91 bd_mpls_t **pp_mpls;
93 /* */
94 int i_clpi;
95 bd_clpi_t **pp_clpi;
97 /* */
98 int i_title;
99 input_title_t **pp_title;
101 /* */
102 es_out_t *p_out;
104 /* Current state */
105 const bd_clpi_t *p_clpi;
106 int i_clpi_ep;
107 stream_t *p_parser;
108 stream_t *p_m2ts;
109 int i_play_item;
110 int i_packet;
111 int i_packet_start;
112 int i_packet_stop;
113 int i_packet_headers;
114 int64_t i_atc_initial;
115 int64_t i_atc_current;
116 int64_t i_atc_wrap;
117 int64_t i_atc_last;
120 static int Control( demux_t *, int, va_list );
121 static int Demux( demux_t * );
123 static char *FindPathBase( const char *, bool *pb_shortname );
125 static int LoadPlaylist( demux_t * );
126 static int LoadClip( demux_t * );
128 static void ReorderPlaylist( demux_t * );
130 static void InitTitles( demux_t * );
131 static int SetTitle( demux_t *, int );
132 static int SetChapter( demux_t *, int );
133 static int64_t GetTime( demux_t * );
134 static double GetPosition( demux_t * );
135 static int SetTime( demux_t *, int64_t );
136 static int SetPosition( demux_t *, double );
138 static int SetPlayItem( demux_t *p_demux, int i_mpls, int i_play_item );
139 static void ClosePlayItem( demux_t * );
141 /* */
142 static int64_t GetClpiPacket( demux_t *p_demux, int *pi_ep, const bd_mpls_clpi_t *p_mpls_clpi, int64_t i_time /* in 45kHz */ );
144 static es_out_t *EsOutNew( demux_t *p_demux );
146 //#define BD_DEBUG
148 /*****************************************************************************
149 * Open:
150 *****************************************************************************/
151 static int Open( vlc_object_t *p_this )
153 demux_t *p_demux = (demux_t*)p_this;
154 demux_sys_t *p_sys;
156 if( *p_demux->psz_access &&
157 strcmp( p_demux->psz_access, "bd" ) &&
158 strcmp( p_demux->psz_access, "file" ) )
159 return VLC_EGENERIC;
161 /* */
162 bool b_shortname;
163 char *psz_base = FindPathBase( p_demux->psz_path, &b_shortname );
164 if( !psz_base )
165 return VLC_EGENERIC;
167 msg_Dbg( p_demux, "Using path '%s'", psz_base );
169 /* Fill p_demux field */
170 p_demux->p_sys = p_sys = malloc( sizeof(*p_sys) );
171 if( !p_sys )
172 return VLC_EGENERIC;
173 p_sys->psz_base = psz_base;
174 p_sys->b_shortname = b_shortname;
175 TAB_INIT( p_sys->i_mpls, p_sys->pp_mpls );
176 TAB_INIT( p_sys->i_clpi, p_sys->pp_clpi );
177 TAB_INIT( p_sys->i_title, p_sys->pp_title );
178 p_demux->info.i_title = -1;
179 p_sys->p_clpi = NULL;
180 p_sys->i_clpi_ep = -1;
181 p_sys->p_parser = NULL;
182 p_sys->p_m2ts = NULL;
183 p_sys->i_play_item = -1;
184 p_sys->i_packet = -1;
185 p_sys->i_packet_start = -1;
186 p_sys->i_packet_stop = -1;
187 p_sys->i_packet_headers = -1;
188 p_sys->p_out = EsOutNew( p_demux );
189 if( !p_sys->p_out )
190 goto error;
192 p_demux->pf_control = Control;
193 p_demux->pf_demux = Demux;
195 /* Load all clip/playlist files */
196 LoadClip( p_demux );
197 LoadPlaylist( p_demux );
199 /* Reorder playlist to have the most significant first
200 * (as we don't have menu support, no idea how to find the main title */
201 ReorderPlaylist( p_demux );
203 /* Setup variables (for TS demuxer) */
204 var_Create( p_demux, "ts-es-id-pid", VLC_VAR_BOOL );
205 var_SetBool( p_demux, "ts-es-id-pid", true );
207 /* */
208 InitTitles( p_demux );
209 if( SetTitle( p_demux, 0 ) )
210 goto error;
212 return VLC_SUCCESS;
214 error:
215 Close( VLC_OBJECT(p_demux) );
216 return VLC_EGENERIC;
219 /*****************************************************************************
220 * Close:
221 *****************************************************************************/
222 static void Close( vlc_object_t *p_this )
224 demux_t *p_demux = (demux_t*)p_this;
225 demux_sys_t *p_sys = p_demux->p_sys;
227 /* */
228 ClosePlayItem( p_demux );
230 /* */
231 es_out_Delete( p_sys->p_out );
233 /* Titles */
234 for( int i = 0; i < p_sys->i_title; i++ )
235 vlc_input_title_Delete( p_sys->pp_title[i] );
236 TAB_CLEAN( p_sys->i_title, p_sys->pp_title );
238 /* CLPI */
239 for( int i = 0; i < p_sys->i_clpi; i++ )
241 bd_clpi_t *p_clpi = p_sys->pp_clpi[i];
243 bd_clpi_Clean( p_clpi );
244 free( p_clpi );
246 TAB_CLEAN( p_sys->i_clpi, p_sys->pp_clpi );
248 /* MPLS */
249 for( int i = 0; i < p_sys->i_mpls; i++ )
251 bd_mpls_t *p_mpls = p_sys->pp_mpls[i];
253 bd_mpls_Clean( p_mpls );
254 free( p_mpls );
256 TAB_CLEAN( p_sys->i_mpls, p_sys->pp_mpls );
258 free( p_sys->psz_base );
259 free( p_sys );
262 /*****************************************************************************
263 * Control:
264 *****************************************************************************/
265 static int Control( demux_t *p_demux, int i_query, va_list args )
267 demux_sys_t *p_sys = p_demux->p_sys;
269 switch( i_query )
271 case DEMUX_GET_TIME:
273 int64_t *pi_time = (int64_t*)va_arg( args, int64_t * );
274 *pi_time = GetTime( p_demux );
275 return VLC_SUCCESS;;
278 case DEMUX_GET_POSITION:
280 double *pf_position = (double*)va_arg( args, double * );
281 *pf_position = GetPosition( p_demux );
282 return VLC_SUCCESS;
285 case DEMUX_SET_TIME:
287 int64_t i_time = (int64_t)va_arg( args, int64_t );
288 return SetTime( p_demux, i_time );
290 case DEMUX_SET_POSITION:
292 double f_position = (double)va_arg( args, double );
293 return SetPosition( p_demux, f_position );
296 case DEMUX_GET_LENGTH:
298 int64_t *pi_length = (int64_t*)va_arg( args, int64_t * );
299 *pi_length = p_sys->pp_title[p_demux->info.i_title]->i_length;
300 return VLC_SUCCESS;
303 /* Special for access_demux */
304 case DEMUX_CAN_PAUSE:
305 case DEMUX_CAN_SEEK:
306 case DEMUX_CAN_CONTROL_PACE:
308 bool *pb_bool = (bool*)va_arg( args, bool * );
309 *pb_bool = true;
310 return VLC_SUCCESS;
313 case DEMUX_SET_PAUSE_STATE:
314 return VLC_SUCCESS;
316 case DEMUX_GET_TITLE_INFO:
318 input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
319 int *pi_int = (int*)va_arg( args, int* );
320 int *pi_title_offset = (int*)va_arg( args, int* );
321 int *pi_chapter_offset = (int*)va_arg( args, int* );
323 /* */
324 *pi_title_offset = 0;
325 *pi_chapter_offset = 0;
327 /* Duplicate title infos */
328 *pi_int = p_sys->i_title;
329 *ppp_title = calloc( p_sys->i_title, sizeof(input_title_t **) );
330 for( int i = 0; i < p_sys->i_title; i++ )
331 (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->pp_title[i] );
333 return VLC_SUCCESS;
336 case DEMUX_SET_TITLE:
338 int i_title = (int)va_arg( args, int );
340 if( SetTitle( p_demux, i_title ) )
341 return VLC_EGENERIC;
342 return VLC_SUCCESS;
344 case DEMUX_SET_SEEKPOINT:
346 int i_chapter = (int)va_arg( args, int );
348 if( SetChapter( p_demux, i_chapter ) )
349 return VLC_EGENERIC;
350 return VLC_SUCCESS;
353 case DEMUX_GET_PTS_DELAY:
355 int64_t *pi_delay = (int64_t*)va_arg( args, int64_t * );
356 *pi_delay = var_GetInteger( p_demux, "bd-caching" ) * INT64_C(1000);
357 return VLC_SUCCESS;
360 case DEMUX_GET_META:
362 default:
363 return VLC_EGENERIC;
367 /*****************************************************************************
368 * Demux:
369 *****************************************************************************/
370 #define BD_TS_PACKET_HEADER (4)
371 #define BD_TS_PACKET_SIZE (192)
372 static int Demux( demux_t *p_demux )
374 demux_sys_t *p_sys = p_demux->p_sys;
375 if( !p_sys->p_m2ts )
376 return -1;
378 /* */
379 if( p_sys->i_packet == p_sys->i_packet_start )
381 stream_Seek( p_sys->p_m2ts, 0 );
383 block_t *p_block = stream_Block( p_sys->p_m2ts,
384 p_sys->i_packet_headers * (int64_t)BD_TS_PACKET_SIZE + BD_TS_PACKET_HEADER );
385 if( p_block )
387 p_block->i_buffer -= BD_TS_PACKET_HEADER;
388 p_block->p_buffer += BD_TS_PACKET_HEADER;
389 stream_DemuxSend( p_sys->p_parser, p_block );
392 stream_Seek( p_sys->p_m2ts, p_sys->i_packet_start * (int64_t)BD_TS_PACKET_SIZE );
395 /* */
396 const int i_packets = __MIN( 5, p_sys->i_packet_stop - p_sys->i_packet );
397 if( i_packets <= 0 )
399 const int i_title = p_demux->info.i_title;
400 const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_title];
402 if( p_sys->i_play_item < p_mpls->i_play_item )
404 if( !SetPlayItem( p_demux, i_title, p_sys->i_play_item + 1 ) )
405 return 1;
406 msg_Warn( p_demux, "Failed to switch to the next play item" );
409 /* */
410 if( SetTitle( p_demux, i_title + 1 ) )
411 return 0; /* EOF */
412 return 1;
415 /* XXX
416 * we ensure that the TS packet start at the begining of the buffer,
417 * it ensure proper TS parsing */
418 block_t *p_block = block_New( p_demux, i_packets * BD_TS_PACKET_SIZE + BD_TS_PACKET_HEADER );
419 if( !p_block )
420 return -1;
422 const int i_read = stream_Read( p_sys->p_m2ts, p_block->p_buffer, p_block->i_buffer - BD_TS_PACKET_HEADER );
423 if( i_read <= 0 )
425 msg_Err( p_demux, "Error reading current title" );
426 return -1;
429 if( i_read > 4 )
431 const int64_t i_atc = GetDWBE( p_block->p_buffer ) & ( (1 << 30) - 1 );
433 if( i_atc < p_sys->i_atc_last )
434 p_sys->i_atc_wrap += 1 << 30;
435 p_sys->i_atc_last = i_atc;
437 if( p_sys->i_atc_initial < 0 )
438 p_sys->i_atc_initial = i_atc + p_sys->i_atc_wrap;
440 p_sys->i_atc_current = i_atc + p_sys->i_atc_wrap;
443 p_block->i_buffer = i_read;
444 p_block->p_buffer += BD_TS_PACKET_HEADER;
445 stream_DemuxSend( p_sys->p_parser, p_block );
447 p_sys->i_packet += i_read / BD_TS_PACKET_SIZE;
449 /* Update EP */
450 if( p_sys->p_clpi->i_ep_map > 0 )
452 const int i_old_clpi_ep = p_sys->i_clpi_ep;
454 const bd_clpi_ep_map_t *p_ep_map = &p_sys->p_clpi->p_ep_map[0];
455 for( ; p_sys->i_clpi_ep+1 < p_ep_map->i_ep; p_sys->i_clpi_ep++ )
457 const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep+1];
459 if( p_ep->i_packet > p_sys->i_packet )
460 break;
462 if( i_old_clpi_ep != p_sys->i_clpi_ep )
464 /* We have changed of EP */
465 p_sys->i_atc_initial = p_sys->i_atc_current; /* FIXME not exact */
467 /* Update seekpoint */
468 const input_title_t *p_title = p_sys->pp_title[p_demux->info.i_title];
469 const int64_t i_time = GetTime( p_demux );
471 for( ; p_demux->info.i_seekpoint+1 < p_title->i_seekpoint; p_demux->info.i_seekpoint++ )
473 const seekpoint_t *p_seekpoint = p_title->seekpoint[p_demux->info.i_seekpoint+1];
474 if( p_seekpoint->i_time_offset > i_time )
475 break;
476 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
480 return 1;
483 /*****************************************************************************
485 *****************************************************************************/
486 #define BD_45KHZ INT64_C(45000)
487 static void InitTitles( demux_t *p_demux )
489 demux_sys_t *p_sys = p_demux->p_sys;
491 /* */
492 for( int i = 0; i < p_sys->i_mpls; i++ )
494 const bd_mpls_t *p_mpls = p_sys->pp_mpls[i];
496 input_title_t *t = vlc_input_title_New();
497 if( !t )
498 break;
500 /* */
501 t->i_length = 0;
502 for( int j = 0; j < p_mpls->i_play_item; j++ )
504 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[j];
506 t->i_length += ( p_item->i_out_time - p_item->i_in_time ) * CLOCK_FREQ / BD_45KHZ;
509 #ifdef BD_DEBUG
511 char psz_length[MSTRTIME_MAX_SIZE];
512 msg_Warn( p_demux, "TITLE[%d] %s", i, secstotimestr( psz_length, t->i_length / CLOCK_FREQ ) );
514 #endif
516 /* Seekpoint */
517 for( int j = 0; j < p_mpls->i_mark; j++ )
519 bd_mpls_mark_t *p_mark = &p_mpls->p_mark[j];
521 if( p_mark->i_type == BD_MPLS_MARK_TYPE_BOOKMARK &&
522 p_mark->i_play_item_id >= 0 && p_mark->i_play_item_id < p_mpls->i_play_item )
524 seekpoint_t *s = vlc_seekpoint_New();
525 if( !s )
526 break;
528 for( int k = 0; k <= p_mark->i_play_item_id; k++ )
530 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[k];
531 int64_t i_out_time;
533 if( k == p_mark->i_play_item_id )
534 i_out_time = p_mark->i_time;
535 else
536 i_out_time = p_item->i_out_time;
537 s->i_time_offset += ( i_out_time - p_item->i_in_time ) * CLOCK_FREQ / BD_45KHZ;
539 #ifdef BD_DEBUG
541 char psz_time[MSTRTIME_MAX_SIZE];
542 msg_Warn( p_demux, " SEEKPOINT[%d] %s", j, secstotimestr( psz_time, s->i_time_offset / CLOCK_FREQ ) );
544 #endif
545 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
548 if( t->i_seekpoint <= 0 )
550 seekpoint_t *s = vlc_seekpoint_New();
551 if( s )
552 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
555 TAB_APPEND( p_sys->i_title, p_sys->pp_title, t );
558 static int SetTitle( demux_t *p_demux, int i_title )
560 demux_sys_t *p_sys = p_demux->p_sys;
562 if( i_title < 0 || i_title >= p_sys->i_title )
563 return VLC_EGENERIC;
566 if( SetPlayItem( p_demux, i_title, 0 ) )
567 return VLC_EGENERIC;
569 /* */
570 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
571 p_demux->info.i_title = i_title;
572 p_demux->info.i_seekpoint = 0;
574 return VLC_SUCCESS;
576 static int SetChapter( demux_t *p_demux, int i_chapter )
578 demux_sys_t *p_sys = p_demux->p_sys;
579 const int i_title = p_demux->info.i_title;
580 const input_title_t *p_title = p_sys->pp_title[i_title];
582 if( i_chapter < 0 || i_chapter > p_title->i_seekpoint )
583 return VLC_EGENERIC;
585 if( SetTime( p_demux, p_title->seekpoint[i_chapter]->i_time_offset ) )
586 return VLC_EGENERIC;
588 return VLC_SUCCESS;
590 static int SetPlayItem( demux_t *p_demux, int i_mpls, int i_play_item )
592 demux_sys_t *p_sys = p_demux->p_sys;
594 /* FIXME TODO do not reopen everything when avoidable
595 * XXX becarefull that then the es_out wrapper need some sort of
596 * locking !!! */
598 /* */
599 const bool b_same_mpls = i_mpls == p_demux->info.i_title;
600 //const bool b_same_play_item = b_same_mpls &&
601 // i_play_item == p_sys->i_play_item;
603 /* */
604 const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_mpls];
606 /* */
607 if( i_play_item < 0 || i_play_item >= p_mpls->i_play_item )
608 return VLC_EGENERIC;
610 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[i_play_item];
611 const bd_mpls_clpi_t *p_mpls_clpi = &p_item->clpi;
613 const bd_clpi_t *p_clpi = NULL;
614 for( int i_clpi = 0; i_clpi < p_sys->i_clpi && !p_clpi; i_clpi++ )
616 if( p_sys->pp_clpi[i_clpi]->i_id == p_mpls_clpi->i_id )
617 p_clpi = p_sys->pp_clpi[i_clpi];
620 const bool b_same_clpi = b_same_mpls && p_sys->p_clpi->i_id == p_clpi->i_id;
621 stream_t *p_m2ts = NULL;
622 if( !b_same_clpi )
624 char *psz_m2ts;
625 if( asprintf( &psz_m2ts, "%s/STREAM/%05d.%s",
626 p_sys->psz_base, p_mpls_clpi->i_id, p_sys->b_shortname ? "MTS" : "m2ts" ) < 0 )
627 return VLC_EGENERIC;
629 p_m2ts = stream_UrlNew( p_demux, psz_m2ts );
630 if( !p_m2ts )
632 msg_Err( p_demux, "Failed to open %s", psz_m2ts );
633 free( psz_m2ts );
634 return VLC_EGENERIC;
636 free( psz_m2ts );
639 /* TODO avoid reopenning the parser when unneeded.
640 * - b_same_play_item is too strict, we should check the play_items connection.
641 * - a way to completely flush the demuxer is also needed !
643 //const bool b_same_parser = b_same_play_item && false;
644 stream_t *p_parser = stream_DemuxNew( p_demux, "ts", p_sys->p_out );
645 if( !p_parser )
647 msg_Err( p_demux, "Failed to create TS demuxer" );
648 if( p_m2ts )
649 stream_Delete( p_m2ts );
650 return VLC_EGENERIC;
653 /* */
654 if( !p_m2ts )
656 msg_Dbg( p_demux, "Reusing stream file" );
657 p_m2ts = p_sys->p_m2ts;
658 p_sys->p_m2ts = NULL;
661 /* */
662 ClosePlayItem( p_demux );
664 /* */
665 p_sys->p_clpi = p_clpi;
666 p_sys->p_parser = p_parser;
667 p_sys->p_m2ts = p_m2ts;
668 p_sys->i_play_item = i_play_item;
670 p_sys->i_packet_start = GetClpiPacket( p_demux, &p_sys->i_clpi_ep, p_mpls_clpi, p_item->i_in_time );
671 if( p_sys->i_packet_start < 0 )
673 p_sys->i_packet_start = 0;
674 p_sys->i_clpi_ep = 0;
677 p_sys->i_packet_stop = GetClpiPacket( p_demux, NULL, p_mpls_clpi, p_item->i_out_time );
678 if( p_sys->i_packet_stop < 0 )
679 p_sys->i_packet_stop = stream_Size( p_m2ts ) / BD_TS_PACKET_SIZE;
680 p_sys->i_packet = p_sys->i_packet_start;
682 /* This is a hack to detect the number of packet to send before any data
683 * to have the PAT/PMT. I have no idea if it is the right, but seems to work.
684 * I used a limits of 10 packets, sufficient if it is really only headers */
685 p_sys->i_packet_headers = 0;
686 if( p_clpi->i_ep_map > 0 )
688 const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[0];
689 if( p_ep_map->i_ep > 0 )
690 p_sys->i_packet_headers = __MIN( p_ep_map->p_ep[0].i_packet, 10 );
693 p_sys->i_atc_initial = -1;
694 p_sys->i_atc_current = -1;
695 p_sys->i_atc_last = -1;
696 p_sys->i_atc_wrap = 0;
698 return VLC_SUCCESS;
700 static void ClosePlayItem( demux_t *p_demux )
702 demux_sys_t *p_sys = p_demux->p_sys;
704 if( p_sys->p_m2ts )
705 stream_Delete( p_sys->p_m2ts );
706 if( p_sys->p_parser )
707 stream_Delete( p_sys->p_parser );
709 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
712 static int64_t GetClpiPacket( demux_t *p_demux, int *pi_ep, const bd_mpls_clpi_t *p_mpls_clpi, int64_t i_time /* in 45kHz */ )
714 demux_sys_t *p_sys = p_demux->p_sys;
716 const bd_clpi_t *p_clpi = p_sys->p_clpi;
717 assert( p_clpi );
719 if( p_clpi->i_ep_map <= 0 )
720 return -1;
721 const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[0];
723 if( p_mpls_clpi->i_stc_id < 0 || p_mpls_clpi->i_stc_id >= p_clpi->i_stc )
724 return -1;
726 const bd_clpi_stc_t *p_stc = &p_clpi->p_stc[p_mpls_clpi->i_stc_id];
727 #if 0
728 /* Not sure it is right */
729 if( i_time < p_stc->i_start || i_time > p_stc->i_end )
730 return -1;
731 #endif
733 const int64_t i_packet = p_stc->i_packet;
734 int i_ep;
735 for( i_ep = 0; i_ep < p_ep_map->i_ep; i_ep++ )
737 if( p_ep_map->p_ep[i_ep].i_packet >= i_packet )
738 break;
740 if( i_ep >= p_ep_map->i_ep )
741 return -1;
743 for( ; i_ep < p_ep_map->i_ep; i_ep++ )
745 const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[i_ep];
746 const bd_clpi_ep_t *p_ep_next = &p_ep_map->p_ep[i_ep+1];
748 if( i_ep+1 < p_ep_map->i_ep && p_ep_next->i_pts / 2 > i_time )
749 break;
750 if( p_ep->i_pts / 2 >= i_time )
751 break;
753 if( i_ep >= p_ep_map->i_ep )
754 return -1;
756 /* */
757 if( pi_ep )
758 *pi_ep = i_ep;
759 return p_ep_map->p_ep[i_ep].i_packet;
763 * Retreive the current time using current EP + ATC delta
765 static int64_t GetTime( demux_t *p_demux )
767 demux_sys_t *p_sys = p_demux->p_sys;
768 const int i_mpls = p_demux->info.i_title;
770 const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_mpls];
771 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[p_sys->i_play_item];
773 const bd_clpi_t *p_clpi = p_sys->p_clpi;
774 if( !p_clpi || p_clpi->i_ep_map <= 0 )
775 return 0;
777 /* */
778 const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[0];
779 if( p_sys->i_clpi_ep < 0 || p_sys->i_clpi_ep >= p_ep_map->i_ep )
780 return 0;
782 const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep];
783 int64_t i_time = p_ep->i_pts / 2 - p_item->i_in_time +
784 ( p_sys->i_atc_current - p_sys->i_atc_initial ) / 300 / 2;
786 for( int j = 0; j < p_sys->i_play_item; j++ )
788 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[j];
789 i_time += ( p_item->i_out_time - p_item->i_in_time );
792 return i_time * CLOCK_FREQ / BD_45KHZ;
795 static double GetPosition( demux_t *p_demux )
797 demux_sys_t *p_sys = p_demux->p_sys;
799 const int64_t i_time = GetTime( p_demux );
800 const input_title_t *p_title = p_sys->pp_title[p_demux->info.i_title];
802 if( p_title->i_length <= 0 )
803 return 0.0;
805 return (double)i_time / p_title->i_length;
808 static int SetTime( demux_t *p_demux, int64_t i_time )
810 demux_sys_t *p_sys = p_demux->p_sys;
811 const int i_mpls = p_demux->info.i_title;
812 const input_title_t *p_title = p_sys->pp_title[i_mpls];
813 const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_mpls];
815 /* Find the play item */
816 int i_item;
817 int64_t i_play_item_time = 0;
818 for( i_item = 0; i_item < p_mpls->i_play_item; i_item++ )
820 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[i_item];
821 const int64_t i_duration = ( p_item->i_out_time - p_item->i_in_time ) * CLOCK_FREQ / BD_45KHZ;
823 if( i_time >= i_play_item_time && i_time < i_play_item_time + i_duration )
824 break;
826 i_play_item_time += i_duration;
829 if( i_item >= p_mpls->i_play_item )
830 return VLC_EGENERIC;
832 if( SetPlayItem( p_demux, i_mpls, i_item ) )
833 return VLC_EGENERIC;
836 /* Find the right entry point */
837 if( p_sys->p_clpi->i_ep_map <= 0 )
838 goto update;
840 const bd_clpi_ep_map_t *p_ep_map = &p_sys->p_clpi->p_ep_map[0];
841 if( p_ep_map->i_ep <= 0 )
842 goto update;
844 int64_t i_next_display_date = -1;
845 for( ; p_sys->i_clpi_ep+1 < p_ep_map->i_ep; p_sys->i_clpi_ep++ )
847 const bd_clpi_ep_t *p_next = &p_ep_map->p_ep[p_sys->i_clpi_ep+1];
848 const int64_t i_next_time = i_play_item_time + ( ( p_next->i_pts / 2 - p_mpls->p_play_item[i_item].i_in_time ) * CLOCK_FREQ / BD_45KHZ );
850 if( i_next_time > i_time )
852 const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep];
853 const int64_t i_ep_time = i_play_item_time + ( ( p_ep->i_pts / 2 - p_mpls->p_play_item[i_item].i_in_time ) * CLOCK_FREQ / BD_45KHZ );
856 i_next_display_date = p_ep->i_pts * CLOCK_FREQ / 90000 + ( i_time - i_ep_time );
857 break;
861 const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep];
862 p_sys->i_packet_start =
863 p_sys->i_packet = p_ep->i_packet;
865 if( i_next_display_date >= 0 )
866 es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_next_display_date );
868 update:
869 /* Update seekpoint */
870 for( p_demux->info.i_seekpoint = 0; p_demux->info.i_seekpoint+1 < p_title->i_seekpoint; p_demux->info.i_seekpoint++ )
872 const seekpoint_t *p_seekpoint = p_title->seekpoint[p_demux->info.i_seekpoint+1];
873 if( p_seekpoint->i_time_offset > i_time )
874 break;
876 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
877 return VLC_SUCCESS;
880 static int SetPosition( demux_t *p_demux, double f_position )
882 demux_sys_t *p_sys = p_demux->p_sys;
883 const input_title_t *p_title = p_sys->pp_title[p_demux->info.i_title];
885 if( p_title->i_length <= 0 )
886 return VLC_EGENERIC;
888 return SetTime( p_demux, f_position * p_title->i_length );
891 /*****************************************************************************
892 * Mpls ordering
893 *****************************************************************************/
894 static int64_t GetMplsUniqueDuration( const bd_mpls_t *p_mpls )
896 int64_t i_length = 0;
898 for( int i = 0; i < p_mpls->i_play_item; i++ )
900 const bd_mpls_play_item_t *p_item0 = &p_mpls->p_play_item[i];
901 int j;
902 for( j = i+1; j < p_mpls->i_play_item; j++ )
904 const bd_mpls_play_item_t *p_item1 = &p_mpls->p_play_item[j];
905 if( p_item0->clpi.i_id == p_item1->clpi.i_id &&
906 p_item0->clpi.i_stc_id == p_item1->clpi.i_stc_id &&
907 p_item0->i_in_time == p_item1->i_in_time &&
908 p_item0->i_out_time == p_item1->i_out_time )
909 break;
911 if( j >= p_mpls->i_play_item )
912 i_length += p_item0->i_out_time - p_item0->i_in_time;
914 return i_length;
916 static int SortMpls( const void *a, const void *b )
918 const bd_mpls_t * const *pp_mpls_a = a;
919 const bd_mpls_t * const *pp_mpls_b = b;
921 const int64_t i_length_a = GetMplsUniqueDuration( *pp_mpls_a );
922 const int64_t i_length_b = GetMplsUniqueDuration( *pp_mpls_b );
924 if( i_length_a == i_length_b )
925 return 0;
926 return i_length_a < i_length_b ? 1 : -1;
929 static void ReorderPlaylist( demux_t *p_demux )
931 demux_sys_t *p_sys = p_demux->p_sys;
932 qsort( p_sys->pp_mpls, p_sys->i_mpls, sizeof(*p_sys->pp_mpls), SortMpls );
934 /*****************************************************************************
935 * Helpers:
936 *****************************************************************************/
937 static int CheckFileList( const char *psz_base, const char *ppsz_name[] )
939 for( int i = 0; ppsz_name[i] != NULL ; i++ )
941 struct stat s;
942 char *psz_tmp;
944 if( asprintf( &psz_tmp, "%s/%s", psz_base, ppsz_name[i] ) < 0 )
945 return VLC_EGENERIC;
947 bool b_ok = vlc_stat( psz_tmp, &s ) == 0 && S_ISREG( s.st_mode );
949 free( psz_tmp );
950 if( !b_ok )
951 return VLC_EGENERIC;
953 return VLC_SUCCESS;
955 /* */
956 static char *FindPathBase( const char *psz_path, bool *pb_shortname )
958 struct stat s;
959 char *psz_tmp;
961 /* */
962 char *psz_base = strdup( psz_path );
963 if( !psz_base )
964 return NULL;
966 /* */
967 while( *psz_base && psz_base[strlen(psz_base)-1] == '/' )
968 psz_base[strlen(psz_base)-1] = '\0';
970 /* */
971 if( vlc_stat( psz_base, &s ) || !S_ISDIR( s.st_mode ) )
972 goto error;
974 /* Check BDMV */
975 if( asprintf( &psz_tmp, "%s/BDMV", psz_base ) < 0 )
976 goto error;
977 if( !vlc_stat( psz_tmp, &s ) && S_ISDIR( s.st_mode ) )
979 free( psz_base );
980 psz_base = psz_tmp;
982 else
984 free( psz_tmp );
987 /* Check presence of mandatory files */
988 static const char *ppsz_name_long[] = {
989 "index.bdmv",
990 "MovieObject.bdmv",
991 NULL
993 static const char *ppsz_name_short[] = {
994 "INDEX.BDM",
995 "MOVIEOBJ.BDM",
996 NULL
998 *pb_shortname = false;
999 if( CheckFileList( psz_base, ppsz_name_long ) )
1001 if( CheckFileList( psz_base, ppsz_name_short ) )
1002 goto error;
1003 *pb_shortname = true;
1005 return psz_base;
1007 error:
1008 free( psz_base );
1009 return NULL;
1012 /* */
1013 static block_t *LoadBlock( demux_t *p_demux, const char *psz_name )
1015 stream_t *s = stream_UrlNew( p_demux, psz_name );
1016 if( !s )
1017 return NULL;
1019 const int64_t i_size = stream_Size( s );
1020 block_t *p_block = NULL;
1022 if( i_size > 0 && i_size < INT_MAX )
1023 p_block = stream_Block( s, i_size );
1025 stream_Delete( s );
1027 return p_block;
1030 /* */
1031 static int FilterMplsLong( const char *psz_name )
1033 return strlen( psz_name ) == strlen( "xxxxx.mpls" ) &&
1034 !strcmp( &psz_name[5], ".mpls" );
1036 static int FilterMplsShort( const char *psz_name )
1038 return strlen( psz_name ) == strlen( "xxxxx.MPL" ) &&
1039 !strcmp( &psz_name[5], ".MPL" );
1042 static void LoadMpls( demux_t *p_demux, const char *psz_name, int i_id )
1044 demux_sys_t *p_sys = p_demux->p_sys;
1046 #if defined(BD_DEBUG)
1047 msg_Err( p_demux, "Loading %s", psz_name );
1048 #endif
1050 block_t *p_block = LoadBlock( p_demux, psz_name );
1051 if( !p_block )
1052 goto error;
1054 /* */
1055 bd_mpls_t *p_mpls = malloc( sizeof(*p_mpls) );
1056 if( !p_mpls )
1057 goto error;
1059 /* */
1060 bs_t s;
1061 bs_init( &s, p_block->p_buffer, p_block->i_buffer );
1063 if( bd_mpls_Parse( p_mpls, &s, i_id ) )
1064 goto error;
1066 #if defined(BD_DEBUG)
1067 msg_Err( p_demux, "MPLS: id=%d", p_mpls->i_id );
1068 msg_Err( p_demux, "MPLS: play_item=%d sub_path=%d",
1069 p_mpls->i_play_item, p_mpls->i_sub_path );
1071 for( int i = 0; i < p_mpls->i_play_item; i++ )
1073 bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[i];
1075 msg_Err( p_demux, "PLAY_ITEM[%d] connection=%d in=%d out=%d still=%d(%d)",
1076 i, p_item->i_connection,
1077 (int)p_item->i_in_time, (int)p_item->i_out_time,
1078 p_item->i_still, p_item->i_still_time );
1079 msg_Err( p_demux, " clpi_default: id=%d stc_id=%d",
1080 p_item->clpi.i_id, p_item->clpi.i_stc_id );
1081 for( int j = 0; j < p_item->i_clpi; j++ )
1082 msg_Err( p_demux, " clpi[%d]: id=%d stc_id=%d",
1083 j, p_item->p_clpi[j].i_id, p_item->p_clpi[j].i_stc_id );
1084 for( int j = 0; j < p_item->i_stream; j++ )
1085 msg_Err( p_demux, " stream[%d]: type=%d class=%d stream_type=0x%x lang=%s charset=%d",
1087 p_item->p_stream[j].i_type,
1088 p_item->p_stream[j].i_class,
1089 p_item->p_stream[j].i_stream_type,
1090 p_item->p_stream[j].psz_language,
1091 p_item->p_stream[j].i_charset );
1094 for( int i = 0; i < p_mpls->i_sub_path; i++ )
1096 bd_mpls_sub_path_t *p_sub = &p_mpls->p_sub_path[i];
1098 msg_Err( p_demux, "SUB_PATH[%d] type=%d repeat=%d item=%d",
1099 i, p_sub->i_type, p_sub->b_repeat, p_sub->i_item );
1102 for( int i = 0; i < p_mpls->i_mark; i++ )
1104 bd_mpls_mark_t *p_mark = &p_mpls->p_mark[i];
1106 msg_Err( p_demux, "M[%d] t=%d play_item_id=%d time=%d entry_es_pid=%d",
1107 i, p_mark->i_type, p_mark->i_play_item_id, (int)p_mark->i_time, p_mark->i_entry_es_pid );
1109 #endif
1111 /* */
1112 TAB_APPEND( p_sys->i_mpls, p_sys->pp_mpls, p_mpls );
1114 /* */
1115 block_Release( p_block );
1116 return;
1118 error:
1119 msg_Err( p_demux, "Failed loading %s", psz_name );
1120 if( p_block )
1121 block_Release( p_block );
1124 /* */
1125 static int FilterClpiLong( const char *psz_name )
1127 return strlen( psz_name ) == strlen( "xxxxx.clpi" ) &&
1128 !strcmp( &psz_name[5], ".clpi" );
1130 static int FilterClpiShort( const char *psz_name )
1132 return strlen( psz_name ) == strlen( "xxxxx.CPI" ) &&
1133 !strcmp( &psz_name[5], ".CPI" );
1136 static void LoadClpi( demux_t *p_demux, const char *psz_name, int i_id )
1138 demux_sys_t *p_sys = p_demux->p_sys;
1140 #if defined(BD_DEBUG)
1141 msg_Err( p_demux, "Loading %s", psz_name );
1142 #endif
1144 block_t *p_block = LoadBlock( p_demux, psz_name );
1145 if( !p_block )
1146 goto error;
1148 /* */
1149 bd_clpi_t *p_clpi = malloc( sizeof(*p_clpi) );
1150 if( !p_clpi )
1151 goto error;
1153 /* */
1154 bs_t s;
1155 bs_init( &s, p_block->p_buffer, p_block->i_buffer );
1157 if( bd_clpi_Parse( p_clpi, &s, i_id ) )
1158 goto error;
1160 #if defined(BD_DEBUG)
1161 msg_Err( p_demux, "CLPI: id=%d", p_clpi->i_id );
1162 msg_Err( p_demux, "CLPI: STC=%d", p_clpi->i_stc );
1163 for( int i = 0; i < p_clpi->i_stc; i++ )
1164 msg_Err( p_demux, " STC[%d] pcr_pid=%d packet=%d start=%d end=%d",
1165 i, p_clpi->p_stc[i].i_pcr_pid, (int)p_clpi->p_stc[i].i_packet,
1166 (int)p_clpi->p_stc[i].i_start, (int)p_clpi->p_stc[i].i_end );
1167 msg_Err( p_demux, "CLPI: Stream=%d", p_clpi->i_stream );
1168 for( int i = 0; i < p_clpi->i_stream; i++ )
1169 msg_Err( p_demux, " Stream[%d] pid=%d type=0x%x",
1170 i, p_clpi->p_stream[i].i_pid, p_clpi->p_stream[i].i_type );
1171 msg_Err( p_demux, "CLPI: Ep Map=%d", p_clpi->i_ep_map );
1172 for( int i = 0; i < p_clpi->i_ep_map; i++ )
1174 const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[i];
1175 msg_Err( p_demux, " Ep Map[%d] pid=%d type=0x%x entry_point=%d",
1176 i, p_ep_map->i_pid, p_ep_map->i_type, p_ep_map->i_ep );
1177 for( int j = 0; j < p_ep_map->i_ep; j++ )
1179 msg_Err( p_demux, " Ep[%d] packet=%d pts=%d",
1180 j, (int)p_ep_map->p_ep[j].i_packet, (int)p_ep_map->p_ep[j].i_pts );
1183 #endif
1185 /* */
1186 TAB_APPEND( p_sys->i_clpi, p_sys->pp_clpi, p_clpi );
1188 /* */
1189 block_Release( p_block );
1190 return;
1192 error:
1193 msg_Err( p_demux, "Failed loading %s", psz_name );
1194 if( p_block )
1195 block_Release( p_block );
1198 /* */
1199 static int ScanSort( const char **ppsz_a, const char **ppsz_b )
1201 return strcmp( *ppsz_a, *ppsz_b );
1204 static int Load( demux_t *p_demux,
1205 const char *psz_dir,
1206 int (*pf_filter)( const char * ),
1207 void (*pf_load)( demux_t *p_demux, const char *psz_name, int i_id ) )
1209 char *psz_playlist;
1210 if( asprintf( &psz_playlist, "%s/%s", p_demux->p_sys->psz_base, psz_dir ) < 0 )
1211 return VLC_EGENERIC;
1213 char **ppsz_list;
1215 int i_list = vlc_scandir( psz_playlist, &ppsz_list, pf_filter, ScanSort );
1217 for( int i = 0; i < i_list; i++ )
1219 char *psz_file = ppsz_list[i];
1220 if( !psz_file )
1221 break;
1223 char *psz_name;
1224 if( asprintf( &psz_name, "%s/%s/%s", p_demux->p_sys->psz_base, psz_dir, psz_file ) >= 0)
1226 const int i_id = strtol( psz_file, NULL, 10 );
1227 pf_load( p_demux, psz_name, i_id );
1228 free( psz_name );
1230 free( psz_file );
1232 free( ppsz_list );
1234 free( psz_playlist );
1235 return VLC_SUCCESS;
1238 static int LoadPlaylist( demux_t *p_demux )
1240 return Load( p_demux, "PLAYLIST",
1241 p_demux->p_sys->b_shortname ? FilterMplsShort : FilterMplsLong, LoadMpls );
1243 static int LoadClip( demux_t *p_demux )
1245 return Load( p_demux, "CLIPINF",
1246 p_demux->p_sys->b_shortname ? FilterClpiShort : FilterClpiLong, LoadClpi );
1249 /* */
1250 struct es_out_sys_t
1252 demux_t *p_demux;
1255 static es_out_id_t *EsOutAdd( es_out_t *p_out, const es_format_t *p_fmt )
1257 demux_t *p_demux = p_out->p_sys->p_demux;
1258 const bd_mpls_t *p_mpls = p_demux->p_sys->pp_mpls[p_demux->info.i_title];
1259 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[p_demux->p_sys->i_play_item];
1261 es_format_t fmt;
1263 es_format_Copy( &fmt, p_fmt );
1264 fmt.i_priority = -2;
1266 for( int i = 0; i < p_item->i_stream; i++ )
1268 const bd_mpls_stream_t *p_stream = &p_item->p_stream[i];
1269 if( p_stream->i_type != BD_MPLS_STREAM_TYPE_PLAY_ITEM ||
1270 p_stream->play_item.i_pid != fmt.i_id )
1271 continue;
1273 /* TODO improved priority for higher quality stream ?
1274 * if so, extending stream attributes parsing might be a good idea
1276 fmt.i_priority = 0;
1278 #if 0
1279 /* Useless, and beside not sure it is the right thing to do */
1280 free( fmt.psz_description );
1281 switch( p_stream->i_class )
1283 case BD_MPLS_STREAM_CLASS_SECONDARY_AUDIO:
1284 fmt.psz_description = strdup( "Secondary audio" );
1285 break;
1286 default:
1287 fmt.psz_description = NULL;
1288 break;
1290 #endif
1292 //msg_Err( p_demux, "Found ref for stream pid %d", fmt.i_id );
1293 if( *p_stream->psz_language && ( !fmt.psz_language || *fmt.psz_language == '\0' ) )
1295 free( fmt.psz_language );
1296 fmt.psz_language = strdup( p_stream->psz_language );
1298 switch( p_stream->i_charset )
1300 /* TODO add all values */
1301 default:
1302 break;
1304 break;
1306 if( fmt.i_priority < 0 )
1307 msg_Dbg( p_demux, "Hidding one stream (pid=%d)", fmt.i_id );
1309 /* */
1310 es_out_id_t *p_es = es_out_Add( p_demux->out, &fmt );
1312 es_format_Clean( &fmt );
1313 return p_es;
1315 static int EsOutSend( es_out_t *p_out, es_out_id_t *p_es, block_t *p_block )
1317 return es_out_Send( p_out->p_sys->p_demux->out, p_es, p_block );
1319 static void EsOutDel( es_out_t *p_out, es_out_id_t *p_es )
1321 es_out_Del( p_out->p_sys->p_demux->out, p_es );
1323 static int EsOutControl( es_out_t *p_out, int i_query, va_list args )
1325 return es_out_vaControl( p_out->p_sys->p_demux->out, i_query, args );
1327 static void EsOutDestroy( es_out_t *p_out )
1329 free( p_out->p_sys );
1330 free( p_out );
1333 static es_out_t *EsOutNew( demux_t *p_demux )
1335 es_out_t *p_out = malloc( sizeof(*p_out) );
1336 es_out_sys_t *p_sys;
1338 if( !p_out )
1339 return NULL;
1341 p_out->pf_add = EsOutAdd;
1342 p_out->pf_send = EsOutSend;
1343 p_out->pf_del = EsOutDel;
1344 p_out->pf_control = EsOutControl;
1345 p_out->pf_destroy = EsOutDestroy;
1347 p_out->p_sys = p_sys = malloc( sizeof(*p_sys) );
1348 if( !p_sys )
1350 free( p_out );
1351 return NULL;
1353 p_sys->p_demux = p_demux;
1355 return p_out;