]> git.sesse.net Git - vlc/blob - modules/access/bd/mpls.c
Update LGPL license blurb, choosing v2.1+.
[vlc] / modules / access / bd / mpls.c
1 /*****************************************************************************
2  * mpls.c: BluRay Disc MPLS
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 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28 #include <limits.h>
29
30 #include <vlc_common.h>
31 #include <vlc_bits.h>
32 #include "mpls.h"
33
34
35 /* MPLS */
36 void bd_mpls_stream_Parse( bd_mpls_stream_t *p_stream, bs_t *s, int i_class )
37 {
38     /* Stream entry parsing */
39     const int i_entry_length = bs_read( s, 8 );
40     const int i_entry_start = bs_pos( s ) / 8;
41
42     p_stream->i_type = bs_read( s, 8 );
43     p_stream->i_class = i_class;
44     if( p_stream->i_type == BD_MPLS_STREAM_TYPE_PLAY_ITEM )
45     {
46         p_stream->play_item.i_pid = bs_read( s, 16 );
47     }
48     else if( p_stream->i_type == BD_MPLS_STREAM_TYPE_SUB_PATH )
49     {
50         p_stream->sub_path.i_sub_path_id = bs_read( s, 8 );
51         p_stream->sub_path.i_sub_clip_id = bs_read( s, 8 );
52         p_stream->sub_path.i_pid = bs_read( s, 16 );
53     }
54     else if( p_stream->i_type == BD_MPLS_STREAM_TYPE_IN_MUX_SUB_PATH )
55     {
56         p_stream->in_mux_sub_path.i_sub_path_id = bs_read( s, 8 );
57         p_stream->in_mux_sub_path.i_pid = bs_read( s, 16 );
58     }
59     bs_skip( s, 8 * ( i_entry_start + i_entry_length ) - bs_pos( s ) );
60
61     /* Stream attributes parsing */
62     const int i_attributes_length = bs_read( s, 8 );
63     const int i_attributes_start = bs_pos( s ) / 8;
64
65     p_stream->i_stream_type = bs_read( s, 8 );
66     strcpy( p_stream->psz_language, "" );
67     p_stream->i_charset = -1;
68
69     if( p_stream->i_stream_type == 0x02 || /* MPEG-I/II */
70         p_stream->i_stream_type == 0x1b || /* AVC */
71         p_stream->i_stream_type == 0xea )  /* VC-1 */
72     {
73         /* Video */
74     }
75     else if( ( p_stream->i_stream_type >= 0x80 && p_stream->i_stream_type <= 0x8f ) ||
76              ( p_stream->i_stream_type >= 0xa0 && p_stream->i_stream_type <= 0xaf ) )
77     {
78         /* Audio */
79         bs_skip( s, 4 );
80         bs_skip( s, 4 );
81         for( int i = 0; i < 3; i++ )
82             p_stream->psz_language[i] = bs_read( s, 8 );
83         p_stream->psz_language[3] = '\0';
84     }
85     else if( p_stream->i_stream_type == 0x90 ||   /* PG stream */
86              p_stream->i_stream_type == 0x91 )    /* IG stream */
87     {
88         for( int i = 0; i < 3; i++ )
89             p_stream->psz_language[i] = bs_read( s, 8 );
90         p_stream->psz_language[3] = '\0';
91     }
92     else if( p_stream->i_stream_type == 0x92 )    /* Text stream */
93     {
94         p_stream->i_charset = bs_read( s, 8 );
95         for( int i = 0; i < 3; i++ )
96             p_stream->psz_language[i] = bs_read( s, 8 );
97         p_stream->psz_language[3] = '\0';
98     }
99
100     bs_skip( s, 8 * ( i_attributes_start + i_attributes_length ) - bs_pos( s ) );
101 }
102
103 void bd_mpls_play_item_Clean( bd_mpls_play_item_t *p_item )
104 {
105     free( p_item->p_clpi );
106     free( p_item->p_stream );
107 }
108 void bd_mpls_play_item_Parse( bd_mpls_play_item_t *p_item, bs_t *s )
109 {
110     const int i_length = bs_read( s, 16 );
111     const int i_start = bs_pos( s ) / 8;
112
113     char psz_name[5+1];
114     for( int j = 0; j < 5; j++ )
115         psz_name[j] = bs_read( s, 8 );
116     psz_name[5] = '\0';
117
118     p_item->clpi.i_id = strtol( psz_name, NULL, 10 );
119
120     bs_skip( s, 32 );
121
122     bs_skip( s, 11 );
123     const bool b_angle = bs_read( s, 1 );
124
125     p_item->i_connection = bs_read( s, 4 );
126     p_item->clpi.i_stc_id = bs_read( s, 8 );
127     p_item->i_in_time = bs_read( s, 32 );
128     p_item->i_out_time = bs_read( s, 32 );
129     bs_skip( s, 64 );
130     bs_skip( s, 1 );
131     bs_skip( s, 7 );
132     p_item->i_still = bs_read( s, 8 );
133     p_item->i_still_time = bs_read( s, 16 );
134     if( p_item->i_still == BD_MPLS_PLAY_ITEM_STILL_NONE )
135         p_item->i_still_time = 0;
136     else if( p_item->i_still == BD_MPLS_PLAY_ITEM_STILL_INFINITE )
137         p_item->i_still_time = INT_MAX;
138
139     if( b_angle )
140     {
141         const int i_angle = bs_read( s, 8 );
142         bs_skip( s, 6 );
143         p_item->b_angle_different_audio = bs_read( s, 1 );
144         p_item->b_angle_seamless = bs_read( s, 1 );
145
146         p_item->p_clpi = calloc( i_angle, sizeof(*p_item->p_clpi) );
147         for( p_item->i_clpi = 0; p_item->i_clpi < i_angle; p_item->i_clpi++ )
148         {
149             if( !p_item->p_clpi )
150                 break;
151
152             bd_mpls_clpi_t *p_clpi = &p_item->p_clpi[p_item->i_clpi];
153
154             char psz_name[5+1];
155             for( int j = 0; j < 5; j++ )
156                 psz_name[j] = bs_read( s, 8 );
157             psz_name[5] = '\0';
158
159             p_clpi->i_id = strtol( psz_name, NULL, 10 );
160
161             bs_skip( s, 32 );
162
163             p_clpi->i_stc_id = bs_read( s, 8 );
164         }
165     }
166     else
167     {
168         p_item->i_clpi = 0;
169         p_item->p_clpi = NULL;
170         p_item->b_angle_different_audio = false;
171         p_item->b_angle_seamless = true;
172     }
173
174     /* STN Table */
175     bs_skip( s, 16 );  /* Length */
176     bs_skip( s, 16 );
177
178     const int i_video = bs_read( s, 8 );
179     const int i_audio = bs_read( s, 8 );
180     const int i_pg = bs_read( s, 8 );
181     const int i_ig = bs_read( s, 8 );
182     const int i_audio_2 = bs_read( s, 8 );
183     const int i_video_2 = bs_read( s, 8 );
184     const int i_pip_pg = bs_read( s, 8 );
185     bs_skip( s, 40 );
186
187     p_item->i_stream = 0;
188     p_item->p_stream = calloc( i_video + i_audio + i_pg + i_ig,
189                                sizeof(*p_item->p_stream) );
190
191     for( int j = 0; j < i_video; j++, p_item->i_stream++ )
192     {
193         if( !p_item->p_stream )
194             break;
195
196         bd_mpls_stream_Parse( &p_item->p_stream[p_item->i_stream], s,
197                               BD_MPLS_STREAM_CLASS_PRIMARY_VIDEO );
198     }
199     for( int j = 0; j < i_audio; j++, p_item->i_stream++ )
200     {
201         if( !p_item->p_stream )
202             break;
203
204         bd_mpls_stream_Parse( &p_item->p_stream[p_item->i_stream], s,
205                               BD_MPLS_STREAM_CLASS_PRIMARY_AUDIO );
206     }
207     for( int j = 0; j < i_pg; j++, p_item->i_stream++ )
208     {
209         if( !p_item->p_stream )
210             break;
211
212         bd_mpls_stream_Parse( &p_item->p_stream[p_item->i_stream], s,
213                               BD_MPLS_STREAM_CLASS_PG );
214     }
215     for( int j = 0; j < i_ig; j++, p_item->i_stream++ )
216     {
217         if( !p_item->p_stream )
218             break;
219
220         bd_mpls_stream_Parse( &p_item->p_stream[p_item->i_stream], s,
221                               BD_MPLS_STREAM_CLASS_IG );
222     }
223     for( int j = 0; j < i_audio_2; j++ )
224     {
225         /* TODO I need samples */
226     }
227     for( int j = 0; j < i_video_2; j++ )
228     {
229         /* TODO I need samples */
230     }
231     for( int j = 0; j < i_pip_pg; j++ )
232     {
233         /* TODO I need samples */
234     }
235
236     bs_skip( s, 8 * ( i_start + i_length ) - bs_pos( s ) );
237 }
238
239 void bd_mpls_sub_path_Parse( bd_mpls_sub_path_t *p_path, bs_t *s )
240 {
241     const uint32_t i_length = bs_read( s, 32 );
242     const int i_start = bs_pos( s ) / 8;
243
244     bs_skip( s, 8 );
245     p_path->i_type = bs_read( s, 8 );
246     bs_skip( s, 15 );
247     p_path->b_repeat = bs_read( s, 1 );
248     bs_skip( s, 8 );
249     p_path->i_item = bs_read( s, 8 );
250
251     for( int j = 0; j < p_path->i_item; j++ )
252     {
253         const int i_length = bs_read( s, 16 );
254         const int i_start = bs_pos( s ) / 8;
255
256         /* TODO */
257
258         bs_skip( s, 8 * ( i_start + i_length ) - bs_pos( s ) );
259     }
260
261     bs_skip( s, 8 * ( i_start + i_length ) - bs_pos( s ) );
262 }
263
264 void bd_mpls_mark_Parse( bd_mpls_mark_t *p_mark, bs_t *s )
265 {
266     bs_skip( s, 8 );
267     p_mark->i_type = bs_read( s, 8 );
268     p_mark->i_play_item_id = bs_read( s, 16 );
269     p_mark->i_time = bs_read( s, 32 );
270     p_mark->i_entry_es_pid = bs_read( s, 16 );
271     bs_skip( s, 32 );
272 }
273
274 void bd_mpls_Clean( bd_mpls_t *p_mpls )
275 {
276     for( int i = 0; i < p_mpls->i_play_item; i++ )
277         bd_mpls_play_item_Clean( &p_mpls->p_play_item[i] );
278     free( p_mpls->p_play_item );
279
280     free( p_mpls->p_sub_path );
281
282     free( p_mpls->p_mark );
283 }
284
285 int bd_mpls_Parse( bd_mpls_t *p_mpls, bs_t *s, int i_id )
286 {
287     const int i_start = bs_pos( s ) / 8;
288
289     /* */
290     if( bs_read( s, 32 ) != 0x4d504c53 )
291         return VLC_EGENERIC;
292     const uint32_t i_version = bs_read( s, 32 );
293     if( i_version != 0x30313030 && i_version != 0x30323030 )
294         return VLC_EGENERIC;
295
296     const uint32_t i_play_item_start = bs_read( s, 32 );
297     const uint32_t i_mark_start = bs_read( s, 32 );
298     bs_skip( s, 32 );   /* Extension start */
299
300     /* */
301     p_mpls->i_id = i_id;
302
303     /* Read AppInfo: ignored */
304
305     /* Read Playlist */
306     bs_t ps = *s;
307     bs_skip( &ps, 8 * ( i_start + i_play_item_start ) - bs_pos( s ) );
308     bs_skip( &ps, 32 ); /* Length */
309     bs_skip( &ps, 16 );
310     const int i_play_item = bs_read( &ps, 16 );
311     const int i_sub_path = bs_read( &ps, 16 );
312
313     p_mpls->p_play_item = calloc( i_play_item, sizeof(*p_mpls->p_play_item) );
314     for( p_mpls->i_play_item = 0; p_mpls->i_play_item < i_play_item; p_mpls->i_play_item++ )
315     {
316         if( !p_mpls->p_play_item )
317             break;
318         bd_mpls_play_item_t *p_item = &p_mpls->p_play_item[p_mpls->i_play_item];
319
320         bd_mpls_play_item_Parse( p_item, &ps );
321     }
322     p_mpls->p_sub_path = calloc( i_sub_path, sizeof(*p_mpls->p_sub_path) );
323     for( p_mpls->i_sub_path = 0; p_mpls->i_sub_path < i_sub_path; p_mpls->i_sub_path++ )
324     {
325         if( !p_mpls->p_sub_path )
326             break;
327         bd_mpls_sub_path_t *p_sub = &p_mpls->p_sub_path[p_mpls->i_sub_path];
328
329         bd_mpls_sub_path_Parse( p_sub, &ps );
330     }
331
332     /* Read Mark */
333     bs_t ms = *s;
334     bs_skip( &ms, 8 * ( i_start + i_mark_start ) - bs_pos( s ) );
335     bs_skip( &ms, 32 );
336     const int i_mark = bs_read( &ms, 16 );
337
338     p_mpls->p_mark = calloc( i_mark, sizeof(*p_mpls->p_mark) );
339     for( p_mpls->i_mark = 0; p_mpls->i_mark < i_mark; p_mpls->i_mark++ )
340     {
341         if( !p_mpls->p_mark )
342             break;
343         bd_mpls_mark_t *p_mark = &p_mpls->p_mark[p_mpls->i_mark];
344
345         bd_mpls_mark_Parse( p_mark, &ms );
346     }
347
348     /* Read Extension: ignored */
349
350     return VLC_SUCCESS;
351 }