* asf.c : ASFv01 file input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: asf.c,v 1.15 2003/01/11 18:10:49 fenrir Exp $
+ * $Id: asf.c,v 1.21 2003/02/27 13:19:43 gbazin Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* Module descriptor
*****************************************************************************/
vlc_module_begin();
- set_description( "ASF v1.0 demuxer (file only)" );
+ set_description( _("ASF v1.0 demuxer (file only)") );
set_capability( "demux", 200 );
set_callbacks( Activate, Deactivate );
add_shortcut( "asf" );
return( -1 );
}
memset( p_demux, 0, sizeof( demux_sys_t ) );
- p_demux->i_first_pts = -1;
/* Now load all object ( except raw data ) */
if( !ASF_ReadObjectRoot( p_input, &p_demux->root, p_input->stream.b_seekable ) )
return( 0 );
}
+
+static mtime_t GetMoviePTS( demux_sys_t *p_demux )
+{
+ mtime_t i_time;
+ int i_stream;
+
+ i_time = -1;
+ for( i_stream = 0; i_stream < 128 ; i_stream++ )
+ {
+#define p_stream p_demux->stream[i_stream]
+ if( p_stream && p_stream->p_es && p_stream->p_es->p_decoder_fifo && p_stream->i_time > 0)
+ {
+ if( i_time < 0 )
+ {
+ i_time = p_stream->i_time;
+ }
+ else
+ {
+ i_time = __MIN( i_time, p_stream->i_time );
+ }
+ }
+#undef p_stream
+ }
+
+ return( i_time );
+}
+
/*****************************************************************************
* Demux: read packet and send them to decoders
*****************************************************************************/
default: var = def; break;\
}
-static int Demux( input_thread_t *p_input )
+static int DemuxPacket( input_thread_t *p_input, vlc_bool_t b_play_audio )
{
demux_sys_t *p_demux = p_input->p_demux_data;
- int i;
+ int i_data_packet_min = p_demux->p_fp->i_min_data_packet_size;
+ uint8_t *p_peek;
+ int i_skip;
- /* catch seek from user */
- if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
+ 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;
+
+ uint32_t i_packet_send_time;
+ uint16_t 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 )
{
- off_t i_offset;
- msleep( DEFAULT_PTS_DELAY );
- i_offset = ASF_TellAbsolute( p_input ) - p_demux->i_data_begin;
+ // EOF ?
+ msg_Warn( p_input, "cannot peek while getting new packet, EOF ?" );
+ return( 0 );
+ }
+ i_skip = 0;
- if( i_offset < 0 )
+ /* *** parse error correction if present *** */
+ if( p_peek[0]&0x80 )
+ {
+ unsigned int i_error_correction_length_type;
+ unsigned int i_error_correction_data_length;
+ unsigned 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 )
{
- i_offset = 0;
+ goto loop_error_recovery;
}
- /* XXX work only when i_min_data_packet_size == i_max_data_packet_size */
- i_offset += p_demux->p_fp->i_min_data_packet_size -
- 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 < 128 ; i++ )
- {
-#define p_stream p_demux->stream[i]
- if( p_stream )
- {
- p_stream->i_time = 0;
- }
-#undef p_stream
- }
- p_demux->i_first_pts = -1;
+ i_skip += i_error_correction_data_length;
+ }
+ else
+ {
+ msg_Warn( p_input, "p_peek[0]&0x80 != 0x80" );
}
-
- for( i = 0; i < 10; i++ ) // parse 10 packets
+ /* sanity check */
+ if( i_skip + 2 >= i_data_packet_min )
{
- int i_data_packet_min = p_demux->p_fp->i_min_data_packet_size;
- uint8_t *p_peek;
- int i_skip;
+ goto loop_error_recovery;
+ }
- int i_packet_size_left;
- int i_packet_flags;
- int i_packet_property;
+ i_packet_flags = p_peek[i_skip]; i_skip++;
+ i_packet_property = p_peek[i_skip]; i_skip++;
- int b_packet_multiple_payload;
- int i_packet_length;
- int i_packet_sequence;
- int i_packet_padding_length;
+ b_packet_multiple_payload = i_packet_flags&0x01;
- uint32_t i_packet_send_time;
- uint16_t i_packet_duration;
- int i_payload;
- int i_payload_count;
- int i_payload_length_type;
+ /* read some value */
+ GETVALUE2b( i_packet_flags >> 5, i_packet_length, i_data_packet_min );
+ GETVALUE2b( i_packet_flags >> 1, i_packet_sequence, 0 );
+ GETVALUE2b( i_packet_flags >> 3, 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;
- if( input_Peek( p_input, &p_peek, i_data_packet_min ) < i_data_packet_min )
+// i_packet_size_left = i_packet_length; // XXX données reellement lu
+ /* FIXME I have to do that for some file, I don't known why */
+ i_packet_size_left = i_data_packet_min;
+
+ 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;
+
+ if( i_skip >= i_packet_size_left )
{
- // EOF ?
- msg_Err( p_input, "cannot peek while getting new packet, EOF ?" );
- return( 0 );
+ /* prevent some segfault with invalid file */
+ break;
}
- i_skip = 0;
- /* *** parse error correction if present *** */
- if( p_peek[0]&0x80 )
+ i_stream_number = p_peek[i_skip] & 0x7f;
+ i_skip++;
+
+ GETVALUE2b( i_packet_property >> 4, i_media_object_number, 0 );
+ GETVALUE2b( i_packet_property >> 2, i_tmp, 0 );
+ GETVALUE2b( i_packet_property, i_replicated_data_length, 0 );
+
+ if( i_replicated_data_length > 1 ) // should be at least 8 bytes
{
- 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 )
+ 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;
+
+ if( i_skip >= i_packet_size_left )
{
- goto loop_error_recovery;
+ break;
}
-
- i_skip += i_error_correction_data_length;
}
- else
+ else if( i_replicated_data_length == 1 )
{
- 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;
+ msg_Dbg( p_input, "found compressed payload" );
- /* read some value */
- GETVALUE2b( i_packet_flags >> 5, i_packet_length, i_data_packet_min );
- GETVALUE2b( i_packet_flags >> 1, i_packet_sequence, 0 );
- GETVALUE2b( i_packet_flags >> 3, i_packet_padding_length, 0 );
+ i_pts = (mtime_t)i_tmp * 1000;
+ i_pts_delta = (mtime_t)p_peek[i_skip] * 1000; i_skip++;
- i_packet_send_time = GetDWLE( p_peek + i_skip ); i_skip += 4;
- i_packet_duration = GetWLE( p_peek + i_skip ); i_skip += 2;
+ i_media_object_offset = 0;
+ }
+ else
+ {
+ i_pts = (mtime_t)i_packet_send_time * 1000;
+ i_pts_delta = 0;
-// i_packet_size_left = i_packet_length; // XXX données reellement lu
- /* FIXME I have to do that for some file, I don't known why */
- i_packet_size_left = i_data_packet_min;
+ i_media_object_offset = i_tmp;
+ }
+ i_pts = __MAX( i_pts - p_demux->p_fp->i_preroll * 1000, 0 );
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++;
+ GETVALUE2b( i_payload_length_type, i_payload_data_length, 0 );
}
else
{
- i_payload_count = 1;
- i_payload_length_type = 0x02; // unused
+ i_payload_data_length = i_packet_length -
+ i_packet_padding_length - i_skip;
}
- for( i_payload = 0; i_payload < i_payload_count ; i_payload++ )
+ if( i_payload_data_length < 0 || i_skip + i_payload_data_length > i_packet_size_left )
{
- 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;
+ break;
+ }
- if( i_skip >= i_packet_size_left )
- {
- /* prevent some segfault with invalid file */
- break;
- }
+#if 0
+ 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 );
+#endif
- i_stream_number = p_peek[i_skip] & 0x7f;
- i_skip++;
+ 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
+ }
- GETVALUE2b( i_packet_property >> 4, i_media_object_number, 0 );
- GETVALUE2b( i_packet_property >> 2, i_tmp, 0 );
- GETVALUE2b( i_packet_property, i_replicated_data_length, 0 );
+ if( !p_stream->p_es || !p_stream->p_es->p_decoder_fifo )
+ {
+ i_skip += i_payload_data_length;
+ continue;
+ }
- 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 )
+ for( i_payload_data_pos = 0;
+ i_payload_data_pos < i_payload_data_length &&
+ i_packet_size_left > 0;
+ 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 )
{
-
- msg_Dbg( 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;
+ i_sub_payload_data_length = p_peek[i_skip]; i_skip++;
+ i_payload_data_pos++;
}
else
{
- i_pts = (mtime_t)i_packet_send_time * 1000;
- i_pts_delta = 0;
+ i_sub_payload_data_length = i_payload_data_length;
+ }
- i_media_object_offset = i_tmp;
+ /* FIXME I don't use i_media_object_number, sould I ? */
+ if( p_stream->p_pes && i_media_object_offset == 0 ) {
+ /* send complete packet to decoder */
+ if( p_stream->p_pes->i_pes_size > 0 )
+ {
+ if( p_stream->p_es->p_decoder_fifo &&
+ ( b_play_audio || p_stream->i_cat != AUDIO_ES ) )
+ {
+ input_DecodePES( p_stream->p_es->p_decoder_fifo,
+ p_stream->p_pes );
+ }
+ else
+ {
+ input_DeletePES( p_input->p_method_data,
+ p_stream->p_pes );
+ }
+ p_stream->p_pes = NULL;
+ }
}
- i_pts = __MAX( i_pts - p_demux->p_fp->i_preroll * 1000, 0 );
- if( b_packet_multiple_payload )
+ if( !p_stream->p_pes ) // add a new PES
{
- GETVALUE2b( i_payload_length_type, i_payload_data_length, 0 );
+ 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;
}
- else
+
+ i_read = i_sub_payload_data_length + i_skip;
+ if( input_SplitBuffer( p_input, &p_data, i_read ) < i_read )
{
- i_payload_data_length = i_packet_length -
- i_packet_padding_length - i_skip;
+ msg_Warn( p_input, "cannot read data" );
+ return( 0 );
}
+ p_data->p_payload_start += i_skip;
+ i_packet_size_left -= i_read;
-#if 0
- 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 );
-#endif
- if( !( p_stream = p_demux->stream[i_stream_number] ) )
+ if( !p_stream->p_pes->p_first )
{
- msg_Warn( p_input,
- "undeclared stream[Id 0x%x]", i_stream_number );
- i_skip += i_payload_data_length;
- continue; // over payload
+ p_stream->p_pes->p_first = p_stream->p_pes->p_last = p_data;
}
-
- if( !p_stream->p_es || !p_stream->p_es->p_decoder_fifo )
+ else
{
- i_skip += i_payload_data_length;
- continue;
+ 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++;
-
- for( i_payload_data_pos = 0;
- i_payload_data_pos < i_payload_data_length &&
- i_packet_size_left > 0;
- i_payload_data_pos += i_sub_payload_data_length )
+ i_skip = 0;
+ if( i_packet_size_left > 0 )
{
- data_packet_t *p_data;
- int i_read;
- // read sub payload length
- if( i_replicated_data_length == 1 )
+ if( input_Peek( p_input, &p_peek, i_packet_size_left ) < i_packet_size_left )
{
- 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;
+ // EOF ?
+ msg_Warn( p_input, "cannot peek, EOF ?" );
+ return( 0 );
}
+ }
+ }
+ }
- /* FIXME I don't use i_media_object_number, sould I ? */
- if( p_stream->p_pes && i_media_object_offset == 0 ) {
- /* 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( i_packet_size_left > 0 )
+ {
+ if( !ASF_SkipBytes( p_input, i_packet_size_left ) )
+ {
+ msg_Warn( p_input, "cannot skip data, EOF ?" );
+ return( 0 );
+ }
+ }
- if( !p_stream->p_pes ) // add a new PES
- {
- p_stream->i_time =
- ( (mtime_t)i_pts + i_payload * (mtime_t)i_pts_delta );
+ return( 1 );
- if( p_demux->i_first_pts == -1 )
- {
- p_demux->i_first_pts = p_stream->i_time;
- }
- p_stream->i_time -= p_demux->i_first_pts;
-
- 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+DEFAULT_PTS_DELAY) * 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;
- }
+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 );
- 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;
+ return( 1 );
+}
+static int Demux( input_thread_t *p_input )
+{
+ demux_sys_t *p_demux = p_input->p_demux_data;
+ vlc_bool_t b_play_audio;
+ int i;
- 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++;
+ /* catch seek from user */
+ if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
+ {
+ off_t i_offset;
- i_skip = 0;
- if( i_packet_size_left > 0 )
- {
- if( input_Peek( p_input, &p_peek, i_packet_size_left ) < i_packet_size_left )
- {
- // EOF ?
- msg_Warn( p_input, "cannot peek, EOF ?" );
- return( 0 );
- }
- }
- }
+ msleep( DEFAULT_PTS_DELAY );
+ 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 += p_demux->p_fp->i_min_data_packet_size -
+ i_offset % p_demux->p_fp->i_min_data_packet_size;
+ ASF_SeekAbsolute( p_input, p_demux->i_data_begin + i_offset );
- if( i_packet_size_left > 0 )
+ p_demux->i_time = -1;
+ for( i = 0; i < 128 ; i++ )
{
- if( !ASF_SkipBytes( p_input, i_packet_size_left ) )
+#define p_stream p_demux->stream[i]
+ if( p_stream )
{
- msg_Warn( p_input, "cannot skip data, EOF ?" );
- return( 0 );
+ p_stream->i_time = -1;
}
+#undef p_stream
}
+ }
- continue;
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ if( p_input->stream.control.i_rate == DEFAULT_RATE )
+ {
+ b_play_audio = VLC_TRUE;
+ }
+ else
+ {
+ int i;
-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 )
+ b_play_audio = VLC_TRUE;
+ for( i = 0; i < 128; i++ )
{
- msg_Err( p_input, "unsupported packet header, fatal error" );
- return( -1 );
+ if( p_demux->stream[i] &&
+ p_demux->stream[i]->i_cat == VIDEO_ES &&
+ p_demux->stream[i]->p_es &&
+ p_demux->stream[i]->p_es->p_decoder_fifo )
+ {
+ /* there is at least ine video track so no need to play audio */
+ b_play_audio = VLC_FALSE;
+ }
}
- ASF_SkipBytes( p_input, i_data_packet_min );
+ }
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
- } // loop over packet
- p_demux->i_time = -1;
- for( i = 0; i < 128 ; i++ )
+ for( ;; )
{
-#define p_stream p_demux->stream[i]
- if( p_stream && p_stream->p_es && p_stream->p_es->p_decoder_fifo )
+ mtime_t i_length;
+ mtime_t i_time_begin = GetMoviePTS( p_demux );
+ int i_result;
+
+ if( ( i_result = DemuxPacket( p_input, b_play_audio ) ) <= 0 )
{
- if( p_demux->i_time < 0 )
- {
- p_demux->i_time = p_stream->i_time;
- }
- else
+ return i_result;
+ }
+ if( i_time_begin == -1 )
+ {
+ i_time_begin = GetMoviePTS( p_demux );
+ }
+ else
+ {
+ i_length = GetMoviePTS( p_demux ) - i_time_begin;
+ if( i_length < 0 || i_length >= 40 * 1000 )
{
- p_demux->i_time = __MIN( p_demux->i_time, p_stream->i_time );
+ break;
}
}
-#undef p_stream
}
+ p_demux->i_time = GetMoviePTS( p_demux );
if( p_demux->i_time >= 0 )
{
/* update pcr XXX in mpeg scale so in 90000 unit/s */
- p_demux->i_pcr =( __MAX( p_demux->i_time /*- DEFAULT_PTS_DELAY*/, 0 ) ) * 9 / 100;
+ p_demux->i_pcr = p_demux->i_time * 9 / 100;
/* first wait for the good time to read next packets */
input_ClockManageRef( p_input,
p_demux->i_pcr );
}
-
return( 1 );
}
}
#undef p_stream
}
-
+ FREE( p_input->p_demux_data );
#undef FREE
}