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