summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Marc Valin <jmvalin@jmvalin.ca>2016-04-20 13:27:06 -0400
committerJean-Marc Valin <jmvalin@jmvalin.ca>2016-09-01 00:41:19 -0400
commit67821109b98ea81e136bf8ddf077529ecfd8bce3 (patch)
treed75d34f91a4d93b89bb0490abb1c4f55a49d2a1c
parented539aa5cf7fefc8a337e2fea72b0fe1b1fc789c (diff)
downloadopus-exp_bitstream5.tar.gz
Make it possible to ignore inverted phase stereo for downmix purposesexp_bitstream5
-rw-r--r--celt/bands.c9
-rw-r--r--celt/bands.h2
-rw-r--r--celt/celt_decoder.c29
-rw-r--r--celt/celt_encoder.c24
-rw-r--r--include/opus_defines.h26
-rw-r--r--src/opus_decoder.c20
-rw-r--r--src/opus_encoder.c20
-rwxr-xr-xtests/run_vectors.sh25
8 files changed, 140 insertions, 15 deletions
diff --git a/celt/bands.c b/celt/bands.c
index 80bc230c..62c034f5 100644
--- a/celt/bands.c
+++ b/celt/bands.c
@@ -683,6 +683,7 @@ struct band_ctx {
opus_uint32 seed;
int arch;
int theta_round;
+ int disable_inv;
};
struct split_ctx {
@@ -832,7 +833,7 @@ static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx,
} else if (stereo) {
if (encode)
{
- inv = itheta > 8192;
+ inv = itheta > 8192 && !ctx->disable_inv;
if (inv)
{
int j;
@@ -849,6 +850,9 @@ static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx,
inv = ec_dec_bit_logp(ec, 2);
} else
inv = 0;
+ /* inv flag override to avoid problems with downmixing. */
+ if (ctx->disable_inv)
+ inv = 0;
itheta = 0;
}
qalloc = ec_tell_frac(ec) - tell;
@@ -1367,7 +1371,7 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
const celt_ener *bandE, int *pulses, int shortBlocks, int spread,
int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits,
opus_int32 balance, ec_ctx *ec, int LM, int codedBands,
- opus_uint32 *seed, int complexity, int arch)
+ opus_uint32 *seed, int complexity, int arch, int disable_inv)
{
int i;
opus_int32 remaining_bits;
@@ -1433,6 +1437,7 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
ctx.seed = *seed;
ctx.spread = spread;
ctx.arch = arch;
+ ctx.disable_inv = disable_inv;
ctx.resynth = resynth;
ctx.theta_round = 0;
for (i=start;i<end;i++)
diff --git a/celt/bands.h b/celt/bands.h
index 41d080f6..c040c7f7 100644
--- a/celt/bands.h
+++ b/celt/bands.h
@@ -105,7 +105,7 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
const celt_ener *bandE, int *pulses, int shortBlocks, int spread,
int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits,
opus_int32 balance, ec_ctx *ec, int M, int codedBands, opus_uint32 *seed,
- int complexity, int arch);
+ int complexity, int arch, int disable_inv);
void anti_collapse(const CELTMode *m, celt_norm *X_,
unsigned char *collapse_masks, int LM, int C, int size, int start,
diff --git a/celt/celt_decoder.c b/celt/celt_decoder.c
index e441d045..58e7b75a 100644
--- a/celt/celt_decoder.c
+++ b/celt/celt_decoder.c
@@ -73,6 +73,7 @@ struct OpusCustomDecoder {
int downsample;
int start, end;
int signalling;
+ int disable_inv;
int arch;
/* Everything beyond this point gets cleared on a reset */
@@ -163,6 +164,11 @@ OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMod
st->start = 0;
st->end = st->mode->effEBands;
st->signalling = 1;
+#ifdef ENABLE_UPDATE_DRAFT
+ st->disable_inv = channels == 1;
+#else
+ st->disable_inv = 0;
+#endif
st->arch = opus_select_arch();
opus_custom_decoder_ctl(st, OPUS_RESET_STATE);
@@ -1043,7 +1049,8 @@ int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *dat
quant_all_bands(0, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks,
NULL, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res,
- len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng, 0, st->arch);
+ len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng, 0,
+ st->arch, st->disable_inv);
if (anti_collapse_rsv > 0)
{
@@ -1298,6 +1305,26 @@ int opus_custom_decoder_ctl(CELTDecoder * OPUS_RESTRICT st, int request, ...)
*value=st->rng;
}
break;
+ case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->disable_inv = value;
+ }
+ break;
+ case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->disable_inv;
+ }
+ break;
default:
goto bad_request;
}
diff --git a/celt/celt_encoder.c b/celt/celt_encoder.c
index 1a031d9e..5be76103 100644
--- a/celt/celt_encoder.c
+++ b/celt/celt_encoder.c
@@ -75,6 +75,7 @@ struct OpusCustomEncoder {
int lsb_depth;
int variable_duration;
int lfe;
+ int disable_inv;
int arch;
/* Everything beyond this point gets cleared on a reset */
@@ -181,7 +182,6 @@ static int opus_custom_encoder_init_arch(CELTEncoder *st, const CELTMode *mode,
st->start = 0;
st->end = st->mode->effEBands;
st->signalling = 1;
-
st->arch = arch;
st->constrained_vbr = 1;
@@ -2079,7 +2079,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
quant_all_bands(1, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks,
bandE, pulses, shortBlocks, st->spread_decision,
dual_stereo, st->intensity, tf_res, nbCompressedBytes*(8<<BITRES)-anti_collapse_rsv,
- balance, enc, LM, codedBands, &st->rng, st->complexity, st->arch);
+ balance, enc, LM, codedBands, &st->rng, st->complexity, st->arch, st->disable_inv);
if (anti_collapse_rsv > 0)
{
@@ -2376,6 +2376,26 @@ int opus_custom_encoder_ctl(CELTEncoder * OPUS_RESTRICT st, int request, ...)
st->variable_duration = value;
}
break;
+ case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->disable_inv = value;
+ }
+ break;
+ case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->disable_inv;
+ }
+ break;
case OPUS_RESET_STATE:
{
int i;
diff --git a/include/opus_defines.h b/include/opus_defines.h
index 315412dd..0d9aab08 100644
--- a/include/opus_defines.h
+++ b/include/opus_defines.h
@@ -165,8 +165,9 @@ extern "C" {
#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041
#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042
#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043
-
/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
+#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046
+#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047
/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
@@ -681,6 +682,29 @@ extern "C" {
*/
#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
+/** If set to 1, disables the use of phase inversion for intensity stereo, improving the
+ * quality of mono downmixes, but slightly reducing normal stereo quality. Disabling phase
+ * inversion does not comply with RFC6716, even though it does not cause any
+ * interoperability issue. It will become part of the Opus standard once RFC6716 gets
+ * updated with draft-ietf-codec-opus-update.
+ * @see OPUS_GET_PHASE_INVERSION_DISABLED
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>0</dt><dd>Enable phase inversion (default).</dd>
+ * <dt>1</dt><dd>Disable phase inversion.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_PHASE_INVERSION_DISABLED(x) OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured phase inversion status.
+ * @see OPUS_SET_PHASE_INVERSION_DISABLED
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>0</dt><dd>Stereo phase inversion enabled (default).</dd>
+ * <dt>1</dt><dd>Stereo phase inversion disabled.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x)
+
/**@}*/
/** @defgroup opus_decoderctls Decoder related CTLs
diff --git a/src/opus_decoder.c b/src/opus_decoder.c
index 080bec50..af46d82f 100644
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -899,6 +899,26 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
*value = st->last_packet_duration;
}
break;
+ case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ celt_decoder_ctl(celt_dec, OPUS_SET_PHASE_INVERSION_DISABLED(value));
+ }
+ break;
+ case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ celt_decoder_ctl(celt_dec, OPUS_GET_PHASE_INVERSION_DISABLED(value));
+ }
+ break;
default:
/*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
ret = OPUS_UNIMPLEMENTED;
diff --git a/src/opus_encoder.c b/src/opus_encoder.c
index f484b0a4..ef464fc5 100644
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -2781,6 +2781,26 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...)
*value = st->silk_mode.reducedDependency;
}
break;
+ case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ celt_encoder_ctl(celt_enc, OPUS_SET_PHASE_INVERSION_DISABLED(value));
+ }
+ break;
+ case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ celt_encoder_ctl(celt_enc, OPUS_GET_PHASE_INVERSION_DISABLED(value));
+ }
+ break;
case OPUS_RESET_STATE:
{
void *silk_enc;
diff --git a/tests/run_vectors.sh b/tests/run_vectors.sh
index 1d447c43..dd74f0cb 100755
--- a/tests/run_vectors.sh
+++ b/tests/run_vectors.sh
@@ -33,8 +33,8 @@
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-rm logs_mono.txt
-rm logs_stereo.txt
+rm logs_mono.txt logs_mono2.txt
+rm logs_stereo.txt logs_stereo2.txt
if [ "$#" -ne "3" ]; then
echo "usage: run_vectors.sh <exec path> <vector path> <rate>"
@@ -87,9 +87,11 @@ do
echo ERROR: decoding failed
exit 1
fi
- $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_mono.txt 2>&1
+ $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector${file}.dec tmp.out >> logs_mono.txt 2>&1
float_ret=$?
- if [ "$float_ret" -eq "0" ]; then
+ $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
@@ -116,9 +118,11 @@ do
echo ERROR: decoding failed
exit 1
fi
- $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_stereo.txt 2>&1
+ $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector${file}.dec tmp.out >> logs_stereo.txt 2>&1
float_ret=$?
- if [ "$float_ret" -eq "0" ]; then
+ $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
@@ -130,5 +134,10 @@ done
echo All tests have passed successfully
-grep quality logs_mono.txt | awk '{sum+=$4}END{print "Average mono quality is", sum/NR, "%"}'
-grep quality logs_stereo.txt | awk '{sum+=$4}END{print "Average stereo quality is", sum/NR, "%"}'
+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, "%"}'