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