Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-2-2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc-2-2
Commits
b6352fa8
Commit
b6352fa8
authored
Mar 28, 2009
by
Laurent Aimar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Review a bit wav demuxer against broken files.
parent
aaddb130
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
92 additions
and
63 deletions
+92
-63
modules/demux/wav.c
modules/demux/wav.c
+92
-63
No files found.
modules/demux/wav.c
View file @
b6352fa8
...
@@ -75,10 +75,10 @@ struct demux_sys_t
...
@@ -75,10 +75,10 @@ struct demux_sys_t
static
int
ChunkFind
(
demux_t
*
,
const
char
*
,
unsigned
int
*
);
static
int
ChunkFind
(
demux_t
*
,
const
char
*
,
unsigned
int
*
);
static
void
FrameInfo_IMA_ADPCM
(
demux_t
*
,
unsigned
int
*
,
in
t
*
);
static
int
FrameInfo_IMA_ADPCM
(
unsigned
int
*
,
int
*
,
const
es_format_
t
*
);
static
void
FrameInfo_MS_ADPCM
(
demux_t
*
,
unsigned
int
*
,
in
t
*
);
static
int
FrameInfo_MS_ADPCM
(
unsigned
int
*
,
int
*
,
const
es_format_
t
*
);
static
void
FrameInfo_PCM
(
demux_t
*
,
unsigned
int
*
,
in
t
*
);
static
int
FrameInfo_PCM
(
unsigned
int
*
,
int
*
,
const
es_format_
t
*
);
static
void
FrameInfo_MSGSM
(
demux_t
*
,
unsigned
int
*
,
in
t
*
);
static
int
FrameInfo_MSGSM
(
unsigned
int
*
,
int
*
,
const
es_format_
t
*
);
static
const
uint32_t
pi_channels_src
[]
=
static
const
uint32_t
pi_channels_src
[]
=
{
WAVE_SPEAKER_FRONT_LEFT
,
WAVE_SPEAKER_FRONT_RIGHT
,
{
WAVE_SPEAKER_FRONT_LEFT
,
WAVE_SPEAKER_FRONT_RIGHT
,
...
@@ -100,7 +100,7 @@ static int Open( vlc_object_t * p_this )
...
@@ -100,7 +100,7 @@ static int Open( vlc_object_t * p_this )
demux_sys_t
*
p_sys
;
demux_sys_t
*
p_sys
;
const
uint8_t
*
p_peek
;
const
uint8_t
*
p_peek
;
u
int32_t
i_size
;
u
nsigned
int
i_size
;
unsigned
int
i_extended
;
unsigned
int
i_extended
;
const
char
*
psz_name
;
const
char
*
psz_name
;
...
@@ -108,7 +108,8 @@ static int Open( vlc_object_t * p_this )
...
@@ -108,7 +108,8 @@ static int Open( vlc_object_t * p_this )
WAVEFORMATEX
*
p_wf
=
NULL
;
WAVEFORMATEX
*
p_wf
=
NULL
;
/* Is it a wav file ? */
/* Is it a wav file ? */
if
(
stream_Peek
(
p_demux
->
s
,
&
p_peek
,
12
)
<
12
)
return
VLC_EGENERIC
;
if
(
stream_Peek
(
p_demux
->
s
,
&
p_peek
,
12
)
<
12
)
return
VLC_EGENERIC
;
if
(
memcmp
(
p_peek
,
"RIFF"
,
4
)
||
memcmp
(
&
p_peek
[
8
],
"WAVE"
,
4
)
)
if
(
memcmp
(
p_peek
,
"RIFF"
,
4
)
||
memcmp
(
&
p_peek
[
8
],
"WAVE"
,
4
)
)
{
{
...
@@ -117,7 +118,7 @@ static int Open( vlc_object_t * p_this )
...
@@ -117,7 +118,7 @@ static int Open( vlc_object_t * p_this )
p_demux
->
pf_demux
=
Demux
;
p_demux
->
pf_demux
=
Demux
;
p_demux
->
pf_control
=
Control
;
p_demux
->
pf_control
=
Control
;
p_demux
->
p_sys
=
p_sys
=
malloc
(
sizeof
(
demux_sys_t
)
);
p_demux
->
p_sys
=
p_sys
=
malloc
(
sizeof
(
*
p_sys
)
);
if
(
p_sys
==
NULL
)
if
(
p_sys
==
NULL
)
return
VLC_ENOMEM
;
return
VLC_ENOMEM
;
...
@@ -126,7 +127,8 @@ static int Open( vlc_object_t * p_this )
...
@@ -126,7 +127,8 @@ static int Open( vlc_object_t * p_this )
p_sys
->
i_channel_mask
=
0
;
p_sys
->
i_channel_mask
=
0
;
/* skip riff header */
/* skip riff header */
stream_Read
(
p_demux
->
s
,
NULL
,
12
);
/* cannot fail as peek succeed */
if
(
stream_Read
(
p_demux
->
s
,
NULL
,
12
)
!=
12
)
goto
error
;
/* search fmt chunk */
/* search fmt chunk */
if
(
ChunkFind
(
p_demux
,
"fmt "
,
&
i_size
)
)
if
(
ChunkFind
(
p_demux
,
"fmt "
,
&
i_size
)
)
...
@@ -140,7 +142,9 @@ static int Open( vlc_object_t * p_this )
...
@@ -140,7 +142,9 @@ static int Open( vlc_object_t * p_this )
msg_Err
(
p_demux
,
"invalid 'fmt ' chunk"
);
msg_Err
(
p_demux
,
"invalid 'fmt ' chunk"
);
goto
error
;
goto
error
;
}
}
stream_Read
(
p_demux
->
s
,
NULL
,
8
);
/* Cannot fail */
if
(
stream_Read
(
p_demux
->
s
,
NULL
,
8
)
!=
8
)
goto
error
;
/* load waveformatex */
/* load waveformatex */
p_wf_ext
=
malloc
(
i_size
);
p_wf_ext
=
malloc
(
i_size
);
...
@@ -150,8 +154,8 @@ static int Open( vlc_object_t * p_this )
...
@@ -150,8 +154,8 @@ static int Open( vlc_object_t * p_this )
p_wf
=
(
WAVEFORMATEX
*
)
p_wf_ext
;
p_wf
=
(
WAVEFORMATEX
*
)
p_wf_ext
;
p_wf
->
cbSize
=
0
;
p_wf
->
cbSize
=
0
;
i_size
-=
2
;
i_size
-=
2
;
if
(
stream_Read
(
p_demux
->
s
,
p_wf
,
i_size
)
!=
(
int
)
i_size
if
(
stream_Read
(
p_demux
->
s
,
p_wf
,
i_size
)
!=
(
int
)
i_size
||
||
(
(
i_size
&
1
)
&&
stream_Read
(
p_demux
->
s
,
NULL
,
1
)
!=
1
)
)
(
(
i_size
&
1
)
&&
stream_Read
(
p_demux
->
s
,
NULL
,
1
)
!=
1
)
)
{
{
msg_Err
(
p_demux
,
"cannot load 'fmt ' chunk"
);
msg_Err
(
p_demux
,
"cannot load 'fmt ' chunk"
);
goto
error
;
goto
error
;
...
@@ -220,6 +224,11 @@ static int Open( vlc_object_t * p_this )
...
@@ -220,6 +224,11 @@ static int Open( vlc_object_t * p_this )
if
(
p_sys
->
fmt
.
i_extra
>
0
)
if
(
p_sys
->
fmt
.
i_extra
>
0
)
{
{
p_sys
->
fmt
.
p_extra
=
malloc
(
p_sys
->
fmt
.
i_extra
);
p_sys
->
fmt
.
p_extra
=
malloc
(
p_sys
->
fmt
.
i_extra
);
if
(
!
p_sys
->
fmt
.
p_extra
)
{
p_sys
->
fmt
.
i_extra
=
0
;
goto
error
;
}
memcpy
(
p_sys
->
fmt
.
p_extra
,
((
uint8_t
*
)
p_wf
)
+
i_extended
,
memcpy
(
p_sys
->
fmt
.
p_extra
,
((
uint8_t
*
)
p_wf
)
+
i_extended
,
p_sys
->
fmt
.
i_extra
);
p_sys
->
fmt
.
i_extra
);
}
}
...
@@ -243,30 +252,35 @@ static int Open( vlc_object_t * p_this )
...
@@ -243,30 +252,35 @@ static int Open( vlc_object_t * p_this )
case
VLC_FOURCC
(
'a'
,
'l'
,
'a'
,
'w'
):
case
VLC_FOURCC
(
'a'
,
'l'
,
'a'
,
'w'
):
case
VLC_FOURCC
(
'm'
,
'l'
,
'a'
,
'w'
):
case
VLC_FOURCC
(
'm'
,
'l'
,
'a'
,
'w'
):
case
VLC_FOURCC
(
'p'
,
'c'
,
'm'
,
' '
):
case
VLC_FOURCC
(
'p'
,
'c'
,
'm'
,
' '
):
FrameInfo_PCM
(
p_demux
,
&
p_sys
->
i_frame_size
,
if
(
FrameInfo_PCM
(
&
p_sys
->
i_frame_size
,
&
p_sys
->
i_frame_samples
,
&
p_sys
->
i_frame_samples
);
&
p_sys
->
fmt
)
)
goto
error
;
break
;
break
;
case
VLC_FOURCC
(
'm'
,
's'
,
0x00
,
0x02
):
case
VLC_FOURCC
(
'm'
,
's'
,
0x00
,
0x02
):
FrameInfo_MS_ADPCM
(
p_demux
,
&
p_sys
->
i_frame_size
,
if
(
FrameInfo_MS_ADPCM
(
&
p_sys
->
i_frame_size
,
&
p_sys
->
i_frame_samples
,
&
p_sys
->
i_frame_samples
);
&
p_sys
->
fmt
)
)
goto
error
;
break
;
break
;
case
VLC_FOURCC
(
'm'
,
's'
,
0x00
,
0x11
):
case
VLC_FOURCC
(
'm'
,
's'
,
0x00
,
0x11
):
FrameInfo_IMA_ADPCM
(
p_demux
,
&
p_sys
->
i_frame_size
,
if
(
FrameInfo_IMA_ADPCM
(
&
p_sys
->
i_frame_size
,
&
p_sys
->
i_frame_samples
,
&
p_sys
->
i_frame_samples
);
&
p_sys
->
fmt
)
)
goto
error
;
break
;
break
;
case
VLC_FOURCC
(
'm'
,
's'
,
0x00
,
0x61
):
case
VLC_FOURCC
(
'm'
,
's'
,
0x00
,
0x61
):
case
VLC_FOURCC
(
'm'
,
's'
,
0x00
,
0x62
):
case
VLC_FOURCC
(
'm'
,
's'
,
0x00
,
0x62
):
/* FIXME not sure at all FIXME */
/* FIXME not sure at all FIXME */
FrameInfo_MS_ADPCM
(
p_demux
,
&
p_sys
->
i_frame_size
,
if
(
FrameInfo_MS_ADPCM
(
&
p_sys
->
i_frame_size
,
&
p_sys
->
i_frame_samples
,
&
p_sys
->
i_frame_samples
);
&
p_sys
->
fmt
)
)
goto
error
;
break
;
break
;
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
):
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
):
case
VLC_FOURCC
(
'a'
,
'5'
,
'2'
,
' '
):
case
VLC_FOURCC
(
'a'
,
'5'
,
'2'
,
' '
):
/* FIXME set end of area FIXME */
/* FIXME set end of area FIXME */
goto
error
;
goto
error
;
case
VLC_FOURCC
(
'a'
,
'g'
,
's'
,
'm'
):
case
VLC_FOURCC
(
'a'
,
'g'
,
's'
,
'm'
):
FrameInfo_MSGSM
(
p_demux
,
&
p_sys
->
i_frame_size
,
if
(
FrameInfo_MSGSM
(
&
p_sys
->
i_frame_size
,
&
p_sys
->
i_frame_samples
,
&
p_sys
->
i_frame_samples
);
&
p_sys
->
fmt
)
)
goto
error
;
break
;
break
;
default:
default:
msg_Err
(
p_demux
,
"unsupported codec (%4.4s)"
,
msg_Err
(
p_demux
,
"unsupported codec (%4.4s)"
,
...
@@ -274,6 +288,17 @@ static int Open( vlc_object_t * p_this )
...
@@ -274,6 +288,17 @@ static int Open( vlc_object_t * p_this )
goto
error
;
goto
error
;
}
}
if
(
p_sys
->
i_frame_size
<=
0
||
p_sys
->
i_frame_samples
<=
0
)
{
msg_Dbg
(
p_demux
,
"invalid frame size"
);
goto
error
;
}
if
(
p_sys
->
fmt
.
audio
.
i_rate
<=
0
)
{
msg_Dbg
(
p_demux
,
"invalid sample rate"
);
goto
error
;
}
msg_Dbg
(
p_demux
,
"found %s audio format"
,
psz_name
);
msg_Dbg
(
p_demux
,
"found %s audio format"
,
psz_name
);
if
(
ChunkFind
(
p_demux
,
"data"
,
&
p_sys
->
i_data_size
)
)
if
(
ChunkFind
(
p_demux
,
"data"
,
&
p_sys
->
i_data_size
)
)
...
@@ -281,12 +306,13 @@ static int Open( vlc_object_t * p_this )
...
@@ -281,12 +306,13 @@ static int Open( vlc_object_t * p_this )
msg_Err
(
p_demux
,
"cannot find 'data' chunk"
);
msg_Err
(
p_demux
,
"cannot find 'data' chunk"
);
goto
error
;
goto
error
;
}
}
stream_Read
(
p_demux
->
s
,
NULL
,
8
);
/* Cannot fail */
if
(
stream_Read
(
p_demux
->
s
,
NULL
,
8
)
!=
8
)
goto
error
;
p_sys
->
i_data_pos
=
stream_Tell
(
p_demux
->
s
);
p_sys
->
i_data_pos
=
stream_Tell
(
p_demux
->
s
);
if
(
p_sys
->
fmt
.
i_bitrate
<=
0
)
if
(
p_sys
->
fmt
.
i_bitrate
<=
0
)
{
{
p_sys
->
fmt
.
i_bitrate
=
(
mtime
_t
)
p_sys
->
i_frame_size
*
p_sys
->
fmt
.
i_bitrate
=
(
int64
_t
)
p_sys
->
i_frame_size
*
p_sys
->
fmt
.
audio
.
i_rate
*
8
/
p_sys
->
i_frame_samples
;
p_sys
->
fmt
.
audio
.
i_rate
*
8
/
p_sys
->
i_frame_samples
;
}
}
...
@@ -311,10 +337,8 @@ error:
...
@@ -311,10 +337,8 @@ error:
static
int
Demux
(
demux_t
*
p_demux
)
static
int
Demux
(
demux_t
*
p_demux
)
{
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
int64_t
i_pos
;
block_t
*
p_block
;
block_t
*
p_block
;
const
int64_t
i_pos
=
stream_Tell
(
p_demux
->
s
);
i_pos
=
stream_Tell
(
p_demux
->
s
);
if
(
p_sys
->
i_data_size
>
0
&&
if
(
p_sys
->
i_data_size
>
0
&&
i_pos
>=
p_sys
->
i_data_pos
+
p_sys
->
i_data_size
)
i_pos
>=
p_sys
->
i_data_pos
+
p_sys
->
i_data_size
)
...
@@ -329,8 +353,8 @@ static int Demux( demux_t *p_demux )
...
@@ -329,8 +353,8 @@ static int Demux( demux_t *p_demux )
return
0
;
return
0
;
}
}
p_block
->
i_dts
=
p_block
->
i_pts
=
p_block
->
i_dts
=
date_Increment
(
&
p_sys
->
pts
,
p_sys
->
i_frame_samples
);
p_block
->
i_pts
=
date_Increment
(
&
p_sys
->
pts
,
p_sys
->
i_frame_samples
);
/* set PCR */
/* set PCR */
es_out_Control
(
p_demux
->
out
,
ES_OUT_SET_PCR
,
p_block
->
i_pts
);
es_out_Control
(
p_demux
->
out
,
ES_OUT_SET_PCR
,
p_block
->
i_pts
);
...
@@ -367,9 +391,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
...
@@ -367,9 +391,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
int64_t
i_end
=
-
1
;
int64_t
i_end
=
-
1
;
if
(
p_sys
->
i_data_size
>
0
)
if
(
p_sys
->
i_data_size
>
0
)
{
i_end
=
p_sys
->
i_data_pos
+
p_sys
->
i_data_size
;
i_end
=
p_sys
->
i_data_pos
+
p_sys
->
i_data_size
;
}
return
demux_vaControlHelper
(
p_demux
->
s
,
p_sys
->
i_data_pos
,
i_end
,
return
demux_vaControlHelper
(
p_demux
->
s
,
p_sys
->
i_data_pos
,
i_end
,
p_sys
->
fmt
.
i_bitrate
,
p_sys
->
fmt
.
i_bitrate
,
...
@@ -408,64 +430,71 @@ static int ChunkFind( demux_t *p_demux, const char *fcc, unsigned int *pi_size )
...
@@ -408,64 +430,71 @@ static int ChunkFind( demux_t *p_demux, const char *fcc, unsigned int *pi_size )
}
}
/* Skip chunk */
/* Skip chunk */
if
(
stream_Read
(
p_demux
->
s
,
NULL
,
8
)
!=
8
if
(
stream_Read
(
p_demux
->
s
,
NULL
,
8
)
!=
8
||
||
stream_Read
(
p_demux
->
s
,
NULL
,
i_size
)
!=
i_size
stream_Read
(
p_demux
->
s
,
NULL
,
i_size
)
!=
(
int
)
i_size
||
||
((
i_size
&
1
)
&&
stream_Read
(
p_demux
->
s
,
NULL
,
1
)
!=
1
)
)
(
(
i_size
&
1
)
&&
stream_Read
(
p_demux
->
s
,
NULL
,
1
)
!=
1
)
)
return
VLC_EGENERIC
;
return
VLC_EGENERIC
;
}
}
}
}
static
void
FrameInfo_PCM
(
demux_t
*
p_demux
,
unsigned
int
*
pi_size
,
static
int
FrameInfo_PCM
(
unsigned
int
*
pi_size
,
int
*
pi_samples
,
int
*
pi_samples
)
const
es_format_t
*
p_fmt
)
{
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
int
i_bytes
;
int
i_bytes
,
i_modulo
;
/* read samples for 50ms of */
/* read samples for 50ms of */
*
pi_samples
=
__MAX
(
p_
sys
->
fmt
.
audio
.
i_rate
/
20
,
1
);
*
pi_samples
=
__MAX
(
p_
fmt
->
audio
.
i_rate
/
20
,
1
);
i_bytes
=
*
pi_samples
*
p_
sys
->
fmt
.
audio
.
i_channels
*
i_bytes
=
*
pi_samples
*
p_
fmt
->
audio
.
i_channels
*
(
(
p_
sys
->
fmt
.
audio
.
i_bitspersample
+
7
)
/
8
);
(
(
p_
fmt
->
audio
.
i_bitspersample
+
7
)
/
8
);
if
(
p_
sys
->
fmt
.
audio
.
i_blockalign
>
0
)
if
(
p_
fmt
->
audio
.
i_blockalign
>
0
)
{
{
if
(
(
i_modulo
=
i_bytes
%
p_sys
->
fmt
.
audio
.
i_blockalign
)
!=
0
)
const
int
i_modulo
=
i_bytes
%
p_fmt
->
audio
.
i_blockalign
;
{
if
(
i_modulo
>
0
)
i_bytes
+=
p_sys
->
fmt
.
audio
.
i_blockalign
-
i_modulo
;
i_bytes
+=
p_fmt
->
audio
.
i_blockalign
-
i_modulo
;
}
}
}
*
pi_size
=
i_bytes
;
*
pi_size
=
i_bytes
;
return
VLC_EGENERIC
;
}
}
static
void
FrameInfo_MS_ADPCM
(
demux_t
*
p_demux
,
unsigned
int
*
pi_size
,
static
int
FrameInfo_MS_ADPCM
(
unsigned
int
*
pi_size
,
int
*
pi_samples
,
int
*
pi_samples
)
const
es_format_t
*
p_fmt
)
{
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
if
(
p_fmt
->
audio
.
i_channels
<=
0
)
return
VLC_EGENERIC
;
*
pi_samples
=
2
+
2
*
(
p_sys
->
fmt
.
audio
.
i_blockalign
-
*
pi_samples
=
2
+
2
*
(
p_fmt
->
audio
.
i_blockalign
-
7
*
p_sys
->
fmt
.
audio
.
i_channels
)
/
p_sys
->
fmt
.
audio
.
i_channels
;
7
*
p_fmt
->
audio
.
i_channels
)
/
p_fmt
->
audio
.
i_channels
;
*
pi_size
=
p_fmt
->
audio
.
i_blockalign
;
*
pi_size
=
p_sys
->
fmt
.
audio
.
i_blockalign
;
return
VLC_SUCCESS
;
}
}
static
void
FrameInfo_IMA_ADPCM
(
demux_t
*
p_demux
,
unsigned
int
*
pi_size
,
static
int
FrameInfo_IMA_ADPCM
(
unsigned
int
*
pi_size
,
int
*
pi_samples
,
int
*
pi_samples
)
const
es_format_t
*
p_fmt
)
{
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
if
(
p_fmt
->
audio
.
i_channels
<=
0
)
return
VLC_EGENERIC
;
*
pi_samples
=
2
*
(
p_sys
->
fmt
.
audio
.
i_blockalign
-
*
pi_samples
=
2
*
(
p_fmt
->
audio
.
i_blockalign
-
4
*
p_sys
->
fmt
.
audio
.
i_channels
)
/
p_sys
->
fmt
.
audio
.
i_channels
;
4
*
p_fmt
->
audio
.
i_channels
)
/
p_fmt
->
audio
.
i_channels
;
*
pi_size
=
p_fmt
->
audio
.
i_blockalign
;
*
pi_size
=
p_sys
->
fmt
.
audio
.
i_blockalign
;
return
VLC_SUCCESS
;
}
}
static
void
FrameInfo_MSGSM
(
demux_t
*
p_demux
,
unsigned
int
*
pi_size
,
static
int
FrameInfo_MSGSM
(
unsigned
int
*
pi_size
,
int
*
pi_samples
,
int
*
pi_samples
)
const
es_format_t
*
p_fmt
)
{
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
if
(
p_fmt
->
i_bitrate
<=
0
)
return
VLC_EGENERIC
;
*
pi_samples
=
(
p_fmt
->
audio
.
i_blockalign
*
p_fmt
->
audio
.
i_rate
*
8
)
/
p_fmt
->
i_bitrate
;
*
pi_size
=
p_fmt
->
audio
.
i_blockalign
;
*
pi_samples
=
(
p_sys
->
fmt
.
audio
.
i_blockalign
*
p_sys
->
fmt
.
audio
.
i_rate
*
8
)
return
VLC_SUCCESS
;
/
p_sys
->
fmt
.
i_bitrate
;
*
pi_size
=
p_sys
->
fmt
.
audio
.
i_blockalign
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment