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