]> git.sesse.net Git - vlc/blob - modules/access/bd/bd.c
ec85e83244f56993270dce7d983a34f11ce37933
[vlc] / modules / access / bd / bd.c
1 /*****************************************************************************
2  * bd.c: BluRay Disc support (uncrypted)
3  *****************************************************************************
4  * Copyright (C) 2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #ifdef HAVE_SYS_STAT_H
33 #   include <sys/stat.h>
34 #endif
35 #include <limits.h>
36
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>
45
46 #include "mpls.h"
47 #include "clpi.h"
48
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." )
56
57 static int  Open ( vlc_object_t * );
58 static void Close( vlc_object_t * );
59
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", "file" )
69     set_callbacks( Open, Close )
70 vlc_module_end ()
71
72 /*****************************************************************************
73  * Documentation
74  * I have used:
75  *  - http://www.stebbins.biz/source/bdtools.tgz
76  *  - hdcookbook java code
77  *  - BDInfo source code
78  *****************************************************************************/
79
80 /*****************************************************************************
81  * Local prototypes
82  *****************************************************************************/
83 struct demux_sys_t
84 {
85     char *psz_base;
86     bool b_shortname;
87
88     /* */
89     int       i_mpls;
90     bd_mpls_t **pp_mpls;
91
92     /* */
93     int       i_clpi;
94     bd_clpi_t **pp_clpi;
95
96     /* */
97     int             i_title;
98     input_title_t   **pp_title;
99
100     /* */
101     es_out_t        *p_out;
102
103     /* Current state */
104     const bd_clpi_t *p_clpi;
105     int             i_clpi_ep;
106     stream_t        *p_parser;
107     stream_t        *p_m2ts;
108     int             i_play_item;
109     int             i_packet;
110     int             i_packet_start;
111     int             i_packet_stop;
112     int             i_packet_headers;
113     int64_t         i_atc_initial;
114     int64_t         i_atc_current;
115     int64_t         i_atc_wrap;
116     int64_t         i_atc_last;
117 };
118
119 static int Control( demux_t *, int, va_list );
120 static int Demux( demux_t * );
121
122 static char *FindPathBase( const char *, bool *pb_shortname );
123
124 static int LoadPlaylist( demux_t * );
125 static int LoadClip( demux_t * );
126
127 static void ReorderPlaylist( demux_t * );
128
129 static void InitTitles( demux_t * );
130 static int  SetTitle( demux_t *, int );
131 static int  SetChapter( demux_t *, int );
132 static int64_t GetTime( demux_t * );
133 static double  GetPosition( demux_t * );
134 static int     SetTime( demux_t *, int64_t );
135 static int     SetPosition( demux_t *, double );
136
137 static int SetPlayItem( demux_t *p_demux, int i_mpls, int i_play_item );
138 static void ClosePlayItem( demux_t * );
139
140 /* */
141 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 */ );
142
143 static es_out_t *EsOutNew( demux_t *p_demux );
144
145 //#define BD_DEBUG
146
147 /*****************************************************************************
148  * Open:
149  *****************************************************************************/
150 static int Open( vlc_object_t *p_this )
151 {
152     demux_t     *p_demux = (demux_t*)p_this;
153     demux_sys_t *p_sys;
154
155     if( *p_demux->psz_access &&
156         strcmp( p_demux->psz_access, "bd" ) &&
157         strcmp( p_demux->psz_access, "file" ) )
158         return VLC_EGENERIC;
159
160     /* */
161     bool b_shortname;
162     char *psz_base = FindPathBase( p_demux->psz_path, &b_shortname );
163     if( !psz_base )
164         return VLC_EGENERIC;
165
166     msg_Dbg( p_demux, "Using path '%s'", psz_base );
167
168     /* Fill p_demux field */
169     p_demux->p_sys = p_sys = malloc( sizeof(*p_sys) );
170     if( !p_sys )
171         return VLC_EGENERIC;
172     p_sys->psz_base = psz_base;
173     p_sys->b_shortname = b_shortname;
174     TAB_INIT( p_sys->i_mpls, p_sys->pp_mpls );
175     TAB_INIT( p_sys->i_clpi, p_sys->pp_clpi );
176     TAB_INIT( p_sys->i_title, p_sys->pp_title );
177     p_demux->info.i_title = -1;
178     p_sys->p_clpi = NULL;
179     p_sys->i_clpi_ep = -1;
180     p_sys->p_parser = NULL;
181     p_sys->p_m2ts = NULL;
182     p_sys->i_play_item = -1;
183     p_sys->i_packet = -1;
184     p_sys->i_packet_start = -1;
185     p_sys->i_packet_stop = -1;
186     p_sys->i_packet_headers = -1;
187     p_sys->p_out = EsOutNew( p_demux );
188     if( !p_sys->p_out )
189         goto error;
190
191     p_demux->pf_control = Control;
192     p_demux->pf_demux = Demux;
193
194     /* Load all clip/playlist files */
195     LoadClip( p_demux );
196     LoadPlaylist( p_demux );
197
198     /* Reorder playlist to have the most significant first
199      * (as we don't have menu support, no idea how to find the main title */
200     ReorderPlaylist( p_demux );
201
202     /* Setup variables (for TS demuxer) */
203     var_Create( p_demux, "ts-es-id-pid", VLC_VAR_BOOL );
204     var_SetBool( p_demux, "ts-es-id-pid", true );
205
206     /* */
207     InitTitles( p_demux );
208     if( SetTitle( p_demux, 0 ) )
209         goto error;
210
211     return VLC_SUCCESS;
212
213 error:
214     Close( VLC_OBJECT(p_demux) );
215     return VLC_EGENERIC;
216 }
217
218 /*****************************************************************************
219  * Close:
220  *****************************************************************************/
221 static void Close( vlc_object_t *p_this )
222 {
223     demux_t     *p_demux = (demux_t*)p_this;
224     demux_sys_t *p_sys = p_demux->p_sys;
225
226     /* */
227     ClosePlayItem( p_demux );
228
229     /* */
230     es_out_Delete( p_sys->p_out );
231
232     /* Titles */
233     for( int i = 0; i < p_sys->i_title; i++ )
234         vlc_input_title_Delete( p_sys->pp_title[i] );
235     TAB_CLEAN( p_sys->i_title, p_sys->pp_title );
236
237     /* CLPI */
238     for( int i = 0; i < p_sys->i_clpi; i++ )
239     {
240         bd_clpi_t *p_clpi = p_sys->pp_clpi[i];
241
242         bd_clpi_Clean( p_clpi );
243         free( p_clpi );
244     }
245     TAB_CLEAN( p_sys->i_clpi, p_sys->pp_clpi );
246
247     /* MPLS */
248     for( int i = 0; i < p_sys->i_mpls; i++ )
249     {
250         bd_mpls_t *p_mpls = p_sys->pp_mpls[i];
251
252         bd_mpls_Clean( p_mpls );
253         free( p_mpls );
254     }
255     TAB_CLEAN( p_sys->i_mpls, p_sys->pp_mpls );
256
257     free( p_sys->psz_base );
258     free( p_sys );
259 }
260
261 /*****************************************************************************
262  * Control:
263  *****************************************************************************/
264 static int Control( demux_t *p_demux, int i_query, va_list args )
265 {
266     demux_sys_t *p_sys = p_demux->p_sys;
267
268     switch( i_query )
269     {
270     case DEMUX_GET_TIME:
271     {
272         int64_t *pi_time = (int64_t*)va_arg( args, int64_t * );
273         *pi_time = GetTime( p_demux );
274         return VLC_SUCCESS;;
275     }
276
277     case DEMUX_GET_POSITION:
278     {
279         double *pf_position = (double*)va_arg( args, double * );
280         *pf_position = GetPosition( p_demux );
281         return VLC_SUCCESS;
282     }
283
284     case DEMUX_SET_TIME:
285     {
286         int64_t i_time = (int64_t)va_arg( args, int64_t );
287         return SetTime( p_demux, i_time );
288     }
289     case DEMUX_SET_POSITION:
290     {
291         double f_position = (double)va_arg( args, double );
292         return SetPosition( p_demux, f_position );
293     }
294
295     case DEMUX_GET_LENGTH:
296     {
297         int64_t *pi_length = (int64_t*)va_arg( args, int64_t * );
298         *pi_length = p_sys->pp_title[p_demux->info.i_title]->i_length;
299         return VLC_SUCCESS;
300     }
301
302     /* Special for access_demux */
303     case DEMUX_CAN_PAUSE:
304     case DEMUX_CAN_SEEK:
305     case DEMUX_CAN_CONTROL_PACE:
306     {
307         bool *pb_bool = (bool*)va_arg( args, bool * );
308         *pb_bool = true;
309         return VLC_SUCCESS;
310     }
311
312     case DEMUX_SET_PAUSE_STATE:
313         return VLC_SUCCESS;
314
315     case DEMUX_GET_TITLE_INFO:
316     {
317         input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
318         int *pi_int    = (int*)va_arg( args, int* );
319         int *pi_title_offset = (int*)va_arg( args, int* );
320         int *pi_chapter_offset = (int*)va_arg( args, int* );
321
322         /* */
323         *pi_title_offset = 0;
324         *pi_chapter_offset = 0;
325
326         /* Duplicate title infos */
327         *pi_int = p_sys->i_title;
328         *ppp_title = calloc( p_sys->i_title, sizeof(input_title_t **) );
329         for( int i = 0; i < p_sys->i_title; i++ )
330             (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->pp_title[i] );
331
332         return VLC_SUCCESS;
333     }
334
335     case DEMUX_SET_TITLE:
336     {
337         int i_title = (int)va_arg( args, int );
338
339         if( SetTitle( p_demux, i_title ) )
340             return VLC_EGENERIC;
341         return VLC_SUCCESS;
342     }
343     case DEMUX_SET_SEEKPOINT:
344     {
345         int i_chapter = (int)va_arg( args, int );
346
347         if( SetChapter( p_demux, i_chapter ) )
348             return VLC_EGENERIC;
349         return VLC_SUCCESS;
350     }
351
352     case DEMUX_GET_PTS_DELAY:
353     {
354         int64_t *pi_delay = (int64_t*)va_arg( args, int64_t * );
355         *pi_delay = var_GetInteger( p_demux, "bd-caching" ) * INT64_C(1000);
356         return VLC_SUCCESS;
357     }
358
359     case DEMUX_GET_META:
360
361     default:
362         return VLC_EGENERIC;
363     }
364 }
365
366 /*****************************************************************************
367  * Demux:
368  *****************************************************************************/
369 #define BD_TS_PACKET_HEADER (4)
370 #define BD_TS_PACKET_SIZE (192)
371 static int Demux( demux_t *p_demux )
372 {
373     demux_sys_t *p_sys = p_demux->p_sys;
374     if( !p_sys->p_m2ts )
375         return -1;
376
377     /* */
378     if( p_sys->i_packet == p_sys->i_packet_start )
379     {
380         stream_Seek( p_sys->p_m2ts, 0 );
381
382         block_t *p_block = stream_Block( p_sys->p_m2ts,
383                                          p_sys->i_packet_headers * (int64_t)BD_TS_PACKET_SIZE + BD_TS_PACKET_HEADER );
384         if( p_block )
385         {
386             p_block->i_buffer -= BD_TS_PACKET_HEADER;
387             p_block->p_buffer += BD_TS_PACKET_HEADER;
388             stream_DemuxSend( p_sys->p_parser, p_block );
389         }
390
391         stream_Seek( p_sys->p_m2ts, p_sys->i_packet_start * (int64_t)BD_TS_PACKET_SIZE );
392     }
393
394     /* */
395     const int i_packets = __MIN( 5, p_sys->i_packet_stop - p_sys->i_packet );
396     if( i_packets <= 0 )
397     {
398         const int i_title = p_demux->info.i_title;
399         const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_title];
400
401         if( p_sys->i_play_item < p_mpls->i_play_item )
402         {
403             if( !SetPlayItem( p_demux, i_title, p_sys->i_play_item + 1 ) )
404                 return 1;
405             msg_Warn( p_demux, "Failed to switch to the next play item" );
406         }
407
408         /* */
409         if( SetTitle( p_demux, i_title + 1 ) )
410             return 0; /* EOF */
411         return 1;
412     }
413
414     /* XXX
415      * we ensure that the TS packet start at the begining of the buffer,
416      * it ensure proper TS parsing */
417     block_t *p_block = block_New( p_demux, i_packets * BD_TS_PACKET_SIZE + BD_TS_PACKET_HEADER );
418     if( !p_block )
419         return -1;
420
421     const int i_read = stream_Read( p_sys->p_m2ts, p_block->p_buffer, p_block->i_buffer - BD_TS_PACKET_HEADER );
422     if( i_read <= 0 )
423     {
424         msg_Err( p_demux, "Error reading current title" );
425         return -1;
426     }
427
428     if( i_read > 4 )
429     {
430         const int64_t i_atc = GetDWBE( p_block->p_buffer ) & ( (1 << 30) - 1 );
431
432         if( i_atc < p_sys->i_atc_last )
433             p_sys->i_atc_wrap += 1 << 30;
434         p_sys->i_atc_last = i_atc;
435
436         if( p_sys->i_atc_initial < 0 )
437             p_sys->i_atc_initial = i_atc + p_sys->i_atc_wrap;
438
439         p_sys->i_atc_current = i_atc + p_sys->i_atc_wrap;
440     }
441
442     p_block->i_buffer = i_read;
443     p_block->p_buffer += BD_TS_PACKET_HEADER;
444     stream_DemuxSend( p_sys->p_parser, p_block );
445
446     p_sys->i_packet += i_read / BD_TS_PACKET_SIZE;
447
448     /* Update EP */
449     if( p_sys->p_clpi->i_ep_map > 0 )
450     {
451         const int i_old_clpi_ep = p_sys->i_clpi_ep;
452
453         const bd_clpi_ep_map_t *p_ep_map = &p_sys->p_clpi->p_ep_map[0];
454         for( ; p_sys->i_clpi_ep+1 < p_ep_map->i_ep; p_sys->i_clpi_ep++ )
455         {
456             const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep+1];
457
458             if( p_ep->i_packet > p_sys->i_packet )
459                 break;
460         }
461         if( i_old_clpi_ep != p_sys->i_clpi_ep )
462         {
463             /* We have changed of EP */
464             p_sys->i_atc_initial = p_sys->i_atc_current; /* FIXME not exact */
465
466             /* Update seekpoint */
467             const input_title_t *p_title = p_sys->pp_title[p_demux->info.i_title];
468             const int64_t i_time = GetTime( p_demux );
469
470             for( ; p_demux->info.i_seekpoint+1 < p_title->i_seekpoint; p_demux->info.i_seekpoint++ )
471             {
472                 const seekpoint_t *p_seekpoint = p_title->seekpoint[p_demux->info.i_seekpoint+1];
473                 if( p_seekpoint->i_time_offset >  i_time )
474                     break;
475                 p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
476             }
477         }
478     }
479     return 1;
480 }
481
482 /*****************************************************************************
483  *
484  *****************************************************************************/
485 #define BD_45KHZ INT64_C(45000)
486 static void InitTitles( demux_t *p_demux )
487 {
488     demux_sys_t *p_sys = p_demux->p_sys;
489
490     /* */
491     for( int i = 0; i < p_sys->i_mpls; i++ )
492     {
493         const bd_mpls_t *p_mpls = p_sys->pp_mpls[i];
494
495         input_title_t *t = vlc_input_title_New();
496         if( !t )
497             break;
498
499         /* */
500         t->i_length = 0;
501         for( int j = 0; j < p_mpls->i_play_item; j++ )
502         {
503             const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[j];
504
505             t->i_length += ( p_item->i_out_time - p_item->i_in_time ) * CLOCK_FREQ / BD_45KHZ;
506         }
507
508 #ifdef BD_DEBUG
509         {
510         char psz_length[MSTRTIME_MAX_SIZE];
511         msg_Warn( p_demux, "TITLE[%d] %s", i, secstotimestr( psz_length, t->i_length / CLOCK_FREQ ) );
512         }
513 #endif
514
515         /* Seekpoint */
516         for( int j = 0; j < p_mpls->i_mark; j++ )
517         {
518             bd_mpls_mark_t *p_mark = &p_mpls->p_mark[j];
519
520             if( p_mark->i_type == BD_MPLS_MARK_TYPE_BOOKMARK &&
521                 p_mark->i_play_item_id >= 0 && p_mark->i_play_item_id < p_mpls->i_play_item )
522             {
523                 seekpoint_t *s = vlc_seekpoint_New();
524                 if( !s )
525                     break;
526
527                 for( int k = 0; k <= p_mark->i_play_item_id; k++ )
528                 {
529                     const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[k];
530                     int64_t i_out_time;
531
532                     if( k == p_mark->i_play_item_id )
533                         i_out_time = p_mark->i_time;
534                     else
535                         i_out_time = p_item->i_out_time;
536                     s->i_time_offset += ( i_out_time - p_item->i_in_time ) * CLOCK_FREQ / BD_45KHZ;
537                 }
538 #ifdef BD_DEBUG
539                 {
540                 char psz_time[MSTRTIME_MAX_SIZE];
541                 msg_Warn( p_demux, "    SEEKPOINT[%d] %s", j, secstotimestr( psz_time, s->i_time_offset / CLOCK_FREQ ) );
542                 }
543 #endif
544                 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
545             }
546         }
547         if( t->i_seekpoint <= 0 )
548         {
549             seekpoint_t *s = vlc_seekpoint_New();
550             if( s )
551                 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
552         }
553
554         TAB_APPEND( p_sys->i_title, p_sys->pp_title, t );
555     }
556 }
557 static int SetTitle( demux_t *p_demux, int i_title )
558 {
559     demux_sys_t *p_sys = p_demux->p_sys;
560
561     if( i_title < 0 || i_title >= p_sys->i_title )
562         return VLC_EGENERIC;
563
564
565     if( SetPlayItem( p_demux, i_title, 0 ) )
566         return VLC_EGENERIC;
567
568     /* */
569     p_demux->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
570     p_demux->info.i_title = i_title;
571     p_demux->info.i_seekpoint = 0;
572
573     return VLC_SUCCESS;
574 }
575 static int SetChapter( demux_t *p_demux, int i_chapter )
576 {
577     demux_sys_t *p_sys = p_demux->p_sys;
578     const int i_title = p_demux->info.i_title;
579     const input_title_t *p_title = p_sys->pp_title[i_title];
580
581     if( i_chapter < 0 || i_chapter > p_title->i_seekpoint )
582         return VLC_EGENERIC;
583
584     if( SetTime( p_demux, p_title->seekpoint[i_chapter]->i_time_offset ) )
585         return VLC_EGENERIC;
586
587     return VLC_SUCCESS;
588 }
589 static int SetPlayItem( demux_t *p_demux, int i_mpls, int i_play_item )
590 {
591     demux_sys_t *p_sys = p_demux->p_sys;
592
593     /* FIXME TODO do not reopen everything when avoidable
594      * XXX becarefull that then the es_out wrapper need some sort of
595      * locking !!! */
596
597     /* */
598     const bool b_same_mpls = i_mpls == p_demux->info.i_title;
599     //const bool b_same_play_item = b_same_mpls &&
600     //                              i_play_item == p_sys->i_play_item;
601
602     /* */
603     const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_mpls];
604
605     /* */
606     if( i_play_item < 0 || i_play_item >= p_mpls->i_play_item )
607         return VLC_EGENERIC;
608
609     const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[i_play_item];
610     const bd_mpls_clpi_t *p_mpls_clpi = &p_item->clpi;
611
612     const bd_clpi_t *p_clpi = NULL;
613     for( int i_clpi = 0; i_clpi < p_sys->i_clpi && !p_clpi; i_clpi++ )
614     {
615         if( p_sys->pp_clpi[i_clpi]->i_id == p_mpls_clpi->i_id )
616             p_clpi = p_sys->pp_clpi[i_clpi];
617     }
618
619     const bool b_same_clpi = b_same_mpls && p_sys->p_clpi->i_id == p_clpi->i_id;
620     stream_t *p_m2ts = NULL;
621     if( !b_same_clpi )
622     {
623         char *psz_m2ts;
624         if( asprintf( &psz_m2ts, "%s/STREAM/%05d.%s",
625                       p_sys->psz_base, p_mpls_clpi->i_id, p_sys->b_shortname ? "MTS" : "m2ts" ) < 0 )
626             return VLC_EGENERIC;
627
628         p_m2ts = stream_UrlNew( p_demux, psz_m2ts );
629         if( !p_m2ts )
630         {
631             msg_Err( p_demux, "Failed to open %s", psz_m2ts );
632             free( psz_m2ts );
633             return VLC_EGENERIC;
634         }
635         free( psz_m2ts );
636     }
637
638     /* TODO avoid reopenning the parser when unneeded.
639      * - b_same_play_item is too strict, we should check the play_items connection.
640      * - a way to completely flush the demuxer is also needed !
641      */
642     //const bool b_same_parser = b_same_play_item && false;
643     stream_t *p_parser = stream_DemuxNew( p_demux, "ts", p_sys->p_out );
644     if( !p_parser )
645     {
646         msg_Err( p_demux, "Failed to create TS demuxer" );
647         if( p_m2ts )
648             stream_Delete( p_m2ts );
649         return VLC_EGENERIC;
650     }
651
652     /* */
653     if( !p_m2ts )
654     {
655         msg_Dbg( p_demux, "Reusing stream file" );
656         p_m2ts = p_sys->p_m2ts;
657         p_sys->p_m2ts = NULL;
658     }
659
660     /* */
661     ClosePlayItem( p_demux );
662
663     /* */
664     p_sys->p_clpi = p_clpi;
665     p_sys->p_parser = p_parser;
666     p_sys->p_m2ts = p_m2ts;
667     p_sys->i_play_item = i_play_item;
668
669     p_sys->i_packet_start = GetClpiPacket( p_demux, &p_sys->i_clpi_ep, p_mpls_clpi, p_item->i_in_time );
670     if( p_sys->i_packet_start < 0 )
671     {
672         p_sys->i_packet_start = 0;
673         p_sys->i_clpi_ep = 0;
674     }
675
676     p_sys->i_packet_stop = GetClpiPacket( p_demux, NULL, p_mpls_clpi, p_item->i_out_time );
677     if( p_sys->i_packet_stop < 0 )
678         p_sys->i_packet_stop = stream_Size( p_m2ts ) / BD_TS_PACKET_SIZE;
679     p_sys->i_packet = p_sys->i_packet_start;
680
681     /* This is a hack to detect the number of packet to send before any data
682      * to have the PAT/PMT. I have no idea if it is the right, but seems to work.
683      * I used a limits of 10 packets, sufficient if it is really only headers */
684     p_sys->i_packet_headers = 0;
685     if( p_clpi->i_ep_map > 0 )
686     {
687         const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[0];
688         if( p_ep_map->i_ep > 0 )
689             p_sys->i_packet_headers = __MIN( p_ep_map->p_ep[0].i_packet, 10 );
690     }
691
692     p_sys->i_atc_initial = -1;
693     p_sys->i_atc_current = -1;
694     p_sys->i_atc_last    = -1;
695     p_sys->i_atc_wrap    = 0;
696
697     return VLC_SUCCESS;
698 }
699 static void ClosePlayItem( demux_t *p_demux )
700 {
701     demux_sys_t *p_sys = p_demux->p_sys;
702
703     if( p_sys->p_m2ts )
704         stream_Delete( p_sys->p_m2ts );
705     if( p_sys->p_parser )
706         stream_Delete( p_sys->p_parser );
707
708     es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
709 }
710
711 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 {
713     demux_sys_t *p_sys = p_demux->p_sys;
714
715     const bd_clpi_t *p_clpi = p_sys->p_clpi;
716     assert( p_clpi );
717
718     if( p_clpi->i_ep_map <= 0 )
719         return -1;
720     const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[0];
721
722     if( p_mpls_clpi->i_stc_id < 0 || p_mpls_clpi->i_stc_id >= p_clpi->i_stc )
723         return -1;
724
725     const bd_clpi_stc_t *p_stc = &p_clpi->p_stc[p_mpls_clpi->i_stc_id];
726 #if 0
727     /* Not sure it is right */
728     if( i_time < p_stc->i_start || i_time > p_stc->i_end )
729         return -1;
730 #endif
731
732     const int64_t i_packet = p_stc->i_packet;
733     int i_ep;
734     for( i_ep = 0; i_ep < p_ep_map->i_ep; i_ep++ )
735     {
736         if( p_ep_map->p_ep[i_ep].i_packet >= i_packet )
737             break;
738     }
739     if( i_ep >= p_ep_map->i_ep )
740         return -1;
741
742     for( ; i_ep < p_ep_map->i_ep; i_ep++ )
743     {
744         const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[i_ep];
745         const bd_clpi_ep_t *p_ep_next = &p_ep_map->p_ep[i_ep+1];
746
747         if( i_ep+1 < p_ep_map->i_ep && p_ep_next->i_pts / 2 > i_time )
748             break;
749         if( p_ep->i_pts / 2 >= i_time )
750             break;
751     }
752     if( i_ep >= p_ep_map->i_ep )
753         return -1;
754
755     /* */
756     if( pi_ep )
757         *pi_ep = i_ep;
758     return p_ep_map->p_ep[i_ep].i_packet;
759 }
760
761 /**
762  * Retreive the current time using current EP + ATC delta
763  */
764 static int64_t GetTime( demux_t *p_demux )
765 {
766     demux_sys_t *p_sys = p_demux->p_sys;
767     const int i_mpls = p_demux->info.i_title;
768
769     const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_mpls];
770     const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[p_sys->i_play_item];
771
772     const bd_clpi_t *p_clpi = p_sys->p_clpi;
773     if( !p_clpi || p_clpi->i_ep_map <= 0 )
774         return 0;
775
776     /* */
777     const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[0];
778     if( p_sys->i_clpi_ep < 0 || p_sys->i_clpi_ep >= p_ep_map->i_ep )
779         return 0;
780
781     const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep];
782     int64_t i_time = p_ep->i_pts / 2 - p_item->i_in_time +
783                      ( p_sys->i_atc_current - p_sys->i_atc_initial ) / 300 / 2;
784
785     for( int j = 0; j < p_sys->i_play_item; j++ )
786     {
787         const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[j];
788         i_time += ( p_item->i_out_time - p_item->i_in_time );
789     }
790
791     return i_time * CLOCK_FREQ / BD_45KHZ;
792 }
793
794 static double GetPosition( demux_t *p_demux )
795 {
796     demux_sys_t *p_sys = p_demux->p_sys;
797
798     const int64_t i_time = GetTime( p_demux );
799     const input_title_t *p_title = p_sys->pp_title[p_demux->info.i_title];
800
801     if( p_title->i_length <= 0 )
802         return 0.0;
803
804     return (double)i_time / p_title->i_length;
805 }
806
807 static int SetTime( demux_t *p_demux, int64_t i_time )
808 {
809     demux_sys_t *p_sys = p_demux->p_sys;
810     const int i_mpls = p_demux->info.i_title;
811     const input_title_t *p_title = p_sys->pp_title[i_mpls];
812     const bd_mpls_t *p_mpls = p_sys->pp_mpls[i_mpls];
813
814     /* Find the play item */
815     int i_item;
816     int64_t i_play_item_time = 0;
817     for( i_item = 0; i_item < p_mpls->i_play_item; i_item++ )
818     {
819         const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[i_item];
820         const int64_t i_duration = ( p_item->i_out_time - p_item->i_in_time ) * CLOCK_FREQ / BD_45KHZ;
821
822         if( i_time >= i_play_item_time && i_time < i_play_item_time + i_duration )
823             break;
824
825         i_play_item_time += i_duration;
826     }
827
828     if( i_item >= p_mpls->i_play_item )
829         return VLC_EGENERIC;
830
831     if( SetPlayItem( p_demux, i_mpls, i_item ) )
832         return VLC_EGENERIC;
833
834
835     /* Find the right entry point */
836     if( p_sys->p_clpi->i_ep_map <= 0 )
837         goto update;
838
839     const bd_clpi_ep_map_t *p_ep_map = &p_sys->p_clpi->p_ep_map[0];
840     if( p_ep_map->i_ep <= 0 )
841         goto update;
842
843     int64_t i_next_display_date = -1;
844     for( ; p_sys->i_clpi_ep+1 < p_ep_map->i_ep; p_sys->i_clpi_ep++ )
845     {
846         const bd_clpi_ep_t *p_next = &p_ep_map->p_ep[p_sys->i_clpi_ep+1];
847         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
849         if( i_next_time > i_time )
850         {
851             const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep];
852             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 );
853
854
855             i_next_display_date = p_ep->i_pts * CLOCK_FREQ / 90000 + ( i_time - i_ep_time );
856             break;
857         }
858     }
859
860     const bd_clpi_ep_t *p_ep = &p_ep_map->p_ep[p_sys->i_clpi_ep];
861     p_sys->i_packet_start =
862     p_sys->i_packet       = p_ep->i_packet;
863
864     if( i_next_display_date >= 0 )
865         es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_next_display_date );
866
867 update:
868     /* Update seekpoint */
869     for( p_demux->info.i_seekpoint = 0; p_demux->info.i_seekpoint+1 < p_title->i_seekpoint; p_demux->info.i_seekpoint++ )
870     {
871         const seekpoint_t *p_seekpoint = p_title->seekpoint[p_demux->info.i_seekpoint+1];
872         if( p_seekpoint->i_time_offset >  i_time )
873             break;
874     }
875     p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
876     return VLC_SUCCESS;
877 }
878
879 static int SetPosition( demux_t *p_demux, double f_position )
880 {
881     demux_sys_t *p_sys = p_demux->p_sys;
882     const input_title_t *p_title = p_sys->pp_title[p_demux->info.i_title];
883
884     if( p_title->i_length <= 0 )
885         return VLC_EGENERIC;
886
887     return SetTime( p_demux, f_position * p_title->i_length );
888 }
889
890 /*****************************************************************************
891  * Mpls ordering
892  *****************************************************************************/
893 static int64_t GetMplsUniqueDuration( const bd_mpls_t *p_mpls )
894 {
895     int64_t i_length = 0;
896
897     for( int i = 0; i < p_mpls->i_play_item; i++ )
898     {
899         const bd_mpls_play_item_t *p_item0 = &p_mpls->p_play_item[i];
900         int j;
901         for( j = i+1; j < p_mpls->i_play_item; j++ )
902         {
903             const bd_mpls_play_item_t *p_item1 = &p_mpls->p_play_item[j];
904             if( p_item0->clpi.i_id == p_item1->clpi.i_id &&
905                 p_item0->clpi.i_stc_id == p_item1->clpi.i_stc_id &&
906                 p_item0->i_in_time == p_item1->i_in_time &&
907                 p_item0->i_out_time == p_item1->i_out_time )
908                 break;
909         }
910         if( j >= p_mpls->i_play_item )
911             i_length += p_item0->i_out_time - p_item0->i_in_time;
912     }
913     return i_length;
914 }
915 static int SortMpls( const void *a, const void *b )
916 {
917     const bd_mpls_t * const *pp_mpls_a = a;
918     const bd_mpls_t * const *pp_mpls_b = b;
919
920     const int64_t i_length_a = GetMplsUniqueDuration( *pp_mpls_a );
921     const int64_t i_length_b = GetMplsUniqueDuration( *pp_mpls_b );
922
923     if( i_length_a == i_length_b )
924         return 0;
925     return i_length_a < i_length_b ? 1 : -1;
926 }
927
928 static void ReorderPlaylist( demux_t *p_demux )
929 {
930     demux_sys_t *p_sys = p_demux->p_sys;
931     qsort( p_sys->pp_mpls, p_sys->i_mpls, sizeof(*p_sys->pp_mpls), SortMpls );
932 }
933 /*****************************************************************************
934  * Helpers:
935  *****************************************************************************/
936 static int CheckFileList( const char *psz_base, const char *ppsz_name[] )
937 {
938     for( int i = 0; ppsz_name[i] != NULL ; i++ )
939     {
940         struct stat s;
941         char *psz_tmp;
942
943         if( asprintf( &psz_tmp, "%s/%s", psz_base, ppsz_name[i] ) < 0 )
944             return VLC_EGENERIC;
945
946         bool b_ok = vlc_stat( psz_tmp, &s ) == 0 && S_ISREG( s.st_mode );
947
948         free( psz_tmp );
949         if( !b_ok )
950             return VLC_EGENERIC;
951     }
952     return VLC_SUCCESS;
953 }
954 /* */
955 static char *FindPathBase( const char *psz_path, bool *pb_shortname )
956 {
957     struct stat s;
958     char *psz_tmp;
959
960     /* */
961     char *psz_base = strdup( psz_path );
962     if( !psz_base )
963         return NULL;
964
965     /* */
966     while( *psz_base && psz_base[strlen(psz_base)-1] == '/' )
967         psz_base[strlen(psz_base)-1] = '\0';
968
969     /* */
970     if( vlc_stat( psz_base, &s ) || !S_ISDIR( s.st_mode ) )
971         goto error;
972
973     /* Check BDMV */
974     if( asprintf( &psz_tmp, "%s/BDMV", psz_base ) < 0 )
975         goto error;
976     if( !vlc_stat( psz_tmp, &s ) && S_ISDIR( s.st_mode ) )
977     {
978         free( psz_base );
979         psz_base = psz_tmp;
980     }
981     else
982     {
983         free( psz_tmp );
984     }
985
986     /* Check presence of mandatory files */
987     static const char *ppsz_name_long[] = {
988         "index.bdmv",
989         "MovieObject.bdmv",
990         NULL
991     };
992     static const char *ppsz_name_short[] = {
993         "INDEX.BDM",
994         "MOVIEOBJ.BDM",
995         NULL
996     };
997     *pb_shortname = false;
998     if( CheckFileList( psz_base, ppsz_name_long ) )
999     {
1000         if( CheckFileList( psz_base, ppsz_name_short ) )
1001             goto error;
1002         *pb_shortname = true;
1003     }
1004     return psz_base;
1005
1006 error:
1007     free( psz_base );
1008     return NULL;
1009 }
1010
1011 /* */
1012 static block_t *LoadBlock( demux_t *p_demux, const char *psz_name )
1013 {
1014     stream_t *s = stream_UrlNew( p_demux, psz_name );
1015     if( !s )
1016         return NULL;
1017
1018     const int64_t i_size = stream_Size( s );
1019     block_t *p_block = NULL;
1020
1021     if( i_size > 0 && i_size < INT_MAX )
1022         p_block = stream_Block( s, i_size );
1023
1024     stream_Delete( s );
1025
1026     return p_block;
1027 }
1028
1029 /* */
1030 static int FilterMplsLong( const char *psz_name )
1031 {
1032     return strlen( psz_name ) == strlen( "xxxxx.mpls" ) &&
1033            !strcmp( &psz_name[5], ".mpls" );
1034 }
1035 static int FilterMplsShort( const char *psz_name )
1036 {
1037     return strlen( psz_name ) == strlen( "xxxxx.MPL" ) &&
1038            !strcmp( &psz_name[5], ".MPL" );
1039 }
1040
1041 static void LoadMpls( demux_t *p_demux, const char *psz_name, int i_id )
1042 {
1043     demux_sys_t *p_sys = p_demux->p_sys;
1044
1045 #if defined(BD_DEBUG)
1046     msg_Err( p_demux, "Loading %s", psz_name );
1047 #endif
1048
1049     block_t *p_block = LoadBlock( p_demux, psz_name );
1050     if( !p_block )
1051         goto error;
1052
1053     /* */
1054     bd_mpls_t *p_mpls = malloc( sizeof(*p_mpls) );
1055     if( !p_mpls )
1056         goto error;
1057
1058     /* */
1059     bs_t s;
1060     bs_init( &s, p_block->p_buffer, p_block->i_buffer );
1061
1062     if( bd_mpls_Parse( p_mpls, &s, i_id ) )
1063         goto error;
1064
1065 #if defined(BD_DEBUG)
1066     msg_Err( p_demux, "MPLS: id=%d", p_mpls->i_id );
1067     msg_Err( p_demux, "MPLS: play_item=%d sub_path=%d",
1068              p_mpls->i_play_item, p_mpls->i_sub_path );
1069
1070     for( int i = 0; i < p_mpls->i_play_item; i++ )
1071     {
1072         bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[i];
1073
1074         msg_Err( p_demux, "PLAY_ITEM[%d] connection=%d in=%d out=%d still=%d(%d)",
1075                  i, p_item->i_connection,
1076                  (int)p_item->i_in_time, (int)p_item->i_out_time,
1077                  p_item->i_still, p_item->i_still_time );
1078         msg_Err( p_demux, "     clpi_default: id=%d stc_id=%d",
1079                  p_item->clpi.i_id, p_item->clpi.i_stc_id );
1080         for( int j = 0; j < p_item->i_clpi; j++ )
1081             msg_Err( p_demux, "     clpi[%d]: id=%d stc_id=%d",
1082                      j, p_item->p_clpi[j].i_id, p_item->p_clpi[j].i_stc_id );
1083         for( int j = 0; j < p_item->i_stream; j++ )
1084             msg_Err( p_demux, "     stream[%d]: type=%d class=%d stream_type=0x%x lang=%s charset=%d",
1085                      j,
1086                      p_item->p_stream[j].i_type,
1087                      p_item->p_stream[j].i_class,
1088                      p_item->p_stream[j].i_stream_type,
1089                      p_item->p_stream[j].psz_language,
1090                      p_item->p_stream[j].i_charset );
1091     }
1092
1093     for( int i = 0; i < p_mpls->i_sub_path; i++ )
1094     {
1095         bd_mpls_sub_path_t *p_sub = &p_mpls->p_sub_path[i];
1096
1097         msg_Err( p_demux, "SUB_PATH[%d] type=%d repeat=%d item=%d",
1098                  i, p_sub->i_type, p_sub->b_repeat, p_sub->i_item );
1099     }
1100
1101     for( int i = 0; i < p_mpls->i_mark; i++ )
1102     {
1103         bd_mpls_mark_t *p_mark = &p_mpls->p_mark[i];
1104
1105         msg_Err( p_demux, "M[%d] t=%d play_item_id=%d time=%d entry_es_pid=%d",
1106                  i, p_mark->i_type, p_mark->i_play_item_id, (int)p_mark->i_time, p_mark->i_entry_es_pid );
1107     }
1108 #endif
1109
1110     /* */
1111     TAB_APPEND( p_sys->i_mpls, p_sys->pp_mpls, p_mpls );
1112
1113     /* */
1114     block_Release( p_block );
1115     return;
1116
1117 error:
1118     msg_Err( p_demux, "Failed loading %s", psz_name );
1119     if( p_block )
1120         block_Release( p_block );
1121 }
1122
1123 /* */
1124 static int FilterClpiLong( const char *psz_name )
1125 {
1126     return strlen( psz_name ) == strlen( "xxxxx.clpi" ) &&
1127            !strcmp( &psz_name[5], ".clpi" );
1128 }
1129 static int FilterClpiShort( const char *psz_name )
1130 {
1131     return strlen( psz_name ) == strlen( "xxxxx.CPI" ) &&
1132            !strcmp( &psz_name[5], ".CPI" );
1133 }
1134
1135 static void LoadClpi( demux_t *p_demux, const char *psz_name, int i_id )
1136 {
1137     demux_sys_t *p_sys = p_demux->p_sys;
1138
1139 #if defined(BD_DEBUG)
1140     msg_Err( p_demux, "Loading %s", psz_name );
1141 #endif
1142
1143     block_t *p_block = LoadBlock( p_demux, psz_name );
1144     if( !p_block )
1145         goto error;
1146
1147     /* */
1148     bd_clpi_t *p_clpi = malloc( sizeof(*p_clpi) );
1149     if( !p_clpi )
1150         goto error;
1151
1152     /* */
1153     bs_t s;
1154     bs_init( &s, p_block->p_buffer, p_block->i_buffer );
1155
1156     if( bd_clpi_Parse( p_clpi, &s, i_id ) )
1157         goto error;
1158
1159 #if defined(BD_DEBUG)
1160     msg_Err( p_demux, "CLPI: id=%d", p_clpi->i_id );
1161     msg_Err( p_demux, "CLPI: STC=%d", p_clpi->i_stc );
1162     for( int i = 0; i < p_clpi->i_stc; i++ )
1163         msg_Err( p_demux, "   STC[%d] pcr_pid=%d packet=%d start=%d end=%d",
1164                  i, p_clpi->p_stc[i].i_pcr_pid, (int)p_clpi->p_stc[i].i_packet,
1165                  (int)p_clpi->p_stc[i].i_start, (int)p_clpi->p_stc[i].i_end );
1166     msg_Err( p_demux, "CLPI: Stream=%d", p_clpi->i_stream );
1167     for( int i = 0; i < p_clpi->i_stream; i++ )
1168         msg_Err( p_demux, "   Stream[%d] pid=%d type=0x%x",
1169                  i, p_clpi->p_stream[i].i_pid, p_clpi->p_stream[i].i_type );
1170     msg_Err( p_demux, "CLPI: Ep Map=%d", p_clpi->i_ep_map );
1171     for( int i = 0; i < p_clpi->i_ep_map; i++ )
1172     {
1173         const bd_clpi_ep_map_t *p_ep_map = &p_clpi->p_ep_map[i];
1174         msg_Err( p_demux, "   Ep Map[%d] pid=%d type=0x%x entry_point=%d",
1175                  i, p_ep_map->i_pid, p_ep_map->i_type, p_ep_map->i_ep );
1176         for( int j = 0; j < p_ep_map->i_ep; j++ )
1177         {
1178             msg_Err( p_demux, "      Ep[%d] packet=%d pts=%d",
1179                      j, (int)p_ep_map->p_ep[j].i_packet, (int)p_ep_map->p_ep[j].i_pts );
1180         }
1181     }
1182 #endif
1183
1184     /* */
1185     TAB_APPEND( p_sys->i_clpi, p_sys->pp_clpi, p_clpi );
1186
1187     /* */
1188     block_Release( p_block );
1189     return;
1190
1191 error:
1192     msg_Err( p_demux, "Failed loading %s", psz_name );
1193     if( p_block )
1194         block_Release( p_block );
1195 }
1196
1197 /* */
1198 static int ScanSort( const char **ppsz_a, const char **ppsz_b )
1199 {
1200     return strcmp( *ppsz_a, *ppsz_b );
1201 }
1202
1203 static int Load( demux_t *p_demux,
1204                  const char *psz_dir,
1205                  int (*pf_filter)( const char * ),
1206                  void (*pf_load)( demux_t *p_demux, const char *psz_name, int i_id ) )
1207 {
1208     char *psz_playlist;
1209     if( asprintf( &psz_playlist, "%s/%s", p_demux->p_sys->psz_base, psz_dir ) < 0 )
1210         return VLC_EGENERIC;
1211
1212     char **ppsz_list;
1213
1214     int i_list = vlc_scandir( psz_playlist, &ppsz_list, pf_filter, ScanSort );
1215
1216     for( int i = 0; i < i_list; i++ )
1217     {
1218         char *psz_file = ppsz_list[i];
1219         if( !psz_file )
1220             break;
1221
1222         char *psz_name;
1223         if( asprintf( &psz_name, "%s/%s/%s", p_demux->p_sys->psz_base, psz_dir, psz_file ) >= 0)
1224         {
1225             const int i_id = strtol( psz_file, NULL, 10 );
1226             pf_load( p_demux, psz_name, i_id );
1227             free( psz_name );
1228         }
1229         free( psz_file );
1230     }
1231     free( ppsz_list );
1232
1233     free( psz_playlist );
1234     return VLC_SUCCESS;
1235 }
1236
1237 static int LoadPlaylist( demux_t *p_demux )
1238 {
1239     return Load( p_demux, "PLAYLIST",
1240                  p_demux->p_sys->b_shortname ? FilterMplsShort : FilterMplsLong, LoadMpls );
1241 }
1242 static int LoadClip( demux_t *p_demux )
1243 {
1244     return Load( p_demux, "CLIPINF",
1245                  p_demux->p_sys->b_shortname ? FilterClpiShort : FilterClpiLong, LoadClpi );
1246 }
1247
1248 /* */
1249 struct es_out_sys_t
1250 {
1251     demux_t *p_demux;
1252 };
1253
1254 static es_out_id_t *EsOutAdd( es_out_t *p_out, const es_format_t *p_fmt )
1255 {
1256     demux_t *p_demux = p_out->p_sys->p_demux;
1257     const bd_mpls_t *p_mpls = p_demux->p_sys->pp_mpls[p_demux->info.i_title];
1258     const bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[p_demux->p_sys->i_play_item];
1259
1260     es_format_t fmt;
1261
1262     es_format_Copy( &fmt, p_fmt );
1263     fmt.i_priority = -2;
1264
1265     for( int i = 0; i < p_item->i_stream; i++ )
1266     {
1267         const bd_mpls_stream_t *p_stream = &p_item->p_stream[i];
1268         if( p_stream->i_type != BD_MPLS_STREAM_TYPE_PLAY_ITEM ||
1269             p_stream->play_item.i_pid != fmt.i_id )
1270             continue;
1271
1272         /* TODO improved priority for higher quality stream ?
1273          * if so, extending stream attributes parsing might be a good idea
1274          */
1275         fmt.i_priority = 0;
1276
1277 #if 0
1278         /* Useless, and beside not sure it is the right thing to do */
1279         free( fmt.psz_description );
1280         switch( p_stream->i_class )
1281         {
1282         case BD_MPLS_STREAM_CLASS_SECONDARY_AUDIO:
1283             fmt.psz_description = strdup( "Secondary audio" );
1284             break;
1285         default:
1286             fmt.psz_description = NULL;
1287             break;
1288         }
1289 #endif
1290
1291         //msg_Err( p_demux, "Found ref for stream pid %d", fmt.i_id );
1292         if( *p_stream->psz_language && ( !fmt.psz_language || *fmt.psz_language == '\0' ) )
1293         {
1294             free( fmt.psz_language );
1295             fmt.psz_language = strdup( p_stream->psz_language );
1296         }
1297         switch( p_stream->i_charset )
1298         {
1299         /* TODO add all values */
1300         default:
1301             break;
1302         }
1303         break;
1304     }
1305     if( fmt.i_priority < 0 )
1306         msg_Dbg( p_demux, "Hidding one stream (pid=%d)", fmt.i_id );
1307
1308     /* */
1309     es_out_id_t *p_es = es_out_Add( p_demux->out, &fmt );
1310
1311     es_format_Clean( &fmt );
1312     return p_es;
1313 }
1314 static int EsOutSend( es_out_t *p_out, es_out_id_t *p_es, block_t *p_block )
1315 {
1316     return es_out_Send( p_out->p_sys->p_demux->out, p_es, p_block );
1317 }
1318 static void EsOutDel( es_out_t *p_out, es_out_id_t *p_es )
1319 {
1320     es_out_Del( p_out->p_sys->p_demux->out, p_es );
1321 }
1322 static int EsOutControl( es_out_t *p_out, int i_query, va_list args )
1323 {
1324     return es_out_vaControl( p_out->p_sys->p_demux->out, i_query, args );
1325 }
1326 static void EsOutDestroy( es_out_t *p_out )
1327 {
1328     free( p_out->p_sys );
1329     free( p_out );
1330 }
1331
1332 static es_out_t *EsOutNew( demux_t *p_demux )
1333 {
1334     es_out_t *p_out = malloc( sizeof(*p_out) );
1335     es_out_sys_t *p_sys;
1336
1337     if( !p_out )
1338         return NULL;
1339
1340     p_out->pf_add     = EsOutAdd;
1341     p_out->pf_send    = EsOutSend;
1342     p_out->pf_del     = EsOutDel;
1343     p_out->pf_control = EsOutControl;
1344     p_out->pf_destroy = EsOutDestroy;
1345
1346     p_out->p_sys = p_sys = malloc( sizeof(*p_sys) );
1347     if( !p_sys )
1348     {
1349         free( p_out );
1350         return NULL;
1351     }
1352     p_sys->p_demux = p_demux;
1353
1354     return p_out;
1355 }
1356