1 /*****************************************************************************
2 * bd.c: BluRay Disc support (uncrypted)
3 *****************************************************************************
4 * Copyright (C) 2009 VLC authors and VideoLAN
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_input.h>
38 #include <vlc_access.h>
39 #include <vlc_demux.h>
47 /*****************************************************************************
49 *****************************************************************************/
50 static int Open ( vlc_object_t * );
51 static void Close( vlc_object_t * );
54 set_shortname( N_("BD") )
55 set_description( N_("Blu-ray Disc Input") )
56 set_category( CAT_INPUT )
57 set_subcategory( SUBCAT_INPUT_ACCESS )
58 set_capability( "access_demux", 60 )
59 add_shortcut( "bd", "file" )
60 set_callbacks( Open, Close )
63 /*****************************************************************************
66 * - http://www.stebbins.biz/source/bdtools.tgz
67 * - hdcookbook java code
68 * - BDInfo source code
69 *****************************************************************************/
71 /*****************************************************************************
73 *****************************************************************************/
89 input_title_t **pp_title;
95 const bd_clpi_t *p_clpi;
103 int i_packet_headers;
104 int64_t i_atc_initial;
105 int64_t i_atc_current;
110 static int Control( demux_t *, int, va_list );
111 static int Demux( demux_t * );
113 static char *FindPathBase( const char *, bool *pb_shortname );
115 static int LoadPlaylist( demux_t * );
116 static int LoadClip( demux_t * );
118 static void ReorderPlaylist( demux_t * );
120 static void InitTitles( demux_t * );
121 static int SetTitle( demux_t *, int );
122 static int SetChapter( demux_t *, int );
123 static int64_t GetTime( demux_t * );
124 static double GetPosition( demux_t * );
125 static int SetTime( demux_t *, int64_t );
126 static int SetPosition( demux_t *, double );
128 static int SetPlayItem( demux_t *p_demux, int i_mpls, int i_play_item );
129 static void ClosePlayItem( demux_t * );
132 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 */ );
134 static es_out_t *EsOutNew( demux_t *p_demux );
138 /*****************************************************************************
140 *****************************************************************************/
141 static int Open( vlc_object_t *p_this )
143 demux_t *p_demux = (demux_t*)p_this;
146 if( p_demux->psz_file == NULL )
148 if( *p_demux->psz_access &&
149 strcmp( p_demux->psz_access, "bd" ) &&
150 strcmp( p_demux->psz_access, "file" ) )
155 char *psz_base = FindPathBase( p_demux->psz_file, &b_shortname );
159 msg_Dbg( p_demux, "Using path '%s'", psz_base );
161 /* Fill p_demux field */
162 p_demux->p_sys = p_sys = malloc( sizeof(*p_sys) );
168 p_sys->psz_base = psz_base;
169 p_sys->b_shortname = b_shortname;
170 TAB_INIT( p_sys->i_mpls, p_sys->pp_mpls );
171 TAB_INIT( p_sys->i_clpi, p_sys->pp_clpi );
172 TAB_INIT( p_sys->i_title, p_sys->pp_title );
173 p_demux->info.i_title = -1;
174 p_sys->p_clpi = NULL;
175 p_sys->i_clpi_ep = -1;
176 p_sys->p_parser = NULL;
177 p_sys->p_m2ts = NULL;
178 p_sys->i_play_item = -1;
179 p_sys->i_packet = -1;
180 p_sys->i_packet_start = -1;
181 p_sys->i_packet_stop = -1;
182 p_sys->i_packet_headers = -1;
183 p_sys->p_out = EsOutNew( p_demux );
187 p_demux->pf_control = Control;
188 p_demux->pf_demux = Demux;
190 /* Load all clip/playlist files */
192 LoadPlaylist( p_demux );
194 /* Reorder playlist to have the most significant first
195 * (as we don't have menu support, no idea how to find the main title */
196 ReorderPlaylist( p_demux );
198 /* Setup variables (for TS demuxer) */
199 var_Create( p_demux, "ts-es-id-pid", VLC_VAR_BOOL );
200 var_SetBool( p_demux, "ts-es-id-pid", true );
203 InitTitles( p_demux );
204 if( SetTitle( p_demux, 0 ) )
210 Close( VLC_OBJECT(p_demux) );
214 /*****************************************************************************
216 *****************************************************************************/
217 static void Close( vlc_object_t *p_this )
219 demux_t *p_demux = (demux_t*)p_this;
220 demux_sys_t *p_sys = p_demux->p_sys;
223 ClosePlayItem( p_demux );
226 es_out_Delete( p_sys->p_out );
229 for( int i = 0; i < p_sys->i_title; i++ )
230 vlc_input_title_Delete( p_sys->pp_title[i] );
231 TAB_CLEAN( p_sys->i_title, p_sys->pp_title );
234 for( int i = 0; i < p_sys->i_clpi; i++ )
236 bd_clpi_t *p_clpi = p_sys->pp_clpi[i];
238 bd_clpi_Clean( p_clpi );
241 TAB_CLEAN( p_sys->i_clpi, p_sys->pp_clpi );
244 for( int i = 0; i < p_sys->i_mpls; i++ )
246 bd_mpls_t *p_mpls = p_sys->pp_mpls[i];
248 bd_mpls_Clean( p_mpls );
251 TAB_CLEAN( p_sys->i_mpls, p_sys->pp_mpls );
253 free( p_sys->psz_base );
257 /*****************************************************************************
259 *****************************************************************************/
260 static int Control( demux_t *p_demux, int i_query, va_list args )
262 demux_sys_t *p_sys = p_demux->p_sys;
268 int64_t *pi_time = (int64_t*)va_arg( args, int64_t * );
269 *pi_time = GetTime( p_demux );
273 case DEMUX_GET_POSITION:
275 double *pf_position = (double*)va_arg( args, double * );
276 *pf_position = GetPosition( p_demux );
282 int64_t i_time = (int64_t)va_arg( args, int64_t );
283 return SetTime( p_demux, i_time );
285 case DEMUX_SET_POSITION:
287 double f_position = (double)va_arg( args, double );
288 return SetPosition( p_demux, f_position );
291 case DEMUX_GET_LENGTH:
293 int64_t *pi_length = (int64_t*)va_arg( args, int64_t * );
294 *pi_length = p_sys->pp_title[p_demux->info.i_title]->i_length;
298 /* Special for access_demux */
299 case DEMUX_CAN_PAUSE:
301 case DEMUX_CAN_CONTROL_PACE:
303 bool *pb_bool = (bool*)va_arg( args, bool * );
308 case DEMUX_SET_PAUSE_STATE:
311 case DEMUX_GET_TITLE_INFO:
313 input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
314 int *pi_int = (int*)va_arg( args, int* );
315 int *pi_title_offset = (int*)va_arg( args, int* );
316 int *pi_chapter_offset = (int*)va_arg( args, int* );
319 *pi_title_offset = 0;
320 *pi_chapter_offset = 0;
322 /* Duplicate title infos */
323 *pi_int = p_sys->i_title;
324 *ppp_title = calloc( p_sys->i_title, sizeof(input_title_t *) );
325 for( int i = 0; i < p_sys->i_title; i++ )
326 (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->pp_title[i] );
331 case DEMUX_SET_TITLE:
333 int i_title = (int)va_arg( args, int );
335 if( SetTitle( p_demux, i_title ) )
339 case DEMUX_SET_SEEKPOINT:
341 int i_chapter = (int)va_arg( args, int );
343 if( SetChapter( p_demux, i_chapter ) )
348 case DEMUX_GET_PTS_DELAY:
350 int64_t *pi_delay = (int64_t*)va_arg( args, int64_t * );
353 INT64_C(1000) * var_InheritInteger( p_demux, "disc-caching" );
364 /*****************************************************************************
366 *****************************************************************************/
367 #define BD_TS_PACKET_HEADER (4)
368 #define BD_TS_PACKET_SIZE (192)
369 static int Demux( demux_t *p_demux )
371 demux_sys_t *p_sys = p_demux->p_sys;
376 if( p_sys->i_packet == p_sys->i_packet_start )
378 stream_Seek( p_sys->p_m2ts, 0 );
380 block_t *p_block = stream_Block( p_sys->p_m2ts,
381 p_sys->i_packet_headers * (int64_t)BD_TS_PACKET_SIZE + BD_TS_PACKET_HEADER );
384 p_block->i_buffer -= BD_TS_PACKET_HEADER;
385 p_block->p_buffer += BD_TS_PACKET_HEADER;
386 stream_DemuxSend( p_sys->p_parser, p_block );
389 stream_Seek( p_sys->p_m2ts, p_sys->i_packet_start * (int64_t)BD_TS_PACKET_SIZE );
393 const int i_packets = __MIN( 5, p_sys->i_packet_stop - p_sys->i_packet );
396 const int i_title = p_demux->info.i_title;
397 const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_title];
399 if( p_sys->i_play_item < p_mpls->i_play_item )
401 if( !SetPlayItem( p_demux, i_title, p_sys->i_play_item + 1 ) )
403 msg_Warn( p_demux, "Failed to switch to the next play item" );
407 if( SetTitle( p_demux, i_title + 1 ) )
413 * we ensure that the TS packet start at the begining of the buffer,
414 * it ensure proper TS parsing */
415 block_t *p_block = block_Alloc( i_packets * BD_TS_PACKET_SIZE + BD_TS_PACKET_HEADER );
419 const int i_read = stream_Read( p_sys->p_m2ts, p_block->p_buffer, p_block->i_buffer - BD_TS_PACKET_HEADER );
422 msg_Err( p_demux, "Error reading current title" );
428 const int64_t i_atc = GetDWBE( p_block->p_buffer ) & ( (1 << 30) - 1 );
430 if( i_atc < p_sys->i_atc_last )
431 p_sys->i_atc_wrap += 1 << 30;
432 p_sys->i_atc_last = i_atc;
434 if( p_sys->i_atc_initial < 0 )
435 p_sys->i_atc_initial = i_atc + p_sys->i_atc_wrap;
437 p_sys->i_atc_current = i_atc + p_sys->i_atc_wrap;
440 p_block->i_buffer = i_read;
441 p_block->p_buffer += BD_TS_PACKET_HEADER;
442 stream_DemuxSend( p_sys->p_parser, p_block );
444 p_sys->i_packet += i_read / BD_TS_PACKET_SIZE;
447 if( p_sys->p_clpi->i_ep_map > 0 )
449 const int i_old_clpi_ep = p_sys->i_clpi_ep;
451 const bd_clpi_ep_map_t *p_ep_map = &p_sys->p_clpi->p_ep_map[0];
452 for( ; p_sys->i_clpi_ep+1 < p_ep_map->i_ep; p_sys->i_clpi_ep++ )
454 const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep+1];
456 if( p_ep->i_packet > p_sys->i_packet )
459 if( i_old_clpi_ep != p_sys->i_clpi_ep )
461 /* We have changed of EP */
462 p_sys->i_atc_initial = p_sys->i_atc_current; /* FIXME not exact */
464 /* Update seekpoint */
465 const input_title_t *p_title = p_sys->pp_title[p_demux->info.i_title];
466 const int64_t i_time = GetTime( p_demux );
468 for( ; p_demux->info.i_seekpoint+1 < p_title->i_seekpoint; p_demux->info.i_seekpoint++ )
470 const seekpoint_t *p_seekpoint = p_title->seekpoint[p_demux->info.i_seekpoint+1];
471 if( p_seekpoint->i_time_offset > i_time )
473 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
480 /*****************************************************************************
482 *****************************************************************************/
483 #define BD_45KHZ INT64_C(45000)
484 static void InitTitles( demux_t *p_demux )
486 demux_sys_t *p_sys = p_demux->p_sys;
489 for( int i = 0; i < p_sys->i_mpls; i++ )
491 const bd_mpls_t *p_mpls = p_sys->pp_mpls[i];
493 input_title_t *t = vlc_input_title_New();
499 for( int j = 0; j < p_mpls->i_play_item; j++ )
501 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[j];
503 t->i_length += ( p_item->i_out_time - p_item->i_in_time ) * CLOCK_FREQ / BD_45KHZ;
508 char psz_length[MSTRTIME_MAX_SIZE];
509 msg_Warn( p_demux, "TITLE[%d] %s", i, secstotimestr( psz_length, t->i_length / CLOCK_FREQ ) );
514 for( int j = 0; j < p_mpls->i_mark; j++ )
516 bd_mpls_mark_t *p_mark = &p_mpls->p_mark[j];
518 if( p_mark->i_type == BD_MPLS_MARK_TYPE_BOOKMARK &&
519 p_mark->i_play_item_id >= 0 && p_mark->i_play_item_id < p_mpls->i_play_item )
521 seekpoint_t *s = vlc_seekpoint_New();
525 for( int k = 0; k <= p_mark->i_play_item_id; k++ )
527 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[k];
530 if( k == p_mark->i_play_item_id )
531 i_out_time = p_mark->i_time;
533 i_out_time = p_item->i_out_time;
534 s->i_time_offset += ( i_out_time - p_item->i_in_time ) * CLOCK_FREQ / BD_45KHZ;
538 char psz_time[MSTRTIME_MAX_SIZE];
539 msg_Warn( p_demux, " SEEKPOINT[%d] %s", j, secstotimestr( psz_time, s->i_time_offset / CLOCK_FREQ ) );
542 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
545 if( t->i_seekpoint <= 0 )
547 seekpoint_t *s = vlc_seekpoint_New();
549 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
552 TAB_APPEND( p_sys->i_title, p_sys->pp_title, t );
555 static int SetTitle( demux_t *p_demux, int i_title )
557 demux_sys_t *p_sys = p_demux->p_sys;
559 if( i_title < 0 || i_title >= p_sys->i_title )
563 if( SetPlayItem( p_demux, i_title, 0 ) )
567 p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
568 p_demux->info.i_title = i_title;
569 p_demux->info.i_seekpoint = 0;
573 static int SetChapter( demux_t *p_demux, int i_chapter )
575 demux_sys_t *p_sys = p_demux->p_sys;
576 const int i_title = p_demux->info.i_title;
577 const input_title_t *p_title = p_sys->pp_title[i_title];
579 if( i_chapter < 0 || i_chapter > p_title->i_seekpoint )
582 if( SetTime( p_demux, p_title->seekpoint[i_chapter]->i_time_offset ) )
587 static int SetPlayItem( demux_t *p_demux, int i_mpls, int i_play_item )
589 demux_sys_t *p_sys = p_demux->p_sys;
591 /* FIXME TODO do not reopen everything when avoidable
592 * XXX becarefull that then the es_out wrapper need some sort of
596 const bool b_same_mpls = i_mpls == p_demux->info.i_title;
597 //const bool b_same_play_item = b_same_mpls &&
598 // i_play_item == p_sys->i_play_item;
601 const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_mpls];
604 if( i_play_item < 0 || i_play_item >= p_mpls->i_play_item )
607 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[i_play_item];
608 const bd_mpls_clpi_t *p_mpls_clpi = &p_item->clpi;
610 const bd_clpi_t *p_clpi = NULL;
611 for( int i_clpi = 0; i_clpi < p_sys->i_clpi && !p_clpi; i_clpi++ )
613 if( p_sys->pp_clpi[i_clpi]->i_id == p_mpls_clpi->i_id )
614 p_clpi = p_sys->pp_clpi[i_clpi];
618 const bool b_same_clpi = b_same_mpls && p_sys->p_clpi->i_id == p_clpi->i_id;
619 stream_t *p_m2ts = NULL;
623 if( asprintf( &psz_m2ts, "%s/STREAM/%05d.%s",
624 p_sys->psz_base, p_mpls_clpi->i_id, p_sys->b_shortname ? "MTS" : "m2ts" ) < 0 )
627 p_m2ts = stream_UrlNew( p_demux, psz_m2ts );
630 msg_Err( p_demux, "Failed to open %s", psz_m2ts );
637 /* TODO avoid reopenning the parser when unneeded.
638 * - b_same_play_item is too strict, we should check the play_items connection.
639 * - a way to completely flush the demuxer is also needed !
641 //const bool b_same_parser = b_same_play_item && false;
642 stream_t *p_parser = stream_DemuxNew( p_demux, "ts", p_sys->p_out );
645 msg_Err( p_demux, "Failed to create TS demuxer" );
647 stream_Delete( p_m2ts );
654 msg_Dbg( p_demux, "Reusing stream file" );
655 p_m2ts = p_sys->p_m2ts;
656 p_sys->p_m2ts = NULL;
660 ClosePlayItem( p_demux );
663 p_sys->p_clpi = p_clpi;
664 p_sys->p_parser = p_parser;
665 p_sys->p_m2ts = p_m2ts;
666 p_sys->i_play_item = i_play_item;
668 p_sys->i_packet_start = GetClpiPacket( p_demux, &p_sys->i_clpi_ep, p_mpls_clpi, p_item->i_in_time );
669 if( p_sys->i_packet_start < 0 )
671 p_sys->i_packet_start = 0;
672 p_sys->i_clpi_ep = 0;
675 p_sys->i_packet_stop = GetClpiPacket( p_demux, NULL, p_mpls_clpi, p_item->i_out_time );
676 if( p_sys->i_packet_stop < 0 )
677 p_sys->i_packet_stop = stream_Size( p_m2ts ) / BD_TS_PACKET_SIZE;
678 p_sys->i_packet = p_sys->i_packet_start;
680 /* This is a hack to detect the number of packet to send before any data
681 * to have the PAT/PMT. I have no idea if it is the right, but seems to work.
682 * I used a limits of 10 packets, sufficient if it is really only headers */
683 p_sys->i_packet_headers = 0;
684 if( p_clpi->i_ep_map > 0 )
686 const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[0];
687 if( p_ep_map->i_ep > 0 )
688 p_sys->i_packet_headers = __MIN( p_ep_map->p_ep[0].i_packet, 10 );
691 p_sys->i_atc_initial = -1;
692 p_sys->i_atc_current = -1;
693 p_sys->i_atc_last = -1;
694 p_sys->i_atc_wrap = 0;
698 static void ClosePlayItem( demux_t *p_demux )
700 demux_sys_t *p_sys = p_demux->p_sys;
703 stream_Delete( p_sys->p_m2ts );
704 if( p_sys->p_parser )
705 stream_Delete( p_sys->p_parser );
707 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
710 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 */ )
712 demux_sys_t *p_sys = p_demux->p_sys;
714 const bd_clpi_t *p_clpi = p_sys->p_clpi;
717 if( p_clpi->i_ep_map <= 0 )
719 const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[0];
721 if( p_mpls_clpi->i_stc_id < 0 || p_mpls_clpi->i_stc_id >= p_clpi->i_stc )
724 const bd_clpi_stc_t *p_stc = &p_clpi->p_stc[p_mpls_clpi->i_stc_id];
726 /* Not sure it is right */
727 if( i_time < p_stc->i_start || i_time > p_stc->i_end )
731 const int64_t i_packet = p_stc->i_packet;
733 for( i_ep = 0; i_ep < p_ep_map->i_ep; i_ep++ )
735 if( p_ep_map->p_ep[i_ep].i_packet >= i_packet )
738 if( i_ep >= p_ep_map->i_ep )
741 for( ; i_ep < p_ep_map->i_ep; i_ep++ )
743 const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[i_ep];
744 const bd_clpi_ep_t *p_ep_next = &p_ep_map->p_ep[i_ep+1];
746 if( i_ep+1 < p_ep_map->i_ep && p_ep_next->i_pts / 2 > i_time )
748 if( p_ep->i_pts / 2 >= i_time )
751 if( i_ep >= p_ep_map->i_ep )
757 return p_ep_map->p_ep[i_ep].i_packet;
761 * Retreive the current time using current EP + ATC delta
763 static int64_t GetTime( demux_t *p_demux )
765 demux_sys_t *p_sys = p_demux->p_sys;
766 const int i_mpls = p_demux->info.i_title;
768 const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_mpls];
769 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[p_sys->i_play_item];
771 const bd_clpi_t *p_clpi = p_sys->p_clpi;
772 if( !p_clpi || p_clpi->i_ep_map <= 0 )
776 const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[0];
777 if( p_sys->i_clpi_ep < 0 || p_sys->i_clpi_ep >= p_ep_map->i_ep )
780 const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep];
781 int64_t i_time = p_ep->i_pts / 2 - p_item->i_in_time +
782 ( p_sys->i_atc_current - p_sys->i_atc_initial ) / 300 / 2;
784 for( int j = 0; j < p_sys->i_play_item; j++ )
786 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[j];
787 i_time += ( p_item->i_out_time - p_item->i_in_time );
790 return i_time * CLOCK_FREQ / BD_45KHZ;
793 static double GetPosition( demux_t *p_demux )
795 demux_sys_t *p_sys = p_demux->p_sys;
797 const int64_t i_time = GetTime( p_demux );
798 const input_title_t *p_title = p_sys->pp_title[p_demux->info.i_title];
800 if( p_title->i_length <= 0 )
803 return (double)i_time / p_title->i_length;
806 static int SetTime( demux_t *p_demux, int64_t i_time )
808 demux_sys_t *p_sys = p_demux->p_sys;
809 const int i_mpls = p_demux->info.i_title;
810 const input_title_t *p_title = p_sys->pp_title[i_mpls];
811 const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_mpls];
813 /* Find the play item */
815 int64_t i_play_item_time = 0;
816 for( i_item = 0; i_item < p_mpls->i_play_item; i_item++ )
818 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[i_item];
819 const int64_t i_duration = ( p_item->i_out_time - p_item->i_in_time ) * CLOCK_FREQ / BD_45KHZ;
821 if( i_time >= i_play_item_time && i_time < i_play_item_time + i_duration )
824 i_play_item_time += i_duration;
827 if( i_item >= p_mpls->i_play_item )
830 if( SetPlayItem( p_demux, i_mpls, i_item ) )
834 /* Find the right entry point */
835 if( p_sys->p_clpi->i_ep_map <= 0 )
838 const bd_clpi_ep_map_t *p_ep_map = &p_sys->p_clpi->p_ep_map[0];
839 if( p_ep_map->i_ep <= 0 )
842 int64_t i_next_display_date = -1;
843 for( ; p_sys->i_clpi_ep+1 < p_ep_map->i_ep; p_sys->i_clpi_ep++ )
845 const bd_clpi_ep_t *p_next = &p_ep_map->p_ep[p_sys->i_clpi_ep+1];
846 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 );
848 if( i_next_time > i_time )
850 const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep];
851 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 );
854 i_next_display_date = p_ep->i_pts * CLOCK_FREQ / 90000 + ( i_time - i_ep_time );
859 const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep];
860 p_sys->i_packet_start =
861 p_sys->i_packet = p_ep->i_packet;
863 if( i_next_display_date >= 0 )
864 es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_next_display_date );
867 /* Update seekpoint */
868 for( p_demux->info.i_seekpoint = 0; p_demux->info.i_seekpoint+1 < p_title->i_seekpoint; p_demux->info.i_seekpoint++ )
870 const seekpoint_t *p_seekpoint = p_title->seekpoint[p_demux->info.i_seekpoint+1];
871 if( p_seekpoint->i_time_offset > i_time )
874 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
878 static int SetPosition( demux_t *p_demux, double f_position )
880 demux_sys_t *p_sys = p_demux->p_sys;
881 const input_title_t *p_title = p_sys->pp_title[p_demux->info.i_title];
883 if( p_title->i_length <= 0 )
886 return SetTime( p_demux, f_position * p_title->i_length );
889 /*****************************************************************************
891 *****************************************************************************/
892 static int64_t GetMplsUniqueDuration( const bd_mpls_t *p_mpls )
894 int64_t i_length = 0;
896 for( int i = 0; i < p_mpls->i_play_item; i++ )
898 const bd_mpls_play_item_t *p_item0 = &p_mpls->p_play_item[i];
900 for( j = i+1; j < p_mpls->i_play_item; j++ )
902 const bd_mpls_play_item_t *p_item1 = &p_mpls->p_play_item[j];
903 if( p_item0->clpi.i_id == p_item1->clpi.i_id &&
904 p_item0->clpi.i_stc_id == p_item1->clpi.i_stc_id &&
905 p_item0->i_in_time == p_item1->i_in_time &&
906 p_item0->i_out_time == p_item1->i_out_time )
909 if( j >= p_mpls->i_play_item )
910 i_length += p_item0->i_out_time - p_item0->i_in_time;
914 static int SortMpls( const void *a, const void *b )
916 const bd_mpls_t * const *pp_mpls_a = a;
917 const bd_mpls_t * const *pp_mpls_b = b;
919 const int64_t i_length_a = GetMplsUniqueDuration( *pp_mpls_a );
920 const int64_t i_length_b = GetMplsUniqueDuration( *pp_mpls_b );
922 if( i_length_a == i_length_b )
924 return i_length_a < i_length_b ? 1 : -1;
927 static void ReorderPlaylist( demux_t *p_demux )
929 demux_sys_t *p_sys = p_demux->p_sys;
930 qsort( p_sys->pp_mpls, p_sys->i_mpls, sizeof(*p_sys->pp_mpls), SortMpls );
932 /*****************************************************************************
934 *****************************************************************************/
935 static int CheckFileList( const char *psz_base, const char *ppsz_name[] )
937 for( int i = 0; ppsz_name[i] != NULL ; i++ )
942 if( asprintf( &psz_tmp, "%s/%s", psz_base, ppsz_name[i] ) < 0 )
945 bool b_ok = vlc_stat( psz_tmp, &s ) == 0 && S_ISREG( s.st_mode );
954 static char *FindPathBase( const char *psz_path, bool *pb_shortname )
960 char *psz_base = strdup( psz_path );
965 while( *psz_base && psz_base[strlen(psz_base)-1] == '/' )
966 psz_base[strlen(psz_base)-1] = '\0';
969 if( vlc_stat( psz_base, &s ) || !S_ISDIR( s.st_mode ) )
973 if( asprintf( &psz_tmp, "%s/BDMV", psz_base ) < 0 )
975 if( !vlc_stat( psz_tmp, &s ) && S_ISDIR( s.st_mode ) )
985 /* Check presence of mandatory files */
986 static const char *ppsz_name_long[] = {
991 static const char *ppsz_name_short[] = {
996 *pb_shortname = false;
997 if( CheckFileList( psz_base, ppsz_name_long ) )
999 if( CheckFileList( psz_base, ppsz_name_short ) )
1001 *pb_shortname = true;
1011 static block_t *LoadBlock( demux_t *p_demux, const char *psz_name )
1013 stream_t *s = stream_UrlNew( p_demux, psz_name );
1017 const int64_t i_size = stream_Size( s );
1018 block_t *p_block = NULL;
1020 if( i_size > 0 && i_size < INT_MAX )
1021 p_block = stream_Block( s, i_size );
1029 static int FilterMplsLong( const char *psz_name )
1031 return strlen( psz_name ) == strlen( "xxxxx.mpls" ) &&
1032 !strcmp( &psz_name[5], ".mpls" );
1034 static int FilterMplsShort( const char *psz_name )
1036 return strlen( psz_name ) == strlen( "xxxxx.MPL" ) &&
1037 !strcmp( &psz_name[5], ".MPL" );
1040 static void LoadMpls( demux_t *p_demux, const char *psz_name, int i_id )
1042 demux_sys_t *p_sys = p_demux->p_sys;
1044 #if defined(BD_DEBUG)
1045 msg_Err( p_demux, "Loading %s", psz_name );
1048 block_t *p_block = LoadBlock( p_demux, psz_name );
1053 bd_mpls_t *p_mpls = malloc( sizeof(*p_mpls) );
1059 bs_init( &s, p_block->p_buffer, p_block->i_buffer );
1061 if( bd_mpls_Parse( p_mpls, &s, i_id ) )
1064 #if defined(BD_DEBUG)
1065 msg_Err( p_demux, "MPLS: id=%d", p_mpls->i_id );
1066 msg_Err( p_demux, "MPLS: play_item=%d sub_path=%d",
1067 p_mpls->i_play_item, p_mpls->i_sub_path );
1069 for( int i = 0; i < p_mpls->i_play_item; i++ )
1071 bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[i];
1073 msg_Err( p_demux, "PLAY_ITEM[%d] connection=%d in=%d out=%d still=%d(%d)",
1074 i, p_item->i_connection,
1075 (int)p_item->i_in_time, (int)p_item->i_out_time,
1076 p_item->i_still, p_item->i_still_time );
1077 msg_Err( p_demux, " clpi_default: id=%d stc_id=%d",
1078 p_item->clpi.i_id, p_item->clpi.i_stc_id );
1079 for( int j = 0; j < p_item->i_clpi; j++ )
1080 msg_Err( p_demux, " clpi[%d]: id=%d stc_id=%d",
1081 j, p_item->p_clpi[j].i_id, p_item->p_clpi[j].i_stc_id );
1082 for( int j = 0; j < p_item->i_stream; j++ )
1083 msg_Err( p_demux, " stream[%d]: type=%d class=%d stream_type=0x%x lang=%s charset=%d",
1085 p_item->p_stream[j].i_type,
1086 p_item->p_stream[j].i_class,
1087 p_item->p_stream[j].i_stream_type,
1088 p_item->p_stream[j].psz_language,
1089 p_item->p_stream[j].i_charset );
1092 for( int i = 0; i < p_mpls->i_sub_path; i++ )
1094 bd_mpls_sub_path_t *p_sub = &p_mpls->p_sub_path[i];
1096 msg_Err( p_demux, "SUB_PATH[%d] type=%d repeat=%d item=%d",
1097 i, p_sub->i_type, p_sub->b_repeat, p_sub->i_item );
1100 for( int i = 0; i < p_mpls->i_mark; i++ )
1102 bd_mpls_mark_t *p_mark = &p_mpls->p_mark[i];
1104 msg_Err( p_demux, "M[%d] t=%d play_item_id=%d time=%d entry_es_pid=%d",
1105 i, p_mark->i_type, p_mark->i_play_item_id, (int)p_mark->i_time, p_mark->i_entry_es_pid );
1110 TAB_APPEND( p_sys->i_mpls, p_sys->pp_mpls, p_mpls );
1113 block_Release( p_block );
1117 msg_Err( p_demux, "Failed loading %s", psz_name );
1119 block_Release( p_block );
1123 static int FilterClpiLong( const char *psz_name )
1125 return strlen( psz_name ) == strlen( "xxxxx.clpi" ) &&
1126 !strcmp( &psz_name[5], ".clpi" );
1128 static int FilterClpiShort( const char *psz_name )
1130 return strlen( psz_name ) == strlen( "xxxxx.CPI" ) &&
1131 !strcmp( &psz_name[5], ".CPI" );
1134 static void LoadClpi( demux_t *p_demux, const char *psz_name, int i_id )
1136 demux_sys_t *p_sys = p_demux->p_sys;
1138 #if defined(BD_DEBUG)
1139 msg_Err( p_demux, "Loading %s", psz_name );
1142 block_t *p_block = LoadBlock( p_demux, psz_name );
1147 bd_clpi_t *p_clpi = malloc( sizeof(*p_clpi) );
1153 bs_init( &s, p_block->p_buffer, p_block->i_buffer );
1155 if( bd_clpi_Parse( p_clpi, &s, i_id ) )
1158 #if defined(BD_DEBUG)
1159 msg_Err( p_demux, "CLPI: id=%d", p_clpi->i_id );
1160 msg_Err( p_demux, "CLPI: STC=%d", p_clpi->i_stc );
1161 for( int i = 0; i < p_clpi->i_stc; i++ )
1162 msg_Err( p_demux, " STC[%d] pcr_pid=%d packet=%d start=%d end=%d",
1163 i, p_clpi->p_stc[i].i_pcr_pid, (int)p_clpi->p_stc[i].i_packet,
1164 (int)p_clpi->p_stc[i].i_start, (int)p_clpi->p_stc[i].i_end );
1165 msg_Err( p_demux, "CLPI: Stream=%d", p_clpi->i_stream );
1166 for( int i = 0; i < p_clpi->i_stream; i++ )
1167 msg_Err( p_demux, " Stream[%d] pid=%d type=0x%x",
1168 i, p_clpi->p_stream[i].i_pid, p_clpi->p_stream[i].i_type );
1169 msg_Err( p_demux, "CLPI: Ep Map=%d", p_clpi->i_ep_map );
1170 for( int i = 0; i < p_clpi->i_ep_map; i++ )
1172 const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[i];
1173 msg_Err( p_demux, " Ep Map[%d] pid=%d type=0x%x entry_point=%d",
1174 i, p_ep_map->i_pid, p_ep_map->i_type, p_ep_map->i_ep );
1175 for( int j = 0; j < p_ep_map->i_ep; j++ )
1177 msg_Err( p_demux, " Ep[%d] packet=%d pts=%d",
1178 j, (int)p_ep_map->p_ep[j].i_packet, (int)p_ep_map->p_ep[j].i_pts );
1184 TAB_APPEND( p_sys->i_clpi, p_sys->pp_clpi, p_clpi );
1187 block_Release( p_block );
1191 msg_Err( p_demux, "Failed loading %s", psz_name );
1193 block_Release( p_block );
1197 static int ScanSort( const char **ppsz_a, const char **ppsz_b )
1199 return strcmp( *ppsz_a, *ppsz_b );
1202 static int Load( demux_t *p_demux,
1203 const char *psz_dir,
1204 int (*pf_filter)( const char * ),
1205 void (*pf_load)( demux_t *p_demux, const char *psz_name, int i_id ) )
1208 if( asprintf( &psz_playlist, "%s/%s", p_demux->p_sys->psz_base, psz_dir ) < 0 )
1209 return VLC_EGENERIC;
1213 int i_list = vlc_scandir( psz_playlist, &ppsz_list, pf_filter, ScanSort );
1215 for( int i = 0; i < i_list; i++ )
1217 char *psz_file = ppsz_list[i];
1222 if( asprintf( &psz_name, "%s/%s/%s", p_demux->p_sys->psz_base, psz_dir, psz_file ) >= 0)
1224 const int i_id = strtol( psz_file, NULL, 10 );
1225 pf_load( p_demux, psz_name, i_id );
1232 free( psz_playlist );
1236 static int LoadPlaylist( demux_t *p_demux )
1238 return Load( p_demux, "PLAYLIST",
1239 p_demux->p_sys->b_shortname ? FilterMplsShort : FilterMplsLong, LoadMpls );
1241 static int LoadClip( demux_t *p_demux )
1243 return Load( p_demux, "CLIPINF",
1244 p_demux->p_sys->b_shortname ? FilterClpiShort : FilterClpiLong, LoadClpi );
1253 static es_out_id_t *EsOutAdd( es_out_t *p_out, const es_format_t *p_fmt )
1255 demux_t *p_demux = p_out->p_sys->p_demux;
1256 const bd_mpls_t *p_mpls = p_demux->p_sys->pp_mpls[p_demux->info.i_title];
1257 const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[p_demux->p_sys->i_play_item];
1261 es_format_Copy( &fmt, p_fmt );
1262 fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
1264 for( int i = 0; i < p_item->i_stream; i++ )
1266 const bd_mpls_stream_t *p_stream = &p_item->p_stream[i];
1267 if( p_stream->i_type != BD_MPLS_STREAM_TYPE_PLAY_ITEM ||
1268 p_stream->play_item.i_pid != fmt.i_id )
1271 /* TODO improved priority for higher quality stream ?
1272 * if so, extending stream attributes parsing might be a good idea
1274 fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
1277 /* Useless, and beside not sure it is the right thing to do */
1278 free( fmt.psz_description );
1279 switch( p_stream->i_class )
1281 case BD_MPLS_STREAM_CLASS_SECONDARY_AUDIO:
1282 fmt.psz_description = strdup( "Secondary audio" );
1285 fmt.psz_description = NULL;
1290 //msg_Err( p_demux, "Found ref for stream pid %d", fmt.i_id );
1291 if( *p_stream->psz_language && ( !fmt.psz_language || *fmt.psz_language == '\0' ) )
1293 free( fmt.psz_language );
1294 fmt.psz_language = strdup( p_stream->psz_language );
1296 switch( p_stream->i_charset )
1298 /* TODO add all values */
1304 if( fmt.i_priority < ES_PRIORITY_SELECTABLE_MIN )
1305 msg_Dbg( p_demux, "Hiding one stream (pid=%d)", fmt.i_id );
1308 es_out_id_t *p_es = es_out_Add( p_demux->out, &fmt );
1310 es_format_Clean( &fmt );
1313 static int EsOutSend( es_out_t *p_out, es_out_id_t *p_es, block_t *p_block )
1315 return es_out_Send( p_out->p_sys->p_demux->out, p_es, p_block );
1317 static void EsOutDel( es_out_t *p_out, es_out_id_t *p_es )
1319 es_out_Del( p_out->p_sys->p_demux->out, p_es );
1321 static int EsOutControl( es_out_t *p_out, int i_query, va_list args )
1323 return es_out_vaControl( p_out->p_sys->p_demux->out, i_query, args );
1325 static void EsOutDestroy( es_out_t *p_out )
1327 free( p_out->p_sys );
1331 static es_out_t *EsOutNew( demux_t *p_demux )
1333 es_out_t *p_out = malloc( sizeof(*p_out) );
1334 es_out_sys_t *p_sys;
1339 p_out->pf_add = EsOutAdd;
1340 p_out->pf_send = EsOutSend;
1341 p_out->pf_del = EsOutDel;
1342 p_out->pf_control = EsOutControl;
1343 p_out->pf_destroy = EsOutDestroy;
1345 p_out->p_sys = p_sys = malloc( sizeof(*p_sys) );
1351 p_sys->p_demux = p_demux;