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