]> git.sesse.net Git - vlc/blob - modules/access/bd/clpi.c
Update LGPL license blurb, choosing v2.1+.
[vlc] / modules / access / bd / clpi.c
1 /*****************************************************************************
2  * clpi.c: BluRay Disc CLPI
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 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #include <limits.h>
28
29 #include <vlc_common.h>
30 #include <vlc_bits.h>
31 #include "clpi.h"
32
33 /* */
34 void bd_clpi_stc_Parse( bd_clpi_stc_t *p_stc, bs_t *s )
35 {
36     p_stc->i_pcr_pid = bs_read( s, 16 );
37     p_stc->i_packet = bs_read( s, 32 );
38     p_stc->i_start = bs_read( s, 32 );
39     p_stc->i_end = bs_read( s, 32 );
40 }
41
42 void bd_clpi_stream_Parse( bd_clpi_stream_t *p_stream, bs_t *s )
43 {
44     p_stream->i_pid = bs_read( s, 16 );
45
46     const int i_length = bs_read( s, 8 );
47
48     p_stream->i_type = bs_read( s, 8 );
49
50     /* Ignore the rest */
51     if( i_length > 1 )
52         bs_skip( s, 8*i_length - 8 );
53 }
54
55 void bd_clpi_ep_map_Clean( bd_clpi_ep_map_t *p_ep_map )
56 {
57     free( p_ep_map->p_ep );
58 }
59 int bd_clpi_ep_map_Parse( bd_clpi_ep_map_t *p_ep_map,
60                           bs_t *s, const int i_ep_map_start )
61 {
62     p_ep_map->i_pid = bs_read( s, 16 );
63     bs_skip( s, 10 );
64     p_ep_map->i_type = bs_read( s, 4 );
65
66     const int i_coarse = bs_read( s, 16 );
67     const int i_fine = bs_read( s, 18 );
68     const uint32_t i_coarse_start = bs_read( s, 32 );
69
70     p_ep_map->i_ep = i_fine;
71     p_ep_map->p_ep = calloc( i_fine, sizeof(*p_ep_map->p_ep) );
72     if( !p_ep_map->p_ep )
73         return VLC_EGENERIC;
74
75     bs_t cs = *s;
76     bs_skip( &cs, 8*(i_ep_map_start + i_coarse_start) - bs_pos( s ) );
77
78     const uint32_t i_fine_start = bs_read( &cs, 32 );
79
80     for( int i = 0; i < i_coarse; i++ )
81     {
82         const int      i_fine_id = bs_read( &cs, 18 );
83         const int      i_pts = bs_read( &cs, 14 );
84         const uint32_t i_packet = bs_read( &cs, 32 );
85
86         for( int j = i_fine_id; j < p_ep_map->i_ep; j++ )
87         {
88             p_ep_map->p_ep[j].i_pts = (int64_t)(i_pts & ~1) << 19;
89             p_ep_map->p_ep[j].i_packet = i_packet & ~( (1 << 17) - 1 );
90         }
91     }
92
93     bs_t fs = *s;
94     bs_skip( &fs, 8*(i_ep_map_start + i_coarse_start + i_fine_start) - bs_pos( s ) );
95     for( int i = 0; i < i_fine; i++ )
96     {
97         const bool b_angle_point = bs_read( &fs, 1 );
98         bs_skip( &fs, 3 );  /* I end position offset */
99         const int i_pts = bs_read( &fs, 11 );
100         const int i_packet = bs_read( &fs, 17 );
101
102         p_ep_map->p_ep[i].b_angle_point = b_angle_point;
103         p_ep_map->p_ep[i].i_pts |= i_pts << 9;
104         p_ep_map->p_ep[i].i_packet |= i_packet;
105     }
106     return VLC_SUCCESS;
107 }
108
109 void bd_clpi_Clean( bd_clpi_t *p_clpi )
110 {
111     free( p_clpi->p_stc );
112
113     free( p_clpi->p_stream );
114
115     for( int i = 0; i < p_clpi->i_ep_map; i++ )
116         bd_clpi_ep_map_Clean( &p_clpi->p_ep_map[i] );
117     free( p_clpi->p_ep_map );
118 }
119
120 int bd_clpi_Parse( bd_clpi_t *p_clpi, bs_t *s, int i_id )
121 {
122     const int i_start = bs_pos( s ) / 8;
123
124     /* */
125     if( bs_read( s, 32 ) != 0x48444D56 )
126         return VLC_EGENERIC;
127     const uint32_t i_version = bs_read( s, 32 );
128     if( i_version != 0x30313030 && i_version != 0x30323030 )
129         return VLC_EGENERIC;
130
131     /* */
132     const uint32_t i_sequence_start = bs_read( s, 32 );
133     const uint32_t i_program_start = bs_read( s, 32 );
134     const uint32_t i_cpi_start = bs_read( s, 32 );
135     bs_skip( s, 32 );   /* mark start */
136     bs_skip( s, 32 );   /* extension start */
137
138     /* */
139     p_clpi->i_id = i_id;
140
141     /* Read sequence */
142     bs_t ss = *s;
143     bs_skip( &ss, 8 * ( i_start + i_sequence_start ) - bs_pos( s ) );
144     bs_skip( &ss, 32 ); /* Length */
145     bs_skip( &ss, 8 );
146     bs_skip( &ss, 8 );  /* ATC sequence count (MUST be 1 ?) */
147     bs_skip( &ss, 32 ); /* ATC start (MUST be 0) */
148     const int i_stc = bs_read( &ss, 8 );
149     bs_skip( &ss, 8 );  /* STC ID offset (MUST be 0 ? */
150
151     p_clpi->p_stc = calloc( i_stc, sizeof(*p_clpi->p_stc) );
152     for( p_clpi->i_stc = 0; p_clpi->i_stc < i_stc; p_clpi->i_stc++ )
153     {
154         if( !p_clpi->p_stc )
155             break;
156         bd_clpi_stc_Parse( &p_clpi->p_stc[p_clpi->i_stc], &ss );
157     }
158
159     /* Program */
160     bs_t ps = *s;
161     bs_skip( &ps, 8 * ( i_start + i_program_start ) - bs_pos( s ) );
162     bs_skip( &ps, 32 ); /* Length */
163     bs_skip( &ps, 8 );
164     bs_skip( &ps, 8 );  /* Program count (MUST be 1 ?) */
165     bs_skip( &ps, 32 ); /* Program sequence start (MUST be 0) */
166     p_clpi->i_pmt_pid = bs_read( &ps, 16 );
167     const int i_stream = bs_read( &ps, 8 );
168     bs_skip( &ps, 8 );  /* Group count (MUST be 1 ?) */
169
170     p_clpi->p_stream = calloc( i_stream, sizeof(*p_clpi->p_stream) );
171     for( p_clpi->i_stream = 0; p_clpi->i_stream < i_stream; p_clpi->i_stream++ )
172     {
173         if( !p_clpi->p_stream )
174             break;
175         bd_clpi_stream_Parse( &p_clpi->p_stream[p_clpi->i_stream], &ps );
176     }
177
178     /* Read CPI */
179     bs_t cs = *s;
180     bs_skip( &cs, 8 * ( i_start + i_cpi_start ) - bs_pos( s ) );
181
182     const uint32_t i_cpi_length = bs_read( &cs, 32 );
183     if( i_cpi_length > 0 )
184     {
185         bs_skip( &cs, 12 );
186         bs_skip( &cs, 4 );  /* Type (MUST be 1) */
187
188         /* EPMap */
189         const int i_epmap_start = bs_pos( &cs ) / 8;
190         bs_skip( &cs, 8 );
191         const int i_ep_map = bs_read( &cs, 8 );
192
193         p_clpi->p_ep_map = calloc( i_ep_map, sizeof(*p_clpi->p_ep_map) );
194         for( p_clpi->i_ep_map = 0; p_clpi->i_ep_map < i_ep_map; p_clpi->i_ep_map++ )
195         {
196             if( !p_clpi->p_ep_map )
197                 break;
198
199             if( bd_clpi_ep_map_Parse( &p_clpi->p_ep_map[p_clpi->i_ep_map],
200                                       &cs, i_epmap_start ) )
201                 break;
202         }
203     }
204     else
205     {
206         p_clpi->i_ep_map = 0;
207         p_clpi->p_ep_map = NULL;
208     }
209     return VLC_SUCCESS;
210 }