* all : add an asf file (v1.0 only) demuxer. Need a lot of work to be
authorLaurent Aimar <fenrir@videolan.org>
Sun, 20 Oct 2002 17:22:33 +0000 (17:22 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Sun, 20 Oct 2002 17:22:33 +0000 (17:22 +0000)
usable, but it begin to give good result.

modules/demux/asf/.cvsignore [new file with mode: 0644]
modules/demux/asf/Modules.am [new file with mode: 0644]
modules/demux/asf/asf.c [new file with mode: 0644]
modules/demux/asf/asf.h [new file with mode: 0644]
modules/demux/asf/libasf.c [new file with mode: 0644]
modules/demux/asf/libasf.h [new file with mode: 0644]

diff --git a/modules/demux/asf/.cvsignore b/modules/demux/asf/.cvsignore
new file mode 100644 (file)
index 0000000..435f39e
--- /dev/null
@@ -0,0 +1,4 @@
+.dep
+*.lo
+*.o.*
+*.lo.*
diff --git a/modules/demux/asf/Modules.am b/modules/demux/asf/Modules.am
new file mode 100644 (file)
index 0000000..08884f5
--- /dev/null
@@ -0,0 +1,8 @@
+SOURCES_asf = \
+       modules/demux/asf/asf.c \
+       modules/demux/asf/libasf.c
+
+
+noinst_HEADERS += \
+       modules/demux/asf/asf.h \
+    modules/demux/asf/libasf.h
diff --git a/modules/demux/asf/asf.c b/modules/demux/asf/asf.c
new file mode 100644 (file)
index 0000000..42aec93
--- /dev/null
@@ -0,0 +1,658 @@
+/*****************************************************************************
+ * asf.c : ASFv01 file input module for vlc
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: asf.c,v 1.1 2002/10/20 17:22:33 fenrir Exp $
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>                                              /* strdup() */
+#include <errno.h>
+#include <sys/types.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include "libasf.h"
+#include "asf.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int    Activate   ( vlc_object_t * );
+static void   Deactivate ( vlc_object_t * );
+static int    Demux      ( input_thread_t * );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( "ASF v1.0 demuxer (file only)" );
+    set_capability( "demux", 200 );
+    set_callbacks( Activate, Deactivate );
+    add_shortcut( "asf" );
+vlc_module_end();
+
+static u16 GetWLE( u8 *p_buff )
+{
+    return( (p_buff[0]) + ( p_buff[1] <<8 ) );
+}
+static u32 GetDWLE( u8 *p_buff )
+{   
+    return( p_buff[0] + ( p_buff[1] <<8 ) +
+            ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
+}
+
+/*****************************************************************************
+ * Activate: check file and initializes ASF structures
+ *****************************************************************************/
+static int Activate( vlc_object_t * p_this )
+{   
+    input_thread_t *p_input = (input_thread_t *)p_this;
+    u8  *p_peek;
+    guid_t guid;
+    
+    demux_sys_t *p_demux;
+    int i_stream;
+    
+    /* Initialize access plug-in structures. */
+    if( p_input->i_mtu == 0 )
+    {
+        /* Improve speed. */
+        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
+    }
+
+    p_input->pf_demux = Demux;
+
+    /* a little test to see if it could be a asf stream */
+    if( input_Peek( p_input, &p_peek, 16 ) < 8 )
+    {
+        msg_Warn( p_input, "ASF v1.0 plugin discarded (cannot peek)" );
+        return( -1 );
+    }
+    GetGUID( &guid, p_peek );
+    if( !CmpGUID( &guid, &asf_object_header_guid ) )
+    {
+        msg_Warn( p_input, "ASF v1.0 plugin discarded (not a valid file)" );
+        return( -1 );
+    }
+
+    /* create our structure that will contains all data */
+    if( !( p_input->p_demux_data = 
+                p_demux = malloc( sizeof( demux_sys_t ) ) ) )
+    {
+        msg_Err( p_input, "out of memory" );
+        return( -1 );
+    }
+    memset( p_demux, 0, sizeof( demux_sys_t ) );
+    p_input->p_demux_data = p_demux;
+       
+
+    /* Now load all object ( except raw data ) */
+    if( !ASF_ReadObjectRoot( p_input, &p_demux->root, p_input->stream.b_seekable ) )
+    {
+        msg_Warn( p_input, "ASF v1.0 plugin discarded (not a valid file)" );
+        free( p_demux );
+        return( -1 );
+    }
+    /* Check if we have found all mandatory asf object */
+    if( !p_demux->root.p_hdr || !p_demux->root.p_data )
+    {
+        ASF_FreeObjectRoot( p_input, &p_demux->root );
+        free( p_demux );
+        msg_Warn( p_input, "ASF v1.0 plugin discarded (not a valid file)" );
+        return( -1 );
+    }
+   
+    if( !( p_demux->p_fp = ASF_FindObject( (asf_object_t*)p_demux->root.p_hdr,
+                                    &asf_object_file_properties_guid, 0 ) ) )
+    {
+        ASF_FreeObjectRoot( p_input, &p_demux->root );
+        free( p_demux );
+        msg_Warn( p_input, "ASF v1.0 plugin discarded (missing file_properties object)" );
+        return( -1 );
+    }
+    
+    if( p_demux->p_fp->i_min_data_packet_size != p_demux->p_fp->i_max_data_packet_size )
+    {
+        ASF_FreeObjectRoot( p_input, &p_demux->root );
+        free( p_demux );
+        msg_Warn( p_input, "ASF v1.0 plugin discarded (invalid file_properties object)" );
+        return( -1 );
+    }
+    
+    p_demux->i_streams = ASF_CountObject( (asf_object_t*)p_demux->root.p_hdr, 
+                                          &asf_object_stream_properties_guid );
+    if( !p_demux->i_streams )
+    {
+        ASF_FreeObjectRoot( p_input, &p_demux->root );
+        free( p_demux );
+        msg_Warn( p_input, "ASF plugin discarded (cannot find any stream!)" );
+        return( -1 );
+    }
+    else
+    {
+        msg_Dbg( p_input, "found %d streams", p_demux->i_streams );
+    }
+
+    /*  create one program */
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( input_InitStream( p_input, 0 ) == -1)
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        msg_Err( p_input, "cannot init stream" );
+        return( -1 );
+    }
+    if( input_AddProgram( p_input, 0, 0) == NULL )
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        msg_Err( p_input, "cannot add program" );
+        return( -1 );
+    }
+    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
+    p_input->stream.i_mux_rate = 0 ; /* FIXME */
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    for( i_stream = 0; i_stream < p_demux->i_streams; i_stream ++ )
+    {
+        asf_stream_t    *p_stream;
+        asf_object_stream_properties_t *p_sp;
+        
+        p_sp = (asf_object_stream_properties_t*)
+                    ASF_FindObject( (asf_object_t*)p_demux->root.p_hdr,
+                                    &asf_object_stream_properties_guid,
+                                    i_stream );
+
+        p_stream = p_demux->stream[p_sp->i_stream_number] = malloc( sizeof( asf_stream_t ) );
+        memset( p_stream, 0, sizeof( asf_stream_t ) );
+        p_stream->p_sp = p_sp;
+
+        vlc_mutex_lock( &p_input->stream.stream_lock );
+        p_stream->p_es = 
+            input_AddES( p_input,
+                         p_input->stream.p_selected_program,
+                         p_sp->i_stream_number,
+                         p_sp->i_type_specific_data_length );
+        if( p_sp->i_type_specific_data_length > 11 )
+        {
+            memcpy( p_stream->p_es->p_demux_data,
+                    p_sp->p_type_specific_data + 11,
+                    p_sp->i_type_specific_data_length - 11 );
+        }
+
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        if( CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_audio ) )
+        {
+            int i_codec;
+            if( p_sp->p_type_specific_data )
+            {
+                i_codec = GetWLE( p_sp->p_type_specific_data );
+            }
+            else
+            {
+                i_codec = -1;
+            }
+
+            p_stream->i_cat = AUDIO_ES;
+            msg_Dbg( p_input,
+                    "adding new audio stream(codec:0x%x,ID:%d)", 
+                    i_codec,
+                    p_sp->i_stream_number );
+            switch( i_codec )
+            {
+                case( 0x50 ):
+                case( 0x55 ):
+                    p_stream->p_es->i_fourcc = 
+                        VLC_FOURCC( 'm','p','g','a' );
+                    break;
+                case( 0x2000 ):
+                    p_stream->p_es->i_fourcc = 
+                        VLC_FOURCC( 'a','5','2',' ' );
+                    break;
+                case( 0x160 ):
+                case( 0x161 ):
+                    p_stream->p_es->i_fourcc = 
+                        VLC_FOURCC( 'w','m','a',' ' );
+                    break;
+                default:
+                    p_stream->p_es->i_fourcc = 
+                        VLC_FOURCC( 'u','n','d','f' );
+            }
+            
+        }
+        else
+        if( CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_video ) )
+        {
+            p_stream->i_cat = VIDEO_ES;
+            msg_Dbg( p_input,
+                    "adding new video stream(ID:%d)", 
+                    p_sp->i_stream_number );
+            if( p_sp->p_type_specific_data )
+            {
+                p_stream->p_es->i_fourcc =
+                    GetDWLE( p_sp->p_type_specific_data + 27 );
+            }
+            else
+            {
+                p_stream->p_es->i_fourcc = 
+                    VLC_FOURCC( 'u','n','d','f' );
+            }
+
+        }
+        else
+        {
+            p_stream->i_cat = UNKNOWN_ES;
+            msg_Dbg( p_input, 
+                    "ignoring unknown stream(ID:%d)", 
+                    p_sp->i_stream_number );
+            p_stream->p_es->i_fourcc = VLC_FOURCC( 'u','n','d','f' );
+        }
+        p_stream->p_es->i_cat = p_stream->i_cat;
+
+        vlc_mutex_lock( &p_input->stream.stream_lock );
+        input_SelectES( p_input, p_stream->p_es );
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+    }
+    
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    p_input->stream.p_selected_program->b_is_ok = 1;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    // go to first packet
+    p_demux->i_data_begin = p_demux->root.p_data->i_object_pos + 50;
+    if( p_demux->root.p_data->i_object_size != 0 )
+    { // local file
+        p_demux->i_data_end = p_demux->root.p_data->i_object_pos +
+                                    p_demux->root.p_data->i_object_size;
+    }
+    else
+    { // live/broacast
+        p_demux->i_data_end = -1;
+    }
+    ASF_SeekAbsolute( p_input, p_demux->i_data_begin );
+    return( 0 );
+}
+
+/*****************************************************************************
+ * Demux: read packet and send them to decoders 
+ *****************************************************************************/
+#define GETVALUE2b( bits, var, def ) \
+    switch( bits ) \
+    { \
+        case 1: var = p_peek[i_skip]; i_skip++; break; \
+        case 2: var = GetWLE( p_peek + i_skip );  i_skip+= 2; break; \
+        case 3: var = GetDWLE( p_peek + i_skip ); i_skip+= 4; break; \
+        case 0: \
+        default: var = def; break;\
+    }
+
+static int Demux( input_thread_t *p_input )
+{
+    demux_sys_t *p_demux = p_input->p_demux_data;
+    int i;
+
+    /* catch seek from user */
+    if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
+    {
+        off_t i_offset;
+        i_offset = ASF_TellAbsolute( p_input ) - p_demux->i_data_begin;
+
+        if( i_offset  < 0 )
+        {
+            i_offset = 0;
+        }
+        /* XXX work only when i_min_data_packet_size == i_max_data_packet_size */
+        i_offset -= i_offset % p_demux->p_fp->i_min_data_packet_size;
+        ASF_SeekAbsolute( p_input, p_demux->i_data_begin + i_offset );
+
+        p_demux->i_time = 0;
+        for( i = 0; i < 127 ; i++ )
+        {
+#define p_stream p_demux->stream[i]
+            if( p_stream )
+            {
+                p_stream->i_time = 0;
+            }
+#undef p_stream
+        }
+
+    }
+    /* first wait for the good time to read a packet */
+
+    input_ClockManageRef( p_input,
+                          p_input->stream.p_selected_program,
+                          p_demux->i_pcr );
+
+    /* update pcr XXX in mpeg scale so in 90000 unit/s */
+    p_demux->i_pcr = p_demux->i_time * 9 / 100;
+    
+//    /* we will read 100ms for each stream so */
+//    p_demux->i_time += 100 * 1000;
+
+    for( i = 0; i < 10; i++ ) // parse 10 packets
+    {
+        int i_data_packet_min = p_demux->p_fp->i_min_data_packet_size;
+        u8  *p_peek;
+        int i_skip;
+        
+        int i_packet_size_left;
+        int i_packet_flags;
+        int i_packet_property;
+
+        int b_packet_multiple_payload;
+        int i_packet_length;
+        int i_packet_sequence;
+        int i_packet_padding_length;
+        
+        u32 i_packet_send_time;
+        u16 i_packet_duration;
+        int i_payload;
+        int i_payload_count;
+        int i_payload_length_type;
+
+        
+        if( input_Peek( p_input, &p_peek, i_data_packet_min ) < i_data_packet_min )
+        {
+            // EOF ?
+            msg_Err( p_input, "cannot peek while getting new packet, EOF ?" );
+            return( 0 );
+        }
+        i_skip = 0;
+        
+        /* *** parse error correction if present *** */
+        if( p_peek[0]&0x80 )
+        {
+            int i_error_correction_length_type;
+            int i_error_correction_data_length;
+            int i_opaque_data_present;
+
+            i_error_correction_data_length = p_peek[0] & 0x0f;  // 4bits
+            i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01;    // 1bit
+            i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03; // 2bits
+            i_skip += 1; // skip error correction flags
+        
+            if( i_error_correction_length_type != 0x00 ||
+                i_opaque_data_present != 0 ||
+                i_error_correction_data_length != 0x02 )
+            {
+                goto loop_error_recovery;
+            }
+
+            i_skip += i_error_correction_data_length;
+        }
+        else
+        {
+            msg_Warn( p_input, "p_peek[0]&0x80 != 0x80" );
+        }
+
+        i_packet_flags = p_peek[i_skip]; i_skip++;
+        i_packet_property = p_peek[i_skip]; i_skip++;
+        
+        b_packet_multiple_payload = i_packet_flags&0x01;
+
+        /* read some value */
+        GETVALUE2b( ( i_packet_flags >> 5 )&0x3, i_packet_length, i_data_packet_min );
+        GETVALUE2b( ( i_packet_flags >> 1 )&0x3, i_packet_sequence, 0 );
+        GETVALUE2b( ( i_packet_flags >> 3 )&0x3, i_packet_padding_length, 0 );
+
+        i_packet_send_time = GetDWLE( p_peek + i_skip ); i_skip += 4;
+        i_packet_duration  = GetWLE( p_peek + i_skip ); i_skip += 2;
+    
+        i_packet_size_left = i_packet_length;   // XXX données reellement lu
+
+        if( b_packet_multiple_payload )
+        {
+            i_payload_count = p_peek[i_skip] & 0x3f;
+            i_payload_length_type = ( p_peek[i_skip] >> 6 )&0x03;
+            i_skip++;
+        }
+        else
+        {
+            i_payload_count = 1;
+            i_payload_length_type = 0x02; // unused
+        }
+
+        for( i_payload = 0; i_payload < i_payload_count ; i_payload++ )
+        {
+            asf_stream_t   *p_stream;
+
+            int i_stream_number;
+            int i_media_object_number;
+            int i_media_object_offset;
+            int i_replicated_data_length;
+            int i_payload_data_length;
+            int i_payload_data_pos;
+            int i_sub_payload_data_length;
+            int i_tmp;
+
+            mtime_t i_pts;
+            mtime_t i_pts_delta;
+
+            i_stream_number = p_peek[i_skip] & 0x7f; 
+            i_skip++;
+            
+            GETVALUE2b( ( i_packet_property >> 4 )&0x03, i_media_object_number, 0 );
+            GETVALUE2b( ( i_packet_property >> 2 )&0x03, i_tmp, 0 );
+            GETVALUE2b( i_packet_property&0x03, i_replicated_data_length, 0 );
+            
+            if( i_replicated_data_length > 1 ) // should be at least 8 bytes
+            {
+                i_pts = (mtime_t)GetDWLE( p_peek + i_skip + 4 ) * 1000;
+                i_skip += i_replicated_data_length;
+                i_pts_delta = 0;
+
+                i_media_object_offset = i_tmp;
+            }
+            else if( i_replicated_data_length == 1 )
+            {
+
+                msg_Warn( p_input, "found compressed payload" );
+
+                i_pts = (mtime_t)i_tmp * 1000;
+                i_pts_delta = (mtime_t)p_peek[i_skip] * 1000; i_skip++;
+
+                i_media_object_offset = 0;
+            }
+            else
+            {
+                i_pts = (mtime_t)i_packet_send_time * 1000;
+                i_pts_delta = 0;
+
+                i_media_object_offset = i_tmp;
+            }
+
+
+            if( b_packet_multiple_payload )
+            {
+                GETVALUE2b( i_payload_length_type, i_payload_data_length, 0 );
+            }
+            else
+            {
+                msg_Warn( p_input, "single payload" );
+                i_payload_data_length = i_packet_length - i_packet_padding_length - i_skip;
+            }
+            
+             msg_Dbg( p_input, 
+                      "payload(%d/%d) stream_number:%d media_object_number:%d media_object_offset:%d replicated_data_length:%d payload_data_length %d",
+                      i_payload + 1, 
+                      i_payload_count,
+                      i_stream_number,
+                      i_media_object_number, 
+                      i_media_object_offset, 
+                      i_replicated_data_length, 
+                      i_payload_data_length );
+           
+
+            if( !( p_stream = p_demux->stream[i_stream_number] ) )
+            {
+                msg_Warn( p_input, "undeclared stream[Id 0x%x]", i_stream_number );
+                i_skip += i_payload_data_length;
+                continue;   // over payload
+            }
+
+            if( !p_stream->p_es || !p_stream->p_es->p_decoder_fifo )
+            {
+                i_skip += i_payload_data_length;
+                continue;
+            }
+
+
+            for( i_payload_data_pos = 0; i_payload_data_pos < i_payload_data_length; i_payload_data_pos += i_sub_payload_data_length )
+            {
+                data_packet_t  *p_data;
+                int i_read;
+                // read sub payload length
+                if( i_replicated_data_length == 1 )
+                {
+                    i_sub_payload_data_length = p_peek[i_skip]; i_skip++;
+                    i_payload_data_pos++;
+                }
+                else
+                {
+                    i_sub_payload_data_length = i_payload_data_length;
+                }
+
+
+                if( p_stream->p_pes && i_media_object_offset == 0 ) // I don't use i_media_object_number, sould I ?
+                {
+                    // send complete packet to decoder
+                    if( p_stream->p_pes->i_pes_size > 0 )
+                    {
+                        input_DecodePES( p_stream->p_es->p_decoder_fifo, p_stream->p_pes );
+                        p_stream->p_pes = NULL;
+                    }
+                }
+
+                if( !p_stream->p_pes )  // add a new PES
+                {
+                    mtime_t i_date;
+                    p_stream->i_time = ( (mtime_t)i_pts + i_payload * (mtime_t)i_pts_delta );
+                    
+                    p_stream->p_pes = input_NewPES( p_input->p_method_data );
+                    p_stream->p_pes->i_dts = 
+                        p_stream->p_pes->i_pts = 
+                            input_ClockGetTS( p_input, 
+                                              p_input->stream.p_selected_program,
+                                              p_stream->i_time * 9 / 100 );
+
+                    p_stream->p_pes->p_next = NULL;
+                    p_stream->p_pes->i_nb_data = 0;
+                    p_stream->p_pes->i_pes_size = 0;
+                }
+
+                i_read = i_sub_payload_data_length + i_skip;
+                if( input_SplitBuffer( p_input, &p_data, i_read ) < i_read )
+                {
+                    msg_Err( p_input, "cannot read data" );
+                    return( 0 );
+                }
+                p_data->p_payload_start += i_skip;
+                i_packet_size_left -= i_read;
+
+                
+                if( !p_stream->p_pes->p_first )
+                {
+                    p_stream->p_pes->p_first = p_stream->p_pes->p_last = p_data;
+                }
+                else
+                {
+                    p_stream->p_pes->p_last->p_next = p_data;
+                    p_stream->p_pes->p_last = p_data;
+                }
+                p_stream->p_pes->i_pes_size += i_sub_payload_data_length;
+                p_stream->p_pes->i_nb_data++;
+
+                i_skip = 0;
+                if( i_packet_size_left <= 0 )
+                {
+                    break;
+                }
+                if( input_Peek( p_input, &p_peek, i_packet_size_left ) < i_packet_size_left )
+                {
+                    // EOF ?
+                    msg_Err( p_input, "cannot peek, EOF ?" );
+                    return( 0 );
+                }
+
+
+            }
+            if( i_packet_size_left <= 0 )
+            {
+                break;
+            }
+        }
+        
+loop_ok:
+        if( i_packet_size_left > 0 )
+        {
+            if( !ASF_SkipBytes( p_input, i_packet_size_left ) )
+            {
+                msg_Err( p_input, "cannot skip data, EOF ?" );
+                return( 0 );
+            }
+        }
+
+
+        continue;
+
+loop_error_recovery:
+        msg_Warn( p_input, "unsupported packet header" );
+        if( p_demux->p_fp->i_min_data_packet_size != p_demux->p_fp->i_max_data_packet_size )
+        {
+            msg_Err( p_input, "unsupported packet header, fatal error" );
+            return( -1 );
+        }
+        ASF_SkipBytes( p_input, i_data_packet_min );
+
+        continue;
+    }   // loop over packet
+    
+    p_demux->i_time = 0;
+    for( i = 0; i < 127 ; i++ )
+    {
+#define p_stream p_demux->stream[i]
+        if( p_stream && p_stream->p_es && p_stream->p_es->p_decoder_fifo )
+        {
+            p_demux->i_time = __MAX( p_demux->i_time, p_stream->i_time );
+        }
+#undef p_stream
+    }
+
+    return( 1 );
+}
+
+/*****************************************************************************
+ * MP4End: frees unused data
+ *****************************************************************************/
+static void Deactivate( vlc_object_t * p_this )
+{   
+#define FREE( p ) \
+    if( p ) { free( p ); } 
+   
+    input_thread_t *  p_input = (input_thread_t *)p_this;
+    demux_sys_t *p_demux = p_input->p_demux_data;
+    
+    msg_Dbg( p_input, "Freeing all memory" );
+    ASF_FreeObjectRoot( p_input, &p_demux->root );
+    
+#undef FREE
+}
+
diff --git a/modules/demux/asf/asf.h b/modules/demux/asf/asf.h
new file mode 100644 (file)
index 0000000..0504f7b
--- /dev/null
@@ -0,0 +1,50 @@
+/*****************************************************************************
+ * asf.h : ASFv01 file input module for vlc
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: asf.h,v 1.1 2002/10/20 17:22:33 fenrir Exp $
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+typedef struct asf_stream_s
+{
+    int i_cat;
+    es_descriptor_t *p_es;
+    asf_object_stream_properties_t *p_sp;
+
+    mtime_t i_time;
+
+    pes_packet_t    *p_pes; // used to keep uncomplete frames
+
+} asf_stream_t;
+
+struct demux_sys_t
+{
+
+    mtime_t             i_pcr;  // 1/90000 s
+    mtime_t             i_time; //  µs
+
+    asf_object_root_t   root;
+    asf_object_file_properties_t    *p_fp;
+    
+    int                 i_streams;
+    asf_stream_t        *stream[128];
+
+    off_t               i_data_begin;
+    off_t               i_data_end;
+    
+};
diff --git a/modules/demux/asf/libasf.c b/modules/demux/asf/libasf.c
new file mode 100644 (file)
index 0000000..93d0289
--- /dev/null
@@ -0,0 +1,941 @@
+/*****************************************************************************
+ * libasf.c : 
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: libasf.c,v 1.1 2002/10/20 17:22:33 fenrir Exp $
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>                                              /* strdup() */
+#include <errno.h>
+#include <sys/types.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include "libasf.h"
+
+#define ASF_DEBUG 1
+
+#define FREE( p ) \
+    if( p ) {free( p ); p = NULL; }
+   
+#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"
+#define GUID_PRINT( guid )  \
+    (guid).v1,              \
+    (guid).v2,              \
+    (guid).v3,              \
+    (guid).v4[0],(guid).v4[1],(guid).v4[2],(guid).v4[3],    \
+    (guid).v4[4],(guid).v4[5],(guid).v4[6],(guid).v4[7]
+
+/* Some functions to manipulate memory */
+static u16 GetWLE( u8 *p_buff )
+{
+    return( (p_buff[0]) + ( p_buff[1] <<8 ) );
+}
+
+static u32 GetDWLE( u8 *p_buff )
+{
+    return( p_buff[0] + ( p_buff[1] <<8 ) +
+            ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
+}
+
+static u64 GetQWLE( u8 *p_buff )
+{
+    return( ( (u64)GetDWLE( p_buff ) )|( (u64)GetDWLE( p_buff + 4 ) << 32) );
+}
+
+void GetGUID( guid_t *p_guid, u8 *p_data )
+{
+    p_guid->v1 = GetDWLE( p_data );
+    p_guid->v2 = GetWLE( p_data + 4);
+    p_guid->v3 = GetWLE( p_data + 6);
+    memcpy( p_guid->v4, p_data + 8, 8 );
+}
+
+int CmpGUID( const guid_t *p_guid1, const guid_t *p_guid2 )
+{
+    if( (p_guid1->v1 != p_guid2->v1 )||(p_guid1->v2 != p_guid2->v2 )||
+        (p_guid1->v3 != p_guid2->v3 )||
+        ( memcmp( p_guid1->v4, p_guid2->v4,8 )) )
+    {
+        return( 0 );
+    }
+    else
+    {
+        return( 1 ); /* match */
+    }
+}
+/*****************************************************************************
+ * Some basic functions to manipulate stream more easily in vlc
+ *
+ * ASF_TellAbsolute get file position
+ * 
+ * ASF_SeekAbsolute seek in the file
+ *
+ * ASF_ReadData read data from the file in a buffer
+ *
+ *****************************************************************************/
+off_t ASF_TellAbsolute( input_thread_t *p_input )
+{
+    off_t i_pos;
+    
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    
+    i_pos= p_input->stream.p_selected_area->i_tell -
+            ( p_input->p_last_data - p_input->p_current_data  );
+
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    return( i_pos );
+}
+int ASF_SeekAbsolute( input_thread_t *p_input,
+                      off_t i_pos)
+{
+    off_t i_filepos;
+
+    if( i_pos >= p_input->stream.p_selected_area->i_size )
+    {
+        return( 0 );
+    }
+            
+    i_filepos = ASF_TellAbsolute( p_input );
+    if( i_pos != i_filepos )
+    {
+        p_input->pf_seek( p_input, i_pos );
+        input_AccessReinit( p_input );
+    }
+    return( 1 );
+}
+
+/* return 1 if success, 0 if fail */
+int ASF_ReadData( input_thread_t *p_input, u8 *p_buff, int i_size )
+{
+    data_packet_t *p_data;
+
+    int i_read;
+
+                
+    if( !i_size )
+    {
+        return( 1 );
+    }
+
+    do
+    {
+        i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size, 1024 ) );
+        if( i_read <= 0 )
+        {
+            return( 0 );
+        }
+        memcpy( p_buff, p_data->p_payload_start, i_read );
+        input_DeletePacket( p_input->p_method_data, p_data );
+        
+        p_buff += i_read;
+        i_size -= i_read;
+                
+    } while( i_size );
+    
+    return( 1 );
+}
+
+int  ASF_SkipBytes( input_thread_t *p_input, int i_count )
+{
+    return( ASF_SeekAbsolute( p_input, 
+                              ASF_TellAbsolute( p_input ) + i_count ) );
+}
+
+/****************************************************************************/
+int  ASF_ReadObjectCommon( input_thread_t *p_input, 
+                           asf_object_t *p_obj )
+{
+    asf_object_common_t *p_common = (asf_object_common_t*)p_obj;
+    u8  *p_peek;
+
+    if( input_Peek( p_input, &p_peek, 24 ) < 24 )
+    {
+        return( 0 );
+    }
+    GetGUID( &p_common->i_object_id, p_peek ); 
+    p_common->i_object_size = GetQWLE( p_peek + 16 );
+    p_common->i_object_pos = ASF_TellAbsolute( p_input );
+    p_common->p_next = NULL;
+#ifdef ASF_DEBUG
+    msg_Dbg(p_input,
+            "Found Object guid: " GUID_FMT " size:%lld",
+            GUID_PRINT( p_common->i_object_id ),
+            p_common->i_object_size );
+#endif
+    
+    return( 1 ); 
+}
+
+int ASF_NextObject( input_thread_t *p_input,
+                    asf_object_t *p_obj )
+{
+    asf_object_t obj;
+    if( !p_obj )
+    {
+        if( !ASF_ReadObjectCommon( p_input, &obj ) )
+        {
+            return( 0 );
+        }
+        p_obj = &obj;
+    }
+
+    if( !p_obj->common.i_object_size )
+    {
+        return( 0 ); /* failed */
+    }
+    if( p_obj->common.p_father )
+    {
+        if( p_obj->common.p_father->common.i_object_pos + p_obj->common.p_father->common.i_object_size <
+                p_obj->common.i_object_pos + p_obj->common.i_object_size + 24 )  
+                                /* 24 is min size of an object */
+        {
+            return( 0 );
+        }
+
+    }
+    return( ASF_SeekAbsolute( p_input, 
+                              p_obj->common.i_object_pos + p_obj->common.i_object_size ) );
+}
+
+int  ASF_GotoObject( input_thread_t *p_input,
+                     asf_object_t *p_obj )
+{
+    if( !p_obj )
+    {
+        return( 0 );
+    }
+    return( ASF_SeekAbsolute( p_input, p_obj->common.i_object_pos ) );
+}
+
+
+void ASF_FreeObject_Null( input_thread_t *p_input,
+                            asf_object_t *pp_obj )
+{
+
+
+}
+
+int  ASF_ReadObject_Header( input_thread_t *p_input,
+                            asf_object_t *p_obj )
+{
+    asf_object_header_t *p_hdr = (asf_object_header_t*)p_obj;
+    asf_object_t *p_subobj;
+    int i_peek;
+    u8  *p_peek;
+    
+    if( ( i_peek = input_Peek( p_input, &p_peek, 30 ) ) < 30 )
+    {
+       return( 0 );
+    }
+    p_hdr->i_sub_object_count = GetDWLE( p_peek + 24 );
+    p_hdr->i_reserved1 = p_peek[28];
+    p_hdr->i_reserved2 = p_peek[29];
+    p_hdr->p_first = NULL;
+    p_hdr->p_last  = NULL;
+#ifdef ASF_DEBUG
+    msg_Dbg(p_input,
+            "Read \"Header Object\" subobj:%d, reserved1:%d, reserved2:%d",
+            p_hdr->i_sub_object_count,
+            p_hdr->i_reserved1,
+            p_hdr->i_reserved2 );
+#endif
+    ASF_SkipBytes( p_input, 30 );
+    /* Now load sub object */
+    for( ; ; )
+    {
+        p_subobj  = malloc( sizeof( asf_object_t ) );
+
+        if( !( ASF_ReadObject( p_input, p_subobj, (asf_object_t*)p_hdr ) ) )
+        {
+            break; 
+        }
+        if( !ASF_NextObject( p_input, p_subobj ) ) /* Go to the next object */
+        {
+            break;
+        }
+    }
+    return( 1 );
+}
+
+int  ASF_ReadObject_Data( input_thread_t *p_input,
+                          asf_object_t *p_obj )
+{
+    asf_object_data_t *p_data = (asf_object_data_t*)p_obj;
+    int i_peek;
+    u8  *p_peek;
+    
+    if( ( i_peek = input_Peek( p_input, &p_peek, 50 ) ) < 50 )
+    {
+       return( 0 );
+    }
+    GetGUID( &p_data->i_file_id, p_peek + 24 );
+    p_data->i_total_data_packets = GetQWLE( p_peek + 40 );
+    p_data->i_reserved = GetWLE( p_peek + 48 );
+#ifdef ASF_DEBUG
+    msg_Dbg( p_input,
+            "Read \"Data Object\" file_id:" GUID_FMT " total data packet:%lld reserved:%d",
+            GUID_PRINT( p_data->i_file_id ),
+            p_data->i_total_data_packets,
+            p_data->i_reserved );
+#endif
+    return( 1 );
+}
+
+int  ASF_ReadObject_Index( input_thread_t *p_input,
+                           asf_object_t *p_obj )
+{
+    asf_object_index_t *p_index = (asf_object_index_t*)p_obj;
+    int i_peek;
+    u8  *p_peek;
+    
+    if( ( i_peek = input_Peek( p_input, &p_peek, 56 ) ) < 56 )
+    {
+       return( 0 );
+    }
+    GetGUID( &p_index->i_file_id, p_peek + 24 );
+    p_index->i_index_entry_time_interval = GetQWLE( p_peek + 40 );
+    p_index->i_max_packet_count = GetDWLE( p_peek + 48 );
+    p_index->i_index_entry_count = GetDWLE( p_peek + 52 );
+    p_index->index_entry = NULL; /* FIXME */
+
+#ifdef ASF_DEBUG
+    msg_Dbg( p_input,
+            "Read \"Index Object\" file_id:" GUID_FMT " index_entry_time_interval:%lld max_packet_count:%d index_entry_count:%d",
+            GUID_PRINT( p_index->i_file_id ),
+            p_index->i_max_packet_count,
+            p_index->i_index_entry_count );
+#endif
+    return( 1 );
+}
+void ASF_FreeObject_Index( input_thread_t *p_input,
+                          asf_object_t *p_obj )
+{
+    asf_object_index_t *p_index = (asf_object_index_t*)p_obj;
+
+    FREE( p_index->index_entry );
+}
+
+int  ASF_ReadObject_file_properties( input_thread_t *p_input,
+                                     asf_object_t *p_obj )
+{
+    asf_object_file_properties_t *p_fp = (asf_object_file_properties_t*)p_obj;
+    int i_peek;
+    u8  *p_peek;
+    
+    if( ( i_peek = input_Peek( p_input, &p_peek,  92) ) < 92 )
+    {
+       return( 0 );
+    }
+    GetGUID( &p_fp->i_file_id, p_peek + 24 );
+    p_fp->i_file_size = GetQWLE( p_peek + 40 );
+    p_fp->i_creation_date = GetQWLE( p_peek + 48 );
+    p_fp->i_data_packets_count = GetQWLE( p_peek + 56 );
+    p_fp->i_play_duration = GetQWLE( p_peek + 64 );
+    p_fp->i_send_duration = GetQWLE( p_peek + 72 );
+    p_fp->i_preroll = GetQWLE( p_peek + 80 );
+    p_fp->i_flags = GetDWLE( p_peek + 88 );
+    p_fp->i_min_data_packet_size = GetDWLE( p_peek + 92 );
+    p_fp->i_max_data_packet_size = GetDWLE( p_peek + 96 );
+    p_fp->i_max_bitrate = GetDWLE( p_peek + 100 );
+        
+#ifdef ASF_DEBUG
+    msg_Dbg( p_input,
+            "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",
+            GUID_PRINT( p_fp->i_file_id ),
+            p_fp->i_file_size,
+            p_fp->i_creation_date,
+            p_fp->i_data_packets_count,
+            p_fp->i_play_duration,
+            p_fp->i_send_duration,
+            p_fp->i_preroll,
+            p_fp->i_flags,
+            p_fp->i_min_data_packet_size,
+            p_fp->i_max_data_packet_size,
+            p_fp->i_max_bitrate );
+#endif
+    return( 1 );
+}
+
+int  ASF_ReadObject_header_extention( input_thread_t *p_input,
+                                      asf_object_t *p_obj )
+{
+    asf_object_header_extention_t *p_he = (asf_object_header_extention_t*)p_obj;
+    int i_peek;
+    u8  *p_peek;
+    
+    if( ( i_peek = input_Peek( p_input, &p_peek, p_he->i_object_size ) ) <  46)
+    {
+       return( 0 );
+    }
+    GetGUID( &p_he->i_reserved1, p_peek + 24 );
+    p_he->i_reserved2 = GetWLE( p_peek + 40 );
+    p_he->i_header_extention_size = GetDWLE( p_peek + 42 );
+    if( p_he->i_header_extention_size )
+    {
+        p_he->p_header_extention_data = malloc( p_he->i_header_extention_size );
+        memcpy( p_he->p_header_extention_data,
+                p_peek + 46,
+                p_he->i_header_extention_size );
+    }
+    else
+    {
+        p_he->p_header_extention_data = NULL;
+    }
+#ifdef ASF_DEBUG
+    msg_Dbg( p_input,
+            "Read \"Header Extention Object\" reserved1:" GUID_FMT " reserved2:%d header_extention_size:%d",
+            GUID_PRINT( p_he->i_reserved1 ),
+            p_he->i_reserved2,
+            p_he->i_header_extention_size );
+#endif 
+    return( 1 );
+}
+void ASF_FreeObject_header_extention( input_thread_t *p_input,
+                                      asf_object_t *p_obj )
+{
+    asf_object_header_extention_t *p_he = (asf_object_header_extention_t*)p_obj;
+
+    FREE( p_he->p_header_extention_data );
+}
+
+int  ASF_ReadObject_stream_properties( input_thread_t *p_input,
+                                       asf_object_t *p_obj )
+{
+    asf_object_stream_properties_t *p_sp = 
+                    (asf_object_stream_properties_t*)p_obj;
+    int i_peek;
+    u8  *p_peek;
+    
+    if( ( i_peek = input_Peek( p_input, &p_peek,  p_sp->i_object_size ) ) < 74 )
+    {
+       return( 0 );
+    }
+    GetGUID( &p_sp->i_stream_type, p_peek + 24 );
+    GetGUID( &p_sp->i_error_correction_type, p_peek + 40 );
+    p_sp->i_time_offset = GetQWLE( p_peek + 56 );
+    p_sp->i_type_specific_data_length = GetDWLE( p_peek + 64 );
+    p_sp->i_error_correction_data_length = GetDWLE( p_peek + 68 );
+    p_sp->i_flags = GetWLE( p_peek + 72 );
+        p_sp->i_stream_number = p_sp->i_flags&0x07f;
+    p_sp->i_reserved = GetDWLE( p_peek + 74 );
+    if( p_sp->i_type_specific_data_length )
+    {
+        p_sp->p_type_specific_data = malloc( p_sp->i_type_specific_data_length );
+        memcpy( p_sp->p_type_specific_data,
+                p_peek + 78,
+                p_sp->i_type_specific_data_length );
+    }
+    else
+    {
+        p_sp->p_type_specific_data = NULL;
+    }
+    if( p_sp->i_error_correction_data_length )
+    {
+        p_sp->p_error_correction_data = malloc( p_sp->i_error_correction_data_length );
+        memcpy( p_sp->p_error_correction_data,
+                p_peek + 78 + p_sp->i_type_specific_data_length,
+                p_sp->i_error_correction_data_length );
+    }
+    else
+    {
+        p_sp->p_error_correction_data = NULL;
+    }
+
+#ifdef ASF_DEBUG
+    msg_Dbg( p_input,
+            "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",
+            GUID_PRINT( p_sp->i_stream_type ),
+            GUID_PRINT( p_sp->i_error_correction_type ),
+            p_sp->i_time_offset,
+            p_sp->i_type_specific_data_length,
+            p_sp->i_error_correction_data_length,
+            p_sp->i_flags,
+            p_sp->i_stream_number );
+
+#endif
+    return( 1 );
+}
+
+void ASF_FreeObject_stream_properties( input_thread_t *p_input,
+                                      asf_object_t *p_obj )
+{
+    asf_object_stream_properties_t *p_sp = 
+                (asf_object_stream_properties_t*)p_obj;
+
+    FREE( p_sp->p_type_specific_data );
+    FREE( p_sp->p_error_correction_data );
+}
+
+
+int  ASF_ReadObject_codec_list( input_thread_t *p_input,
+                                asf_object_t *p_obj )
+{
+    asf_object_codec_list_t *p_cl = (asf_object_codec_list_t*)p_obj;
+    int i_peek;
+    u8  *p_peek, *p_data;
+
+    int i_codec;
+    
+    if( ( i_peek = input_Peek( p_input, &p_peek, p_cl->i_object_size ) ) < 44 )
+    {
+       return( 0 );
+    }
+
+    GetGUID( &p_cl->i_reserved, p_peek + 24 );
+    p_cl->i_codec_entries_count = GetWLE( p_peek + 40 );
+    if( p_cl->i_codec_entries_count > 0 )
+    {
+
+        p_cl->codec = calloc( p_cl->i_codec_entries_count, sizeof( asf_codec_entry_t ) );
+        memset( p_cl->codec, 0, p_cl->i_codec_entries_count * sizeof( asf_codec_entry_t ) );
+
+        p_data = p_peek + 44;
+        for( i_codec = 0; i_codec < p_cl->i_codec_entries_count; i_codec++ )
+        {
+#define codec p_cl->codec[i_codec]
+            int i_len, i;
+
+            codec.i_type = GetWLE( p_data ); p_data += 2;
+            /* codec name */
+            i_len = GetWLE( p_data ); p_data += 2;
+            codec.psz_name = calloc( sizeof( char ), i_len + 1);
+            for( i = 0; i < i_len; i++ )
+            {
+                codec.psz_name[i] = GetWLE( p_data + 2*i );
+            }
+            codec.psz_name[i_len] = '\0';
+            p_data += 2 * i_len;
+
+            /* description */
+            i_len = GetWLE( p_data ); p_data += 2;
+            codec.psz_description = calloc( sizeof( char ), i_len + 1);
+            for( i = 0; i < i_len; i++ )
+            {
+                codec.psz_description[i] = GetWLE( p_data + 2*i );
+            }
+            codec.psz_description[i_len] = '\0';
+            p_data += 2 * i_len;
+            
+            /* opaque information */
+            codec.i_information_length = GetWLE( p_data ); p_data += 2;
+            if( codec.i_information_length > 0 )
+            {
+                codec.p_information = malloc( codec.i_information_length );
+                memcpy( codec.p_information, p_data, codec.i_information_length );
+                p_data += codec.i_information_length;
+            }
+            else
+            {
+                codec.p_information = NULL;
+            }
+#undef  codec
+        }
+
+    }
+    else
+    {
+        p_cl->codec = NULL;
+    }
+
+#ifdef ASF_DEBUG
+    msg_Dbg( p_input,
+            "Read \"Codec List Object\" reserved_guid:" GUID_FMT " codec_entries_count:%d",
+            GUID_PRINT( p_cl->i_reserved ),
+            p_cl->i_codec_entries_count );
+    for( i_codec = 0; i_codec < p_cl->i_codec_entries_count; i_codec++ )
+    {
+#define codec p_cl->codec[i_codec]
+         msg_Dbg( p_input,
+                 "Read \"Codec List Object\" codec[%d] %s name:\"%s\" description:\"%s\" information_length:%d",
+                 i_codec,
+                 ( codec.i_type == ASF_CODEC_TYPE_VIDEO ) ? "video" : ( ( codec.i_type == ASF_CODEC_TYPE_AUDIO ) ? "audio" : "unknown" ),
+                 codec.psz_name, 
+                 codec.psz_description, 
+                 codec.i_information_length );
+       
+#undef  codec
+    }
+#endif
+    return( 1 );
+}
+void ASF_FreeObject_codec_list( input_thread_t *p_input,
+                                asf_object_t *p_obj )
+{
+    asf_object_codec_list_t *p_cl = (asf_object_codec_list_t*)p_obj;
+    int i_codec;
+
+    for( i_codec = 0; i_codec < p_cl->i_codec_entries_count; i_codec++ )
+    {
+#define codec p_cl->codec[i_codec]
+        FREE( codec.psz_name );
+        FREE( codec.psz_description );
+        FREE( codec.p_information );
+
+#undef  codec
+    }
+    FREE( p_cl->codec );
+}
+
+/* Microsoft should qo to hell. This time the length give number of bytes
+ * and for the some others object, length give char16 count ... */
+int  ASF_ReadObject_content_description( input_thread_t *p_input,
+                                         asf_object_t *p_obj )
+{
+    asf_object_content_description_t *p_cd = (asf_object_content_description_t*)p_obj;
+    int i_peek;
+    u8  *p_peek, *p_data;
+
+    int i_len;
+    int i_title;
+    int i_author;
+    int i_copyright;
+    int i_description;
+    int i_rating;
+    
+#define GETSTRINGW( psz_str, i_size ) \
+   psz_str = calloc( i_size/2 + 1, sizeof( char ) ); \
+   for( i_len = 0; i_len < i_size/2; i_len++ ) \
+   { \
+       psz_str[i_len] = GetWLE( p_data + 2*i_len ); \
+   } \
+   psz_str[i_size/2] = '\0'; \
+   p_data += i_size;
+   
+    if( ( i_peek = input_Peek( p_input, &p_peek, p_cd->i_object_size ) ) < 34 )
+    {
+       return( 0 );
+    }
+    p_data = p_peek + 24;
+
+    i_title = GetWLE( p_data ); p_data += 2;
+    i_author= GetWLE( p_data ); p_data += 2;
+    i_copyright     = GetWLE( p_data ); p_data += 2;
+    i_description   = GetWLE( p_data ); p_data += 2;
+    i_rating        = GetWLE( p_data ); p_data += 2;
+
+    GETSTRINGW( p_cd->psz_title, i_title );
+    GETSTRINGW( p_cd->psz_author, i_author );
+    GETSTRINGW( p_cd->psz_copyright, i_copyright );
+    GETSTRINGW( p_cd->psz_description, i_description );
+    GETSTRINGW( p_cd->psz_rating, i_rating );
+
+#undef  GETSTRINGW
+
+#ifdef ASF_DEBUG
+    msg_Dbg( p_input,
+             "Read \"Content Description Object\" title:\"%s\" author:\"%s\" copyright:\"%s\" description:\"%s\" rating:\"%s\"",
+             p_cd->psz_title,
+             p_cd->psz_author,
+             p_cd->psz_copyright,
+             p_cd->psz_description,
+             p_cd->psz_rating );
+#endif 
+    return( 1 );
+}
+
+void ASF_FreeObject_content_description( input_thread_t *p_input,
+                                         asf_object_t *p_obj )
+{
+    asf_object_content_description_t *p_cd = (asf_object_content_description_t*)p_obj;
+    
+    FREE( p_cd->psz_title );
+    FREE( p_cd->psz_author );
+    FREE( p_cd->psz_copyright );
+    FREE( p_cd->psz_description );
+    FREE( p_cd->psz_rating );
+}
+
+static struct
+{
+    const guid_t  *p_id;
+    int     i_type;
+    int     (*ASF_ReadObject_function)( input_thread_t *p_input, 
+                                        asf_object_t *p_obj );
+    void    (*ASF_FreeObject_function)( input_thread_t *p_input,
+                                        asf_object_t *p_obj );
+} ASF_Object_Function [] =
+{
+    { &asf_object_header_guid,            ASF_OBJECT_TYPE_HEADER,             ASF_ReadObject_Header, ASF_FreeObject_Null },
+    { &asf_object_data_guid,              ASF_OBJECT_TYPE_DATA,               ASF_ReadObject_Data,   ASF_FreeObject_Null },
+    { &asf_object_index_guid,             ASF_OBJECT_TYPE_INDEX,              ASF_ReadObject_Index,  ASF_FreeObject_Index },
+    { &asf_object_file_properties_guid,   ASF_OBJECT_TYPE_FILE_PROPERTIES,    ASF_ReadObject_file_properties,  ASF_FreeObject_Null },
+    { &asf_object_stream_properties_guid, ASF_OBJECT_TYPE_STREAM_PROPERTIES,  ASF_ReadObject_stream_properties,ASF_FreeObject_stream_properties },
+    { &asf_object_header_extention_guid,  ASF_OBJECT_TYPE_EXTENTION_HEADER,   ASF_ReadObject_header_extention, ASF_FreeObject_header_extention},
+    { &asf_object_codec_list_guid,        ASF_OBJECT_TYPE_CODEC_LIST,         ASF_ReadObject_codec_list,       ASF_FreeObject_codec_list },
+    { &asf_object_marker_guid,            ASF_OBJECT_TYPE_MARKER,             NULL,                  NULL },
+    { &asf_object_content_description_guid, ASF_OBJECT_TYPE_CONTENT_DESCRIPTION, ASF_ReadObject_content_description, ASF_FreeObject_content_description },
+
+    { &asf_object_null_guid,   0,                      NULL,                  NULL }
+};
+
+int  ASF_ReadObject( input_thread_t *p_input,
+                     asf_object_t *p_obj,
+                     asf_object_t *p_father )
+{
+    int i_result;
+    int i_index;
+
+    if( !p_obj )
+    {
+        return( 0 );
+    }
+    if( !ASF_ReadObjectCommon( p_input, p_obj ) )
+    {
+        msg_Warn( p_input, "Cannot read one asf object" );
+        return( 0 );
+    }
+    p_obj->common.p_father = p_father;
+    p_obj->common.p_first = NULL;
+    p_obj->common.p_next = NULL;
+    p_obj->common.p_last = NULL;
+    
+
+    if( p_obj->common.i_object_size < 24 )
+    {
+        msg_Warn( p_input, "Found a corrupted asf object (size<24)" );
+        return( 0 );
+    }
+    /* find this object */
+    for( i_index = 0; ; i_index++ )
+    {
+        if( CmpGUID( ASF_Object_Function[i_index].p_id,
+                     &p_obj->common.i_object_id )||
+            CmpGUID( ASF_Object_Function[i_index].p_id,
+                     &asf_object_null_guid ) )
+        {
+            break;
+        }
+    }
+    p_obj->common.i_type = ASF_Object_Function[i_index].i_type;
+
+    /* Now load this object */
+    if( ASF_Object_Function[i_index].ASF_ReadObject_function == NULL )
+    {
+        msg_Warn( p_input, "Unknown asf object (not loaded)" );
+        i_result = 1;
+    }
+    else
+    {
+        /* XXX ASF_ReadObject_function realloc *pp_obj XXX */
+        i_result =  
+            (ASF_Object_Function[i_index].ASF_ReadObject_function)( p_input,
+                                                                    p_obj );
+    }
+    
+    /* link this object with father */
+    if( p_father )
+    {
+        if( p_father->common.p_first )
+        {
+            p_father->common.p_last->common.p_next = p_obj;
+        }
+        else
+        {
+            p_father->common.p_first = p_obj;
+        }
+        p_father->common.p_last = p_obj;
+    }
+
+    return( i_result );
+}
+
+void ASF_FreeObject( input_thread_t *p_input,
+                     asf_object_t *p_obj )
+{
+    int i_index;
+    asf_object_t *p_child;
+    
+    if( !p_obj )
+    {
+        return;
+    }
+    
+    /* Free all child object */
+    p_child = p_obj->common.p_first;
+    while( p_child )
+    {
+        asf_object_t *p_next;
+        p_next = p_child->common.p_next;
+        ASF_FreeObject( p_input, p_child );
+        p_child = p_next;
+    }
+
+    /* find this object */
+    for( i_index = 0; ; i_index++ )
+    {
+        if( CmpGUID( ASF_Object_Function[i_index].p_id,
+                     &p_obj->common.i_object_id )||
+            CmpGUID( ASF_Object_Function[i_index].p_id,
+                     &asf_object_null_guid ) )
+        {
+            break;
+        }
+    }
+
+    /* Now free this object */
+    if( ASF_Object_Function[i_index].ASF_FreeObject_function == NULL )
+    {
+        msg_Warn( p_input, 
+                  "Unknown asf object " GUID_FMT,
+                  GUID_PRINT( p_obj->common.i_object_id ) );
+    }
+    else
+    {
+#ifdef ASF_DEBUG
+        msg_Dbg( p_input, 
+                  "Free asf object " GUID_FMT,
+                  GUID_PRINT( p_obj->common.i_object_id ) );
+#endif
+        (ASF_Object_Function[i_index].ASF_FreeObject_function)( p_input,
+                                                                p_obj );
+    }
+    free( p_obj );
+    return;
+}
+
+/*****************************************************************************
+ * ASF_ReadObjetRoot : parse the entire stream/file
+ *****************************************************************************/
+int ASF_ReadObjectRoot( input_thread_t *p_input,
+                        asf_object_root_t *p_root,
+                        int b_seekable )
+{
+    asf_object_t *p_obj;
+
+    p_root->i_type = ASF_OBJECT_TYPE_ROOT;
+    memcpy( &p_root->i_object_id, &asf_object_null_guid, sizeof( guid_t ) );
+    p_root->i_object_pos = 0;
+    p_root->i_object_size = p_input->stream.p_selected_area->i_size;
+    p_root->p_first = NULL;
+    p_root->p_last = NULL;
+    p_root->p_next = NULL;
+    p_root->p_hdr = NULL;
+    p_root->p_data = NULL;
+    p_root->p_index = NULL;
+   
+    for( ; ; )
+    {
+        p_obj  = malloc( sizeof( asf_object_t ) );
+
+        if( !( ASF_ReadObject( p_input, p_obj, (asf_object_t*)p_root ) ) )
+        {
+            return( 1 );
+        }
+        switch( p_obj->common.i_type )
+        {
+            case( ASF_OBJECT_TYPE_HEADER ):
+                p_root->p_hdr = (asf_object_header_t*)p_obj;
+                break;
+            case( ASF_OBJECT_TYPE_DATA ):
+                p_root->p_data = (asf_object_data_t*)p_obj;
+                break;
+            case( ASF_OBJECT_TYPE_INDEX ):
+                p_root->p_index = (asf_object_index_t*)p_obj;
+                break;
+            default:
+                msg_Warn( p_input, "Unknow Object found" );
+                break;
+        }
+        if( !b_seekable && ( p_root->p_hdr && p_root->p_data ) )
+        {
+            /* For unseekable stream it's enouth to play */
+            return( 1 );
+        }
+
+        if( !ASF_NextObject( p_input, p_obj ) ) /* Go to the next object */
+        {
+            return( 1 );
+        }
+    }
+}
+
+void ASF_FreeObjectRoot( input_thread_t *p_input,
+                         asf_object_root_t *p_root )
+{
+    asf_object_t *p_obj;
+    
+    p_obj = p_root->p_first;
+    while( p_obj )
+    {
+        asf_object_t *p_next;
+        p_next = p_obj->common.p_next;
+        ASF_FreeObject( p_input, p_obj );
+        p_obj = p_next;
+    }
+    p_root->p_first = NULL;
+    p_root->p_last = NULL;
+    p_root->p_next = NULL;
+
+    p_root->p_hdr = NULL;
+    p_root->p_data = NULL;
+    p_root->p_index = NULL;
+    
+}
+
+int  ASF_CountObject( asf_object_t *p_obj, const guid_t *p_guid )
+{
+    int i_count;
+    asf_object_t *p_child;
+
+    if( !p_obj )
+    {
+        return( 0 );
+    }
+
+    i_count = 0;
+    p_child = p_obj->common.p_first;
+    while( p_child )
+    {
+        if( CmpGUID( &p_child->common.i_object_id, p_guid ) )
+        {
+            i_count++;
+        }
+        p_child = p_child->common.p_next;
+    }
+    return( i_count );
+}
+
+asf_object_t *ASF_FindObject( asf_object_t *p_obj, const guid_t *p_guid, int i_number )
+{
+    asf_object_t *p_child;
+
+    p_child = p_obj->common.p_first;
+
+    while( p_child )
+    {
+        if( CmpGUID( &p_child->common.i_object_id, p_guid ) )
+        {
+            if( i_number == 0 )
+            {
+                /* We found it */
+                return( p_child );
+            }
+
+            i_number--;
+        }
+        p_child = p_child->common.p_next;
+    }
+    return( NULL );
+}
+
+
diff --git a/modules/demux/asf/libasf.h b/modules/demux/asf/libasf.h
new file mode 100644 (file)
index 0000000..67b2019
--- /dev/null
@@ -0,0 +1,447 @@
+/*****************************************************************************
+ * libasf.h : 
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: libasf.h,v 1.1 2002/10/20 17:22:33 fenrir Exp $
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Structure needed for decoder
+ *****************************************************************************/
+typedef struct bitmapinfoheader_s
+{
+    u32 i_size; /* size of header 40 + size of data follwoing this header */
+    u32 i_width;
+    u32 i_height;
+    u16 i_planes;
+    u16 i_bitcount;
+    u32 i_compression;
+    u32 i_sizeimage;
+    u32 i_xpelspermeter;
+    u32 i_ypelspermeter;
+    u32 i_clrused;
+    u32 i_clrimportant;
+} bitmapinfoheader_t;
+
+typedef struct waveformatex_s
+{
+    u16 i_format;
+    u16 i_channels;
+    u32 i_samplepersec;
+    u32 i_avgbytespersec;
+    u16 i_blockalign;
+    u16 i_bitspersample;
+    u16 i_size;          /* This give size of data 
+                            imediatly following this header. */
+} waveformatex_t;
+
+typedef struct guid_s
+{
+    u32 v1; /* le */
+    u16 v2; /* le */
+    u16 v3; /* le */
+    u8  v4[8];
+} guid_t;
+
+#define ASF_OBJECT_TYPE_NULL      0x0000
+#define ASF_OBJECT_TYPE_ROOT      0x0001
+#define ASF_OBJECT_TYPE_HEADER    0x0002
+#define ASF_OBJECT_TYPE_DATA      0x0003
+#define ASF_OBJECT_TYPE_INDEX     0x0004
+#define ASF_OBJECT_TYPE_FILE_PROPERTIES     0x0005
+#define ASF_OBJECT_TYPE_STREAM_PROPERTIES   0x0006
+#define ASF_OBJECT_TYPE_EXTENTION_HEADER    0x0007
+#define ASF_OBJECT_TYPE_CODEC_LIST          0x0008
+#define ASF_OBJECT_TYPE_MARKER              0x0009
+#define ASF_OBJECT_TYPE_CONTENT_DESCRIPTION 0x000a
+
+static const guid_t asf_object_null_guid =
+{
+    0x00000000,
+    0x0000,
+    0x0000,
+    { 0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00 }
+};
+
+static const guid_t asf_object_header_guid = 
+{
+    0x75B22630,
+    0x668E,
+    0x11CF,
+    { 0xA6,0xD9, 0x00,0xAA,0x00,0x62,0xCE,0x6C }
+};
+
+static const guid_t asf_object_data_guid = 
+{
+    0x75B22636,
+    0x668E,
+    0x11CF,
+    { 0xA6,0xD9, 0x00,0xAA,0x00,0x62,0xCE,0x6C }
+};
+
+
+
+static const guid_t asf_object_index_guid =
+{
+    0x33000890,
+    0xE5B1,
+    0x11CF,
+    { 0x89,0xF4, 0x00,0xA0,0xC9,0x03,0x49,0xCB }
+};
+
+static const guid_t asf_object_file_properties_guid =
+{
+    0x8cabdca1,
+    0xa947,
+    0x11cf,
+    { 0x8e,0xe4, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
+
+};
+static const guid_t asf_object_stream_properties_guid =
+{
+    0xB7DC0791,
+    0xA9B7,
+    0x11CF,
+    { 0x8E,0xE6, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
+
+};
+
+static const guid_t asf_object_content_description_guid =
+{
+    0x75B22633,
+    0x668E,
+    0x11CF,
+    { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }
+};
+
+static const guid_t asf_object_header_extention_guid = 
+{
+   0x5FBF03B5,
+   0xA92E,
+   0x11CF,
+   { 0x8E,0xE3, 0x00,0xC0,0x0C,0x20,0x53,0x65 } 
+};
+
+static const guid_t asf_object_codec_list_guid =
+{
+    0x86D15240,
+    0x311D,
+    0x11D0,
+    { 0xA3,0xA4, 0x00,0xA0,0xC9,0x03,0x48,0xF6 }
+};
+
+static const guid_t asf_object_marker_guid =
+{
+    0xF487CD01,
+    0xA951,
+    0x11CF,
+    { 0x8E,0xE6, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
+
+};
+
+static const guid_t asf_object_stream_type_audio =
+{
+    0xF8699E40,
+    0x5B4D,
+    0x11CF,
+    { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
+};
+
+static const guid_t asf_object_stream_type_video =
+{
+    0xbc19efc0,
+    0x5B4D,
+    0x11CF,
+    { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
+};
+
+static const guid_t asf_object_stream_type_command =
+{
+    0x59DACFC0,
+    0x59E6,
+    0x11D0,
+    { 0xA3,0xAC, 0x00,0xA0,0xC9,0x03,0x48,0xF6 }
+};
+
+#if 0
+static const guid_t asf_object_
+{
+
+
+};
+#endif
+#if 0
+typedef struct asf_packet_s
+{
+    int i_stream_number;
+
+    int i_payload_size;
+    u8  *p_payload_data;
+    
+} asf_packet_t;
+#endif
+
+#define ASF_OBJECT_COMMON           \
+    int          i_type;            \
+    guid_t       i_object_id;       \
+    u64          i_object_size;     \
+    u64          i_object_pos;      \
+    union asf_object_u *p_father;  \
+    union asf_object_u *p_first;   \
+    union asf_object_u *p_last;    \
+    union asf_object_u *p_next;
+
+typedef struct asf_object_common_s
+{
+    ASF_OBJECT_COMMON
+
+} asf_object_common_t;
+
+typedef struct asf_index_entry_s
+{
+    u32 i_packet_number;
+    u16 i_packet_count;
+
+} asf_index_entry_t;
+
+/****************************************************************************
+ * High level asf object 
+ ****************************************************************************/
+/* This is the first header find in a asf file
+ * It's the only object that have subobject */
+typedef struct asf_object_header_s
+{
+    ASF_OBJECT_COMMON
+    u32 i_sub_object_count;
+    u8  i_reserved1; /* 0x01, but could be safely ignored */
+    u8  i_reserved2; /* 0x02, if not must failed to source the contain */
+   
+} asf_object_header_t;
+
+typedef struct asf_object_data_s
+{
+    ASF_OBJECT_COMMON
+    guid_t  i_file_id;
+    u64     i_total_data_packets;
+    u16     i_reserved;
+    
+} asf_object_data_t;
+
+
+typedef struct asf_object_index_s
+{
+    ASF_OBJECT_COMMON
+    guid_t  i_file_id;
+    u64     i_index_entry_time_interval;
+    u32     i_max_packet_count;
+    u32     i_index_entry_count;
+    
+    asf_index_entry_t *index_entry;
+
+} asf_object_index_t;
+
+typedef struct asf_object_root_s
+{
+    ASF_OBJECT_COMMON
+    
+    asf_object_header_t *p_hdr;
+    asf_object_data_t   *p_data;
+    asf_object_index_t  *p_index;
+
+} asf_object_root_t;
+
+/****************************************************************************
+ * Sub level asf object
+ ****************************************************************************/
+#define ASF_FILE_PROPERTIES_BROADCAST   0x01
+#define ASF_FILE_PROPERTIES_SEEKABLE    0x02
+
+typedef struct asf_object_file_properties_s
+{
+    ASF_OBJECT_COMMON
+    
+    guid_t  i_file_id;
+    u64     i_file_size;
+    u64     i_creation_date;
+    u64     i_data_packets_count;
+    u64     i_play_duration;
+    u64     i_send_duration;
+    u64     i_preroll;
+    u32     i_flags;
+    u32     i_min_data_packet_size;
+    u32     i_max_data_packet_size;
+    u32     i_max_bitrate;
+    
+} asf_object_file_properties_t;
+
+#define ASF_STREAM_PROPERTIES_ENCRYPTED 0x8000
+typedef struct asf_object_stream_properties_s
+{
+    ASF_OBJECT_COMMON
+
+    guid_t  i_stream_type;
+    guid_t  i_error_correction_type;
+    u64     i_time_offset;
+    u32     i_type_specific_data_length;
+    u32     i_error_correction_data_length;
+    u16     i_flags;
+        /* extrated from flags */
+        u8      i_stream_number;
+    u32     i_reserved;
+    u8      *p_type_specific_data;
+    u8      *p_error_correction_data;
+} asf_object_stream_properties_t;
+
+typedef struct asf_object_header_extention_s
+{
+    ASF_OBJECT_COMMON
+
+    guid_t  i_reserved1;
+    u16     i_reserved2;
+    u32     i_header_extention_size;
+    u8      *p_header_extention_data;
+
+} asf_object_header_extention_t;
+
+typedef struct asf_objec_content_description_s
+{
+    ASF_OBJECT_COMMON
+
+    char *psz_title;
+    char *psz_author;
+    char *psz_copyright;
+    char *psz_description;
+    char *psz_rating;
+
+} asf_object_content_description_t;
+
+typedef struct string16_s
+{
+    u16 i_length;
+    u16 *i_char;
+} string16_t;
+
+#define ASF_CODEC_TYPE_VIDEO    0x0001
+#define ASF_CODEC_TYPE_AUDIO    0x0002
+#define ASF_CODEC_TYPE_UNKNOW   0xffff
+
+typedef struct asf_codec_entry_s
+{
+    u16         i_type;
+    char        *psz_name;
+    char        *psz_description;
+    
+    u16         i_information_length;
+    u8          *p_information;
+} asf_codec_entry_t;
+
+typedef struct asf_object_codec_list_s
+{
+    ASF_OBJECT_COMMON
+    guid_t  i_reserved;
+    u32     i_codec_entries_count;
+    asf_codec_entry_t *codec; 
+
+} asf_object_codec_list_t;
+
+#if 0
+typedef struct asf_object_script_command_s
+{
+    ASF_OBJECT_COMMON
+
+    
+} asf_object_script_command_t;
+#endif
+typedef struct asf_marker_s
+{
+    u64     i_offset;
+    u64     i_presentation_time;
+    u16     i_entry_length;
+    u32     i_send_time;
+    u32     i_flags;
+    u32     i_marker_description_length;
+    u8      *i_marker_description;
+    /* u8 padding */
+            
+} asf_marker_t;
+
+typedef struct asf_object_marker_s
+{
+    ASF_OBJECT_COMMON
+    guid_t  i_reserved1;
+    u32     i_count;
+    u16     i_reserved2;
+    string16_t name;
+    asf_marker_t *marker;
+
+} asf_object_marker_t;
+
+#if 0
+typedef struct asf_object__s
+{
+    ASF_OBJECT_COMMON
+
+} asf_object__t;
+#endif
+
+typedef union asf_object_u
+{
+    asf_object_common_t common;
+    asf_object_header_t header;
+    asf_object_data_t   data;
+    asf_object_index_t  index;
+    asf_object_root_t   root;
+    asf_object_file_properties_t    file_properties;
+    asf_object_stream_properties_t  stream_properties;
+    asf_object_header_extention_t   header_extention;   
+    asf_object_codec_list_t         codec_list;
+    asf_object_marker_t             marker;
+    
+} asf_object_t;
+
+
+off_t   ASF_TellAbsolute( input_thread_t *p_input );
+int     ASF_SeekAbsolute( input_thread_t *p_input, off_t i_pos);
+int     ASF_ReadData( input_thread_t *p_input, u8 *p_buff, int i_size );
+int     ASF_SkipBytes( input_thread_t *p_input, int i_count );
+
+void GetGUID( guid_t *p_guid, u8 *p_data );
+int  CmpGUID( const guid_t *p_guid1, const guid_t *p_guid2 );
+    
+int  ASF_ReadObjectCommon( input_thread_t *p_input,
+                           asf_object_t *p_obj );
+int  ASF_NextObject( input_thread_t *p_input,
+                     asf_object_t *p_obj );
+int  ASF_GotoObject( input_thread_t *p_input,
+                     asf_object_t *p_obj );
+
+int  ASF_ReadObject( input_thread_t *p_input,
+                     asf_object_t *p_obj,
+                     asf_object_t *p_father );
+void ASF_FreeObject( input_thread_t *p_input,
+                     asf_object_t *p_obj );
+int  ASF_ReadObjectRoot( input_thread_t *p_input,
+                         asf_object_root_t *p_root,
+                         int b_seekable );
+void ASF_FreeObjectRoot( input_thread_t *p_input,
+                         asf_object_root_t *p_root );
+
+int  ASF_CountObject( asf_object_t *p_obj, const guid_t *p_guid );
+asf_object_t *ASF_FindObject( asf_object_t *p_obj, const guid_t *p_guid, int i_number );
+
+