first commit

This commit is contained in:
sanya
2025-09-01 14:20:39 +00:00
committed by ExternPointer
commit 490fc11f6a
4328 changed files with 1796224 additions and 0 deletions

39
third_party/opus/tests/meson.build vendored Normal file
View File

@@ -0,0 +1,39 @@
# Tests that link to libopus
opus_tests = [
['test_opus_api'],
['test_opus_decode', [], 120],
['test_opus_encode', 'opus_encode_regressions.c', 240],
['test_opus_extensions', [], 120],
['test_opus_padding'],
['test_opus_projection'],
]
if opt_dred.enabled()
opus_tests += [['test_opus_dred', [], 60 * 20]]
endif
foreach t : opus_tests
test_name = t.get(0)
extra_srcs = t.get(1, [])
test_kwargs = {}
if t.length() > 2
test_kwargs += {'timeout': t[2]}
endif
exe_kwargs = {}
# This test uses private symbols
if test_name == 'test_opus_projection' or test_name == 'test_opus_extensions'
exe_kwargs = {
'link_with': [celt_lib, silk_lib, dnn_lib],
'objects': opus_lib.extract_all_objects(),
}
endif
exe = executable(test_name, '@0@.c'.format(test_name), extra_srcs,
include_directories: opus_includes,
dependencies: [libm, opus_dep],
install: false,
kwargs: exe_kwargs)
test(test_name, exe, kwargs: test_kwargs)
endforeach

File diff suppressed because it is too large Load Diff

143
third_party/opus/tests/run_vectors.sh vendored Executable file
View File

@@ -0,0 +1,143 @@
#!/bin/sh
# Copyright (c) 2011-2012 Jean-Marc Valin
#
# This file is extracted from RFC6716. Please see that RFC for additional
# information.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# - Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# - Neither the name of Internet Society, IETF or IETF Trust, nor the
# names of specific contributors, may be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
rm -f logs_mono.txt logs_mono2.txt
rm -f logs_stereo.txt logs_stereo2.txt
if [ "$#" -ne "3" ]; then
echo "usage: run_vectors.sh <exec path> <vector path> <rate>"
exit 1
fi
CMD_PATH=$1
VECTOR_PATH=$2
RATE=$3
: ${OPUS_DEMO:=$CMD_PATH/opus_demo}
: ${OPUS_COMPARE:=$CMD_PATH/opus_compare}
if [ -d "$VECTOR_PATH" ]; then
echo "Test vectors found in $VECTOR_PATH"
else
echo "No test vectors found"
#Don't make the test fail here because the test vectors
#will be distributed separately
exit 0
fi
if [ ! -x "$OPUS_COMPARE" ]; then
echo "ERROR: Compare program not found: $OPUS_COMPARE"
exit 1
fi
if [ -x "$OPUS_DEMO" ]; then
echo "Decoding with $OPUS_DEMO"
else
echo "ERROR: Decoder not found: $OPUS_DEMO"
exit 1
fi
echo "=============="
echo "Testing mono"
echo "=============="
echo
for file in 01 02 03 04 05 06 07 08 09 10 11 12
do
if [ -e "$VECTOR_PATH/testvector$file.bit" ]; then
echo "Testing testvector$file"
else
echo "Bitstream file not found: testvector$file.bit"
fi
if "$OPUS_DEMO" -d "$RATE" 1 "$VECTOR_PATH/testvector$file.bit" tmp.out >> logs_mono.txt 2>&1; then
echo "successfully decoded"
else
echo "ERROR: decoding failed"
exit 1
fi
"$OPUS_COMPARE" -r "$RATE" "$VECTOR_PATH/testvector${file}.dec" tmp.out >> logs_mono.txt 2>&1
float_ret=$?
"$OPUS_COMPARE" -r "$RATE" "$VECTOR_PATH/testvector${file}m.dec" tmp.out >> logs_mono2.txt 2>&1
float_ret2=$?
if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then
echo "output matches reference"
else
echo "ERROR: output does not match reference"
exit 1
fi
echo
done
echo "=============="
echo Testing stereo
echo "=============="
echo
for file in 01 02 03 04 05 06 07 08 09 10 11 12
do
if [ -e "$VECTOR_PATH/testvector$file.bit" ]; then
echo "Testing testvector$file"
else
echo "Bitstream file not found: testvector$file"
fi
if "$OPUS_DEMO" -d "$RATE" 2 "$VECTOR_PATH/testvector$file.bit" tmp.out >> logs_stereo.txt 2>&1; then
echo "successfully decoded"
else
echo "ERROR: decoding failed"
exit 1
fi
"$OPUS_COMPARE" -s -r "$RATE" "$VECTOR_PATH/testvector${file}.dec" tmp.out >> logs_stereo.txt 2>&1
float_ret=$?
"$OPUS_COMPARE" -s -r "$RATE" "$VECTOR_PATH/testvector${file}m.dec" tmp.out >> logs_stereo2.txt 2>&1
float_ret2=$?
if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then
echo "output matches reference"
else
echo "ERROR: output does not match reference"
exit 1
fi
echo
done
echo "All tests have passed successfully"
mono1=`grep quality logs_mono.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'`
mono2=`grep quality logs_mono2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'`
echo $mono1 $mono2 | awk '{if ($2 > $1) $1 = $2; print "Average mono quality is", $1, "%"}'
stereo1=`grep quality logs_stereo.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'`
stereo2=`grep quality logs_stereo2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'`
echo $stereo1 $stereo2 | awk '{if ($2 > $1) $1 = $2; print "Average stereo quality is", $1, "%"}'

1904
third_party/opus/tests/test_opus_api.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,86 @@
/* Copyright (c) 2011 Xiph.Org Foundation
Written by Gregory Maxwell */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
static OPUS_INLINE void deb2_impl(unsigned char *_t,unsigned char **_p,int _k,int _x,int _y)
{
int i;
if(_x>2){
if(_y<3)for(i=0;i<_y;i++)*(--*_p)=_t[i+1];
}else{
_t[_x]=_t[_x-_y];
deb2_impl(_t,_p,_k,_x+1,_y);
for(i=_t[_x-_y]+1;i<_k;i++){
_t[_x]=i;
deb2_impl(_t,_p,_k,_x+1,_x);
}
}
}
/*Generates a De Bruijn sequence (k,2) with length k^2*/
static OPUS_INLINE void debruijn2(int _k, unsigned char *_res)
{
unsigned char *p;
unsigned char *t;
t=malloc(sizeof(unsigned char)*_k*2);
memset(t,0,sizeof(unsigned char)*_k*2);
p=&_res[_k*_k];
deb2_impl(t,&p,_k,1,1);
free(t);
}
/*MWC RNG of George Marsaglia*/
static opus_uint32 Rz, Rw;
static OPUS_INLINE opus_uint32 fast_rand(void)
{
Rz=36969*(Rz&65535)+(Rz>>16);
Rw=18000*(Rw&65535)+(Rw>>16);
return (Rz<<16)+Rw;
}
static opus_uint32 iseed;
#ifdef __GNUC__
__attribute__((noreturn))
#elif defined(_MSC_VER)
__declspec(noreturn)
#endif
static OPUS_INLINE void _test_failed(const char *file, int line)
{
fprintf(stderr,"\n ***************************************************\n");
fprintf(stderr," *** A fatal error was detected. ***\n");
fprintf(stderr," ***************************************************\n");
fprintf(stderr,"Please report this failure and include\n");
fprintf(stderr,"'make check SEED=%u fails %s at line %d for %s'\n",iseed,file,line,opus_get_version_string());
fprintf(stderr,"and any relevant details about your system.\n\n");
#if defined(_MSC_VER)
_set_abort_behavior( 0, _WRITE_ABORT_MSG);
#endif
abort();
}
#define test_failed() _test_failed(__FILE__, __LINE__);
#define opus_test_assert(cond) {if (!(cond)) {test_failed();}}
#define expect_true(cond, msg) {if (!(cond)) {fprintf(stderr, "FAIL - %s\n", msg); test_failed();}}
void regression_test(void);

View File

@@ -0,0 +1,481 @@
/* Copyright (c) 2011-2013 Xiph.Org Foundation
Written by Gregory Maxwell */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <time.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include <process.h>
#define getpid _getpid
#endif
#include "opus.h"
#include "test_opus_common.h"
#define MAX_PACKET (1500)
#define MAX_FRAME_SAMP (5760)
int test_decoder_code0(int no_fuzz)
{
static const opus_int32 fsv[5]={48000,24000,16000,12000,8000};
int err,skip,plen;
int out_samples,fec;
int t;
opus_int32 i;
OpusDecoder *dec[5*2];
opus_int32 decsize;
OpusDecoder *decbak;
opus_uint32 dec_final_range1,dec_final_range2,dec_final_acc;
unsigned char *packet;
unsigned char modes[4096];
short *outbuf_int;
short *outbuf;
dec_final_range1=dec_final_range2=2;
packet=malloc(sizeof(unsigned char)*MAX_PACKET);
if(packet==NULL)test_failed();
outbuf_int=malloc(sizeof(short)*(MAX_FRAME_SAMP+16)*2);
for(i=0;i<(MAX_FRAME_SAMP+16)*2;i++)outbuf_int[i]=32749;
outbuf=&outbuf_int[8*2];
fprintf(stdout," Starting %d decoders...\n",5*2);
for(t=0;t<5*2;t++)
{
int fs=fsv[t>>1];
int c=(t&1)+1;
err=OPUS_INTERNAL_ERROR;
dec[t] = opus_decoder_create(fs, c, &err);
if(err!=OPUS_OK || dec[t]==NULL)test_failed();
fprintf(stdout," opus_decoder_create(%5d,%d) OK. Copy ",fs,c);
{
OpusDecoder *dec2;
/*The opus state structures contain no pointers and can be freely copied*/
dec2=(OpusDecoder *)malloc(opus_decoder_get_size(c));
if(dec2==NULL)test_failed();
memcpy(dec2,dec[t],opus_decoder_get_size(c));
memset(dec[t],255,opus_decoder_get_size(c));
opus_decoder_destroy(dec[t]);
printf("OK.\n");
dec[t]=dec2;
}
}
decsize=opus_decoder_get_size(1);
decbak=(OpusDecoder *)malloc(decsize);
if(decbak==NULL)test_failed();
for(t=0;t<5*2;t++)
{
int factor=48000/fsv[t>>1];
for(fec=0;fec<2;fec++)
{
opus_int32 dur;
#if defined(ENABLE_OSCE) || defined(ENABLE_DEEP_PLC)
opus_decoder_ctl(dec[t], OPUS_SET_COMPLEXITY(fast_rand()%11));
#endif
/*Test PLC on a fresh decoder*/
out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor, fec);
if(out_samples!=120/factor)test_failed();
if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
if(dur!=120/factor)test_failed();
/*Test on a size which isn't a multiple of 2.5ms*/
out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor+2, fec);
if(out_samples!=OPUS_BAD_ARG)test_failed();
/*Test null pointer input*/
out_samples = opus_decode(dec[t], 0, -1, outbuf, 120/factor, fec);
if(out_samples!=120/factor)test_failed();
out_samples = opus_decode(dec[t], 0, 1, outbuf, 120/factor, fec);
if(out_samples!=120/factor)test_failed();
out_samples = opus_decode(dec[t], 0, 10, outbuf, 120/factor, fec);
if(out_samples!=120/factor)test_failed();
out_samples = opus_decode(dec[t], 0, fast_rand(), outbuf, 120/factor, fec);
if(out_samples!=120/factor)test_failed();
if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
if(dur!=120/factor)test_failed();
/*Zero lengths*/
out_samples = opus_decode(dec[t], packet, 0, outbuf, 120/factor, fec);
if(out_samples!=120/factor)test_failed();
/*Zero buffer*/
outbuf[0]=32749;
out_samples = opus_decode(dec[t], packet, 0, outbuf, 0, fec);
if(out_samples>0)test_failed();
#if !defined(OPUS_BUILD) && (OPUS_GNUC_PREREQ(4, 6) || (defined(__clang_major__) && __clang_major__ >= 3))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
#endif
out_samples = opus_decode(dec[t], packet, 0, 0, 0, fec);
#if !defined(OPUS_BUILD) && (OPUS_GNUC_PREREQ(4, 6) || (defined(__clang_major__) && __clang_major__ >= 3))
#pragma GCC diagnostic pop
#endif
if(out_samples>0)test_failed();
if(outbuf[0]!=32749)test_failed();
/*Invalid lengths*/
out_samples = opus_decode(dec[t], packet, -1, outbuf, MAX_FRAME_SAMP, fec);
if(out_samples>=0)test_failed();
out_samples = opus_decode(dec[t], packet, INT_MIN, outbuf, MAX_FRAME_SAMP, fec);
if(out_samples>=0)test_failed();
out_samples = opus_decode(dec[t], packet, -1, outbuf, -1, fec);
if(out_samples>=0)test_failed();
/*Crazy FEC values*/
out_samples = opus_decode(dec[t], packet, 1, outbuf, MAX_FRAME_SAMP, fec?-1:2);
if(out_samples>=0)test_failed();
/*Reset the decoder*/
if(opus_decoder_ctl(dec[t], OPUS_RESET_STATE)!=OPUS_OK)test_failed();
}
}
fprintf(stdout," dec[all] initial frame PLC OK.\n");
/*Count code 0 tests*/
for(i=0;i<64;i++)
{
opus_int32 dur;
int j,expected[5*2];
packet[0]=i<<2;
packet[1]=255;
packet[2]=255;
err=opus_packet_get_nb_channels(packet);
if(err!=(i&1)+1)test_failed();
for(t=0;t<5*2;t++){
expected[t]=opus_decoder_get_nb_samples(dec[t],packet,1);
if(expected[t]>2880)test_failed();
}
for(j=0;j<256;j++)
{
packet[1]=j;
for(t=0;t<5*2;t++)
{
#if defined(ENABLE_OSCE) || defined(ENABLE_DEEP_PLC)
opus_decoder_ctl(dec[t], OPUS_SET_COMPLEXITY(fast_rand()%11));
#endif
out_samples = opus_decode(dec[t], packet, 3, outbuf, MAX_FRAME_SAMP, 0);
if(out_samples!=expected[t])test_failed();
if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
if(dur!=out_samples)test_failed();
opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1));
if(t==0)dec_final_range2=dec_final_range1;
else if(dec_final_range1!=dec_final_range2)test_failed();
}
}
for(t=0;t<5*2;t++){
int factor=48000/fsv[t>>1];
/* The PLC is run for 6 frames in order to get better PLC coverage. */
for(j=0;j<6;j++)
{
#if defined(ENABLE_OSCE) || defined(ENABLE_DEEP_PLC)
opus_decoder_ctl(dec[t], OPUS_SET_COMPLEXITY(fast_rand()%11));
#endif
out_samples = opus_decode(dec[t], 0, 0, outbuf, expected[t], 0);
if(out_samples!=expected[t])test_failed();
if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
if(dur!=out_samples)test_failed();
}
/* Run the PLC once at 2.5ms, as a simulation of someone trying to
do small drift corrections. */
if(expected[t]!=120/factor)
{
out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor, 0);
if(out_samples!=120/factor)test_failed();
if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
if(dur!=out_samples)test_failed();
}
out_samples = opus_decode(dec[t], packet, 2, outbuf, expected[t]-1, 0);
if(out_samples>0)test_failed();
}
}
fprintf(stdout," dec[all] all 2-byte prefix for length 3 and PLC, all modes (64) OK.\n");
if(no_fuzz)
{
fprintf(stdout," Skipping many tests which fuzz the decoder as requested.\n");
free(decbak);
for(t=0;t<5*2;t++)opus_decoder_destroy(dec[t]);
printf(" Decoders stopped.\n");
err=0;
for(i=0;i<8*2;i++)err|=outbuf_int[i]!=32749;
for(i=MAX_FRAME_SAMP*2;i<(MAX_FRAME_SAMP+8)*2;i++)err|=outbuf[i]!=32749;
if(err)test_failed();
free(outbuf_int);
free(packet);
return 0;
}
{
/*We only test a subset of the modes here simply because the longer
durations end up taking a long time.*/
static const int cmodes[4]={16,20,24,28};
static const opus_uint32 cres[4]={116290185,2172123586u,2172123586u,2172123586u};
static const opus_uint32 lres[3]={3285687739u,1481572662,694350475};
static const int lmodes[3]={0,4,8};
int mode=fast_rand()%4;
packet[0]=cmodes[mode]<<3;
dec_final_acc=0;
t=fast_rand()%10;
for(i=0;i<65536;i++)
{
int factor=48000/fsv[t>>1];
packet[1]=i>>8;
packet[2]=i&255;
packet[3]=255;
out_samples = opus_decode(dec[t], packet, 4, outbuf, MAX_FRAME_SAMP, 0);
if(out_samples!=120/factor)test_failed();
opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1));
dec_final_acc+=dec_final_range1;
}
if(dec_final_acc!=cres[mode])test_failed();
fprintf(stdout," dec[%3d] all 3-byte prefix for length 4, mode %2d OK.\n",t,cmodes[mode]);
mode=fast_rand()%3;
packet[0]=lmodes[mode]<<3;
dec_final_acc=0;
t=fast_rand()%10;
for(i=0;i<65536;i++)
{
int factor=48000/fsv[t>>1];
packet[1]=i>>8;
packet[2]=i&255;
packet[3]=255;
out_samples = opus_decode(dec[t], packet, 4, outbuf, MAX_FRAME_SAMP, 0);
if(out_samples!=480/factor)test_failed();
opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1));
dec_final_acc+=dec_final_range1;
}
if(dec_final_acc!=lres[mode])test_failed();
fprintf(stdout," dec[%3d] all 3-byte prefix for length 4, mode %2d OK.\n",t,lmodes[mode]);
}
skip=fast_rand()%7;
for(i=0;i<64;i++)
{
int j,expected[5*2];
packet[0]=i<<2;
for(t=0;t<5*2;t++)expected[t]=opus_decoder_get_nb_samples(dec[t],packet,1);
for(j=2+skip;j<1275;j+=4)
{
int jj;
for(jj=0;jj<j;jj++)packet[jj+1]=fast_rand()&255;
for(t=0;t<5*2;t++)
{
#if defined(ENABLE_OSCE) || defined(ENABLE_DEEP_PLC)
opus_decoder_ctl(dec[t], OPUS_SET_COMPLEXITY(fast_rand()%11));
#endif
out_samples = opus_decode(dec[t], packet, j+1, outbuf, MAX_FRAME_SAMP, 0);
if(out_samples!=expected[t])test_failed();
opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1));
if(t==0)dec_final_range2=dec_final_range1;
else if(dec_final_range1!=dec_final_range2)test_failed();
}
}
}
fprintf(stdout," dec[all] random packets, all modes (64), every 8th size from from %d bytes to maximum OK.\n",2+skip);
debruijn2(64,modes);
plen=(fast_rand()%18+3)*8+skip+3;
for(i=0;i<4096;i++)
{
int j,expected[5*2];
packet[0]=modes[i]<<2;
for(t=0;t<5*2;t++)expected[t]=opus_decoder_get_nb_samples(dec[t],packet,plen);
for(j=0;j<plen;j++)packet[j+1]=(fast_rand()|fast_rand())&255;
memcpy(decbak,dec[0],decsize);
if(opus_decode(decbak, packet, plen+1, outbuf, expected[0], 1)!=expected[0])test_failed();
memcpy(decbak,dec[0],decsize);
if(opus_decode(decbak, 0, 0, outbuf, MAX_FRAME_SAMP, 1)<20)test_failed();
memcpy(decbak,dec[0],decsize);
if(opus_decode(decbak, 0, 0, outbuf, MAX_FRAME_SAMP, 0)<20)test_failed();
for(t=0;t<5*2;t++)
{
opus_int32 dur;
#if defined(ENABLE_OSCE) || defined(ENABLE_DEEP_PLC)
opus_decoder_ctl(dec[t], OPUS_SET_COMPLEXITY(fast_rand()%11));
#endif
out_samples = opus_decode(dec[t], packet, plen+1, outbuf, MAX_FRAME_SAMP, 0);
if(out_samples!=expected[t])test_failed();
if(t==0)dec_final_range2=dec_final_range1;
else if(dec_final_range1!=dec_final_range2)test_failed();
if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed();
if(dur!=out_samples)test_failed();
}
}
fprintf(stdout," dec[all] random packets, all mode pairs (4096), %d bytes/frame OK.\n",plen+1);
plen=(fast_rand()%18+3)*8+skip+3;
t=rand()&3;
for(i=0;i<4096;i++)
{
int count,j,expected;
packet[0]=modes[i]<<2;
expected=opus_decoder_get_nb_samples(dec[t],packet,plen);
for(count=0;count<10;count++)
{
#if defined(ENABLE_OSCE) || defined(ENABLE_DEEP_PLC)
opus_decoder_ctl(dec[t], OPUS_SET_COMPLEXITY(fast_rand()%11));
#endif
for(j=0;j<plen;j++)packet[j+1]=(fast_rand()|fast_rand())&255;
out_samples = opus_decode(dec[t], packet, plen+1, outbuf, MAX_FRAME_SAMP, 0);
if(out_samples!=expected)test_failed();
}
}
fprintf(stdout," dec[%3d] random packets, all mode pairs (4096)*10, %d bytes/frame OK.\n",t,plen+1);
{
int tmodes[1]={25<<2};
opus_uint32 tseeds[1]={140441};
int tlen[1]={157};
opus_int32 tret[1]={480};
t=fast_rand()&1;
for(i=0;i<1;i++)
{
int j;
packet[0]=tmodes[i];
Rw=Rz=tseeds[i];
for(j=1;j<tlen[i];j++)packet[j]=fast_rand()&255;
out_samples=opus_decode(dec[t], packet, tlen[i], outbuf, MAX_FRAME_SAMP, 0);
if(out_samples!=tret[i])test_failed();
}
fprintf(stdout," dec[%3d] pre-selected random packets OK.\n",t);
}
free(decbak);
for(t=0;t<5*2;t++)opus_decoder_destroy(dec[t]);
printf(" Decoders stopped.\n");
err=0;
for(i=0;i<8*2;i++)err|=outbuf_int[i]!=32749;
for(i=MAX_FRAME_SAMP*2;i<(MAX_FRAME_SAMP+8)*2;i++)err|=outbuf[i]!=32749;
if(err)test_failed();
free(outbuf_int);
free(packet);
return 0;
}
#ifndef DISABLE_FLOAT_API
void test_soft_clip(void)
{
int i,j;
float x[1024];
float s[8] = {0, 0, 0, 0, 0, 0, 0, 0};
fprintf(stdout," Testing opus_pcm_soft_clip... ");
for(i=0;i<1024;i++)
{
for (j=0;j<1024;j++)
{
x[j]=(j&255)*(1/32.f)-4.f;
}
opus_pcm_soft_clip(&x[i],1024-i,1,s);
for (j=i;j<1024;j++)
{
if(x[j]>1.f)test_failed();
if(x[j]<-1.f)test_failed();
}
}
for(i=1;i<9;i++)
{
for (j=0;j<1024;j++)
{
x[j]=(j&255)*(1/32.f)-4.f;
}
opus_pcm_soft_clip(x,1024/i,i,s);
for (j=0;j<(1024/i)*i;j++)
{
if(x[j]>1.f)test_failed();
if(x[j]<-1.f)test_failed();
}
}
opus_pcm_soft_clip(x,0,1,s);
opus_pcm_soft_clip(x,1,0,s);
opus_pcm_soft_clip(x,1,1,0);
opus_pcm_soft_clip(x,1,-1,s);
opus_pcm_soft_clip(x,-1,1,s);
opus_pcm_soft_clip(0,1,1,s);
printf("OK.\n");
}
#endif
int main(int _argc, char **_argv)
{
const char * oversion;
const char * env_seed;
int env_used;
if(_argc>2)
{
fprintf(stderr,"Usage: %s [<seed>]\n",_argv[0]);
return 1;
}
env_used=0;
env_seed=getenv("SEED");
if(_argc>1)iseed=atoi(_argv[1]);
else if(env_seed)
{
iseed=atoi(env_seed);
env_used=1;
}
else iseed=(opus_uint32)time(NULL)^(((opus_uint32)getpid()&65535)<<16);
Rw=Rz=iseed;
oversion=opus_get_version_string();
if(!oversion)test_failed();
fprintf(stderr,"Testing %s decoder. 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);
/*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.*/
test_decoder_code0(getenv("TEST_OPUS_NOFUZZ")!=NULL);
#ifndef DISABLE_FLOAT_API
test_soft_clip();
#endif
return 0;
}

107
third_party/opus/tests/test_opus_dred.c vendored Normal file
View File

@@ -0,0 +1,107 @@
/* Copyright (c) 2023 Amazon
Written by Michael Klingbeil */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include <process.h>
#define getpid _getpid
#endif
/* including sources directly to test internal APIs */
#define CELT_C /* to make celt_assert work */
#include "opus.h"
#include "test_opus_common.h"
#define NB_RANDOM_EXTENSIONS 10000000
#define MAX_EXTENSION_SIZE 200
#define MAX_NB_EXTENSIONS 100
void test_random_dred(void)
{
int error;
int i;
OpusDREDDecoder *dred_dec;
OpusDRED *dred;
dred_dec = opus_dred_decoder_create(&error);
expect_true(error == OPUS_OK, "opus_dred_decoder_create() failed");
dred = opus_dred_alloc(&error);
expect_true(error == OPUS_OK, "opus_dred_create() failed");
for (i=0;i<NB_RANDOM_EXTENSIONS;i++)
{
unsigned char payload[MAX_EXTENSION_SIZE];
int len;
int j;
int res1, res2;
int dred_end;
len = fast_rand()%(MAX_EXTENSION_SIZE+1);
for (j=0;j<len;j++)
payload[j] = fast_rand()&0xFF;
res1 = opus_dred_parse(dred_dec, dred, payload, len, 48000, 48000, &dred_end, fast_rand()&0x1);
if (res1 > 0)
{
res2 = opus_dred_process(dred_dec, dred, dred);
expect_true(res2 == OPUS_OK, "process should succeed if parse succeeds");
expect_true(res1 >= dred_end, "end before beginning");
}
}
opus_dred_free(dred);
opus_dred_decoder_destroy(dred_dec);
}
int main(int argc, char **argv)
{
int env_used;
char *env_seed;
env_used=0;
env_seed=getenv("SEED");
if(argc>1)iseed=atoi(argv[1]);
else if(env_seed)
{
iseed=atoi(env_seed);
env_used=1;
}
else iseed=(opus_uint32)time(NULL)^(((opus_uint32)getpid()&65535)<<16);
Rw=Rz=iseed;
fprintf(stderr,"Testing dred. Random seed: %u (%.4X)\n", iseed, fast_rand() % 65535);
if(env_used)fprintf(stderr," Random seed set from the environment (SEED=%s).\n", env_seed);
test_random_dred();
fprintf(stderr,"Tests completed successfully.\n");
return 0;
}

View File

@@ -0,0 +1,738 @@
/* Copyright (c) 2011-2013 Xiph.Org Foundation
Written by Gregory Maxwell */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <time.h>
#if (!defined WIN32 && !defined _WIN32) || defined(__MINGW32__)
#include <unistd.h>
#else
#include <process.h>
#define getpid _getpid
#endif
#include "opus_multistream.h"
#include "opus.h"
#include "../src/opus_private.h"
#include "test_opus_common.h"
#define MAX_PACKET (1500)
#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)
{
opus_int32 a1,b1,a2,b2;
opus_int32 c1,c2,d1,d2;
opus_int32 i,j;
a1=b1=a2=b2=0;
c1=c2=d1=d2=0;
j=0;
/*60ms silence*/
for(i=0;i<2880;i++)buf[i*2]=buf[i*2+1]=0;
for(i=2880;i<len;i++)
{
opus_uint32 r;
opus_int32 v1,v2;
v1=v2=(((j*((j>>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15;
r=fast_rand();v1+=r&65535;v1-=r>>16;
r=fast_rand();v2+=r&65535;v2-=r>>16;
b1=v1-a1+((b1*61+32)>>6);a1=v1;
b2=v2-a2+((b2*61+32)>>6);a2=v2;
c1=(30*(c1+b1+d1)+32)>>6;d1=b1;
c2=(30*(c2+b2+d2)+32)>>6;d2=b2;
v1=(c1+128)>>8;
v2=(c2+128)>>8;
buf[i*2]=v1>32767?32767:(v1<-32768?-32768:v1);
buf[i*2+1]=v2>32767?32767:(v2<-32768?-32768:v2);
if(i%6==0)j++;
}
}
#if 0
static int save_ctr = 0;
static void int_to_char(opus_uint32 i, unsigned char ch[4])
{
ch[0] = i>>24;
ch[1] = (i>>16)&0xFF;
ch[2] = (i>>8)&0xFF;
ch[3] = i&0xFF;
}
static OPUS_INLINE void save_packet(unsigned char* p, int len, opus_uint32 rng)
{
FILE *fout;
unsigned char int_field[4];
char name[256];
snprintf(name,255,"test_opus_encode.%llu.%d.bit",(unsigned long long)iseed,save_ctr);
fprintf(stdout,"writing %d byte packet to %s\n",len,name);
fout=fopen(name, "wb+");
if(fout==NULL)test_failed();
int_to_char(len, int_field);
fwrite(int_field, 1, 4, fout);
int_to_char(rng, int_field);
fwrite(int_field, 1, 4, fout);
fwrite(p, 1, len, fout);
fclose(fout);
save_ctr++;
}
#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;
}
int test_encode(OpusEncoder *enc, int channels, int frame_size, OpusDecoder *dec)
{
int samp_count = 0;
opus_int16 *inbuf;
unsigned char packet[MAX_PACKET+257];
int len;
opus_int16 *outbuf;
int out_samples;
int ret = 0;
#ifdef ENABLE_DRED
OpusDREDDecoder *dred_dec;
OpusDRED *dred;
int dred_end;
int dred_amount;
int dred_ret;
dred_dec = opus_dred_decoder_create(&dred_ret);
dred = opus_dred_alloc(&dred_ret);
#endif
/* 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,"opus_encode() returned %d\n",len);
ret = -1;
break;
}
#ifdef ENABLE_DRED
dred_amount = opus_dred_parse(dred_dec, dred, packet, len, 48000, 48000, &dred_end, 0);
if(dred_amount<0) {
fprintf(stderr,"opus_dred_parse() returned %d\n",dred_amount);
ret = -1;
break;
}
if (dred_amount >= frame_size && (fast_rand()&1)) {
dred_ret = opus_decoder_dred_decode(dec, dred, frame_size, outbuf, frame_size);
if(dred_ret<0) {
fprintf(stderr,"opus_decoder_dred_decode() returned %d\n",dred_ret);
ret = -1;
break;
}
}
#endif
out_samples = opus_decode(dec, packet, len, outbuf, MAX_FRAME_SAMP, 0);
if(out_samples!=frame_size) {
fprintf(stderr,"opus_decode() returned %d\n",out_samples);
ret = -1;
break;
}
samp_count += frame_size;
} while (samp_count < ((SSAMPLES/2)-MAX_FRAME_SAMP));
#ifdef ENABLE_DRED
opus_dred_decoder_destroy(dred_dec);
opus_dred_free(dred);
#endif
/* Clean up */
free(inbuf);
free(outbuf);
return ret;
}
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 */
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);
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();
#ifdef ENABLE_DRED
if(opus_encoder_ctl(enc, OPUS_SET_DRED_DURATION(fast_rand()%101)) != OPUS_OK) test_failed();
#endif
if(test_encode(enc, num_channels, frame_size, dec)) {
fprintf(stderr,
"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);
test_failed();
}
}
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,j;
int rc,err;
OpusEncoder *enc;
OpusMSEncoder *MSenc;
OpusDecoder *dec;
OpusMSDecoder *MSdec;
OpusMSDecoder *MSdec_err;
OpusDecoder *dec_err[10];
short *inbuf;
short *outbuf;
short *out2buf;
opus_int32 bitrate_bps;
unsigned char packet[MAX_PACKET+257];
opus_uint32 enc_final_range;
opus_uint32 dec_final_range;
int fswitch;
int fsize;
int count;
/*FIXME: encoder api tests, fs!=48k, mono, VBR*/
fprintf(stdout," Encode+Decode tests.\n");
fflush(stdout);
enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, &err);
if(err != OPUS_OK || enc==NULL)test_failed();
for(i=0;i<2;i++)
{
int *ret_err;
ret_err = i?0:&err;
MSenc = opus_multistream_encoder_create(8000, 2, 2, 0, mapping, OPUS_UNIMPLEMENTED, ret_err);
if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
MSenc = opus_multistream_encoder_create(8000, 0, 1, 0, mapping, OPUS_APPLICATION_VOIP, ret_err);
if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
MSenc = opus_multistream_encoder_create(44100, 2, 2, 0, mapping, OPUS_APPLICATION_VOIP, ret_err);
if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
MSenc = opus_multistream_encoder_create(8000, 2, 2, 3, mapping, OPUS_APPLICATION_VOIP, ret_err);
if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
MSenc = opus_multistream_encoder_create(8000, 2, -1, 0, mapping, OPUS_APPLICATION_VOIP, ret_err);
if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
MSenc = opus_multistream_encoder_create(8000, 256, 2, 0, mapping, OPUS_APPLICATION_VOIP, ret_err);
if((ret_err && *ret_err != OPUS_BAD_ARG) || MSenc!=NULL)test_failed();
}
MSenc = opus_multistream_encoder_create(8000, 2, 2, 0, mapping, OPUS_APPLICATION_AUDIO, &err);
if(err != OPUS_OK || MSenc==NULL)test_failed();
/*Some multistream encoder API tests*/
if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_BITRATE(&i))!=OPUS_OK)test_failed();
if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_LSB_DEPTH(&i))!=OPUS_OK)test_failed();
if(i<16)test_failed();
{
OpusEncoder *tmp_enc;
if(opus_multistream_encoder_ctl(MSenc, OPUS_MULTISTREAM_GET_ENCODER_STATE(1,&tmp_enc))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(tmp_enc, OPUS_GET_LSB_DEPTH(&j))!=OPUS_OK)test_failed();
if(i!=j)test_failed();
if(opus_multistream_encoder_ctl(MSenc, OPUS_MULTISTREAM_GET_ENCODER_STATE(2,&tmp_enc))!=OPUS_BAD_ARG)test_failed();
}
dec = opus_decoder_create(48000, 2, &err);
if(err != OPUS_OK || dec==NULL)test_failed();
MSdec = opus_multistream_decoder_create(48000, 2, 2, 0, mapping, &err);
if(err != OPUS_OK || MSdec==NULL)test_failed();
MSdec_err = opus_multistream_decoder_create(48000, 3, 2, 0, mapping, &err);
if(err != OPUS_OK || MSdec_err==NULL)test_failed();
dec_err[0]=(OpusDecoder *)malloc(opus_decoder_get_size(2));
memcpy(dec_err[0],dec,opus_decoder_get_size(2));
dec_err[1] = opus_decoder_create(48000, 1, &err);
dec_err[2] = opus_decoder_create(24000, 2, &err);
dec_err[3] = opus_decoder_create(24000, 1, &err);
dec_err[4] = opus_decoder_create(16000, 2, &err);
dec_err[5] = opus_decoder_create(16000, 1, &err);
dec_err[6] = opus_decoder_create(12000, 2, &err);
dec_err[7] = opus_decoder_create(12000, 1, &err);
dec_err[8] = opus_decoder_create(8000, 2, &err);
dec_err[9] = opus_decoder_create(8000, 1, &err);
for(i=0;i<10;i++)if(dec_err[i]==NULL)test_failed();
{
OpusEncoder *enccpy;
/*The opus state structures contain no pointers and can be freely copied*/
enccpy=(OpusEncoder *)malloc(opus_encoder_get_size(2));
memcpy(enccpy,enc,opus_encoder_get_size(2));
memset(enc,255,opus_encoder_get_size(2));
opus_encoder_destroy(enc);
enc=enccpy;
}
inbuf=(short *)malloc(sizeof(short)*SAMPLES*2);
outbuf=(short *)malloc(sizeof(short)*SAMPLES*2);
out2buf=(short *)malloc(sizeof(short)*MAX_FRAME_SAMP*3);
if(inbuf==NULL || outbuf==NULL || out2buf==NULL)test_failed();
generate_music(inbuf,SAMPLES);
/* FILE *foo;
foo = fopen("foo.sw", "wb+");
fwrite(inbuf, 1, SAMPLES*2*2, foo);
fclose(foo);*/
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++)
{
if(opus_encoder_ctl(enc, OPUS_SET_VBR(rc<2))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(rc==0))!=OPUS_OK)test_failed();
#ifdef ENABLE_DRED
if(opus_encoder_ctl(enc, OPUS_SET_DRED_DURATION(fast_rand()%101)) != OPUS_OK) test_failed();
#endif
for(j=0;j<13;j++)
{
int rate;
int modes[13]={0,0,0,1,1,1,1,2,2,2,2,2,2};
int rates[13]={6000,12000,48000,16000,32000,48000,64000,512000,13000,24000,48000,64000,96000};
int frame[13]={960*2,960,480,960,960,960,480,960*3,960*3,960,480,240,120};
rate=rates[j]+fast_rand()%rates[j];
count=i=0;
do {
int bw,len,out_samples,frame_size;
frame_size=frame[j];
if((fast_rand()&255)==0)
{
if(opus_encoder_ctl(enc, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
if(opus_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
if((fast_rand()&1)!=0)
{
if(opus_decoder_ctl(dec_err[fast_rand()&1], OPUS_RESET_STATE)!=OPUS_OK)test_failed();
}
}
if((fast_rand()&127)==0)
{
if(opus_decoder_ctl(dec_err[fast_rand()&1], OPUS_RESET_STATE)!=OPUS_OK)test_failed();
}
if(fast_rand()%10==0){
int complex=fast_rand()%11;
if(opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complex))!=OPUS_OK)test_failed();
}
if(fast_rand()%50==0)opus_decoder_ctl(dec, OPUS_RESET_STATE);
if(opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(rc==0))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_SILK_ONLY+modes[j]))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_DTX(fast_rand()&1))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_BITRATE(rate))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS((rates[j]>=64000?2:1)))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY((count>>2)%11))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC((fast_rand()&15)&(fast_rand()%15)))!=OPUS_OK)test_failed();
bw=modes[j]==0?OPUS_BANDWIDTH_NARROWBAND+(fast_rand()%3):
modes[j]==1?OPUS_BANDWIDTH_SUPERWIDEBAND+(fast_rand()&1):
OPUS_BANDWIDTH_NARROWBAND+(fast_rand()%5);
if(modes[j]==2&&bw==OPUS_BANDWIDTH_MEDIUMBAND)bw+=3;
if(opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bw))!=OPUS_OK)test_failed();
len = opus_encode(enc, &inbuf[i<<1], frame_size, packet, MAX_PACKET);
if(len<0 || len>MAX_PACKET)test_failed();
if(opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed();
if((fast_rand()&3)==0)
{
if(opus_packet_pad(packet,len,len+1)!=OPUS_OK)test_failed();
len++;
}
if((fast_rand()&7)==0)
{
if(opus_packet_pad(packet,len,len+256)!=OPUS_OK)test_failed();
len+=256;
}
if((fast_rand()&3)==0)
{
len=opus_packet_unpad(packet,len);
if(len<1)test_failed();
}
out_samples = opus_decode(dec, packet, len, &outbuf[i<<1], MAX_FRAME_SAMP, 0);
if(out_samples!=frame_size)test_failed();
if(opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range))!=OPUS_OK)test_failed();
if(enc_final_range!=dec_final_range)test_failed();
/*LBRR decode*/
out_samples = opus_decode(dec_err[0], packet, len, out2buf, frame_size, (fast_rand()&3)!=0);
if(out_samples!=frame_size)test_failed();
out_samples = opus_decode(dec_err[1], packet, (fast_rand()&3)==0?0:len, out2buf, MAX_FRAME_SAMP, (fast_rand()&7)!=0);
if(out_samples<120)test_failed();
i+=frame_size;
count++;
}while(i<(SSAMPLES-MAX_FRAME_SAMP));
fprintf(stdout," Mode %s FB encode %s, %6d bps OK.\n",mstrings[modes[j]],rc==0?" VBR":rc==1?"CVBR":" CBR",rate);
fflush(stdout);
}
}
if(opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(OPUS_AUTO))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0))!=OPUS_OK)test_failed();
if(opus_encoder_ctl(enc, OPUS_SET_DTX(0))!=OPUS_OK)test_failed();
for(rc=0;rc<3;rc++)
{
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR(rc<2))!=OPUS_OK)test_failed();
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed();
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed();
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_INBAND_FEC(rc==0))!=OPUS_OK)test_failed();
for(j=0;j<16;j++)
{
int rate;
int modes[16]={0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2};
int rates[16]={4000,12000,32000,8000,16000,32000,48000,88000,4000,12000,32000,8000,16000,32000,48000,88000};
int frame[16]={160*1,160,80,160,160,80,40,20,160*1,160,80,160,160,80,40,20};
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_INBAND_FEC(rc==0&&j==1))!=OPUS_OK)test_failed();
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_FORCE_MODE(MODE_SILK_ONLY+modes[j]))!=OPUS_OK)test_failed();
rate=rates[j]+fast_rand()%rates[j];
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_DTX(fast_rand()&1))!=OPUS_OK)test_failed();
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_BITRATE(rate))!=OPUS_OK)test_failed();
count=i=0;
do {
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];
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_COMPLEXITY((count>>2)%11))!=OPUS_OK)test_failed();
if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_PACKET_LOSS_PERC((fast_rand()&15)&(fast_rand()%15)))!=OPUS_OK)test_failed();
if((fast_rand()&255)==0)
{
if(opus_multistream_encoder_ctl(MSenc, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
if(opus_multistream_decoder_ctl(MSdec, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
if((fast_rand()&3)!=0)
{
if(opus_multistream_decoder_ctl(MSdec_err, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
}
}
if((fast_rand()&255)==0)
{
if(opus_multistream_decoder_ctl(MSdec_err, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
}
len = opus_multistream_encode(MSenc, &inbuf[i<<1], frame_size, packet, MAX_PACKET);
if(len<0 || len>MAX_PACKET)test_failed();
if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed();
if((fast_rand()&3)==0)
{
if(opus_multistream_packet_pad(packet,len,len+1,2)!=OPUS_OK)test_failed();
len++;
}
if((fast_rand()&7)==0)
{
if(opus_multistream_packet_pad(packet,len,len+256,2)!=OPUS_OK)test_failed();
len+=256;
}
if((fast_rand()&3)==0)
{
len=opus_multistream_packet_unpad(packet,len,2);
if(len<1)test_failed();
}
out_samples = opus_multistream_decode(MSdec, packet, len, out2buf, MAX_FRAME_SAMP, 0);
if(out_samples!=frame_size*6)test_failed();
if(opus_multistream_decoder_ctl(MSdec, OPUS_GET_FINAL_RANGE(&dec_final_range))!=OPUS_OK)test_failed();
if(enc_final_range!=dec_final_range)test_failed();
/*LBRR decode*/
loss=(fast_rand()&63)==0;
out_samples = opus_multistream_decode(MSdec_err, packet, loss?0:len, out2buf, frame_size*6, (fast_rand()&3)!=0);
if(out_samples!=(frame_size*6))test_failed();
i+=frame_size;
count++;
}while(i<(SSAMPLES/12-MAX_FRAME_SAMP));
fprintf(stdout," Mode %s NB dual-mono MS encode %s, %6d bps OK.\n",mstrings[modes[j]],rc==0?" VBR":rc==1?"CVBR":" CBR",rate);
fflush(stdout);
}
}
bitrate_bps=512000;
fsize=fast_rand()%31;
fswitch=100;
debruijn2(6,db62);
count=i=0;
do {
unsigned char toc;
const unsigned char *frames[48];
short size[48];
int payload_offset;
opus_uint32 dec_final_range2;
int jj,dec2;
int len,out_samples;
int frame_size=fsizes[db62[fsize]];
opus_int32 offset=i%(SAMPLES-MAX_FRAME_SAMP);
opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
len = opus_encode(enc, &inbuf[offset<<1], frame_size, packet, MAX_PACKET);
if(len<0 || len>MAX_PACKET)test_failed();
count++;
opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range));
out_samples = opus_decode(dec, packet, len, &outbuf[offset<<1], MAX_FRAME_SAMP, 0);
if(out_samples!=frame_size)test_failed();
opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range));
/* compare final range encoder rng values of encoder and decoder */
if(dec_final_range!=enc_final_range)test_failed();
/* We fuzz the packet, but take care not to only corrupt the payload
Corrupted headers are tested elsewhere and we need to actually run
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=(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*/
opus_decoder_ctl(dec_err[0], OPUS_GET_FINAL_RANGE(&dec_final_range));
/*randomly select one of the decoders to compare with*/
dec2=fast_rand()%9+1;
out_samples = opus_decode(dec_err[dec2], len>0?packet:NULL, len, out2buf, MAX_FRAME_SAMP, 0);
if(out_samples<0||out_samples>MAX_FRAME_SAMP)test_failed(); /*FIXME, use factor, lastframe for loss*/
opus_decoder_ctl(dec_err[dec2], OPUS_GET_FINAL_RANGE(&dec_final_range2));
if(len>0&&dec_final_range!=dec_final_range2)test_failed();
fswitch--;
if(fswitch<1)
{
int new_size;
fsize=(fsize+1)%36;
new_size=fsizes[db62[fsize]];
if(new_size==960||new_size==480)fswitch=2880/new_size*(fast_rand()%19+1);
else fswitch=(fast_rand()%(2880/new_size))+1;
}
bitrate_bps=((fast_rand()%508000+4000)+bitrate_bps)>>1;
i+=frame_size;
}while(i<SAMPLES*4);
fprintf(stdout," All framesize pairs switching encode, %d frames OK.\n",count);
fflush(stdout);
if(opus_encoder_ctl(enc, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
opus_encoder_destroy(enc);
if(opus_multistream_encoder_ctl(MSenc, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
opus_multistream_encoder_destroy(MSenc);
if(opus_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
opus_decoder_destroy(dec);
if(opus_multistream_decoder_ctl(MSdec, OPUS_RESET_STATE)!=OPUS_OK)test_failed();
opus_multistream_decoder_destroy(MSdec);
opus_multistream_decoder_destroy(MSdec_err);
for(i=0;i<10;i++)opus_decoder_destroy(dec_err[i]);
free(inbuf);
free(outbuf);
free(out2buf);
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;
int num_encoders_to_fuzz=5;
int num_setting_changes=40;
env_used=0;
env_seed=getenv("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)^(((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;
}

View File

@@ -0,0 +1,450 @@
/* Copyright (c) 2023 Amazon
Written by Michael Klingbeil */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include <process.h>
#define getpid _getpid
#endif
#include "../src/opus_private.h"
#include "test_opus_common.h"
void test_extensions_generate_success(void)
{
static const opus_extension_data ext[] = {
{2, 0, (const unsigned char *)"a", 1},
{32, 10, (const unsigned char *)"DRED", 4},
{33, 1, (const unsigned char *)"NOT DRED", 8},
{3, 4, (const unsigned char *)NULL, 0}
};
int result;
unsigned char packet[32];
const unsigned char *p = packet;
result = opus_packet_extensions_generate(packet, 23+4, ext, 4, 1);
expect_true(result == 23+4, "expected length 23+4");
/* expect padding */
expect_true(p[0] == 1 && p[1] == 1 && p[2] == 1 && p[3] == 1, "expected padding");
p += 4;
/* extension ID=2 */
expect_true((p[0] >> 1) == 2, "expected extension id 2");
/* For extension IDs 1 through 31, L=0 means that no data follows the
extension, whereas L=1 means that exactly one byte of extension data follows. */
expect_true((p[0] & 0x01) == 1, "expected L-bit set");
/* content */
expect_true(p[1] == 'a', "expected extension content");
p += 2;
/* next byte should increment the frame count, ID=1, L=0 */
expect_true(p[0] == 0x02, "bad frame separator");
p += 1;
/* extension ID=33 */
expect_true((p[0] >> 1) == 33, "expected extension id 33");
/* For IDs 32 to 127, L=0 signals that the extension data takes up the
rest of the padding, and L=1 signals that a length indicator follows. */
expect_true((p[0] & 0x01) == 1, "expected L-bit set");
/* content */
expect_true(p[1] == ext[2].len, "expected length");
p += 2;
expect_true(0 == memcmp(p, ext[2].data, ext[2].len), "expected extension content");
p += ext[2].len;
/* advance to frame 4, increment by 3 */
/* next byte should increment the frame count, ID=1, L=1 */
expect_true(p[0] == 0x03, "bad frame separator");
expect_true(p[1] == 0x03, "bad frame increment");
p += 2;
/* extension ID=3 */
expect_true((p[0] >> 1) == 3, "expected extension id 3");
/* For extension IDs 1 through 31, L=0 means that no data follows the
extension, whereas L=1 means that exactly one byte of extension data follows. */
expect_true((p[0] & 0x01) == 0, "expected L-bit unset");
p += 1;
/* advance to frame 10, increment by 6 */
/* next byte should increment the frame count, ID=1, L=1 */
expect_true(p[0] == 0x03, "bad frame separator");
expect_true(p[1] == 0x06, "bad frame increment");
p += 2;
/* extension ID=32 */
expect_true((p[0] >> 1) == 32, "expected extension id 32");
/* For IDs 32 to 127, L=0 signals that the extension data takes up the
rest of the padding */
expect_true((p[0] & 0x01) == 0, "expected L-bit unset");
p += 1;
expect_true(0 == memcmp(p, ext[1].data, ext[1].len), "expected extension content");
}
void test_extensions_generate_zero(void)
{
int result;
unsigned char packet[32];
/* zero length packet, zero extensions */
result = opus_packet_extensions_generate(packet, 0, NULL, 0, 1);
expect_true(result == 0, "expected length 0");
}
void test_extensions_generate_no_padding(void)
{
static const opus_extension_data ext[] = {
{2, 0, (const unsigned char *)"a", 1},
{32, 10, (const unsigned char *)"DRED", 4},
{33, 1, (const unsigned char *)"NOT DRED", 8},
{3, 4, (const unsigned char *)NULL, 0}
};
int result;
unsigned char packet[32];
result = opus_packet_extensions_generate(packet, sizeof(packet), ext, 4, 0);
expect_true(result == 23, "expected length 23");
}
void test_extensions_generate_fail(void)
{
static const opus_extension_data ext[] = {
{2, 0, (const unsigned char *)"a", 1},
{32, 10, (const unsigned char *)"DRED", 4},
{33, 1, (const unsigned char *)"NOT DRED", 8},
{3, 4, (const unsigned char *)NULL, 0}
};
int result;
unsigned char packet[100];
/* buffer too small */
result = opus_packet_extensions_generate(packet, 4, ext, 4, 1);
expect_true(result == OPUS_BUFFER_TOO_SMALL, "expected OPUS_BUFFER_TOO_SMALL");
/* invalid id */
{
static const opus_extension_data id_too_big[] = {
{256, 0, (const unsigned char *)"a", 1},
};
result = opus_packet_extensions_generate(packet, sizeof(packet), id_too_big, 1, 1);
expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
}
/* invalid id */
{
static const opus_extension_data id_too_small[] = {
{1, 0, (const unsigned char *)"a", 1},
};
result = opus_packet_extensions_generate(packet, sizeof(packet), id_too_small, 1, 1);
expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
}
/* frame index too big */
{
static const opus_extension_data frame_too_big[] = {
{33, 48, (const unsigned char *)"a", 1},
};
result = opus_packet_extensions_generate(packet, sizeof(packet), frame_too_big, 1, 1);
expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
}
/* size too big for extension IDs 1 through 31 */
{
static const opus_extension_data size_too_big[] = {
{2, 0, (const unsigned char *)"abcd", 4},
};
result = opus_packet_extensions_generate(packet, sizeof(packet), size_too_big, 1, 1);
expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
}
/* negative size for extension IDs 1 through 31 */
{
static const opus_extension_data neg_size[] = {
{2, 0, NULL, -4},
};
result = opus_packet_extensions_generate(packet, sizeof(packet), neg_size, 1, 1);
expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
}
/* negative size for extension IDs 32 through 127 */
{
static const opus_extension_data neg_size_33[] = {
{33, 0, NULL, -4},
};
result = opus_packet_extensions_generate(packet, sizeof(packet), neg_size_33, 1, 1);
expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
}
}
void test_extensions_parse_success(void)
{
static const opus_extension_data ext[] = {
{2, 0, (const unsigned char *)"a", 1},
{32, 10, (const unsigned char *)"DRED", 4},
{33, 1, (const unsigned char *)"NOT DRED", 8},
{3, 4, (const unsigned char *)NULL, 0}
};
opus_extension_data ext_out[10];
int nb_ext;
int len, result;
unsigned char packet[32];
nb_ext = 10;
len = opus_packet_extensions_generate(packet, 32, ext, 4, 1);
expect_true(len == 32, "expected length 32");
result = opus_packet_extensions_count(packet, len);
expect_true(result == 4, "expected opus_packet_extensions_count 4");
result = opus_packet_extensions_parse(packet, len, ext_out, &nb_ext);
expect_true(nb_ext == 4, "expected 4 extensions");
expect_true(ext_out[0].id == 2, "expected id 2");
expect_true(ext_out[0].frame == 0, "expected frame 0");
expect_true(ext_out[0].len == 1, "expected len 1");
expect_true(0 == memcmp(ext_out[0].data, ext[0].data, 1), "expected data");
expect_true(ext_out[1].id == 33, "expected id 33");
expect_true(ext_out[1].frame == 1, "expected frame 1");
expect_true(ext_out[1].len == 8, "expected len 8");
expect_true(0 == memcmp(ext_out[1].data, ext[2].data, 8), "expected data");
expect_true(ext_out[2].id == 3, "expected id 3");
expect_true(ext_out[2].frame == 4, "expected frame 4");
expect_true(ext_out[2].len == 0, "expected len 0");
expect_true(ext_out[3].id == 32, "expected id 32");
expect_true(ext_out[3].frame == 10, "expected frame 10");
expect_true(ext_out[3].len == 4, "expected len 4");
expect_true(0 == memcmp(ext_out[3].data, ext[1].data, 4), "expected data");
}
void test_extensions_parse_zero(void)
{
static const opus_extension_data ext[] = {
{32, 1, (const unsigned char *)"DRED", 4},
};
int nb_ext;
int len, result;
unsigned char packet[32];
len = opus_packet_extensions_generate(packet, 32, ext, 1, 1);
expect_true(len == 32, "expected length 32");
nb_ext = 0;
result = opus_packet_extensions_parse(packet, len, NULL, &nb_ext);
expect_true(result == OPUS_BUFFER_TOO_SMALL, "expected OPUS_BUFFER_TOO_SMALL");
}
void test_extensions_parse_fail(void)
{
static const opus_extension_data ext[] = {
{2, 0, (const unsigned char *)"a", 1},
{33, 1, (const unsigned char *)"NOT DRED", 8},
{3, 4, (const unsigned char *)NULL, 0},
{32, 10, (const unsigned char *)"DRED", 4}
};
opus_extension_data ext_out[10];
int nb_ext;
int len, result;
unsigned char packet[32];
/* create invalid length */
len = opus_packet_extensions_generate(packet, sizeof(packet), ext, 4, 0);
packet[4] = 255;
nb_ext = 10;
result = opus_packet_extensions_parse(packet, len, ext_out, &nb_ext);
expect_true(result == OPUS_INVALID_PACKET, "expected OPUS_INVALID_PACKET");
result = opus_packet_extensions_count(packet, len);
expect_true(result == OPUS_INVALID_PACKET, "expected OPUS_INVALID_PACKET");
/* create invalid frame increment */
nb_ext = 10;
len = opus_packet_extensions_generate(packet, sizeof(packet), ext, 4, 0);
packet[14] = 255;
result = opus_packet_extensions_parse(packet, len, ext_out, &nb_ext);
expect_true(result == OPUS_INVALID_PACKET, "expected OPUS_INVALID_PACKET");
/* note, opus_packet_extensions_count does not read the invalid frame increment
and tells us that we have 4 extensions */
result = opus_packet_extensions_count(packet, len);
expect_true(result == 4, "expected opus_packet_extensions_count to return 4");
/* not enough space */
nb_ext = 1;
len = opus_packet_extensions_generate(packet, sizeof(packet), ext, 4, 0);
result = opus_packet_extensions_parse(packet, len, ext_out, &nb_ext);
expect_true(result == OPUS_BUFFER_TOO_SMALL, "expected OPUS_BUFFER_TOO_SMALL");
}
#define NB_RANDOM_EXTENSIONS 100000000
#define MAX_EXTENSION_SIZE 200
#define MAX_NB_EXTENSIONS 100
void test_random_extensions_parse(void)
{
int i;
for (i=0;i<NB_RANDOM_EXTENSIONS;i++)
{
opus_extension_data ext_out[MAX_NB_EXTENSIONS];
int nb_ext;
unsigned char payload[MAX_EXTENSION_SIZE];
int len;
int j;
int result;
len = fast_rand()%(MAX_EXTENSION_SIZE+1);
for (j=0;j<len;j++)
payload[j] = fast_rand()&0xFF;
nb_ext = fast_rand()%(MAX_NB_EXTENSIONS+1);
result = opus_packet_extensions_parse(payload, len, ext_out, &nb_ext);
expect_true(result == OPUS_OK || result == OPUS_BUFFER_TOO_SMALL || result == OPUS_INVALID_PACKET, "expected OPUS_OK, OPUS_BUFFER_TOO_SMALL or OPUS_INVALID_PACKET");
/* Even if parsing fails, check that the extensions that got extracted make sense. */
for (j=0;j<nb_ext;j++)
{
expect_true(ext_out[j].frame >= 0 && ext_out[j].frame < 48, "expected frame between 0 and 47");
expect_true(ext_out[j].id >= 2 && ext_out[j].id <= 127, "expected id between 2 and 127");
expect_true(ext_out[j].data >= payload && ext_out[j].data+ext_out[j].len <= payload+len, "expected data to be within packet");
}
}
}
void test_opus_repacketizer_out_range_impl(void)
{
OpusRepacketizer rp;
unsigned char packet[1024];
unsigned char packet_out[1024];
opus_int16 size[48];
const unsigned char *padding;
opus_int32 padding_len;
opus_extension_data ext_out[10];
int i;
int nb_ext;
int res, len;
int first_count = 0, second_count = 0;
static const opus_extension_data ext[] = {
{33, 0, (const unsigned char *)"abcdefg", 7},
{100, 0, (const unsigned char *)"uvwxyz", 6},
};
opus_repacketizer_init(&rp);
memset(packet, 0, sizeof(packet));
/* Hybrid Packet with 20 msec frames, Code 3 */
packet[0] = (15 << 3) | 3;
/* Code 3, padding bit set, 1 frame */
packet[1] = 1 << 6 | 1;
packet[2] = 0;
packet[3] = 0;
/* generate 2 extensions, id 33 and 100 */
len = opus_packet_extensions_generate(&packet[4], sizeof(packet)-4, ext, 2, 0);
/* update the padding length */
packet[2] = len;
/* concatenate 3 frames */
res = opus_repacketizer_cat(&rp, packet, 4+len);
/* for the middle frame, no padding, no extensions */
packet[1] = 1;
res = opus_repacketizer_cat(&rp, packet, 4);
/* switch back to extensions for the last frame extensions */
packet[1] = 1 << 6 | 1;
res = opus_repacketizer_cat(&rp, packet, 4+len);
expect_true(rp.nb_frames == 3, "Expected 3 frames");
res = opus_repacketizer_out_range_impl(&rp,
0, 3, /* begin, end */
packet_out, /* unsigned char *data */
sizeof(packet_out), /* opus_int32 maxlen */
0, /*int self_delimited */
0, /* int pad */
NULL, /* const opus_extension_data *extensions */
0 /* int nb_extensions */);
expect_true(res > 0, "expected valid packet length");
/* now verify that we have the expected extensions */
res = opus_packet_parse_impl(packet_out, res, 0, NULL, NULL, size,
NULL, NULL, &padding, &padding_len);
nb_ext = 10;
res = opus_packet_extensions_parse(padding, padding_len, ext_out, &nb_ext);
expect_true(nb_ext == 4, "Expected 4 extensions");
for (i = 0 ; i < nb_ext; i++)
{
if (ext_out[i].id == 33)
{
opus_test_assert(ext_out[i].len == ext[0].len);
opus_test_assert(0 == memcmp(ext_out[i].data, ext[0].data, ext[0].len));
first_count++;
}
else if (ext_out[i].id == 100)
{
opus_test_assert(ext_out[i].len == ext[1].len);
opus_test_assert(0 == memcmp(ext_out[i].data, ext[1].data, ext[1].len));
second_count++;
}
if (i < 2)
opus_test_assert(ext_out[i].frame == 0)
else
opus_test_assert(ext_out[i].frame == 2)
}
opus_test_assert(first_count == 2);
opus_test_assert(second_count == 2);
}
int main(int argc, char **argv)
{
int env_used;
char *env_seed;
env_used=0;
env_seed=getenv("SEED");
if(argc>1)iseed=atoi(argv[1]);
else if(env_seed)
{
iseed=atoi(env_seed);
env_used=1;
}
else iseed=(opus_uint32)time(NULL)^(((opus_uint32)getpid()&65535)<<16);
Rw=Rz=iseed;
fprintf(stderr,"Testing extensions. Random seed: %u (%.4X)\n", iseed, fast_rand() % 65535);
if(env_used)fprintf(stderr," Random seed set from the environment (SEED=%s).\n", env_seed);
test_extensions_generate_success();
test_extensions_generate_zero();
test_extensions_generate_no_padding();
test_extensions_generate_fail();
test_extensions_parse_success();
test_extensions_parse_zero();
test_extensions_parse_fail();
test_random_extensions_parse();
test_opus_repacketizer_out_range_impl();
fprintf(stderr,"Tests completed successfully.\n");
return 0;
}

View File

@@ -0,0 +1,94 @@
/* Copyright (c) 2012 Xiph.Org Foundation
Written by Jüri Aedla and Ralph Giles */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Check for overflow in reading the padding length.
* http://lists.xiph.org/pipermail/opus/2012-November/001834.html
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "opus.h"
#include "test_opus_common.h"
#define PACKETSIZE 16909318
#define CHANNELS 2
#define FRAMESIZE 5760
void test_overflow(void)
{
OpusDecoder *decoder;
int result;
int error;
unsigned char *in = malloc(PACKETSIZE);
opus_int16 *out = malloc(FRAMESIZE*CHANNELS*sizeof(*out));
fprintf(stderr, " Checking for padding overflow... ");
if (!in || !out) {
fprintf(stderr, "FAIL (out of memory)\n");
test_failed();
}
in[0] = 0xff;
in[1] = 0x41;
memset(in + 2, 0xff, PACKETSIZE - 3);
in[PACKETSIZE-1] = 0x0b;
decoder = opus_decoder_create(48000, CHANNELS, &error);
result = opus_decode(decoder, in, PACKETSIZE, out, FRAMESIZE, 0);
opus_decoder_destroy(decoder);
free(in);
free(out);
if (result != OPUS_INVALID_PACKET) {
fprintf(stderr, "FAIL!\n");
test_failed();
}
fprintf(stderr, "OK.\n");
}
int main(void)
{
const char *oversion;
iseed = 0;
oversion = opus_get_version_string();
if (!oversion) test_failed();
fprintf(stderr, "Testing %s padding.\n", oversion);
test_overflow();
fprintf(stderr, "All padding tests passed.\n");
return 0;
}

View File

@@ -0,0 +1,393 @@
/* Copyright (c) 2017 Google Inc.
Written by Andrew Allen */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "float_cast.h"
#include "opus.h"
#include "test_opus_common.h"
#include "opus_projection.h"
#include "mathops.h"
#include "../src/mapping_matrix.h"
#include "mathops.h"
#define BUFFER_SIZE 960
#define MAX_DATA_BYTES 32768
#define MAX_FRAME_SAMPLES 5760
#define ERROR_TOLERANCE 1
#define SIMPLE_MATRIX_SIZE 12
#define SIMPLE_MATRIX_FRAME_SIZE 10
#define SIMPLE_MATRIX_INPUT_SIZE 30
#define SIMPLE_MATRIX_OUTPUT_SIZE 40
int assert_is_equal(
const opus_val16 *a, const opus_int16 *b, int size, opus_int16 tolerance)
{
int i;
for (i = 0; i < size; i++)
{
#ifdef FIXED_POINT
opus_int16 val = a[i];
#else
opus_int16 val = FLOAT2INT16(a[i]);
#endif
if (abs(val - b[i]) > tolerance)
return 1;
}
return 0;
}
int assert_is_equal_short(
const opus_int16 *a, const opus_int16 *b, int size, opus_int16 tolerance)
{
int i;
for (i = 0; i < size; i++)
if (abs(a[i] - b[i]) > tolerance)
return 1;
return 0;
}
void test_simple_matrix(void)
{
const MappingMatrix simple_matrix_params = {4, 3, 0};
const opus_int16 simple_matrix_data[SIMPLE_MATRIX_SIZE] = {0, 32767, 0, 0, 32767, 0, 0, 0, 0, 0, 0, 32767};
const opus_int16 input_int16[SIMPLE_MATRIX_INPUT_SIZE] = {
32767, 0, -32768, 29491, -3277, -29491, 26214, -6554, -26214, 22938, -9830,
-22938, 19661, -13107, -19661, 16384, -16384, -16384, 13107, -19661, -13107,
9830, -22938, -9830, 6554, -26214, -6554, 3277, -29491, -3277};
const opus_int16 expected_output_int16[SIMPLE_MATRIX_OUTPUT_SIZE] = {
0, 32767, 0, -32768, -3277, 29491, 0, -29491, -6554, 26214, 0, -26214,
-9830, 22938, 0, -22938, -13107, 19661, 0, -19661, -16384, 16384, 0, -16384,
-19661, 13107, 0, -13107, -22938, 9830, 0, -9830, -26214, 6554, 0, -6554,
-29491, 3277, 0, -3277};
int i, ret;
opus_int32 simple_matrix_size;
opus_val16 *input_val16;
opus_val16 *output_val16;
opus_int16 *output_int16;
MappingMatrix *simple_matrix;
/* Allocate input/output buffers. */
input_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_INPUT_SIZE);
output_int16 = (opus_int16 *)opus_alloc(sizeof(opus_int16) * SIMPLE_MATRIX_OUTPUT_SIZE);
output_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_OUTPUT_SIZE);
/* Initialize matrix */
simple_matrix_size = mapping_matrix_get_size(simple_matrix_params.rows,
simple_matrix_params.cols);
if (!simple_matrix_size)
test_failed();
simple_matrix = (MappingMatrix *)opus_alloc(simple_matrix_size);
mapping_matrix_init(simple_matrix, simple_matrix_params.rows,
simple_matrix_params.cols, simple_matrix_params.gain, simple_matrix_data,
sizeof(simple_matrix_data));
/* Copy inputs. */
for (i = 0; i < SIMPLE_MATRIX_INPUT_SIZE; i++)
{
#ifdef FIXED_POINT
input_val16[i] = input_int16[i];
#else
input_val16[i] = (1/32768.f)*input_int16[i];
#endif
}
/* _in_short */
for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
output_val16[i] = 0;
for (i = 0; i < simple_matrix->rows; i++)
{
mapping_matrix_multiply_channel_in_short(simple_matrix,
input_int16, simple_matrix->cols, &output_val16[i], i,
simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
}
ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
if (ret)
test_failed();
/* _out_short */
for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
output_int16[i] = 0;
for (i = 0; i < simple_matrix->cols; i++)
{
mapping_matrix_multiply_channel_out_short(simple_matrix,
&input_val16[i], i, simple_matrix->cols, output_int16,
simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
}
ret = assert_is_equal_short(output_int16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
if (ret)
test_failed();
#if !defined(DISABLE_FLOAT_API) && !defined(FIXED_POINT)
/* _in_float */
for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
output_val16[i] = 0;
for (i = 0; i < simple_matrix->rows; i++)
{
mapping_matrix_multiply_channel_in_float(simple_matrix,
input_val16, simple_matrix->cols, &output_val16[i], i,
simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
}
ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
if (ret)
test_failed();
/* _out_float */
for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
output_val16[i] = 0;
for (i = 0; i < simple_matrix->cols; i++)
{
mapping_matrix_multiply_channel_out_float(simple_matrix,
&input_val16[i], i, simple_matrix->cols, output_val16,
simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
}
ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
if (ret)
test_failed();
#endif
opus_free(input_val16);
opus_free(output_int16);
opus_free(output_val16);
opus_free(simple_matrix);
}
void test_creation_arguments(const int channels, const int mapping_family)
{
int streams;
int coupled_streams;
int enc_error;
int dec_error;
int ret;
OpusProjectionEncoder *st_enc = NULL;
OpusProjectionDecoder *st_dec = NULL;
const opus_int32 Fs = 48000;
const int application = OPUS_APPLICATION_AUDIO;
int order_plus_one = (int)floor(sqrt((float)channels));
int nondiegetic_channels = channels - order_plus_one * order_plus_one;
int is_channels_valid = 0;
int is_projection_valid = 0;
st_enc = opus_projection_ambisonics_encoder_create(Fs, channels,
mapping_family, &streams, &coupled_streams, application, &enc_error);
if (st_enc != NULL)
{
opus_int32 matrix_size;
unsigned char *matrix;
ret = opus_projection_encoder_ctl(st_enc,
OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size);
if (ret != OPUS_OK || !matrix_size)
test_failed();
matrix = (unsigned char *)opus_alloc(matrix_size);
ret = opus_projection_encoder_ctl(st_enc,
OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size);
opus_projection_encoder_destroy(st_enc);
st_dec = opus_projection_decoder_create(Fs, channels, streams,
coupled_streams, matrix, matrix_size, &dec_error);
if (st_dec != NULL)
{
opus_projection_decoder_destroy(st_dec);
}
opus_free(matrix);
}
is_channels_valid = (order_plus_one >= 2 && order_plus_one <= 6) &&
(nondiegetic_channels == 0 || nondiegetic_channels == 2);
is_projection_valid = (enc_error == OPUS_OK && dec_error == OPUS_OK);
if (is_channels_valid ^ is_projection_valid)
{
fprintf(stderr, "Channels: %d, Family: %d\n", channels, mapping_family);
fprintf(stderr, "Order+1: %d, Non-diegetic Channels: %d\n",
order_plus_one, nondiegetic_channels);
fprintf(stderr, "Streams: %d, Coupled Streams: %d\n",
streams, coupled_streams);
test_failed();
}
}
void generate_music(short *buf, opus_int32 len, opus_int32 channels)
{
opus_int32 i,j,k;
opus_int32 *a,*b,*c,*d;
a = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
b = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
c = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
d = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
memset(a, 0, sizeof(opus_int32) * channels);
memset(b, 0, sizeof(opus_int32) * channels);
memset(c, 0, sizeof(opus_int32) * channels);
memset(d, 0, sizeof(opus_int32) * channels);
j=0;
for(i=0;i<len;i++)
{
for(k=0;k<channels;k++)
{
opus_uint32 r;
opus_int32 v;
v=(((j*((j>>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15;
r=fast_rand();v+=r&65535;v-=r>>16;
b[k]=v-a[k]+((b[k]*61+32)>>6);a[k]=v;
c[k]=(30*(c[k]+b[k]+d[k])+32)>>6;d[k]=b[k];
v=(c[k]+128)>>8;
buf[i*channels+k]=v>32767?32767:(v<-32768?-32768:v);
if(i%6==0)j++;
}
}
free(a);
free(b);
free(c);
free(d);
}
void test_encode_decode(opus_int32 bitrate, opus_int32 channels,
const int mapping_family)
{
const opus_int32 Fs = 48000;
const int application = OPUS_APPLICATION_AUDIO;
OpusProjectionEncoder *st_enc;
OpusProjectionDecoder *st_dec;
int streams;
int coupled;
int error;
short *buffer_in;
short *buffer_out;
unsigned char data[MAX_DATA_BYTES] = { 0 };
int len;
int out_samples;
opus_int32 matrix_size = 0;
unsigned char *matrix = NULL;
buffer_in = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels);
buffer_out = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels);
st_enc = opus_projection_ambisonics_encoder_create(Fs, channels,
mapping_family, &streams, &coupled, application, &error);
if (error != OPUS_OK) {
fprintf(stderr,
"Couldn\'t create encoder with %d channels and mapping family %d.\n",
channels, mapping_family);
free(buffer_in);
free(buffer_out);
test_failed();
}
error = opus_projection_encoder_ctl(st_enc,
OPUS_SET_BITRATE(bitrate * 1000 * (streams + coupled)));
if (error != OPUS_OK)
{
goto bad_cleanup;
}
error = opus_projection_encoder_ctl(st_enc,
OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size);
if (error != OPUS_OK || !matrix_size)
{
goto bad_cleanup;
}
matrix = (unsigned char *)opus_alloc(matrix_size);
error = opus_projection_encoder_ctl(st_enc,
OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size);
st_dec = opus_projection_decoder_create(Fs, channels, streams, coupled,
matrix, matrix_size, &error);
opus_free(matrix);
if (error != OPUS_OK) {
fprintf(stderr,
"Couldn\'t create decoder with %d channels, %d streams "
"and %d coupled streams.\n", channels, streams, coupled);
goto bad_cleanup;
}
generate_music(buffer_in, BUFFER_SIZE, channels);
len = opus_projection_encode(
st_enc, buffer_in, BUFFER_SIZE, data, MAX_DATA_BYTES);
if(len<0 || len>MAX_DATA_BYTES) {
fprintf(stderr,"opus_encode() returned %d\n", len);
goto bad_cleanup;
}
out_samples = opus_projection_decode(
st_dec, data, len, buffer_out, MAX_FRAME_SAMPLES, 0);
if(out_samples!=BUFFER_SIZE) {
fprintf(stderr,"opus_decode() returned %d\n", out_samples);
goto bad_cleanup;
}
opus_projection_decoder_destroy(st_dec);
opus_projection_encoder_destroy(st_enc);
free(buffer_in);
free(buffer_out);
return;
bad_cleanup:
free(buffer_in);
free(buffer_out);
test_failed();
}
int main(int _argc, char **_argv)
{
unsigned int i;
(void)_argc;
(void)_argv;
/* Test simple matrix multiplication routines. */
test_simple_matrix();
/* Test full range of channels in creation arguments. */
for (i = 0; i < 255; i++)
test_creation_arguments(i, 3);
/* Test encode/decode pipeline. */
test_encode_decode(64 * 18, 18, 3);
fprintf(stderr, "All projection tests passed.\n");
return 0;
}