Index: third_party/opus/src/tests/test_opus_encode.c |
diff --git a/third_party/opus/src/tests/test_opus_encode.c b/third_party/opus/src/tests/test_opus_encode.c |
index 132d074d3025456f9d2297e7988e85ac51610b85..dae49c3d5351bd556c03d74ed8ae69c21952062a 100644 |
--- a/third_party/opus/src/tests/test_opus_encode.c |
+++ b/third_party/opus/src/tests/test_opus_encode.c |
@@ -51,8 +51,8 @@ |
#define SAMPLES (48000*30) |
#define SSAMPLES (SAMPLES/3) |
#define MAX_FRAME_SAMP (5760) |
- |
#define PI (3.141592653589793238462643f) |
+#define RAND_SAMPLE(a) (a[fast_rand() % sizeof(a)/sizeof(a[0])]) |
void generate_music(short *buf, opus_int32 len) |
{ |
@@ -112,14 +112,169 @@ static OPUS_INLINE void save_packet(unsigned char* p, int len, opus_uint32 rng) |
} |
#endif |
+int get_frame_size_enum(int frame_size, int sampling_rate) |
+{ |
+ int frame_size_enum; |
+ |
+ if(frame_size==sampling_rate/400) |
+ frame_size_enum = OPUS_FRAMESIZE_2_5_MS; |
+ else if(frame_size==sampling_rate/200) |
+ frame_size_enum = OPUS_FRAMESIZE_5_MS; |
+ else if(frame_size==sampling_rate/100) |
+ frame_size_enum = OPUS_FRAMESIZE_10_MS; |
+ else if(frame_size==sampling_rate/50) |
+ frame_size_enum = OPUS_FRAMESIZE_20_MS; |
+ else if(frame_size==sampling_rate/25) |
+ frame_size_enum = OPUS_FRAMESIZE_40_MS; |
+ else if(frame_size==3*sampling_rate/50) |
+ frame_size_enum = OPUS_FRAMESIZE_60_MS; |
+ else if(frame_size==4*sampling_rate/50) |
+ frame_size_enum = OPUS_FRAMESIZE_80_MS; |
+ else if(frame_size==5*sampling_rate/50) |
+ frame_size_enum = OPUS_FRAMESIZE_100_MS; |
+ else if(frame_size==6*sampling_rate/50) |
+ frame_size_enum = OPUS_FRAMESIZE_120_MS; |
+ else |
+ test_failed(); |
+ |
+ return frame_size_enum; |
+} |
+ |
+void test_encode(OpusEncoder *enc, int channels, int frame_size, OpusDecoder *dec, const char* debug_info) |
+{ |
+ int samp_count = 0; |
+ opus_int16 *inbuf; |
+ unsigned char packet[MAX_PACKET+257]; |
+ int len; |
+ opus_int16 *outbuf; |
+ int out_samples; |
+ |
+ /* Generate input data */ |
+ inbuf = (opus_int16*)malloc(sizeof(*inbuf)*SSAMPLES); |
+ generate_music(inbuf, SSAMPLES/2); |
+ |
+ /* Allocate memory for output data */ |
+ outbuf = (opus_int16*)malloc(sizeof(*outbuf)*MAX_FRAME_SAMP*3); |
+ |
+ /* Encode data, then decode for sanity check */ |
+ do { |
+ len = opus_encode(enc, &inbuf[samp_count*channels], frame_size, packet, MAX_PACKET); |
+ if(len<0 || len>MAX_PACKET) { |
+ fprintf(stderr,"%s\n",debug_info); |
+ fprintf(stderr,"opus_encode() returned %d\n",len); |
+ test_failed(); |
+ } |
+ |
+ out_samples = opus_decode(dec, packet, len, outbuf, MAX_FRAME_SAMP, 0); |
+ if(out_samples!=frame_size) { |
+ fprintf(stderr,"%s\n",debug_info); |
+ fprintf(stderr,"opus_decode() returned %d\n",out_samples); |
+ test_failed(); |
+ } |
+ |
+ samp_count += frame_size; |
+ } while (samp_count < ((SSAMPLES/2)-MAX_FRAME_SAMP)); |
+ |
+ /* Clean up */ |
+ free(inbuf); |
+ free(outbuf); |
+} |
+ |
+void fuzz_encoder_settings(const int num_encoders, const int num_setting_changes) |
+{ |
+ OpusEncoder *enc; |
+ OpusDecoder *dec; |
+ int i,j,err; |
+ |
+ /* Parameters to fuzz. Some values are duplicated to increase their probability of being tested. */ |
+ int sampling_rates[5] = {8000, 12000, 16000, 24000, 48000}; |
+ int channels[2] = {1, 2}; |
+ int applications[3] = {OPUS_APPLICATION_AUDIO, OPUS_APPLICATION_VOIP, OPUS_APPLICATION_RESTRICTED_LOWDELAY}; |
+ int bitrates[11] = {6000, 12000, 16000, 24000, 32000, 48000, 64000, 96000, 510000, OPUS_AUTO, OPUS_BITRATE_MAX}; |
+ int force_channels[4] = {OPUS_AUTO, OPUS_AUTO, 1, 2}; |
+ int use_vbr[3] = {0, 1, 1}; |
+ int vbr_constraints[3] = {0, 1, 1}; |
+ int complexities[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; |
+ int max_bandwidths[6] = {OPUS_BANDWIDTH_NARROWBAND, OPUS_BANDWIDTH_MEDIUMBAND, |
+ OPUS_BANDWIDTH_WIDEBAND, OPUS_BANDWIDTH_SUPERWIDEBAND, |
+ OPUS_BANDWIDTH_FULLBAND, OPUS_BANDWIDTH_FULLBAND}; |
+ int signals[4] = {OPUS_AUTO, OPUS_AUTO, OPUS_SIGNAL_VOICE, OPUS_SIGNAL_MUSIC}; |
+ int inband_fecs[3] = {0, 0, 1}; |
+ int packet_loss_perc[4] = {0, 1, 2, 5}; |
+ int lsb_depths[2] = {8, 24}; |
+ int prediction_disabled[3] = {0, 0, 1}; |
+ int use_dtx[2] = {0, 1}; |
+ int frame_sizes_ms_x2[9] = {5, 10, 20, 40, 80, 120, 160, 200, 240}; /* x2 to avoid 2.5 ms */ |
+ char debug_info[512]; |
+ |
+ for (i=0; i<num_encoders; i++) { |
+ int sampling_rate = RAND_SAMPLE(sampling_rates); |
+ int num_channels = RAND_SAMPLE(channels); |
+ int application = RAND_SAMPLE(applications); |
+ |
+ dec = opus_decoder_create(sampling_rate, num_channels, &err); |
+ if(err!=OPUS_OK || dec==NULL)test_failed(); |
+ |
+ enc = opus_encoder_create(sampling_rate, num_channels, application, &err); |
+ if(err!=OPUS_OK || enc==NULL)test_failed(); |
+ |
+ for (j=0; j<num_setting_changes; j++) { |
+ int bitrate = RAND_SAMPLE(bitrates); |
+ int force_channel = RAND_SAMPLE(force_channels); |
+ int vbr = RAND_SAMPLE(use_vbr); |
+ int vbr_constraint = RAND_SAMPLE(vbr_constraints); |
+ int complexity = RAND_SAMPLE(complexities); |
+ int max_bw = RAND_SAMPLE(max_bandwidths); |
+ int sig = RAND_SAMPLE(signals); |
+ int inband_fec = RAND_SAMPLE(inband_fecs); |
+ int pkt_loss = RAND_SAMPLE(packet_loss_perc); |
+ int lsb_depth = RAND_SAMPLE(lsb_depths); |
+ int pred_disabled = RAND_SAMPLE(prediction_disabled); |
+ int dtx = RAND_SAMPLE(use_dtx); |
+ int frame_size_ms_x2 = RAND_SAMPLE(frame_sizes_ms_x2); |
+ int frame_size = frame_size_ms_x2*sampling_rate/2000; |
+ int frame_size_enum = get_frame_size_enum(frame_size, sampling_rate); |
+ force_channel = IMIN(force_channel, num_channels); |
+ |
+ sprintf(debug_info, |
+ "fuzz_encoder_settings: %d kHz, %d ch, application: %d, " |
+ "%d bps, force ch: %d, vbr: %d, vbr constraint: %d, complexity: %d, " |
+ "max bw: %d, signal: %d, inband fec: %d, pkt loss: %d%%, lsb depth: %d, " |
+ "pred disabled: %d, dtx: %d, (%d/2) ms\n", |
+ sampling_rate/1000, num_channels, application, bitrate, |
+ force_channel, vbr, vbr_constraint, complexity, max_bw, sig, inband_fec, |
+ pkt_loss, lsb_depth, pred_disabled, dtx, frame_size_ms_x2); |
+ |
+ if(opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(force_channel)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_VBR(vbr)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(vbr_constraint)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(max_bw)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_SIGNAL(sig)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(inband_fec)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(pkt_loss)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(lsb_depth)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(pred_disabled)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_DTX(dtx)) != OPUS_OK) test_failed(); |
+ if(opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(frame_size_enum)) != OPUS_OK) test_failed(); |
+ |
+ test_encode(enc, num_channels, frame_size, dec, debug_info); |
+ } |
+ |
+ opus_encoder_destroy(enc); |
+ opus_decoder_destroy(dec); |
+ } |
+} |
+ |
int run_test1(int no_fuzz) |
{ |
static const int fsizes[6]={960*3,960*2,120,240,480,960}; |
static const char *mstrings[3] = {" LP","Hybrid"," MDCT"}; |
unsigned char mapping[256] = {0,1,255}; |
unsigned char db62[36]; |
- opus_int32 i; |
- int rc,j,err; |
+ opus_int32 i,j; |
+ int rc,err; |
OpusEncoder *enc; |
OpusMSEncoder *MSenc; |
OpusDecoder *dec; |
@@ -229,6 +384,7 @@ int run_test1(int no_fuzz) |
if(opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO))!=OPUS_OK)test_failed(); |
if(opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(-2))!=OPUS_BAD_ARG)test_failed(); |
+ if(opus_encode(enc, inbuf, 500, packet, MAX_PACKET)!=OPUS_BAD_ARG)test_failed(); |
for(rc=0;rc<3;rc++) |
{ |
@@ -335,7 +491,8 @@ int run_test1(int no_fuzz) |
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_BITRATE(rate))!=OPUS_OK)test_failed(); |
count=i=0; |
do { |
- int pred,len,out_samples,frame_size,loss; |
+ int len,out_samples,frame_size,loss; |
+ opus_int32 pred; |
if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_PREDICTION_DISABLED(&pred))!=OPUS_OK)test_failed(); |
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_PREDICTION_DISABLED((int)(fast_rand()&15)<(pred?11:4)))!=OPUS_OK)test_failed(); |
frame_size=frame[j]; |
@@ -425,7 +582,7 @@ int run_test1(int no_fuzz) |
the decoders in order to compare them. */ |
if(opus_packet_parse(packet,len,&toc,frames,size,&payload_offset)<=0)test_failed(); |
if((fast_rand()&1023)==0)len=0; |
- for(j=(frames[0]-packet);j<len;j++)for(jj=0;jj<8;jj++)packet[j]^=((!no_fuzz)&&((fast_rand()&1023)==0))<<jj; |
+ for(j=(opus_int32)(frames[0]-packet);j<len;j++)for(jj=0;jj<8;jj++)packet[j]^=((!no_fuzz)&&((fast_rand()&1023)==0))<<jj; |
out_samples = opus_decode(dec_err[0], len>0?packet:NULL, len, out2buf, MAX_FRAME_SAMP, 0); |
if(out_samples<0||out_samples>MAX_FRAME_SAMP)test_failed(); |
if((len>0&&out_samples!=frame_size))test_failed(); /*FIXME use lastframe*/ |
@@ -470,39 +627,74 @@ int run_test1(int no_fuzz) |
return 0; |
} |
+void print_usage(char* _argv[]) |
+{ |
+ fprintf(stderr,"Usage: %s [<seed>] [-fuzz <num_encoders> <num_settings_per_encoder>]\n",_argv[0]); |
+} |
+ |
int main(int _argc, char **_argv) |
{ |
+ int args=1; |
+ char * strtol_str=NULL; |
const char * oversion; |
const char * env_seed; |
int env_used; |
- |
- if(_argc>2) |
- { |
- fprintf(stderr,"Usage: %s [<seed>]\n",_argv[0]); |
- return 1; |
- } |
+ int num_encoders_to_fuzz=5; |
+ int num_setting_changes=40; |
env_used=0; |
env_seed=getenv("SEED"); |
- if(_argc>1)iseed=atoi(_argv[1]); |
- else if(env_seed) |
- { |
+ if(_argc>1) |
+ iseed=strtol(_argv[1], &strtol_str, 10); /* the first input argument might be the seed */ |
+ if(strtol_str!=NULL && strtol_str[0]=='\0') /* iseed is a valid number */ |
+ args++; |
+ else if(env_seed) { |
iseed=atoi(env_seed); |
env_used=1; |
} |
- else iseed=(opus_uint32)time(NULL)^((getpid()&65535)<<16); |
+ else iseed=(opus_uint32)time(NULL)^(((opus_uint32)getpid()&65535)<<16); |
Rw=Rz=iseed; |
+ while(args<_argc) |
+ { |
+ if(strcmp(_argv[args], "-fuzz")==0 && _argc==(args+3)) { |
+ num_encoders_to_fuzz=strtol(_argv[args+1], &strtol_str, 10); |
+ if(strtol_str[0]!='\0' || num_encoders_to_fuzz<=0) { |
+ print_usage(_argv); |
+ return EXIT_FAILURE; |
+ } |
+ num_setting_changes=strtol(_argv[args+2], &strtol_str, 10); |
+ if(strtol_str[0]!='\0' || num_setting_changes<=0) { |
+ print_usage(_argv); |
+ return EXIT_FAILURE; |
+ } |
+ args+=3; |
+ } |
+ else { |
+ print_usage(_argv); |
+ return EXIT_FAILURE; |
+ } |
+ } |
+ |
oversion=opus_get_version_string(); |
if(!oversion)test_failed(); |
fprintf(stderr,"Testing %s encoder. Random seed: %u (%.4X)\n", oversion, iseed, fast_rand() % 65535); |
if(env_used)fprintf(stderr," Random seed set from the environment (SEED=%s).\n", env_seed); |
+ regression_test(); |
+ |
/*Setting TEST_OPUS_NOFUZZ tells the tool not to send garbage data |
into the decoders. This is helpful because garbage data |
may cause the decoders to clip, which angers CLANG IOC.*/ |
run_test1(getenv("TEST_OPUS_NOFUZZ")!=NULL); |
+ /* Fuzz encoder settings online */ |
+ if(getenv("TEST_OPUS_NOFUZZ")==NULL) { |
+ fprintf(stderr,"Running fuzz_encoder_settings with %d encoder(s) and %d setting change(s) each.\n", |
+ num_encoders_to_fuzz, num_setting_changes); |
+ fuzz_encoder_settings(num_encoders_to_fuzz, num_setting_changes); |
+ } |
+ |
fprintf(stderr,"Tests completed successfully.\n"); |
return 0; |