Commit 18aaaf30 authored by Christophe Massiot's avatar Christophe Massiot

* Hooks for fast forward and slow motion support.

parent b788332a
...@@ -192,6 +192,7 @@ INPUT = src/input/input_ps.o \ ...@@ -192,6 +192,7 @@ INPUT = src/input/input_ps.o \
src/input/input_dec.o \ src/input/input_dec.o \
src/input/input_programs.o \ src/input/input_programs.o \
src/input/input_netlist.o \ src/input/input_netlist.o \
src/input/input_clock.o \
src/input/input.o src/input/input.o
AUDIO_OUTPUT = src/audio_output/audio_output.o AUDIO_OUTPUT = src/audio_output/audio_output.o
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* input_ext-dec.h: structures exported to the VideoLAN decoders * input_ext-dec.h: structures exported to the VideoLAN decoders
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ext-dec.h,v 1.19 2001/01/22 18:04:10 massiot Exp $ * $Id: input_ext-dec.h,v 1.20 2001/01/24 19:05:55 massiot Exp $
* *
* Authors: * Authors:
* *
...@@ -59,8 +59,10 @@ typedef struct pes_packet_s ...@@ -59,8 +59,10 @@ typedef struct pes_packet_s
boolean_t b_discontinuity; /* This packet doesn't follow the boolean_t b_discontinuity; /* This packet doesn't follow the
* previous one */ * previous one */
mtime_t i_pts;/* the PTS for this packet (zero if unset) */ mtime_t i_pts; /* PTS for this packet (zero if unset) */
mtime_t i_dts;/* the DTS for this packet (zero if unset) */ mtime_t i_dts; /* DTS for this packet (zero if unset) */
int i_rate; /* current pace of reading
* (see stream_control.h) */
int i_pes_size; /* size of the current PES packet */ int i_pes_size; /* size of the current PES packet */
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* control the pace of reading. * control the pace of reading.
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ext-intf.h,v 1.9 2001/01/14 07:08:00 stef Exp $ * $Id: input_ext-intf.h,v 1.10 2001/01/24 19:05:55 massiot Exp $
* *
* Authors: * Authors:
* *
...@@ -47,6 +47,9 @@ typedef struct es_descriptor_s ...@@ -47,6 +47,9 @@ typedef struct es_descriptor_s
u16 i_id; /* stream ID for PS, PID for TS */ u16 i_id; /* stream ID for PS, PID for TS */
u8 i_stream_id; /* stream ID defined in the PES */ u8 i_stream_id; /* stream ID defined in the PES */
u8 i_type; /* stream type */ u8 i_type; /* stream type */
boolean_t b_audio; /* is the stream an audio stream that
* will need to be discarded with
* fast forward and slow motion ? */
/* Demultiplexer information */ /* Demultiplexer information */
void * p_demux_data; void * p_demux_data;
...@@ -85,7 +88,7 @@ typedef struct es_descriptor_s ...@@ -85,7 +88,7 @@ typedef struct es_descriptor_s
/* These ones might violate the norm : */ /* These ones might violate the norm : */
#define DVD_SPU_ES 0x82 #define DVD_SPU_ES 0x82
#define LPCM_AUDIO_ES 0x83 #define LPCM_AUDIO_ES 0x83
#define UNKNOWN_ES 0xFF #define UNKNOWN_ES 0xFF
/***************************************************************************** /*****************************************************************************
* pgrm_descriptor_t * pgrm_descriptor_t
...@@ -105,9 +108,8 @@ typedef struct pgrm_descriptor_s ...@@ -105,9 +108,8 @@ typedef struct pgrm_descriptor_s
char * psz_srv_name; char * psz_srv_name;
/* Synchronization information */ /* Synchronization information */
/* system_date = PTS_date + delta_cr + delta_absolute */
mtime_t delta_cr; mtime_t delta_cr;
mtime_t delta_absolute; mtime_t cr_ref, sysdate_ref;
mtime_t last_cr; mtime_t last_cr;
count_t c_average_count; count_t c_average_count;
/* counter used to compute dynamic average values */ /* counter used to compute dynamic average values */
...@@ -127,9 +129,8 @@ typedef struct pgrm_descriptor_s ...@@ -127,9 +129,8 @@ typedef struct pgrm_descriptor_s
/* Synchro states */ /* Synchro states */
#define SYNCHRO_OK 0 #define SYNCHRO_OK 0
#define SYNCHRO_NOT_STARTED 1 #define SYNCHRO_START 1
#define SYNCHRO_START 2 #define SYNCHRO_REINIT 2
#define SYNCHRO_REINIT 3
/***************************************************************************** /*****************************************************************************
* stream_descriptor_t * stream_descriptor_t
...@@ -147,8 +148,15 @@ typedef struct stream_descriptor_s ...@@ -147,8 +148,15 @@ typedef struct stream_descriptor_s
boolean_t b_pace_control; /* can we read when we want ? */ boolean_t b_pace_control; /* can we read when we want ? */
boolean_t b_seekable; /* can we do lseek() ? */ boolean_t b_seekable; /* can we do lseek() ? */
/* if (b_seekable) : */ /* if (b_seekable) : */
off_t i_size; /* total size of the file (in bytes) */ off_t i_size; /* total size of the file
off_t i_tell;/* actual location in the file (in bytes) */ * (in arbitrary units) */
off_t i_tell; /* actual location in the file
* (in arbitrary units) */
off_t i_seek; /* next requested location (changed
* by the interface thread */
/* New status and rate requested by the interface */
int i_new_status, i_new_rate;
/* Demultiplexer data */ /* Demultiplexer data */
void * p_demux_data; void * p_demux_data;
......
...@@ -12,8 +12,6 @@ typedef struct stream_ctrl_s ...@@ -12,8 +12,6 @@ typedef struct stream_ctrl_s
int i_status; int i_status;
/* if i_status == FORWARD_S or BACKWARD_S */ /* if i_status == FORWARD_S or BACKWARD_S */
int i_rate; int i_rate;
s64 i_ref_sysdate;
s64 i_ref_clock;
boolean_t b_mute; boolean_t b_mute;
boolean_t b_bw; /* black & white */ boolean_t b_bw; /* black & white */
...@@ -24,5 +22,8 @@ typedef struct stream_ctrl_s ...@@ -24,5 +22,8 @@ typedef struct stream_ctrl_s
#define PAUSE_S 1 #define PAUSE_S 1
#define FORWARD_S 2 #define FORWARD_S 2
#define BACKWARD_S 3 #define BACKWARD_S 3
#define REWIND_S 4 /* Not supported for the moment */
#define NOT_STARTED_S 10
#define START_S 11
#define DEFAULT_RATE 1000 #define DEFAULT_RATE 1000
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* decoders. * decoders.
***************************************************************************** *****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN * Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: input.c,v 1.72 2001/01/20 20:59:44 stef Exp $ * $Id: input.c,v 1.73 2001/01/24 19:05:55 massiot Exp $
* *
* Authors: * Authors:
* *
...@@ -103,8 +103,6 @@ input_thread_t *input_CreateThread ( input_config_t * p_config, int *pi_status ) ...@@ -103,8 +103,6 @@ input_thread_t *input_CreateThread ( input_config_t * p_config, int *pi_status )
/* Initialize stream control properties. */ /* Initialize stream control properties. */
p_input->stream.control.i_status = PLAYING_S; p_input->stream.control.i_status = PLAYING_S;
p_input->stream.control.i_rate = DEFAULT_RATE; p_input->stream.control.i_rate = DEFAULT_RATE;
p_input->stream.control.i_ref_sysdate = 0;
p_input->stream.control.i_ref_clock = 0;
p_input->stream.control.b_mute = 0; p_input->stream.control.b_mute = 0;
p_input->stream.control.b_bw = 0; p_input->stream.control.b_bw = 0;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* input.h: structures of the input not exported to other modules * input.h: structures of the input not exported to other modules
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: input.h,v 1.11 2001/01/18 17:40:06 massiot Exp $ * $Id: input.h,v 1.12 2001/01/24 19:05:55 massiot Exp $
* *
* Authors: * Authors:
* *
...@@ -100,6 +100,14 @@ vlc_thread_t input_RunDecoder( struct decoder_capabilities_s *, void * ); ...@@ -100,6 +100,14 @@ vlc_thread_t input_RunDecoder( struct decoder_capabilities_s *, void * );
void input_EndDecoder( struct input_thread_s *, struct es_descriptor_s * ); void input_EndDecoder( struct input_thread_s *, struct es_descriptor_s * );
void input_DecodePES( struct decoder_fifo_s *, struct pes_packet_s * ); void input_DecodePES( struct decoder_fifo_s *, struct pes_packet_s * );
/*****************************************************************************
* Prototypes from input_clock.c
*****************************************************************************/
mtime_t input_ClockToSysdate( struct input_thread_s *,
struct pgrm_descriptor_s *, mtime_t );
void input_ClockNewRef( struct input_thread_s *,
struct pgrm_descriptor_s *, mtime_t );
/***************************************************************************** /*****************************************************************************
* Create a NULL packet for padding in case of a data loss * Create a NULL packet for padding in case of a data loss
*****************************************************************************/ *****************************************************************************/
...@@ -138,6 +146,7 @@ static __inline__ void input_NullPacket( input_thread_t * p_input, ...@@ -138,6 +146,7 @@ static __inline__ void input_NullPacket( input_thread_t * p_input,
return; return;
} }
p_pes->i_rate = p_input->stream.control.i_rate;
p_pes->p_first = p_pad_data; p_pes->p_first = p_pad_data;
p_pes->b_messed_up = p_pes->b_discontinuity = 1; p_pes->b_messed_up = p_pes->b_discontinuity = 1;
input_DecodePES( p_es->p_decoder_fifo, p_pes ); input_DecodePES( p_es->p_decoder_fifo, p_pes );
......
/*****************************************************************************
* input_clock.c: Clock/System date conversions, stream management
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_clock.c,v 1.1 2001/01/24 19:05:55 massiot Exp $
*
* Authors: Christophe Massiot <massiot@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 "defs.h"
#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
#include "intf_msg.h"
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input.h"
/*****************************************************************************
* input_ClockToSysdate: converts a movie clock to system date
*****************************************************************************/
mtime_t input_ClockToSysdate( input_thread_t * p_input,
pgrm_descriptor_t * p_pgrm, mtime_t i_clock )
{
mtime_t i_sysdate = 0;
if( p_pgrm->i_synchro_state == SYNCHRO_OK )
{
i_sysdate = (i_clock - p_pgrm->cr_ref)
* p_input->stream.control.i_rate
* 300
/ 27
/ DEFAULT_RATE
+ p_pgrm->sysdate_ref;
}
return( i_sysdate );
}
/*****************************************************************************
* input_ClockNewRef: writes a new clock reference
*****************************************************************************/
void input_ClockNewRef( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm,
mtime_t i_clock )
{
p_pgrm->cr_ref = i_clock;
p_pgrm->sysdate_ref = mdate();
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* input_programs.c: es_descriptor_t, pgrm_descriptor_t management * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: input_programs.c,v 1.26 2001/01/18 05:13:22 sam Exp $ * $Id: input_programs.c,v 1.27 2001/01/24 19:05:55 massiot Exp $
* *
* Authors: * Authors:
* *
...@@ -148,11 +148,12 @@ pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input, ...@@ -148,11 +148,12 @@ pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
p_input->stream.pp_programs[i_pgrm_index]->pp_es = NULL; p_input->stream.pp_programs[i_pgrm_index]->pp_es = NULL;
p_input->stream.pp_programs[i_pgrm_index]->delta_cr = 0; p_input->stream.pp_programs[i_pgrm_index]->delta_cr = 0;
p_input->stream.pp_programs[i_pgrm_index]->delta_absolute = 0; p_input->stream.pp_programs[i_pgrm_index]->cr_ref = 0;
p_input->stream.pp_programs[i_pgrm_index]->sysdate_ref = 0;
p_input->stream.pp_programs[i_pgrm_index]->last_cr = 0; p_input->stream.pp_programs[i_pgrm_index]->last_cr = 0;
p_input->stream.pp_programs[i_pgrm_index]->c_average_count = 0; p_input->stream.pp_programs[i_pgrm_index]->c_average_count = 0;
p_input->stream.pp_programs[i_pgrm_index]->i_synchro_state p_input->stream.pp_programs[i_pgrm_index]->i_synchro_state
= SYNCHRO_NOT_STARTED; = SYNCHRO_START;
p_input->stream.pp_programs[i_pgrm_index]->b_discontinuity = 0; p_input->stream.pp_programs[i_pgrm_index]->b_discontinuity = 0;
p_input->stream.pp_programs[i_pgrm_index]->p_vout p_input->stream.pp_programs[i_pgrm_index]->p_vout
...@@ -277,12 +278,13 @@ es_descriptor_t * input_AddES( input_thread_t * p_input, ...@@ -277,12 +278,13 @@ es_descriptor_t * input_AddES( input_thread_t * p_input,
return( NULL ); return( NULL );
} }
p_input->stream.pp_es[p_input->stream.i_es_number - 1] = p_es; p_input->stream.pp_es[p_input->stream.i_es_number - 1] = p_es;
p_es->i_id = i_es_id;
/* Init its values */ /* Init its values */
p_es->i_id = i_es_id;
p_es->b_discontinuity = 0; p_es->b_discontinuity = 0;
p_es->p_pes = NULL; p_es->p_pes = NULL;
p_es->p_decoder_fifo = NULL; p_es->p_decoder_fifo = NULL;
p_es->b_audio = 0;
if( i_data_len ) if( i_data_len )
{ {
...@@ -412,9 +414,6 @@ void input_DumpStream( input_thread_t * p_input ) ...@@ -412,9 +414,6 @@ void input_DumpStream( input_thread_t * p_input )
intf_Msg( "input info: Dumping program 0x%x, version %d (%s)", intf_Msg( "input info: Dumping program 0x%x, version %d (%s)",
P->i_number, P->i_version, P->i_number, P->i_version,
P->b_is_ok ? "complete" : "partial" ); P->b_is_ok ? "complete" : "partial" );
if( P->i_synchro_state == SYNCHRO_OK )
intf_Msg( "input info: synchro absolute delta : %lld (jitter : %lld)",
P->delta_absolute, P->delta_cr );
#undef P #undef P
for( j = 0; j < p_input->stream.pp_programs[i]->i_es_number; j++ ) for( j = 0; j < p_input->stream.pp_programs[i]->i_es_number; j++ )
{ {
......
This diff is collapsed.
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* video_parser.h : video parser thread * video_parser.h : video parser thread
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: video_parser.h,v 1.7 2001/01/21 01:36:25 massiot Exp $ * $Id: video_parser.h,v 1.8 2001/01/24 19:05:55 massiot Exp $
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* *
...@@ -114,10 +114,6 @@ typedef struct vpar_thread_s ...@@ -114,10 +114,6 @@ typedef struct vpar_thread_s
video_synchro_t synchro; video_synchro_t synchro;
/* Lookup tables */ /* Lookup tables */
#ifdef MPEG2_COMPLIANT
s16 pi_crop_buf[8192];
s16 * pi_crop;
#endif
lookup_t pl_mb_addr_inc[2048]; /* for macroblock lookup_t pl_mb_addr_inc[2048]; /* for macroblock
address increment */ address increment */
/* tables for macroblock types 0=P 1=B */ /* tables for macroblock types 0=P 1=B */
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* vpar_headers.h : video parser : headers parsing * vpar_headers.h : video parser : headers parsing
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: vpar_headers.h,v 1.4 2001/01/17 18:17:30 massiot Exp $ * $Id: vpar_headers.h,v 1.5 2001/01/24 19:05:55 massiot Exp $
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* Stphane Borel <stef@via.ecp.fr> * Stphane Borel <stef@via.ecp.fr>
...@@ -83,6 +83,7 @@ typedef struct sequence_s ...@@ -83,6 +83,7 @@ typedef struct sequence_s
picture_t * p_forward; /* current forward reference frame */ picture_t * p_forward; /* current forward reference frame */
picture_t * p_backward; /* current backward reference frame */ picture_t * p_backward; /* current backward reference frame */
mtime_t next_pts, next_dts; mtime_t next_pts, next_dts;
int i_current_rate;
/* Copyright extension */ /* Copyright extension */
boolean_t b_copyright_flag; /* Whether the following boolean_t b_copyright_flag; /* Whether the following
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* video_parser.c : video parser thread * video_parser.c : video parser thread
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: video_parser.c,v 1.69 2001/01/18 05:13:23 sam Exp $ * $Id: video_parser.c,v 1.70 2001/01/24 19:05:55 massiot Exp $
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr> * Samuel Hocevar <sam@via.ecp.fr>
...@@ -528,5 +528,7 @@ static void BitstreamCallback ( bit_stream_t * p_bit_stream, ...@@ -528,5 +528,7 @@ static void BitstreamCallback ( bit_stream_t * p_bit_stream,
DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts; DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts;
p_vpar->sequence.next_dts = p_vpar->sequence.next_dts =
DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_dts; DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_dts;
p_vpar->sequence.i_current_rate =
DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_rate;
} }
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* vpar_synchro.c : frame dropping routines * vpar_synchro.c : frame dropping routines
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: vpar_synchro.c,v 1.79 2001/01/18 17:40:06 massiot Exp $ * $Id: vpar_synchro.c,v 1.80 2001/01/24 19:05:55 massiot Exp $
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr> * Samuel Hocevar <sam@via.ecp.fr>
...@@ -41,8 +41,6 @@ ...@@ -41,8 +41,6 @@
* Please bear in mind that B's and IP's will be inverted when displaying * Please bear in mind that B's and IP's will be inverted when displaying
* (decoding order != presentation order). Thus, t1 < t0. * (decoding order != presentation order). Thus, t1 < t0.
* *
* FIXME: write a few words about stream structure changes.
*
* 2. Definitions * 2. Definitions
* =========== * ===========
* t[0..12] : Presentation timestamps of pictures 0..12. * t[0..12] : Presentation timestamps of pictures 0..12.
...@@ -230,7 +228,8 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type, ...@@ -230,7 +228,8 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
#endif #endif
now = mdate(); now = mdate();
period = 1000000 * 1001 / p_vpar->sequence.i_frame_rate; period = 1000000 * 1001 / p_vpar->sequence.i_frame_rate
* p_vpar->sequence.i_current_rate / DEFAULT_RATE;
vlc_mutex_lock( &p_vpar->p_vout->change_lock ); vlc_mutex_lock( &p_vpar->p_vout->change_lock );
tau_yuv = p_vpar->p_vout->render_time; tau_yuv = p_vpar->p_vout->render_time;
...@@ -265,7 +264,8 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type, ...@@ -265,7 +264,8 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
b_decode = (pts - now) > (TAU_PRIME(I_CODING_TYPE) + DELTA); b_decode = (pts - now) > (TAU_PRIME(I_CODING_TYPE) + DELTA);
} }
if( !b_decode ) if( !b_decode )
intf_WarnMsg( 3, "vpar synchro warning: trashing I" ); intf_WarnMsg( 3, "vpar synchro warning: trashing I (%lld)",
pts - now);
break; break;
case P_CODING_TYPE: case P_CODING_TYPE:
...@@ -422,7 +422,8 @@ mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar ) ...@@ -422,7 +422,8 @@ mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar )
void vpar_SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type, void vpar_SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type,
int i_repeat_field ) int i_repeat_field )
{ {
mtime_t period = 1000000 * 1001 / p_vpar->sequence.i_frame_rate; mtime_t period = 1000000 * 1001 / p_vpar->sequence.i_frame_rate
* p_vpar->sequence.i_current_rate / DEFAULT_RATE;
switch( i_coding_type ) switch( i_coding_type )
{ {
......
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