]> git.sesse.net Git - vlc/blob - modules/access/mms/asf.c
decklink: update build rules
[vlc] / modules / access / mms / asf.c
1 /*****************************************************************************
2  * asf.c: MMS access plug-in
3  *****************************************************************************
4  * Copyright (C) 2001-2004 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * 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
28 #include <vlc_common.h>
29 #include <vlc_rand.h>
30 #include <vlc_codecs.h>
31
32 #include "asf.h"
33 #include "buffer.h"
34
35 void  GenerateGuid ( guid_t *p_guid )
36 {
37     p_guid->Data1 = 0xbabac001;
38     vlc_rand_bytes(&p_guid->Data2, sizeof(p_guid->Data2));
39     vlc_rand_bytes(&p_guid->Data3, sizeof(p_guid->Data3));
40     vlc_rand_bytes(p_guid->Data4, sizeof(p_guid->Data4));
41 }
42
43 void  asf_HeaderParse ( asf_header_t *hdr,
44                             uint8_t *p_header, int i_header )
45 {
46     var_buffer_t buffer;
47     guid_t      guid;
48     uint64_t    i_size;
49
50     hdr->i_file_size = 0;
51     hdr->i_data_packets_count = 0;
52     hdr->i_min_data_packet_size = 0;
53     for( unsigned i = 0; i < 128; i++ )
54     {
55         hdr->stream[i].i_cat = ASF_CODEC_TYPE_UNKNOWN;
56         hdr->stream[i].i_selected = 0;
57         hdr->stream[i].i_bitrate = -1;
58     }
59
60     var_buffer_initread( &buffer, p_header, i_header );
61     var_buffer_getguid( &buffer, &guid );
62
63     if( !guidcmp( &guid, &asf_object_header_guid ) )
64     {
65         /* ERROR: */
66     }
67     var_buffer_getmemory( &buffer, NULL, 30 - 16 );
68
69     for( ;; )
70     {
71         var_buffer_getguid( &buffer, &guid );
72         i_size = var_buffer_get64( &buffer );
73
74         if( guidcmp( &guid, &asf_object_file_properties_guid ) )
75         {
76             var_buffer_getmemory( &buffer, NULL, 16 );
77             hdr->i_file_size            = var_buffer_get64( &buffer );
78             var_buffer_getmemory( &buffer, NULL, 8 );
79             hdr->i_data_packets_count   = var_buffer_get64( &buffer );
80             var_buffer_getmemory( &buffer, NULL, 8+8+8+4);
81             hdr->i_min_data_packet_size = var_buffer_get32( &buffer );
82
83             var_buffer_getmemory( &buffer, NULL, i_size - 24 - 16 - 8 - 8 - 8 - 8-8-8-4 - 4);
84         }
85         else if( guidcmp( &guid, &asf_object_header_extension_guid ) )
86         {
87             /* Enter it */
88             var_buffer_getmemory( &buffer, NULL, 46 - 24 );
89         }
90         else if( guidcmp( &guid, &asf_object_extended_stream_properties_guid ) )
91         {
92             /* Grrrrrr */
93             int16_t i_count1, i_count2;
94             int i_subsize;
95
96             var_buffer_getmemory( &buffer, NULL, 84 - 24 );
97
98             i_count1 = var_buffer_get16( &buffer );
99             i_count2 = var_buffer_get16( &buffer );
100
101             i_subsize = 88;
102             for( int i = 0; i < i_count1; i++ )
103             {
104                 int i_len;
105
106                 var_buffer_get16( &buffer );
107                 i_len = var_buffer_get16( &buffer );
108                 var_buffer_getmemory( &buffer, NULL, i_len );
109
110                 i_subsize += 4 + i_len;
111             }
112
113             for( int i = 0; i < i_count2; i++ )
114             {
115                 int i_len;
116                 var_buffer_getmemory( &buffer, NULL, 16 + 2 );
117                 i_len = var_buffer_get32( &buffer );
118                 var_buffer_getmemory( &buffer, NULL, i_len );
119
120                 i_subsize += 16 + 6 + i_len;
121             }
122
123             if( i_size - i_subsize <= 24 )
124             {
125                 var_buffer_getmemory( &buffer, NULL, i_size - i_subsize );
126             }
127             /* It's a hack we just skip the first part of the object until
128              * the embed stream properties if any (ugly, but whose fault ?) */
129         }
130         else if( guidcmp( &guid, &asf_object_stream_properties_guid ) )
131         {
132             int     i_stream_id;
133             guid_t  stream_type;
134
135             var_buffer_getguid( &buffer, &stream_type );
136             var_buffer_getmemory( &buffer, NULL, 32 );
137
138             i_stream_id = var_buffer_get8( &buffer ) & 0x7f;
139             var_buffer_getmemory( &buffer, NULL, i_size - 24 - 32 - 16 - 1);
140
141             if( guidcmp( &stream_type, &asf_object_stream_type_video ) )
142             {
143                 hdr->stream[i_stream_id].i_cat = ASF_CODEC_TYPE_VIDEO;
144             }
145             else if( guidcmp( &stream_type, &asf_object_stream_type_audio ) )
146             {
147                 hdr->stream[i_stream_id].i_cat = ASF_CODEC_TYPE_AUDIO;
148             }
149             else
150             {
151                 hdr->stream[i_stream_id].i_cat = ASF_CODEC_TYPE_UNKNOWN;
152             }
153         }
154         else if ( guidcmp( &guid, &asf_object_stream_bitrate_properties ) )
155         {
156             int     i_count;
157             uint8_t i_stream_id;
158
159             i_count = var_buffer_get16( &buffer );
160             i_size -= 2;
161             while( i_count > 0 )
162             {
163                 i_stream_id = var_buffer_get16( &buffer )&0x7f;
164                 hdr->stream[i_stream_id].i_bitrate =  var_buffer_get32( &buffer );
165                 i_count--;
166                 i_size -= 6;
167             }
168             var_buffer_getmemory( &buffer, NULL, i_size - 24 );
169         }
170         else
171         {
172             // skip unknown guid
173             var_buffer_getmemory( &buffer, NULL, i_size - 24 );
174         }
175
176         if( var_buffer_readempty( &buffer ) )
177             return;
178     }
179 }
180
181 void  asf_StreamSelect  ( asf_header_t *hdr,
182                               int i_bitrate_max,
183                               bool b_all, bool b_audio, bool b_video )
184 {
185     /* XXX FIXME use mututal eclusion information */
186     unsigned i;
187     int i_audio, i_video;
188     int i_bitrate_total;
189 #if 0
190     char *psz_stream;
191 #endif
192
193     i_audio = 0;
194     i_video = 0;
195     i_bitrate_total = 0;
196     if( b_all )
197     {
198         /* select all valid stream */
199         for( i = 1; i < 128; i++ )
200         {
201             if( hdr->stream[i].i_cat != ASF_CODEC_TYPE_UNKNOWN )
202             {
203                 hdr->stream[i].i_selected = 1;
204             }
205         }
206         return;
207     }
208     else
209     {
210         for( i = 0; i < 128; i++ )
211         {
212             /* by default, not selected */
213             hdr->stream[i].i_selected = 0;
214         }
215     }
216
217     /* big test:
218      * select a stream if
219      *    - no audio nor video stream
220      *    - or:
221      *         - if i_bitrate_max not set keep the highest bitrate
222      *         - if i_bitrate_max is set, keep stream that make we used best
223      *           quality regarding i_bitrate_max
224      *
225      * XXX: little buggy:
226      *        - it doesn't use mutual exclusion info..
227      *        - when selecting a better stream we could select
228      *        something that make i_bitrate_total> i_bitrate_max
229      */
230     for( i = 1; i < 128; i++ )
231     {
232         if( hdr->stream[i].i_cat == ASF_CODEC_TYPE_UNKNOWN )
233         {
234             continue;
235         }
236         else if( hdr->stream[i].i_cat == ASF_CODEC_TYPE_AUDIO && b_audio &&
237                  ( i_audio <= 0 ||
238                     ( ( ( hdr->stream[i].i_bitrate > hdr->stream[i_audio].i_bitrate &&
239                           ( i_bitrate_total + hdr->stream[i].i_bitrate - hdr->stream[i_audio].i_bitrate
240                                             < i_bitrate_max || !i_bitrate_max) ) ||
241                         ( hdr->stream[i].i_bitrate < hdr->stream[i_audio].i_bitrate &&
242                               i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
243                       ) )  ) )
244         {
245             /* unselect old stream */
246             if( i_audio > 0 )
247             {
248                 hdr->stream[i_audio].i_selected = 0;
249                 if( hdr->stream[i_audio].i_bitrate> 0 )
250                 {
251                     i_bitrate_total -= hdr->stream[i_audio].i_bitrate;
252                 }
253             }
254
255             hdr->stream[i].i_selected = 1;
256             if( hdr->stream[i].i_bitrate> 0 )
257             {
258                 i_bitrate_total += hdr->stream[i].i_bitrate;
259             }
260             i_audio = i;
261         }
262         else if( hdr->stream[i].i_cat == ASF_CODEC_TYPE_VIDEO && b_video &&
263                  ( i_video <= 0 ||
264                     (
265                         ( ( hdr->stream[i].i_bitrate > hdr->stream[i_video].i_bitrate &&
266                             ( i_bitrate_total + hdr->stream[i].i_bitrate - hdr->stream[i_video].i_bitrate
267                                             < i_bitrate_max || !i_bitrate_max) ) ||
268                           ( hdr->stream[i].i_bitrate < hdr->stream[i_video].i_bitrate &&
269                             i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
270                         ) ) )  )
271         {
272             /* unselect old stream */
273             if( i_video > 0 )
274             {
275                 hdr->stream[i_video].i_selected = 0;
276                 if( hdr->stream[i_video].i_bitrate> 0 )
277                 {
278                     i_bitrate_total -= hdr->stream[i_video].i_bitrate;
279                 }
280             }
281
282             hdr->stream[i].i_selected = 1;
283             if( hdr->stream[i].i_bitrate> 0 )
284             {
285                 i_bitrate_total += hdr->stream[i].i_bitrate;
286             }
287             i_video = i;
288         }
289
290     }
291 }