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