Commit c72215f6 authored by Laurent Aimar's avatar Laurent Aimar

* all : add an asf file (v1.0 only) demuxer. Need a lot of work to be

usable, but it begin to give good result.
parent 54929735
.dep
*.lo
*.o.*
*.lo.*
SOURCES_asf = \
modules/demux/asf/asf.c \
modules/demux/asf/libasf.c
noinst_HEADERS += \
modules/demux/asf/asf.h \
modules/demux/asf/libasf.h
/*****************************************************************************
* 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 donnes 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
}
/*****************************************************************************
* 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;
};
/*****************************************************************************
* 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 );
}
/*****************************************************************************
* 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 );
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment