]> git.sesse.net Git - vlc/blob - modules/demux/asf/libasf.c
93d02892ebdcafb19741933abf8ff79b1ec6cfc0
[vlc] / modules / demux / asf / libasf.c
1 /*****************************************************************************
2  * libasf.c : 
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: libasf.c,v 1.1 2002/10/20 17:22:33 fenrir Exp $
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 #include <stdlib.h>                                      /* malloc(), free() */
24 #include <string.h>                                              /* strdup() */
25 #include <errno.h>
26 #include <sys/types.h>
27
28 #include <vlc/vlc.h>
29 #include <vlc/input.h>
30
31 #include "libasf.h"
32
33 #define ASF_DEBUG 1
34
35 #define FREE( p ) \
36     if( p ) {free( p ); p = NULL; }
37    
38 #define GUID_FMT "0x%x-0x%x-0x%x-0x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x"
39 #define GUID_PRINT( guid )  \
40     (guid).v1,              \
41     (guid).v2,              \
42     (guid).v3,              \
43     (guid).v4[0],(guid).v4[1],(guid).v4[2],(guid).v4[3],    \
44     (guid).v4[4],(guid).v4[5],(guid).v4[6],(guid).v4[7]
45
46 /* Some functions to manipulate memory */
47 static u16 GetWLE( u8 *p_buff )
48 {
49     return( (p_buff[0]) + ( p_buff[1] <<8 ) );
50 }
51
52 static u32 GetDWLE( u8 *p_buff )
53 {
54     return( p_buff[0] + ( p_buff[1] <<8 ) +
55             ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
56 }
57
58 static u64 GetQWLE( u8 *p_buff )
59 {
60     return( ( (u64)GetDWLE( p_buff ) )|( (u64)GetDWLE( p_buff + 4 ) << 32) );
61 }
62
63 void GetGUID( guid_t *p_guid, u8 *p_data )
64 {
65     p_guid->v1 = GetDWLE( p_data );
66     p_guid->v2 = GetWLE( p_data + 4);
67     p_guid->v3 = GetWLE( p_data + 6);
68     memcpy( p_guid->v4, p_data + 8, 8 );
69 }
70
71 int CmpGUID( const guid_t *p_guid1, const guid_t *p_guid2 )
72 {
73     if( (p_guid1->v1 != p_guid2->v1 )||(p_guid1->v2 != p_guid2->v2 )||
74         (p_guid1->v3 != p_guid2->v3 )||
75         ( memcmp( p_guid1->v4, p_guid2->v4,8 )) )
76     {
77         return( 0 );
78     }
79     else
80     {
81         return( 1 ); /* match */
82     }
83 }
84 /*****************************************************************************
85  * Some basic functions to manipulate stream more easily in vlc
86  *
87  * ASF_TellAbsolute get file position
88  * 
89  * ASF_SeekAbsolute seek in the file
90  *
91  * ASF_ReadData read data from the file in a buffer
92  *
93  *****************************************************************************/
94 off_t ASF_TellAbsolute( input_thread_t *p_input )
95 {
96     off_t i_pos;
97     
98     vlc_mutex_lock( &p_input->stream.stream_lock );
99     
100     i_pos= p_input->stream.p_selected_area->i_tell -
101             ( p_input->p_last_data - p_input->p_current_data  );
102
103     vlc_mutex_unlock( &p_input->stream.stream_lock );
104
105     return( i_pos );
106 }
107  
108 int ASF_SeekAbsolute( input_thread_t *p_input,
109                       off_t i_pos)
110 {
111     off_t i_filepos;
112
113     if( i_pos >= p_input->stream.p_selected_area->i_size )
114     {
115         return( 0 );
116     }
117             
118     i_filepos = ASF_TellAbsolute( p_input );
119     if( i_pos != i_filepos )
120     {
121         p_input->pf_seek( p_input, i_pos );
122         input_AccessReinit( p_input );
123     }
124     return( 1 );
125 }
126
127 /* return 1 if success, 0 if fail */
128 int ASF_ReadData( input_thread_t *p_input, u8 *p_buff, int i_size )
129 {
130     data_packet_t *p_data;
131
132     int i_read;
133
134                 
135     if( !i_size )
136     {
137         return( 1 );
138     }
139
140     do
141     {
142         i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size, 1024 ) );
143         if( i_read <= 0 )
144         {
145             return( 0 );
146         }
147         memcpy( p_buff, p_data->p_payload_start, i_read );
148         input_DeletePacket( p_input->p_method_data, p_data );
149         
150         p_buff += i_read;
151         i_size -= i_read;
152                 
153     } while( i_size );
154     
155     return( 1 );
156 }
157
158 int  ASF_SkipBytes( input_thread_t *p_input, int i_count )
159 {
160     return( ASF_SeekAbsolute( p_input, 
161                               ASF_TellAbsolute( p_input ) + i_count ) );
162 }
163
164 /****************************************************************************/
165 int  ASF_ReadObjectCommon( input_thread_t *p_input, 
166                            asf_object_t *p_obj )
167 {
168     asf_object_common_t *p_common = (asf_object_common_t*)p_obj;
169     u8  *p_peek;
170
171     if( input_Peek( p_input, &p_peek, 24 ) < 24 )
172     {
173         return( 0 );
174     }
175     GetGUID( &p_common->i_object_id, p_peek ); 
176     p_common->i_object_size = GetQWLE( p_peek + 16 );
177     p_common->i_object_pos = ASF_TellAbsolute( p_input );
178     p_common->p_next = NULL;
179 #ifdef ASF_DEBUG
180     msg_Dbg(p_input,
181             "Found Object guid: " GUID_FMT " size:%lld",
182             GUID_PRINT( p_common->i_object_id ),
183             p_common->i_object_size );
184 #endif
185     
186     return( 1 ); 
187 }
188
189 int ASF_NextObject( input_thread_t *p_input,
190                     asf_object_t *p_obj )
191 {
192     asf_object_t obj;
193     if( !p_obj )
194     {
195         if( !ASF_ReadObjectCommon( p_input, &obj ) )
196         {
197             return( 0 );
198         }
199         p_obj = &obj;
200     }
201
202     if( !p_obj->common.i_object_size )
203     {
204         return( 0 ); /* failed */
205     }
206     if( p_obj->common.p_father )
207     {
208         if( p_obj->common.p_father->common.i_object_pos + p_obj->common.p_father->common.i_object_size <
209                 p_obj->common.i_object_pos + p_obj->common.i_object_size + 24 )  
210                                 /* 24 is min size of an object */
211         {
212             return( 0 );
213         }
214
215     }
216     return( ASF_SeekAbsolute( p_input, 
217                               p_obj->common.i_object_pos + p_obj->common.i_object_size ) );
218 }
219
220 int  ASF_GotoObject( input_thread_t *p_input,
221                      asf_object_t *p_obj )
222 {
223     if( !p_obj )
224     {
225         return( 0 );
226     }
227     return( ASF_SeekAbsolute( p_input, p_obj->common.i_object_pos ) );
228 }
229
230
231 void ASF_FreeObject_Null( input_thread_t *p_input,
232                             asf_object_t *pp_obj )
233 {
234
235
236 }
237
238 int  ASF_ReadObject_Header( input_thread_t *p_input,
239                             asf_object_t *p_obj )
240 {
241     asf_object_header_t *p_hdr = (asf_object_header_t*)p_obj;
242     asf_object_t *p_subobj;
243     int i_peek;
244     u8  *p_peek;
245     
246     if( ( i_peek = input_Peek( p_input, &p_peek, 30 ) ) < 30 )
247     {
248        return( 0 );
249     }
250     p_hdr->i_sub_object_count = GetDWLE( p_peek + 24 );
251     p_hdr->i_reserved1 = p_peek[28];
252     p_hdr->i_reserved2 = p_peek[29];
253     p_hdr->p_first = NULL;
254     p_hdr->p_last  = NULL;
255 #ifdef ASF_DEBUG
256     msg_Dbg(p_input,
257             "Read \"Header Object\" subobj:%d, reserved1:%d, reserved2:%d",
258             p_hdr->i_sub_object_count,
259             p_hdr->i_reserved1,
260             p_hdr->i_reserved2 );
261 #endif
262     ASF_SkipBytes( p_input, 30 );
263     /* Now load sub object */
264     for( ; ; )
265     {
266         p_subobj  = malloc( sizeof( asf_object_t ) );
267
268         if( !( ASF_ReadObject( p_input, p_subobj, (asf_object_t*)p_hdr ) ) )
269         {
270             break; 
271         }
272         if( !ASF_NextObject( p_input, p_subobj ) ) /* Go to the next object */
273         {
274             break;
275         }
276     }
277     return( 1 );
278 }
279
280 int  ASF_ReadObject_Data( input_thread_t *p_input,
281                           asf_object_t *p_obj )
282 {
283     asf_object_data_t *p_data = (asf_object_data_t*)p_obj;
284     int i_peek;
285     u8  *p_peek;
286     
287     if( ( i_peek = input_Peek( p_input, &p_peek, 50 ) ) < 50 )
288     {
289        return( 0 );
290     }
291     GetGUID( &p_data->i_file_id, p_peek + 24 );
292     p_data->i_total_data_packets = GetQWLE( p_peek + 40 );
293     p_data->i_reserved = GetWLE( p_peek + 48 );
294 #ifdef ASF_DEBUG
295     msg_Dbg( p_input,
296             "Read \"Data Object\" file_id:" GUID_FMT " total data packet:%lld reserved:%d",
297             GUID_PRINT( p_data->i_file_id ),
298             p_data->i_total_data_packets,
299             p_data->i_reserved );
300 #endif
301     return( 1 );
302 }
303
304 int  ASF_ReadObject_Index( input_thread_t *p_input,
305                            asf_object_t *p_obj )
306 {
307     asf_object_index_t *p_index = (asf_object_index_t*)p_obj;
308     int i_peek;
309     u8  *p_peek;
310     
311     if( ( i_peek = input_Peek( p_input, &p_peek, 56 ) ) < 56 )
312     {
313        return( 0 );
314     }
315     GetGUID( &p_index->i_file_id, p_peek + 24 );
316     p_index->i_index_entry_time_interval = GetQWLE( p_peek + 40 );
317     p_index->i_max_packet_count = GetDWLE( p_peek + 48 );
318     p_index->i_index_entry_count = GetDWLE( p_peek + 52 );
319     p_index->index_entry = NULL; /* FIXME */
320
321 #ifdef ASF_DEBUG
322     msg_Dbg( p_input,
323             "Read \"Index Object\" file_id:" GUID_FMT " index_entry_time_interval:%lld max_packet_count:%d index_entry_count:%d",
324             GUID_PRINT( p_index->i_file_id ),
325             p_index->i_max_packet_count,
326             p_index->i_index_entry_count );
327 #endif
328     return( 1 );
329 }
330 void ASF_FreeObject_Index( input_thread_t *p_input,
331                           asf_object_t *p_obj )
332 {
333     asf_object_index_t *p_index = (asf_object_index_t*)p_obj;
334
335     FREE( p_index->index_entry );
336 }
337
338 int  ASF_ReadObject_file_properties( input_thread_t *p_input,
339                                      asf_object_t *p_obj )
340 {
341     asf_object_file_properties_t *p_fp = (asf_object_file_properties_t*)p_obj;
342     int i_peek;
343     u8  *p_peek;
344     
345     if( ( i_peek = input_Peek( p_input, &p_peek,  92) ) < 92 )
346     {
347        return( 0 );
348     }
349     GetGUID( &p_fp->i_file_id, p_peek + 24 );
350     p_fp->i_file_size = GetQWLE( p_peek + 40 );
351     p_fp->i_creation_date = GetQWLE( p_peek + 48 );
352     p_fp->i_data_packets_count = GetQWLE( p_peek + 56 );
353     p_fp->i_play_duration = GetQWLE( p_peek + 64 );
354     p_fp->i_send_duration = GetQWLE( p_peek + 72 );
355     p_fp->i_preroll = GetQWLE( p_peek + 80 );
356     p_fp->i_flags = GetDWLE( p_peek + 88 );
357     p_fp->i_min_data_packet_size = GetDWLE( p_peek + 92 );
358     p_fp->i_max_data_packet_size = GetDWLE( p_peek + 96 );
359     p_fp->i_max_bitrate = GetDWLE( p_peek + 100 );
360         
361 #ifdef ASF_DEBUG
362     msg_Dbg( p_input,
363             "Read \"File Properties Object\" file_id:" GUID_FMT " file_size:%lld creation_date:%lld data_packets_count:%lld play_duration:%lld send_duration:%lld preroll:%lld flags:%d min_data_packet_size:%d max_data_packet_size:%d max_bitrate:%d",
364             GUID_PRINT( p_fp->i_file_id ),
365             p_fp->i_file_size,
366             p_fp->i_creation_date,
367             p_fp->i_data_packets_count,
368             p_fp->i_play_duration,
369             p_fp->i_send_duration,
370             p_fp->i_preroll,
371             p_fp->i_flags,
372             p_fp->i_min_data_packet_size,
373             p_fp->i_max_data_packet_size,
374             p_fp->i_max_bitrate );
375 #endif
376     return( 1 );
377 }
378
379 int  ASF_ReadObject_header_extention( input_thread_t *p_input,
380                                       asf_object_t *p_obj )
381 {
382     asf_object_header_extention_t *p_he = (asf_object_header_extention_t*)p_obj;
383     int i_peek;
384     u8  *p_peek;
385     
386     if( ( i_peek = input_Peek( p_input, &p_peek, p_he->i_object_size ) ) <  46)
387     {
388        return( 0 );
389     }
390     GetGUID( &p_he->i_reserved1, p_peek + 24 );
391     p_he->i_reserved2 = GetWLE( p_peek + 40 );
392     p_he->i_header_extention_size = GetDWLE( p_peek + 42 );
393     if( p_he->i_header_extention_size )
394     {
395         p_he->p_header_extention_data = malloc( p_he->i_header_extention_size );
396         memcpy( p_he->p_header_extention_data,
397                 p_peek + 46,
398                 p_he->i_header_extention_size );
399     }
400     else
401     {
402         p_he->p_header_extention_data = NULL;
403     }
404 #ifdef ASF_DEBUG
405     msg_Dbg( p_input,
406             "Read \"Header Extention Object\" reserved1:" GUID_FMT " reserved2:%d header_extention_size:%d",
407             GUID_PRINT( p_he->i_reserved1 ),
408             p_he->i_reserved2,
409             p_he->i_header_extention_size );
410 #endif 
411     return( 1 );
412 }
413 void ASF_FreeObject_header_extention( input_thread_t *p_input,
414                                       asf_object_t *p_obj )
415 {
416     asf_object_header_extention_t *p_he = (asf_object_header_extention_t*)p_obj;
417
418     FREE( p_he->p_header_extention_data );
419 }
420
421 int  ASF_ReadObject_stream_properties( input_thread_t *p_input,
422                                        asf_object_t *p_obj )
423 {
424     asf_object_stream_properties_t *p_sp = 
425                     (asf_object_stream_properties_t*)p_obj;
426     int i_peek;
427     u8  *p_peek;
428     
429     if( ( i_peek = input_Peek( p_input, &p_peek,  p_sp->i_object_size ) ) < 74 )
430     {
431        return( 0 );
432     }
433     GetGUID( &p_sp->i_stream_type, p_peek + 24 );
434     GetGUID( &p_sp->i_error_correction_type, p_peek + 40 );
435     p_sp->i_time_offset = GetQWLE( p_peek + 56 );
436     p_sp->i_type_specific_data_length = GetDWLE( p_peek + 64 );
437     p_sp->i_error_correction_data_length = GetDWLE( p_peek + 68 );
438     p_sp->i_flags = GetWLE( p_peek + 72 );
439         p_sp->i_stream_number = p_sp->i_flags&0x07f;
440     p_sp->i_reserved = GetDWLE( p_peek + 74 );
441     if( p_sp->i_type_specific_data_length )
442     {
443         p_sp->p_type_specific_data = malloc( p_sp->i_type_specific_data_length );
444         memcpy( p_sp->p_type_specific_data,
445                 p_peek + 78,
446                 p_sp->i_type_specific_data_length );
447     }
448     else
449     {
450         p_sp->p_type_specific_data = NULL;
451     }
452     if( p_sp->i_error_correction_data_length )
453     {
454         p_sp->p_error_correction_data = malloc( p_sp->i_error_correction_data_length );
455         memcpy( p_sp->p_error_correction_data,
456                 p_peek + 78 + p_sp->i_type_specific_data_length,
457                 p_sp->i_error_correction_data_length );
458     }
459     else
460     {
461         p_sp->p_error_correction_data = NULL;
462     }
463
464 #ifdef ASF_DEBUG
465     msg_Dbg( p_input,
466             "Read \"Stream Properties Object\" stream_type:" GUID_FMT " error_correction_type:" GUID_FMT " time_offset:%lld type_specific_data_length:%d error_correction_data_length:%d flags:0x%x stream_number:%d",
467             GUID_PRINT( p_sp->i_stream_type ),
468             GUID_PRINT( p_sp->i_error_correction_type ),
469             p_sp->i_time_offset,
470             p_sp->i_type_specific_data_length,
471             p_sp->i_error_correction_data_length,
472             p_sp->i_flags,
473             p_sp->i_stream_number );
474
475 #endif
476     return( 1 );
477 }
478
479 void ASF_FreeObject_stream_properties( input_thread_t *p_input,
480                                       asf_object_t *p_obj )
481 {
482     asf_object_stream_properties_t *p_sp = 
483                 (asf_object_stream_properties_t*)p_obj;
484
485     FREE( p_sp->p_type_specific_data );
486     FREE( p_sp->p_error_correction_data );
487 }
488
489
490 int  ASF_ReadObject_codec_list( input_thread_t *p_input,
491                                 asf_object_t *p_obj )
492 {
493     asf_object_codec_list_t *p_cl = (asf_object_codec_list_t*)p_obj;
494     int i_peek;
495     u8  *p_peek, *p_data;
496
497     int i_codec;
498     
499     if( ( i_peek = input_Peek( p_input, &p_peek, p_cl->i_object_size ) ) < 44 )
500     {
501        return( 0 );
502     }
503
504     GetGUID( &p_cl->i_reserved, p_peek + 24 );
505     p_cl->i_codec_entries_count = GetWLE( p_peek + 40 );
506     if( p_cl->i_codec_entries_count > 0 )
507     {
508
509         p_cl->codec = calloc( p_cl->i_codec_entries_count, sizeof( asf_codec_entry_t ) );
510         memset( p_cl->codec, 0, p_cl->i_codec_entries_count * sizeof( asf_codec_entry_t ) );
511
512         p_data = p_peek + 44;
513         for( i_codec = 0; i_codec < p_cl->i_codec_entries_count; i_codec++ )
514         {
515 #define codec p_cl->codec[i_codec]
516             int i_len, i;
517
518             codec.i_type = GetWLE( p_data ); p_data += 2;
519             /* codec name */
520             i_len = GetWLE( p_data ); p_data += 2;
521             codec.psz_name = calloc( sizeof( char ), i_len + 1);
522             for( i = 0; i < i_len; i++ )
523             {
524                 codec.psz_name[i] = GetWLE( p_data + 2*i );
525             }
526             codec.psz_name[i_len] = '\0';
527             p_data += 2 * i_len;
528
529             /* description */
530             i_len = GetWLE( p_data ); p_data += 2;
531             codec.psz_description = calloc( sizeof( char ), i_len + 1);
532             for( i = 0; i < i_len; i++ )
533             {
534                 codec.psz_description[i] = GetWLE( p_data + 2*i );
535             }
536             codec.psz_description[i_len] = '\0';
537             p_data += 2 * i_len;
538             
539             /* opaque information */
540             codec.i_information_length = GetWLE( p_data ); p_data += 2;
541             if( codec.i_information_length > 0 )
542             {
543                 codec.p_information = malloc( codec.i_information_length );
544                 memcpy( codec.p_information, p_data, codec.i_information_length );
545                 p_data += codec.i_information_length;
546             }
547             else
548             {
549                 codec.p_information = NULL;
550             }
551 #undef  codec
552         }
553
554     }
555     else
556     {
557         p_cl->codec = NULL;
558     }
559
560 #ifdef ASF_DEBUG
561     msg_Dbg( p_input,
562             "Read \"Codec List Object\" reserved_guid:" GUID_FMT " codec_entries_count:%d",
563             GUID_PRINT( p_cl->i_reserved ),
564             p_cl->i_codec_entries_count );
565     for( i_codec = 0; i_codec < p_cl->i_codec_entries_count; i_codec++ )
566     {
567 #define codec p_cl->codec[i_codec]
568          msg_Dbg( p_input,
569                  "Read \"Codec List Object\" codec[%d] %s name:\"%s\" description:\"%s\" information_length:%d",
570                  i_codec,
571                  ( codec.i_type == ASF_CODEC_TYPE_VIDEO ) ? "video" : ( ( codec.i_type == ASF_CODEC_TYPE_AUDIO ) ? "audio" : "unknown" ),
572                  codec.psz_name, 
573                  codec.psz_description, 
574                  codec.i_information_length );
575        
576 #undef  codec
577     }
578 #endif
579     return( 1 );
580 }
581 void ASF_FreeObject_codec_list( input_thread_t *p_input,
582                                 asf_object_t *p_obj )
583 {
584     asf_object_codec_list_t *p_cl = (asf_object_codec_list_t*)p_obj;
585     int i_codec;
586
587     for( i_codec = 0; i_codec < p_cl->i_codec_entries_count; i_codec++ )
588     {
589 #define codec p_cl->codec[i_codec]
590         FREE( codec.psz_name );
591         FREE( codec.psz_description );
592         FREE( codec.p_information );
593
594 #undef  codec
595     }
596     FREE( p_cl->codec );
597 }
598
599 /* Microsoft should qo to hell. This time the length give number of bytes
600  * and for the some others object, length give char16 count ... */
601 int  ASF_ReadObject_content_description( input_thread_t *p_input,
602                                          asf_object_t *p_obj )
603 {
604     asf_object_content_description_t *p_cd = (asf_object_content_description_t*)p_obj;
605     int i_peek;
606     u8  *p_peek, *p_data;
607
608     int i_len;
609     int i_title;
610     int i_author;
611     int i_copyright;
612     int i_description;
613     int i_rating;
614     
615 #define GETSTRINGW( psz_str, i_size ) \
616    psz_str = calloc( i_size/2 + 1, sizeof( char ) ); \
617    for( i_len = 0; i_len < i_size/2; i_len++ ) \
618    { \
619        psz_str[i_len] = GetWLE( p_data + 2*i_len ); \
620    } \
621    psz_str[i_size/2] = '\0'; \
622    p_data += i_size;
623    
624     if( ( i_peek = input_Peek( p_input, &p_peek, p_cd->i_object_size ) ) < 34 )
625     {
626        return( 0 );
627     }
628     p_data = p_peek + 24;
629
630     i_title = GetWLE( p_data ); p_data += 2;
631     i_author= GetWLE( p_data ); p_data += 2;
632     i_copyright     = GetWLE( p_data ); p_data += 2;
633     i_description   = GetWLE( p_data ); p_data += 2;
634     i_rating        = GetWLE( p_data ); p_data += 2;
635
636     GETSTRINGW( p_cd->psz_title, i_title );
637     GETSTRINGW( p_cd->psz_author, i_author );
638     GETSTRINGW( p_cd->psz_copyright, i_copyright );
639     GETSTRINGW( p_cd->psz_description, i_description );
640     GETSTRINGW( p_cd->psz_rating, i_rating );
641
642 #undef  GETSTRINGW
643
644 #ifdef ASF_DEBUG
645     msg_Dbg( p_input,
646              "Read \"Content Description Object\" title:\"%s\" author:\"%s\" copyright:\"%s\" description:\"%s\" rating:\"%s\"",
647              p_cd->psz_title,
648              p_cd->psz_author,
649              p_cd->psz_copyright,
650              p_cd->psz_description,
651              p_cd->psz_rating );
652 #endif 
653     return( 1 );
654 }
655
656 void ASF_FreeObject_content_description( input_thread_t *p_input,
657                                          asf_object_t *p_obj )
658 {
659     asf_object_content_description_t *p_cd = (asf_object_content_description_t*)p_obj;
660     
661     FREE( p_cd->psz_title );
662     FREE( p_cd->psz_author );
663     FREE( p_cd->psz_copyright );
664     FREE( p_cd->psz_description );
665     FREE( p_cd->psz_rating );
666 }
667
668 static struct
669 {
670     const guid_t  *p_id;
671     int     i_type;
672     int     (*ASF_ReadObject_function)( input_thread_t *p_input, 
673                                         asf_object_t *p_obj );
674     void    (*ASF_FreeObject_function)( input_thread_t *p_input,
675                                         asf_object_t *p_obj );
676 } ASF_Object_Function [] =
677 {
678     { &asf_object_header_guid,            ASF_OBJECT_TYPE_HEADER,             ASF_ReadObject_Header, ASF_FreeObject_Null },
679     { &asf_object_data_guid,              ASF_OBJECT_TYPE_DATA,               ASF_ReadObject_Data,   ASF_FreeObject_Null },
680     { &asf_object_index_guid,             ASF_OBJECT_TYPE_INDEX,              ASF_ReadObject_Index,  ASF_FreeObject_Index },
681     { &asf_object_file_properties_guid,   ASF_OBJECT_TYPE_FILE_PROPERTIES,    ASF_ReadObject_file_properties,  ASF_FreeObject_Null },
682     { &asf_object_stream_properties_guid, ASF_OBJECT_TYPE_STREAM_PROPERTIES,  ASF_ReadObject_stream_properties,ASF_FreeObject_stream_properties },
683     { &asf_object_header_extention_guid,  ASF_OBJECT_TYPE_EXTENTION_HEADER,   ASF_ReadObject_header_extention, ASF_FreeObject_header_extention},
684     { &asf_object_codec_list_guid,        ASF_OBJECT_TYPE_CODEC_LIST,         ASF_ReadObject_codec_list,       ASF_FreeObject_codec_list },
685     { &asf_object_marker_guid,            ASF_OBJECT_TYPE_MARKER,             NULL,                  NULL },
686     { &asf_object_content_description_guid, ASF_OBJECT_TYPE_CONTENT_DESCRIPTION, ASF_ReadObject_content_description, ASF_FreeObject_content_description },
687
688     { &asf_object_null_guid,   0,                      NULL,                  NULL }
689 };
690
691 int  ASF_ReadObject( input_thread_t *p_input,
692                      asf_object_t *p_obj,
693                      asf_object_t *p_father )
694 {
695     int i_result;
696     int i_index;
697
698     if( !p_obj )
699     {
700         return( 0 );
701     }
702     if( !ASF_ReadObjectCommon( p_input, p_obj ) )
703     {
704         msg_Warn( p_input, "Cannot read one asf object" );
705         return( 0 );
706     }
707     p_obj->common.p_father = p_father;
708     p_obj->common.p_first = NULL;
709     p_obj->common.p_next = NULL;
710     p_obj->common.p_last = NULL;
711     
712
713     if( p_obj->common.i_object_size < 24 )
714     {
715         msg_Warn( p_input, "Found a corrupted asf object (size<24)" );
716         return( 0 );
717     }
718     /* find this object */
719     for( i_index = 0; ; i_index++ )
720     {
721         if( CmpGUID( ASF_Object_Function[i_index].p_id,
722                      &p_obj->common.i_object_id )||
723             CmpGUID( ASF_Object_Function[i_index].p_id,
724                      &asf_object_null_guid ) )
725         {
726             break;
727         }
728     }
729     p_obj->common.i_type = ASF_Object_Function[i_index].i_type;
730
731     /* Now load this object */
732     if( ASF_Object_Function[i_index].ASF_ReadObject_function == NULL )
733     {
734         msg_Warn( p_input, "Unknown asf object (not loaded)" );
735         i_result = 1;
736     }
737     else
738     {
739         /* XXX ASF_ReadObject_function realloc *pp_obj XXX */
740         i_result =  
741             (ASF_Object_Function[i_index].ASF_ReadObject_function)( p_input,
742                                                                     p_obj );
743     }
744     
745     /* link this object with father */
746     if( p_father )
747     {
748         if( p_father->common.p_first )
749         {
750             p_father->common.p_last->common.p_next = p_obj;
751         }
752         else
753         {
754             p_father->common.p_first = p_obj;
755         }
756         p_father->common.p_last = p_obj;
757     }
758
759     return( i_result );
760 }
761
762 void ASF_FreeObject( input_thread_t *p_input,
763                      asf_object_t *p_obj )
764 {
765     int i_index;
766     asf_object_t *p_child;
767     
768     if( !p_obj )
769     {
770         return;
771     }
772     
773     /* Free all child object */
774     p_child = p_obj->common.p_first;
775     while( p_child )
776     {
777         asf_object_t *p_next;
778         p_next = p_child->common.p_next;
779         ASF_FreeObject( p_input, p_child );
780         p_child = p_next;
781     }
782
783     /* find this object */
784     for( i_index = 0; ; i_index++ )
785     {
786         if( CmpGUID( ASF_Object_Function[i_index].p_id,
787                      &p_obj->common.i_object_id )||
788             CmpGUID( ASF_Object_Function[i_index].p_id,
789                      &asf_object_null_guid ) )
790         {
791             break;
792         }
793     }
794
795     /* Now free this object */
796     if( ASF_Object_Function[i_index].ASF_FreeObject_function == NULL )
797     {
798         msg_Warn( p_input, 
799                   "Unknown asf object " GUID_FMT,
800                   GUID_PRINT( p_obj->common.i_object_id ) );
801     }
802     else
803     {
804 #ifdef ASF_DEBUG
805         msg_Dbg( p_input, 
806                   "Free asf object " GUID_FMT,
807                   GUID_PRINT( p_obj->common.i_object_id ) );
808 #endif
809         (ASF_Object_Function[i_index].ASF_FreeObject_function)( p_input,
810                                                                 p_obj );
811     }
812     free( p_obj );
813     return;
814 }
815
816 /*****************************************************************************
817  * ASF_ReadObjetRoot : parse the entire stream/file
818  *****************************************************************************/
819 int ASF_ReadObjectRoot( input_thread_t *p_input,
820                         asf_object_root_t *p_root,
821                         int b_seekable )
822 {
823     asf_object_t *p_obj;
824
825     p_root->i_type = ASF_OBJECT_TYPE_ROOT;
826     memcpy( &p_root->i_object_id, &asf_object_null_guid, sizeof( guid_t ) );
827     p_root->i_object_pos = 0;
828     p_root->i_object_size = p_input->stream.p_selected_area->i_size;
829     p_root->p_first = NULL;
830     p_root->p_last = NULL;
831     p_root->p_next = NULL;
832     p_root->p_hdr = NULL;
833     p_root->p_data = NULL;
834     p_root->p_index = NULL;
835    
836     for( ; ; )
837     {
838         p_obj  = malloc( sizeof( asf_object_t ) );
839
840         if( !( ASF_ReadObject( p_input, p_obj, (asf_object_t*)p_root ) ) )
841         {
842             return( 1 );
843         }
844         switch( p_obj->common.i_type )
845         {
846             case( ASF_OBJECT_TYPE_HEADER ):
847                 p_root->p_hdr = (asf_object_header_t*)p_obj;
848                 break;
849             case( ASF_OBJECT_TYPE_DATA ):
850                 p_root->p_data = (asf_object_data_t*)p_obj;
851                 break;
852             case( ASF_OBJECT_TYPE_INDEX ):
853                 p_root->p_index = (asf_object_index_t*)p_obj;
854                 break;
855             default:
856                 msg_Warn( p_input, "Unknow Object found" );
857                 break;
858         }
859         if( !b_seekable && ( p_root->p_hdr && p_root->p_data ) )
860         {
861             /* For unseekable stream it's enouth to play */
862             return( 1 );
863         }
864
865         if( !ASF_NextObject( p_input, p_obj ) ) /* Go to the next object */
866         {
867             return( 1 );
868         }
869     }
870 }
871
872 void ASF_FreeObjectRoot( input_thread_t *p_input,
873                          asf_object_root_t *p_root )
874 {
875     asf_object_t *p_obj;
876     
877     p_obj = p_root->p_first;
878     while( p_obj )
879     {
880         asf_object_t *p_next;
881         p_next = p_obj->common.p_next;
882         ASF_FreeObject( p_input, p_obj );
883         p_obj = p_next;
884     }
885     p_root->p_first = NULL;
886     p_root->p_last = NULL;
887     p_root->p_next = NULL;
888
889     p_root->p_hdr = NULL;
890     p_root->p_data = NULL;
891     p_root->p_index = NULL;
892     
893 }
894
895 int  ASF_CountObject( asf_object_t *p_obj, const guid_t *p_guid )
896 {
897     int i_count;
898     asf_object_t *p_child;
899
900     if( !p_obj )
901     {
902         return( 0 );
903     }
904
905     i_count = 0;
906     p_child = p_obj->common.p_first;
907     while( p_child )
908     {
909         if( CmpGUID( &p_child->common.i_object_id, p_guid ) )
910         {
911             i_count++;
912         }
913         p_child = p_child->common.p_next;
914     }
915     return( i_count );
916 }
917
918 asf_object_t *ASF_FindObject( asf_object_t *p_obj, const guid_t *p_guid, int i_number )
919 {
920     asf_object_t *p_child;
921
922     p_child = p_obj->common.p_first;
923
924     while( p_child )
925     {
926         if( CmpGUID( &p_child->common.i_object_id, p_guid ) )
927         {
928             if( i_number == 0 )
929             {
930                 /* We found it */
931                 return( p_child );
932             }
933
934             i_number--;
935         }
936         p_child = p_child->common.p_next;
937     }
938     return( NULL );
939 }
940
941