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