1 /*****************************************************************************
2 * bd.c: BluRay Disc support (uncrypted)
3 *****************************************************************************
4 * Copyright (C) 2009 the VideoLAN team
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 /*****************************************************************************
26 *****************************************************************************/
32 #ifdef HAVE_SYS_STAT_H
33 # include <sys/stat.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>
49 /*****************************************************************************
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
* );
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 )
69 add_shortcut( "file" )
70 set_callbacks( Open
, Close
)
73 /*****************************************************************************
76 * - http://www.stebbins.biz/source/bdtools.tgz
77 * - hdcookbook java code
78 * - BDInfo source code
79 *****************************************************************************/
81 /*****************************************************************************
83 *****************************************************************************/
99 input_title_t
**pp_title
;
105 const bd_clpi_t
*p_clpi
;
113 int i_packet_headers
;
114 int64_t i_atc_initial
;
115 int64_t i_atc_current
;
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
* );
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
);
148 /*****************************************************************************
150 *****************************************************************************/
151 static int Open( vlc_object_t
*p_this
)
153 demux_t
*p_demux
= (demux_t
*)p_this
;
156 if( *p_demux
->psz_access
&&
157 strcmp( p_demux
->psz_access
, "bd" ) &&
158 strcmp( p_demux
->psz_access
, "file" ) )
163 char *psz_base
= FindPathBase( p_demux
->psz_path
, &b_shortname
);
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
) );
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
);
192 p_demux
->pf_control
= Control
;
193 p_demux
->pf_demux
= Demux
;
195 /* Load all clip/playlist files */
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 );
208 InitTitles( p_demux
);
209 if( SetTitle( p_demux
, 0 ) )
215 Close( VLC_OBJECT(p_demux
) );
219 /*****************************************************************************
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
;
228 ClosePlayItem( p_demux
);
231 es_out_Delete( p_sys
->p_out
);
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
);
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
);
246 TAB_CLEAN( p_sys
->i_clpi
, p_sys
->pp_clpi
);
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
);
256 TAB_CLEAN( p_sys
->i_mpls
, p_sys
->pp_mpls
);
258 free( p_sys
->psz_base
);
262 /*****************************************************************************
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
;
273 int64_t *pi_time
= (int64_t*)va_arg( args
, int64_t * );
274 *pi_time
= GetTime( p_demux
);
278 case DEMUX_GET_POSITION
:
280 double *pf_position
= (double*)va_arg( args
, double * );
281 *pf_position
= GetPosition( p_demux
);
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
;
303 /* Special for access_demux */
304 case DEMUX_CAN_PAUSE
:
306 case DEMUX_CAN_CONTROL_PACE
:
308 bool *pb_bool
= (bool*)va_arg( args
, bool * );
313 case DEMUX_SET_PAUSE_STATE
:
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* );
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
] );
336 case DEMUX_SET_TITLE
:
338 int i_title
= (int)va_arg( args
, int );
340 if( SetTitle( p_demux
, i_title
) )
344 case DEMUX_SET_SEEKPOINT
:
346 int i_chapter
= (int)va_arg( args
, int );
348 if( SetChapter( p_demux
, i_chapter
) )
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);
367 /*****************************************************************************
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
;
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
);
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
);
396 const int i_packets
= __MIN( 5, p_sys
->i_packet_stop
- p_sys
->i_packet
);
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 ) )
406 msg_Warn( p_demux
, "Failed to switch to the next play item" );
410 if( SetTitle( p_demux
, i_title
+ 1 ) )
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
);
422 const int i_read
= stream_Read( p_sys
->p_m2ts
, p_block
->p_buffer
, p_block
->i_buffer
- BD_TS_PACKET_HEADER
);
425 msg_Err( p_demux
, "Error reading current title" );
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
;
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
)
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
)
476 p_demux
->info
.i_update
|= INPUT_UPDATE_SEEKPOINT
;
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
;
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();
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
;
511 char psz_length
[MSTRTIME_MAX_SIZE
];
512 msg_Warn( p_demux
, "TITLE[%d] %s", i
, secstotimestr( psz_length
, t
->i_length
/ CLOCK_FREQ
) );
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();
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
];
533 if( k
== p_mark
->i_play_item_id
)
534 i_out_time
= p_mark
->i_time
;
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
;
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
) );
545 TAB_APPEND( t
->i_seekpoint
, t
->seekpoint
, s
);
548 if( t
->i_seekpoint
<= 0 )
550 seekpoint_t
*s
= vlc_seekpoint_New();
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
)
566 if( SetPlayItem( p_demux
, i_title
, 0 ) )
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;
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
)
585 if( SetTime( p_demux
, p_title
->seekpoint
[i_chapter
]->i_time_offset
) )
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
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;
604 const bd_mpls_t
*p_mpls
= p_sys
->pp_mpls
[i_mpls
];
607 if( i_play_item
< 0 || i_play_item
>= p_mpls
->i_play_item
)
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
;
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 )
629 p_m2ts
= stream_UrlNew( p_demux
, psz_m2ts
);
632 msg_Err( p_demux
, "Failed to open %s", 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
);
647 msg_Err( p_demux
, "Failed to create TS demuxer" );
649 stream_Delete( p_m2ts
);
656 msg_Dbg( p_demux
, "Reusing stream file" );
657 p_m2ts
= p_sys
->p_m2ts
;
658 p_sys
->p_m2ts
= NULL
;
662 ClosePlayItem( p_demux
);
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;
700 static void ClosePlayItem( demux_t
*p_demux
)
702 demux_sys_t
*p_sys
= p_demux
->p_sys
;
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
;
719 if( p_clpi
->i_ep_map
<= 0 )
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
)
726 const bd_clpi_stc_t
*p_stc
= &p_clpi
->p_stc
[p_mpls_clpi
->i_stc_id
];
728 /* Not sure it is right */
729 if( i_time
< p_stc
->i_start
|| i_time
> p_stc
->i_end
)
733 const int64_t i_packet
= p_stc
->i_packet
;
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
)
740 if( i_ep
>= p_ep_map
->i_ep
)
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
)
750 if( p_ep
->i_pts
/ 2 >= i_time
)
753 if( i_ep
>= p_ep_map
->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 )
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
)
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 )
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 */
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
)
826 i_play_item_time
+= i_duration
;
829 if( i_item
>= p_mpls
->i_play_item
)
832 if( SetPlayItem( p_demux
, i_mpls
, i_item
) )
836 /* Find the right entry point */
837 if( p_sys
->p_clpi
->i_ep_map
<= 0 )
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 )
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
);
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
);
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
)
876 p_demux
->info
.i_update
|= INPUT_UPDATE_SEEKPOINT
;
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 )
888 return SetTime( p_demux
, f_position
* p_title
->i_length
);
891 /*****************************************************************************
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
];
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
)
911 if( j
>= p_mpls
->i_play_item
)
912 i_length
+= p_item0
->i_out_time
- p_item0
->i_in_time
;
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
)
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 /*****************************************************************************
936 *****************************************************************************/
937 static int CheckFileList( const char *psz_base
, const char *ppsz_name
[] )
939 for( int i
= 0; ppsz_name
[i
] != NULL
; i
++ )
944 if( asprintf( &psz_tmp
, "%s/%s", psz_base
, ppsz_name
[i
] ) < 0 )
947 bool b_ok
= vlc_stat( psz_tmp
, &s
) == 0 && S_ISREG( s
.st_mode
);
956 static char *FindPathBase( const char *psz_path
, bool *pb_shortname
)
962 char *psz_base
= strdup( psz_path
);
967 while( *psz_base
&& psz_base
[strlen(psz_base
)-1] == '/' )
968 psz_base
[strlen(psz_base
)-1] = '\0';
971 if( vlc_stat( psz_base
, &s
) || !S_ISDIR( s
.st_mode
) )
975 if( asprintf( &psz_tmp
, "%s/BDMV", psz_base
) < 0 )
977 if( !vlc_stat( psz_tmp
, &s
) && S_ISDIR( s
.st_mode
) )
987 /* Check presence of mandatory files */
988 static const char *ppsz_name_long
[] = {
993 static const char *ppsz_name_short
[] = {
998 *pb_shortname
= false;
999 if( CheckFileList( psz_base
, ppsz_name_long
) )
1001 if( CheckFileList( psz_base
, ppsz_name_short
) )
1003 *pb_shortname
= true;
1013 static block_t
*LoadBlock( demux_t
*p_demux
, const char *psz_name
)
1015 stream_t
*s
= stream_UrlNew( p_demux
, psz_name
);
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
);
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
);
1050 block_t
*p_block
= LoadBlock( p_demux
, psz_name
);
1055 bd_mpls_t
*p_mpls
= malloc( sizeof(*p_mpls
) );
1061 bs_init( &s
, p_block
->p_buffer
, p_block
->i_buffer
);
1063 if( bd_mpls_Parse( p_mpls
, &s
, i_id
) )
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
);
1112 TAB_APPEND( p_sys
->i_mpls
, p_sys
->pp_mpls
, p_mpls
);
1115 block_Release( p_block
);
1119 msg_Err( p_demux
, "Failed loading %s", psz_name
);
1121 block_Release( p_block
);
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
);
1144 block_t
*p_block
= LoadBlock( p_demux
, psz_name
);
1149 bd_clpi_t
*p_clpi
= malloc( sizeof(*p_clpi
) );
1155 bs_init( &s
, p_block
->p_buffer
, p_block
->i_buffer
);
1157 if( bd_clpi_Parse( p_clpi
, &s
, i_id
) )
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
);
1186 TAB_APPEND( p_sys
->i_clpi
, p_sys
->pp_clpi
, p_clpi
);
1189 block_Release( p_block
);
1193 msg_Err( p_demux
, "Failed loading %s", psz_name
);
1195 block_Release( p_block
);
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
) )
1210 if( asprintf( &psz_playlist
, "%s/%s", p_demux
->p_sys
->psz_base
, psz_dir
) < 0 )
1211 return VLC_EGENERIC
;
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
];
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
);
1234 free( psz_playlist
);
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
);
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
];
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
)
1273 /* TODO improved priority for higher quality stream ?
1274 * if so, extending stream attributes parsing might be a good idea
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" );
1287 fmt
.psz_description
= NULL
;
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 */
1306 if( fmt
.i_priority
< 0 )
1307 msg_Dbg( p_demux
, "Hidding one stream (pid=%d)", fmt
.i_id
);
1310 es_out_id_t
*p_es
= es_out_Add( p_demux
->out
, &fmt
);
1312 es_format_Clean( &fmt
);
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
);
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
;
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
) );
1353 p_sys
->p_demux
= p_demux
;