usable, but it begin to give good result.
--- /dev/null
+.dep
+*.lo
+*.o.*
+*.lo.*
--- /dev/null
+SOURCES_asf = \
+ modules/demux/asf/asf.c \
+ modules/demux/asf/libasf.c
+
+
+noinst_HEADERS += \
+ modules/demux/asf/asf.h \
+ modules/demux/asf/libasf.h
--- /dev/null
+/*****************************************************************************
+ * 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
+}
+
--- /dev/null
+/*****************************************************************************
+ * 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;
+
+};
--- /dev/null
+/*****************************************************************************
+ * 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 );
+}
+
+
--- /dev/null
+/*****************************************************************************
+ * 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 );
+
+