summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Marc Valin <jmvalin@jmvalin.ca>2013-02-18 18:17:03 -0500
committerJean-Marc Valin <jmvalin@jmvalin.ca>2013-02-18 18:17:03 -0500
commita465956cc84b9e9a8d5cafbb0f591be59530acab (patch)
treed6927e750d5a0db1fdddc2103d68b13389e7d98d
parent4b70dddfe980225922d154647c8aaf9c47c30728 (diff)
downloadopus-a465956cc84b9e9a8d5cafbb0f591be59530acab.tar.gz
Moves tonality_get_info() with the analysis
Avoids the special case for >20 ms CELT packets
-rw-r--r--src/analysis.c43
-rw-r--r--src/analysis.h6
-rw-r--r--src/opus_encoder.c115
-rw-r--r--src/opus_multistream_encoder.c33
-rw-r--r--src/opus_private.h7
5 files changed, 108 insertions, 96 deletions
diff --git a/src/analysis.c b/src/analysis.c
index ba684d57..18e6ee8f 100644
--- a/src/analysis.c
+++ b/src/analysis.c
@@ -211,10 +211,9 @@ void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int
#endif
}
-void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info_out, CELTEncoder *celt_enc, const void *x, int len, int offset, int C, int lsb_depth, downmix_func downmix)
+void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info_out, const CELTMode *celt_mode, const void *x, int len, int offset, int C, int lsb_depth, downmix_func downmix)
{
int i, b;
- const CELTMode *mode;
const kiss_fft_state *kfft;
kiss_fft_cpx in[480], out[480];
int N = 480, N2=240;
@@ -245,8 +244,6 @@ void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info_out, CEL
int remaining;
AnalysisInfo *info;
- celt_encoder_ctl(celt_enc, CELT_GET_MODE(&mode));
-
tonal->last_transition++;
alpha = 1.f/IMIN(20, 1+tonal->count);
alphaE = 1.f/IMIN(50, 1+tonal->count);
@@ -254,7 +251,7 @@ void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info_out, CEL
if (tonal->count<4)
tonal->music_prob = .5;
- kfft = mode->mdct.kfft[0];
+ kfft = celt_mode->mdct.kfft[0];
if (tonal->count==0)
tonal->mem_fill = 240;
downmix(x, &tonal->inmem[tonal->mem_fill], IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, C);
@@ -584,3 +581,39 @@ void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info_out, CEL
if (info_out!=NULL)
OPUS_COPY(info_out, info, 1);
}
+
+int run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *pcm,
+ const void *analysis_pcm, int frame_size, int C, int Fs, int bitrate_bps,
+ int delay_compensation, int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info)
+{
+ int offset;
+ int pcm_len;
+ int LM = 3;
+
+ pcm_len = frame_size - analysis->analysis_offset;
+ offset = 0;
+ do {
+ tonality_analysis(analysis, NULL, celt_mode, analysis_pcm, IMIN(480, pcm_len), offset, C, lsb_depth, downmix);
+ offset += 480;
+ pcm_len -= 480;
+ } while (pcm_len>0);
+ analysis->analysis_offset = frame_size;
+
+ //return frame_size;
+#ifndef FIXED_POINT
+ LM = optimize_framesize(pcm, frame_size, C, Fs, bitrate_bps,
+ analysis->prev_tonality, analysis->subframe_mem, delay_compensation, downmix);
+#endif
+ while ((Fs/400<<LM)>frame_size)
+ LM--;
+ frame_size = (Fs/400<<LM);
+ //frame_size = st->Fs/50;
+ analysis->analysis_offset -= frame_size;
+
+ /* Only perform analysis up to 20-ms frames. Longer ones will be split if
+ they're in CELT-only mode. */
+ analysis_info->valid = 0;
+ tonality_get_info(analysis, analysis_info, frame_size);
+
+ return frame_size;
+}
diff --git a/src/analysis.h b/src/analysis.h
index 28db0f89..b5e53d72 100644
--- a/src/analysis.h
+++ b/src/analysis.h
@@ -72,8 +72,12 @@ typedef struct {
} TonalityAnalysisState;
void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info,
- CELTEncoder *celt_enc, const void *x, int len, int offset, int C, int lsb_depth, downmix_func downmix);
+ const CELTMode *celt_mode, const void *x, int len, int offset, int C, int lsb_depth, downmix_func downmix);
void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len);
+int run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *pcm,
+ const void *analysis_pcm, int frame_size, int C, int Fs, int bitrate_bps,
+ int delay_compensation, int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info);
+
#endif
diff --git a/src/opus_encoder.c b/src/opus_encoder.c
index 560f9b14..94b8becc 100644
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -760,38 +760,14 @@ int optimize_framesize(const opus_val16 *x, int len, int C, opus_int32 Fs,
return bestLM;
}
-static int run_analysis(TonalityAnalysisState *analysis, CELTEncoder *celt_enc, const void *pcm, const void *analysis_pcm,
- int frame_size, int C, int Fs, int bitrate_bps, int delay_compensation, int lsb_depth, downmix_func downmix)
-{
- int offset;
- int pcm_len;
- int LM = 3;
-
- pcm_len = frame_size - analysis->analysis_offset;
- offset = 0;
- do {
- tonality_analysis(analysis, NULL, celt_enc, analysis_pcm, IMIN(480, pcm_len), offset, C, lsb_depth, downmix);
- offset += 480;
- pcm_len -= 480;
- } while (pcm_len>0);
- analysis->analysis_offset = frame_size;
-
- //return frame_size;
-#ifndef FIXED_POINT
- LM = optimize_framesize(pcm, frame_size, C, Fs, bitrate_bps,
- analysis->prev_tonality, analysis->subframe_mem, delay_compensation, downmix);
-#endif
- while ((Fs/400<<LM)>frame_size)
- LM--;
- frame_size = (Fs/400<<LM);
- //frame_size = st->Fs/50;
- analysis->analysis_offset -= frame_size;
- return frame_size;
-}
#endif
opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
- unsigned char *data, opus_int32 out_data_bytes, int lsb_depth)
+ unsigned char *data, opus_int32 out_data_bytes, int lsb_depth
+#ifndef FIXED_POINT
+ , AnalysisInfo *analysis_info
+#endif
+ )
{
void *silk_enc;
CELTEncoder *celt_enc;
@@ -819,11 +795,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_
opus_val16 HB_gain;
opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */
int total_buffer;
- int perform_analysis=0;
int orig_frame_size;
-#ifndef FIXED_POINT
- AnalysisInfo analysis_info;
-#endif
VARDECL(opus_val16, tmp_prefill);
ALLOC_STACK;
@@ -853,26 +825,12 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_
st->voice_ratio = -1;
st->detected_bandwidth = 0;
-#if 0
- perform_analysis = st->silk_mode.complexity >= 7 && st->Fs==48000;
- if (perform_analysis)
- frame_size = run_analysis(&st->analysis, celt_enc, pcm, pcm+st->channels*st->analysis.analysis_offset, frame_size, st->channels, st->Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix_float);
-#endif
-
#ifndef FIXED_POINT
- /* Only perform analysis up to 20-ms frames. Longer ones will be split if
- they're in CELT-only mode. */
- analysis_info.valid = 0;
- perform_analysis = st->silk_mode.complexity >= 7 && st->Fs==48000;
- if (perform_analysis && frame_size <= st->Fs/50)
+ if (analysis_info->valid)
{
- tonality_get_info(&st->analysis, &analysis_info, frame_size);
- if (analysis_info.valid)
- {
- if (st->signal_type == OPUS_AUTO)
- st->voice_ratio = (int)floor(.5+100*(1-analysis_info.music_prob));
- st->detected_bandwidth = analysis_info.opus_bandwidth;
- }
+ if (st->signal_type == OPUS_AUTO)
+ st->voice_ratio = (int)floor(.5+100*(1-analysis_info->music_prob));
+ st->detected_bandwidth = analysis_info->opus_bandwidth;
}
#endif
@@ -1182,7 +1140,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_
/* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */
if (to_celt && i==nb_frames-1)
st->user_forced_mode = MODE_CELT_ONLY;
- tmp_len = opus_encode_native(st, pcm+i*(st->channels*st->Fs/50), st->Fs/50, tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth);
+ tmp_len = opus_encode_native(st, pcm+i*(st->channels*st->Fs/50), st->Fs/50, tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth, analysis_info);
if (tmp_len<0)
{
RESTORE_STACK;
@@ -1208,17 +1166,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_
RESTORE_STACK;
return ret;
}
-#ifndef FIXED_POINT
- /* FIXME: This needs to go */
- /* Perform analysis for 40-60 ms frames */
- if (perform_analysis && frame_size > st->Fs/50)
- {
- int nb_analysis = frame_size/(st->Fs/100);
- //for (i=0;i<nb_analysis;i++)
- // tonality_analysis(&st->analysis, &analysis_info, celt_enc, pcm+i*(st->Fs/100)*st->channels, 480, st->channels, lsb_depth, downmix_float);
- st->voice_ratio = (int)floor(.5+100*(1-analysis_info.music_prob));
- }
-#endif
curr_bandwidth = st->bandwidth;
/* Chooses the appropriate mode for speech
@@ -1470,9 +1417,9 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_
#ifndef FIXED_POINT
if (st->variable_duration && orig_frame_size != frame_size)
{
- bonus = (40*st->stream_channels+40)*(48000/frame_size-48000/orig_frame_size);
- if (analysis_info.valid)
- bonus = bonus*(1.f+.5*analysis_info.tonality);
+ bonus = (40*st->stream_channels+40)*(48000/frame_size-50);
+ if (analysis_info->valid)
+ bonus = bonus*(1.f+.5*analysis_info->tonality);
}
#endif
celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1));
@@ -1609,8 +1556,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_
if (ec_tell(&enc) <= 8*nb_compr_bytes)
{
#ifndef FIXED_POINT
- if (perform_analysis)
- celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(&analysis_info));
+ celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(analysis_info));
#endif
ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc);
if (ret < 0)
@@ -1737,13 +1683,14 @@ opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
unsigned char *data, opus_int32 max_data_bytes)
{
int i, ret;
- CELTEncoder *celt_enc;
+ const CELTMode *celt_mode;
int delay_compensation;
int lsb_depth;
VARDECL(float, in);
+ AnalysisInfo analysis_info;
ALLOC_STACK;
- celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+ opus_encoder_ctl(st, CELT_GET_MODE(&celt_mode));
if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
delay_compensation = 0;
else
@@ -1752,24 +1699,28 @@ opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
lsb_depth = IMIN(16, st->lsb_depth);
if (st->silk_mode.complexity >= 7 && st->Fs==48000)
- frame_size = run_analysis(&st->analysis, celt_enc, pcm, pcm+st->channels*st->analysis.analysis_offset, frame_size, st->channels, st->Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix_int);
+ {
+ frame_size = run_analysis(&st->analysis, celt_mode, pcm, pcm+st->channels*st->analysis.analysis_offset,
+ frame_size, st->channels, st->Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix_int, &analysis_info);
+ }
ALLOC(in, frame_size*st->channels, float);
for (i=0;i<frame_size*st->channels;i++)
in[i] = (1.0f/32768)*pcm[i];
- ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16);
+ ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, &analysis_info);
RESTORE_STACK;
return ret;
}
opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int frame_size,
unsigned char *data, opus_int32 out_data_bytes)
{
- CELTEncoder *celt_enc;
+ const CELTMode *celt_mode;
int delay_compensation;
int lsb_depth;
+ AnalysisInfo analysis_info;
- celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+ opus_encoder_ctl(st, CELT_GET_MODE(&celt_mode));
if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
delay_compensation = 0;
else
@@ -1778,9 +1729,12 @@ opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int frame_size,
lsb_depth = IMIN(24, st->lsb_depth);
if (st->silk_mode.complexity >= 7 && st->Fs==48000)
- frame_size = run_analysis(&st->analysis, celt_enc, pcm, pcm+st->channels*st->analysis.analysis_offset, frame_size, st->channels, st->Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix_float);
+ {
+ frame_size = run_analysis(&st->analysis, celt_mode, pcm, pcm+st->channels*st->analysis.analysis_offset,
+ frame_size, st->channels, st->Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix_float, &analysis_info);
+ }
- return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24);
+ return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24, &analysis_info);
}
#endif
@@ -2092,6 +2046,15 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...)
st->user_forced_mode = value;
}
break;
+
+ case CELT_GET_MODE_REQUEST:
+ {
+ const CELTMode ** value = va_arg(ap, const CELTMode**);
+ if (value==0)
+ goto bad_arg;
+ celt_encoder_ctl(celt_enc, CELT_GET_MODE(value));
+ }
+ break;
default:
/* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/
ret = OPUS_UNIMPLEMENTED;
diff --git a/src/opus_multistream_encoder.c b/src/opus_multistream_encoder.c
index c5fb3669..be96efc4 100644
--- a/src/opus_multistream_encoder.c
+++ b/src/opus_multistream_encoder.c
@@ -36,8 +36,10 @@
#include <stdarg.h>
#include "float_cast.h"
#include "os_support.h"
+#include "analysis.h"
struct OpusMSEncoder {
+ TonalityAnalysisState analysis;
ChannelLayout layout;
int variable_duration;
opus_int32 bitrate_bps;
@@ -187,6 +189,7 @@ static int opus_multistream_encode_native
int lsb_depth
#ifndef FIXED_POINT
, downmix_func downmix
+ , const void *pcm_analysis
#endif
)
{
@@ -202,10 +205,15 @@ static int opus_multistream_encode_native
int orig_frame_size;
int coded_channels;
opus_int32 channel_rate;
+ opus_int32 complexity;
+ AnalysisInfo analysis_info;
+ const CELTMode *celt_mode;
ALLOC_STACK;
ptr = (char*)st + align(sizeof(OpusMSEncoder));
opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_COMPLEXITY(&complexity));
+ opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode));
if (400*frame_size < Fs)
{
@@ -213,23 +221,20 @@ static int opus_multistream_encode_native
return OPUS_BAD_ARG;
}
orig_frame_size = IMIN(frame_size,Fs/50);
- if (st->variable_duration)
+#ifndef FIXED_POINT
+ if (complexity >= 7 && Fs==48000)
{
- int LM = 3;
- int channels;
opus_int32 delay_compensation;
+ int channels;
channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_LOOKAHEAD(&delay_compensation));
delay_compensation -= Fs/400;
-#ifndef FIXED_POINT
- LM = optimize_framesize(pcm, frame_size, channels, Fs, st->bitrate_bps,
- 0.f, st->subframe_mem, delay_compensation, downmix);
-#endif
- while ((Fs/400<<LM)>frame_size)
- LM--;
- frame_size = (Fs/400<<LM);
+
+ frame_size = run_analysis(&st->analysis, celt_mode, pcm, pcm_analysis,
+ frame_size, channels, Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix, &analysis_info);
}
+#endif
/* Validate frame_size before using it to allocate stack space.
This mirrors the checks in opus_encode[_float](). */
@@ -313,7 +318,7 @@ static int opus_multistream_encode_native
/* Reserve three bytes for the last stream and four for the others */
curr_max -= IMAX(0,4*(st->layout.nb_streams-s-1)-1);
curr_max = IMIN(curr_max,MS_FRAME_TMP);
- len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth);
+ len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth, &analysis_info);
if (len<0)
{
RESTORE_STACK;
@@ -412,8 +417,9 @@ int opus_multistream_encode_float
opus_int32 max_data_bytes
)
{
+ int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
return opus_multistream_encode_native(st, opus_copy_channel_in_float,
- pcm, frame_size, data, max_data_bytes, 24, downmix_float);
+ pcm, frame_size, data, max_data_bytes, 24, downmix_float, pcm+channels*st->analysis.analysis_offset);
}
int opus_multistream_encode(
@@ -424,8 +430,9 @@ int opus_multistream_encode(
opus_int32 max_data_bytes
)
{
+ int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
return opus_multistream_encode_native(st, opus_copy_channel_in_short,
- pcm, frame_size, data, max_data_bytes, 16, downmix_int);
+ pcm, frame_size, data, max_data_bytes, 16, downmix_int, pcm+channels*st->analysis.analysis_offset);
}
#endif
diff --git a/src/opus_private.h b/src/opus_private.h
index e39e06f6..e615e295 100644
--- a/src/opus_private.h
+++ b/src/opus_private.h
@@ -31,6 +31,7 @@
#include "arch.h"
#include "opus.h"
+#include "celt.h"
struct OpusRepacketizer {
unsigned char toc;
@@ -92,7 +93,11 @@ int optimize_framesize(const opus_val16 *x, int len, int C, opus_int32 Fs,
int encode_size(int size, unsigned char *data);
opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
- unsigned char *data, opus_int32 out_data_bytes, int lsb_depth);
+ unsigned char *data, opus_int32 out_data_bytes, int lsb_depth
+#ifndef FIXED_POINT
+ , AnalysisInfo *analysis_info
+#endif
+ );
int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len,
opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, int *packet_offset);