Commit e344c1ea authored by Steve L'Homme's avatar Steve L'Homme Committed by Diego Biurrun

reindentation, patch by From: Steve Lhomme, slhomme divxcorp com

Originally committed as revision 6864 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 484267f3
......@@ -33,20 +33,19 @@
* instead of simply using 32bit integer arithmetic.
*/
typedef struct Float11 {
int sign; /**< 1bit sign */
int exp; /**< 4bit exponent */
int mant; /**< 6bit mantissa */
int sign; /**< 1bit sign */
int exp; /**< 4bit exponent */
int mant; /**< 6bit mantissa */
} Float11;
static inline Float11* i2f(int16_t i, Float11* f)
{
f->sign = (i < 0);
if (f->sign)
i = -i;
f->exp = av_log2_16bit(i) + !!i;
f->mant = i? (i<<6) >> f->exp :
1<<5;
return f;
f->sign = (i < 0);
if (f->sign)
i = -i;
f->exp = av_log2_16bit(i) + !!i;
f->mant = i? (i<<6) >> f->exp : 1<<5;
return f;
}
static inline int16_t mult(Float11* f1, Float11* f2)
......@@ -61,39 +60,39 @@ static inline int16_t mult(Float11* f1, Float11* f2)
static inline int sgn(int value)
{
return (value < 0) ? -1 : 1;
return (value < 0) ? -1 : 1;
}
typedef struct G726Tables {
int bits; /**< bits per sample */
int* quant; /**< quantization table */
int* iquant; /**< inverse quantization table */
int* W; /**< special table #1 ;-) */
int* F; /**< special table #2 */
int bits; /**< bits per sample */
int* quant; /**< quantization table */
int* iquant; /**< inverse quantization table */
int* W; /**< special table #1 ;-) */
int* F; /**< special table #2 */
} G726Tables;
typedef struct G726Context {
G726Tables* tbls; /**< static tables needed for computation */
Float11 sr[2]; /**< prev. reconstructed samples */
Float11 dq[6]; /**< prev. difference */
int a[2]; /**< second order predictor coeffs */
int b[6]; /**< sixth order predictor coeffs */
int pk[2]; /**< signs of prev. 2 sez + dq */
int ap; /**< scale factor control */
int yu; /**< fast scale factor */
int yl; /**< slow scale factor */
int dms; /**< short average magnitude of F[i] */
int dml; /**< long average magnitude of F[i] */
int td; /**< tone detect */
int se; /**< estimated signal for the next iteration */
int sez; /**< estimated second order prediction */
int y; /**< quantizer scaling factor for the next iteration */
G726Tables* tbls; /**< static tables needed for computation */
Float11 sr[2]; /**< prev. reconstructed samples */
Float11 dq[6]; /**< prev. difference */
int a[2]; /**< second order predictor coeffs */
int b[6]; /**< sixth order predictor coeffs */
int pk[2]; /**< signs of prev. 2 sez + dq */
int ap; /**< scale factor control */
int yu; /**< fast scale factor */
int yl; /**< slow scale factor */
int dms; /**< short average magnitude of F[i] */
int dml; /**< long average magnitude of F[i] */
int td; /**< tone detect */
int se; /**< estimated signal for the next iteration */
int sez; /**< estimated second order prediction */
int y; /**< quantizer scaling factor for the next iteration */
} G726Context;
static int quant_tbl16[] = /**< 16kbit/s 2bits per sample */
static int quant_tbl16[] = /**< 16kbit/s 2bits per sample */
{ 260, INT_MAX };
static int iquant_tbl16[] =
{ 116, 365, 365, 116 };
......@@ -102,7 +101,7 @@ static int W_tbl16[] =
static int F_tbl16[] =
{ 0, 7, 7, 0 };
static int quant_tbl24[] = /**< 24kbit/s 3bits per sample */
static int quant_tbl24[] = /**< 24kbit/s 3bits per sample */
{ 7, 217, 330, INT_MAX };
static int iquant_tbl24[] =
{ INT_MIN, 135, 273, 373, 373, 273, 135, INT_MIN };
......@@ -111,7 +110,7 @@ static int W_tbl24[] =
static int F_tbl24[] =
{ 0, 1, 2, 7, 7, 2, 1, 0 };
static int quant_tbl32[] = /**< 32kbit/s 4bits per sample */
static int quant_tbl32[] = /**< 32kbit/s 4bits per sample */
{ -125, 79, 177, 245, 299, 348, 399, INT_MAX };
static int iquant_tbl32[] =
{ INT_MIN, 4, 135, 213, 273, 323, 373, 425,
......@@ -122,7 +121,7 @@ static int W_tbl32[] =
static int F_tbl32[] =
{ 0, 0, 0, 1, 1, 1, 3, 7, 7, 3, 1, 1, 1, 0, 0, 0 };
static int quant_tbl40[] = /**< 40kbit/s 5bits per sample */
static int quant_tbl40[] = /**< 40kbit/s 5bits per sample */
{ -122, -16, 67, 138, 197, 249, 297, 338,
377, 412, 444, 474, 501, 527, 552, INT_MAX };
static int iquant_tbl40[] =
......@@ -151,25 +150,25 @@ static G726Tables G726Tables_pool[] =
*/
static inline uint8_t quant(G726Context* c, int d)
{
int sign, exp, i, dln;
int sign, exp, i, dln;
sign = i = 0;
if (d < 0) {
sign = 1;
d = -d;
}
exp = av_log2_16bit(d);
dln = ((exp<<7) + (((d<<7)>>exp)&0x7f)) - (c->y>>2);
sign = i = 0;
if (d < 0) {
sign = 1;
d = -d;
}
exp = av_log2_16bit(d);
dln = ((exp<<7) + (((d<<7)>>exp)&0x7f)) - (c->y>>2);
while (c->tbls->quant[i] < INT_MAX && c->tbls->quant[i] < dln)
while (c->tbls->quant[i] < INT_MAX && c->tbls->quant[i] < dln)
++i;
if (sign)
i = ~i;
if (c->tbls->bits != 2 && i == 0) /* I'm not sure this is a good idea */
i = 0xff;
if (sign)
i = ~i;
if (c->tbls->bits != 2 && i == 0) /* I'm not sure this is a good idea */
i = 0xff;
return i;
return i;
}
/**
......@@ -211,7 +210,7 @@ static inline int16_t g726_iterate(G726Context* c, int16_t I)
c->a[0] = 0;
c->a[1] = 0;
for (i=0; i<6; i++)
c->b[i] = 0;
c->b[i] = 0;
} else {
/* This is a bit crazy, but it really is +255 not +256 */
fa1 = clip((-c->a[0]*c->pk[0]*pk0)>>5, -256, 255);
......@@ -222,7 +221,7 @@ static inline int16_t g726_iterate(G726Context* c, int16_t I)
c->a[0] = clip(c->a[0], -(15360 - c->a[1]), 15360 - c->a[1]);
for (i=0; i<6; i++)
c->b[i] += 128*dq0*sgn(-c->dq[i].sign) - (c->b[i]>>8);
c->b[i] += 128*dq0*sgn(-c->dq[i].sign) - (c->b[i]>>8);
}
/* Update Dq and Sr and Pk */
......@@ -231,7 +230,7 @@ static inline int16_t g726_iterate(G726Context* c, int16_t I)
c->sr[1] = c->sr[0];
i2f(re_signal, &c->sr[0]);
for (i=5; i>0; i--)
c->dq[i] = c->dq[i-1];
c->dq[i] = c->dq[i-1];
i2f(dq, &c->dq[0]);
c->dq[0].sign = I >> (c->tbls->bits - 1); /* Isn't it crazy ?!?! */
......@@ -242,11 +241,11 @@ static inline int16_t g726_iterate(G726Context* c, int16_t I)
c->dms += ((c->tbls->F[I]<<9) - c->dms) >> 5;
c->dml += ((c->tbls->F[I]<<11) - c->dml) >> 7;
if (tr)
c->ap = 256;
c->ap = 256;
else if (c->y > 1535 && !c->td && (abs((c->dms << 2) - c->dml) < (c->dml >> 3)))
c->ap += (-c->ap) >> 4;
c->ap += (-c->ap) >> 4;
else
c->ap += (0x200 - c->ap) >> 4;
c->ap += (0x200 - c->ap) >> 4;
/* Update Yu and Yl */
c->yu = clip(c->y + (((c->tbls->W[I] << 5) - c->y) >> 5), 544, 5120);
......@@ -259,10 +258,10 @@ static inline int16_t g726_iterate(G726Context* c, int16_t I)
/* Next iteration for SE and SEZ */
c->se = 0;
for (i=0; i<6; i++)
c->se += mult(i2f(c->b[i] >> 2, &f), &c->dq[i]);
c->se += mult(i2f(c->b[i] >> 2, &f), &c->dq[i]);
c->sez = c->se >> 1;
for (i=0; i<2; i++)
c->se += mult(i2f(c->a[i] >> 2, &f), &c->sr[i]);
c->se += mult(i2f(c->a[i] >> 2, &f), &c->sr[i]);
c->se >>= 1;
return clip(re_signal << 2, -0xffff, 0xffff);
......@@ -274,13 +273,13 @@ static int g726_reset(G726Context* c, int bit_rate)
c->tbls = &G726Tables_pool[bit_rate/8000 - 2];
for (i=0; i<2; i++) {
i2f(0, &c->sr[i]);
c->a[i] = 0;
c->pk[i] = 1;
i2f(0, &c->sr[i]);
c->a[i] = 0;
c->pk[i] = 1;
}
for (i=0; i<6; i++) {
i2f(0, &c->dq[i]);
c->b[i] = 0;
i2f(0, &c->dq[i]);
c->b[i] = 0;
}
c->ap = 0;
c->dms = 0;
......@@ -304,21 +303,21 @@ static int16_t g726_decode(G726Context* c, int16_t i)
#ifdef CONFIG_ENCODERS
static int16_t g726_encode(G726Context* c, int16_t sig)
{
uint8_t i;
uint8_t i;
i = quant(c, sig/4 - c->se) & ((1<<c->tbls->bits) - 1);
g726_iterate(c, i);
return i;
i = quant(c, sig/4 - c->se) & ((1<<c->tbls->bits) - 1);
g726_iterate(c, i);
return i;
}
#endif
/* Interfacing to the libavcodec */
typedef struct AVG726Context {
G726Context c;
int bits_left;
int bit_buffer;
int code_size;
G726Context c;
int bits_left;
int bit_buffer;
int code_size;
} AVG726Context;
static int g726_init(AVCodecContext * avctx)
......@@ -365,7 +364,7 @@ static int g726_encode_frame(AVCodecContext *avctx,
init_put_bits(&pb, dst, 1024*1024);
for (; buf_size; buf_size--)
put_bits(&pb, c->code_size, g726_encode(&c->c, *samples++));
put_bits(&pb, c->code_size, g726_encode(&c->c, *samples++));
flush_put_bits(&pb);
......
......@@ -30,51 +30,51 @@
#define BUFFER_SIZE (2*MPA_FRAME_SIZE)
typedef struct Mp3AudioContext {
lame_global_flags *gfp;
int stereo;
uint8_t buffer[BUFFER_SIZE];
int buffer_index;
lame_global_flags *gfp;
int stereo;
uint8_t buffer[BUFFER_SIZE];
int buffer_index;
} Mp3AudioContext;
static int MP3lame_encode_init(AVCodecContext *avctx)
{
Mp3AudioContext *s = avctx->priv_data;
if (avctx->channels > 2)
return -1;
s->stereo = avctx->channels > 1 ? 1 : 0;
if ((s->gfp = lame_init()) == NULL)
goto err;
lame_set_in_samplerate(s->gfp, avctx->sample_rate);
lame_set_out_samplerate(s->gfp, avctx->sample_rate);
lame_set_num_channels(s->gfp, avctx->channels);
/* lame 3.91 dies on quality != 5 */
lame_set_quality(s->gfp, 5);
/* lame 3.91 doesn't work in mono */
lame_set_mode(s->gfp, JOINT_STEREO);
lame_set_brate(s->gfp, avctx->bit_rate/1000);
Mp3AudioContext *s = avctx->priv_data;
if (avctx->channels > 2)
return -1;
s->stereo = avctx->channels > 1 ? 1 : 0;
if ((s->gfp = lame_init()) == NULL)
goto err;
lame_set_in_samplerate(s->gfp, avctx->sample_rate);
lame_set_out_samplerate(s->gfp, avctx->sample_rate);
lame_set_num_channels(s->gfp, avctx->channels);
/* lame 3.91 dies on quality != 5 */
lame_set_quality(s->gfp, 5);
/* lame 3.91 doesn't work in mono */
lame_set_mode(s->gfp, JOINT_STEREO);
lame_set_brate(s->gfp, avctx->bit_rate/1000);
if(avctx->flags & CODEC_FLAG_QSCALE) {
lame_set_brate(s->gfp, 0);
lame_set_VBR(s->gfp, vbr_default);
lame_set_VBR_q(s->gfp, avctx->global_quality / (float)FF_QP2LAMBDA);
}
lame_set_bWriteVbrTag(s->gfp,0);
if (lame_init_params(s->gfp) < 0)
goto err_close;
lame_set_bWriteVbrTag(s->gfp,0);
if (lame_init_params(s->gfp) < 0)
goto err_close;
avctx->frame_size = lame_get_framesize(s->gfp);
avctx->frame_size = lame_get_framesize(s->gfp);
avctx->coded_frame= avcodec_alloc_frame();
avctx->coded_frame->key_frame= 1;
avctx->coded_frame= avcodec_alloc_frame();
avctx->coded_frame->key_frame= 1;
return 0;
return 0;
err_close:
lame_close(s->gfp);
lame_close(s->gfp);
err:
return -1;
return -1;
}
static const int sSampleRates[3] = {
......@@ -138,11 +138,11 @@ static int mp3len(void *data, int *samplesPerFrame, int *sampleRate)
int MP3lame_encode_frame(AVCodecContext *avctx,
unsigned char *frame, int buf_size, void *data)
{
Mp3AudioContext *s = avctx->priv_data;
int len;
int lame_result;
Mp3AudioContext *s = avctx->priv_data;
int len;
int lame_result;
/* lame 3.91 dies on '1-channel interleaved' data */
/* lame 3.91 dies on '1-channel interleaved' data */
if(data){
if (s->stereo) {
......@@ -200,12 +200,12 @@ int MP3lame_encode_frame(AVCodecContext *avctx,
int MP3lame_encode_close(AVCodecContext *avctx)
{
Mp3AudioContext *s = avctx->priv_data;
Mp3AudioContext *s = avctx->priv_data;
av_freep(&avctx->coded_frame);
av_freep(&avctx->coded_frame);
lame_close(s->gfp);
return 0;
lame_close(s->gfp);
return 0;
}
......
......@@ -3109,93 +3109,93 @@ static int mpeg_decode_frame(AVCodecContext *avctx,
av_log(avctx, AV_LOG_DEBUG, "%3X at %zd left %d\n", start_code, buf_ptr-buf, input_size);
}
/* prepare data for next start code */
switch(start_code) {
case SEQ_START_CODE:
mpeg1_decode_sequence(avctx, buf_ptr,
input_size);
break;
/* prepare data for next start code */
switch(start_code) {
case SEQ_START_CODE:
mpeg1_decode_sequence(avctx, buf_ptr,
input_size);
break;
case PICTURE_START_CODE:
/* we have a complete image : we try to decompress it */
mpeg1_decode_picture(avctx,
buf_ptr, input_size);
break;
case EXT_START_CODE:
mpeg_decode_extension(avctx,
buf_ptr, input_size);
break;
case USER_START_CODE:
mpeg_decode_user_data(avctx,
buf_ptr, input_size);
break;
case GOP_START_CODE:
s2->first_field=0;
mpeg_decode_gop(avctx,
buf_ptr, input_size);
case PICTURE_START_CODE:
/* we have a complete image : we try to decompress it */
mpeg1_decode_picture(avctx,
buf_ptr, input_size);
break;
case EXT_START_CODE:
mpeg_decode_extension(avctx,
buf_ptr, input_size);
break;
case USER_START_CODE:
mpeg_decode_user_data(avctx,
buf_ptr, input_size);
break;
case GOP_START_CODE:
s2->first_field=0;
mpeg_decode_gop(avctx,
buf_ptr, input_size);
break;
default:
if (start_code >= SLICE_MIN_START_CODE &&
start_code <= SLICE_MAX_START_CODE) {
int mb_y= start_code - SLICE_MIN_START_CODE;
if(s2->last_picture_ptr==NULL){
/* skip b frames if we dont have reference frames */
if(s2->pict_type==B_TYPE) break;
/* skip P frames if we dont have reference frame no valid header */
// if(s2->pict_type==P_TYPE && s2->first_field && !s2->first_slice) break;
}
/* skip b frames if we are in a hurry */
if(avctx->hurry_up && s2->pict_type==B_TYPE) break;
if( (avctx->skip_frame >= AVDISCARD_NONREF && s2->pict_type==B_TYPE)
||(avctx->skip_frame >= AVDISCARD_NONKEY && s2->pict_type!=I_TYPE)
|| avctx->skip_frame >= AVDISCARD_ALL)
break;
default:
if (start_code >= SLICE_MIN_START_CODE &&
start_code <= SLICE_MAX_START_CODE) {
int mb_y= start_code - SLICE_MIN_START_CODE;
if(s2->last_picture_ptr==NULL){
/* skip b frames if we dont have reference frames */
if(s2->pict_type==B_TYPE) break;
/* skip P frames if we dont have reference frame no valid header */
// if(s2->pict_type==P_TYPE && s2->first_field && !s2->first_slice) break;
}
/* skip b frames if we are in a hurry */
if(avctx->hurry_up && s2->pict_type==B_TYPE) break;
if( (avctx->skip_frame >= AVDISCARD_NONREF && s2->pict_type==B_TYPE)
||(avctx->skip_frame >= AVDISCARD_NONKEY && s2->pict_type!=I_TYPE)
|| avctx->skip_frame >= AVDISCARD_ALL)
break;
/* skip everything if we are in a hurry>=5 */
if(avctx->hurry_up>=5) break;
if (!s->mpeg_enc_ctx_allocated) break;
if(s2->codec_id == CODEC_ID_MPEG2VIDEO){
if(mb_y < avctx->skip_top || mb_y >= s2->mb_height - avctx->skip_bottom)
break;
}
/* skip everything if we are in a hurry>=5 */
if(avctx->hurry_up>=5) break;
if(s2->first_slice){
s2->first_slice=0;
if(mpeg_field_start(s2) < 0)
return -1;
}
if (!s->mpeg_enc_ctx_allocated) break;
if(s2->codec_id == CODEC_ID_MPEG2VIDEO){
if(mb_y < avctx->skip_top || mb_y >= s2->mb_height - avctx->skip_bottom)
break;
}
if(avctx->thread_count > 1){
int threshold= (s2->mb_height*s->slice_count + avctx->thread_count/2) / avctx->thread_count;
if(threshold <= mb_y){
MpegEncContext *thread_context= s2->thread_context[s->slice_count];
if(s2->first_slice){
s2->first_slice=0;
if(mpeg_field_start(s2) < 0)
return -1;
}
thread_context->start_mb_y= mb_y;
thread_context->end_mb_y = s2->mb_height;
if(s->slice_count){
s2->thread_context[s->slice_count-1]->end_mb_y= mb_y;
ff_update_duplicate_context(thread_context, s2);
}
init_get_bits(&thread_context->gb, buf_ptr, input_size*8);
s->slice_count++;
}
buf_ptr += 2; //FIXME add minimum num of bytes per slice
}else{
ret = mpeg_decode_slice(s, mb_y, &buf_ptr, input_size);
emms_c();
if(ret < 0){
if(s2->resync_mb_x>=0 && s2->resync_mb_y>=0)
ff_er_add_slice(s2, s2->resync_mb_x, s2->resync_mb_y, s2->mb_x, s2->mb_y, AC_ERROR|DC_ERROR|MV_ERROR);
}else{
ff_er_add_slice(s2, s2->resync_mb_x, s2->resync_mb_y, s2->mb_x-1, s2->mb_y, AC_END|DC_END|MV_END);
}
if(avctx->thread_count > 1){
int threshold= (s2->mb_height*s->slice_count + avctx->thread_count/2) / avctx->thread_count;
if(threshold <= mb_y){
MpegEncContext *thread_context= s2->thread_context[s->slice_count];
thread_context->start_mb_y= mb_y;
thread_context->end_mb_y = s2->mb_height;
if(s->slice_count){
s2->thread_context[s->slice_count-1]->end_mb_y= mb_y;
ff_update_duplicate_context(thread_context, s2);
}
init_get_bits(&thread_context->gb, buf_ptr, input_size*8);
s->slice_count++;
}
buf_ptr += 2; //FIXME add minimum num of bytes per slice
}else{
ret = mpeg_decode_slice(s, mb_y, &buf_ptr, input_size);
emms_c();
if(ret < 0){
if(s2->resync_mb_x>=0 && s2->resync_mb_y>=0)
ff_er_add_slice(s2, s2->resync_mb_x, s2->resync_mb_y, s2->mb_x, s2->mb_y, AC_ERROR|DC_ERROR|MV_ERROR);
}else{
ff_er_add_slice(s2, s2->resync_mb_x, s2->resync_mb_y, s2->mb_x-1, s2->mb_y, AC_END|DC_END|MV_END);
}
break;
}
}
break;
}
}
}
......
......@@ -287,7 +287,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
tag1 = get_le32(pb);
handler = get_le32(pb); /* codec tag */
#ifdef DEBUG
print_tag("strh", tag1, -1);
print_tag("strh", tag1, -1);
#endif
if(tag1 == MKTAG('i', 'a', 'v', 's') || tag1 == MKTAG('i', 'v', 'a', 's')){
/*
......@@ -399,11 +399,11 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
get_le32(pb); /* ClrUsed */
get_le32(pb); /* ClrImportant */
if(size > 10*4 && size<(1<<30)){
st->codec->extradata_size= size - 10*4;
st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
get_buffer(pb, st->codec->extradata, st->codec->extradata_size);
}
if(size > 10*4 && size<(1<<30)){
st->codec->extradata_size= size - 10*4;
st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
get_buffer(pb, st->codec->extradata, st->codec->extradata_size);
}
if(st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly
get_byte(pb);
......
......@@ -1341,7 +1341,7 @@ static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov,
if (mov->mode == MODE_PSP)
mov_write_uuidusmt_tag(pb, s);
else
mov_write_udta_tag(pb, mov, s);
mov_write_udta_tag(pb, mov, s);
return updateSize(pb, pos);
}
......
......@@ -547,8 +547,8 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st,
buf[3] = get_byte(pb);
buf[4] = 0;
} else {
get_str8(pb, buf, sizeof(buf)); /* desc */
get_str8(pb, buf, sizeof(buf)); /* desc */
get_str8(pb, buf, sizeof(buf)); /* desc */
get_str8(pb, buf, sizeof(buf)); /* desc */
}
st->codec->codec_type = CODEC_TYPE_AUDIO;
if (!strcmp(buf, "dnet")) {
......
......@@ -302,10 +302,10 @@ static int vmd_read_packet(AVFormatContext *s,
pkt->data, pkt->size, vmd->audio_block_align);
}
av_log(NULL, AV_LOG_INFO, " dispatching %s frame with %d bytes and pts %"PRId64" (%0.1f sec)\n",
(frame->frame_record[0] == 0x02) ? "video" : "audio",
frame->frame_size + BYTES_PER_FRAME_RECORD,
pkt->pts, (float)(pkt->pts / 90000.0));
av_log(NULL, AV_LOG_INFO, " dispatching %s frame with %d bytes and pts %"PRId64" (%0.1f sec)\n",
(frame->frame_record[0] == 0x02) ? "video" : "audio",
frame->frame_size + BYTES_PER_FRAME_RECORD,
pkt->pts, (float)(pkt->pts / 90000.0));
vmd->current_frame++;
......
......@@ -1854,8 +1854,8 @@ int av_find_stream_info(AVFormatContext *ic)
/* duplicate the packet */
if (av_dup_packet(pkt) < 0) {
ret = AVERROR_NOMEM;
break;
ret = AVERROR_NOMEM;
break;
}
read_size += pkt->size;
......
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