Adds OPUS_SET_RESTRICTED_LOWDELAY() encoder ctl
[opus.git] / src / opus_encoder.c
index 25baaa4..7987e31 100644 (file)
@@ -57,15 +57,17 @@ struct OpusEncoder {
     int          application;
     int          channels;
     int          delay_compensation;
-    int          force_mono;
+    int          force_channels;
     int          signal_type;
     int          user_bandwidth;
+    int          user_forced_mode;
     int          voice_ratio;
-    int          Fs;
+    opus_int32   Fs;
     int          use_vbr;
     int          vbr_constraint;
     int          bitrate_bps;
     int          user_bitrate_bps;
+    int          lowdelay;
     int          encoder_buffer;
 
 #define OPUS_ENCODER_RESET_START stream_channels
@@ -80,7 +82,7 @@ struct OpusEncoder {
     int          first;
     opus_val16   delay_buffer[MAX_ENCODER_BUFFER*2];
 
-    int          rangeFinal;
+    opus_uint32  rangeFinal;
 };
 
 /* Transition tables for the voice and music. First column is the
@@ -124,6 +126,8 @@ int opus_encoder_get_size(int channels)
 {
     int silkEncSizeBytes, celtEncSizeBytes;
     int ret;
+    if (channels<1 || channels > 2)
+        return 0;
     ret = silk_Get_Encoder_Size( &silkEncSizeBytes );
     if (ret)
         return 0;
@@ -132,7 +136,7 @@ int opus_encoder_get_size(int channels)
     return align(sizeof(OpusEncoder))+silkEncSizeBytes+celtEncSizeBytes;
 }
 
-int opus_encoder_init(OpusEncoder* st, int Fs, int channels, int application)
+int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int application)
 {
     void *silk_enc;
     CELTEncoder *celt_enc;
@@ -162,8 +166,7 @@ int opus_encoder_init(OpusEncoder* st, int Fs, int channels, int application)
     st->Fs = Fs;
 
     ret = silk_InitEncoder( silk_enc, &st->silk_mode );
-    if (ret)
-        goto failure;
+    if(ret)return OPUS_INTERNAL_ERROR;
 
     /* default SILK parameters */
     st->silk_mode.nChannelsAPI              = channels;
@@ -183,16 +186,18 @@ int opus_encoder_init(OpusEncoder* st, int Fs, int channels, int application)
     /* Create CELT encoder */
     /* Initialize CELT encoder */
     err = celt_encoder_init(celt_enc, Fs, channels);
-    if (err != OPUS_OK)
-        goto failure;
+    if(err!=OPUS_OK)return OPUS_INTERNAL_ERROR;
+
     celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0));
 
     st->use_vbr = 0;
-    st->user_bitrate_bps = OPUS_BITRATE_AUTO;
+    st->user_bitrate_bps = OPUS_AUTO;
     st->bitrate_bps = 3000+Fs*channels;
     st->application = application;
-    st->signal_type = OPUS_SIGNAL_AUTO;
-    st->user_bandwidth = OPUS_BANDWIDTH_AUTO;
+    st->signal_type = OPUS_AUTO;
+    st->user_bandwidth = OPUS_AUTO;
+    st->force_channels = OPUS_AUTO;
+    st->user_forced_mode = OPUS_AUTO;
     st->voice_ratio = -1;
     st->encoder_buffer = st->Fs/100;
 
@@ -213,10 +218,6 @@ int opus_encoder_init(OpusEncoder* st, int Fs, int channels, int application)
     st->bandwidth = OPUS_BANDWIDTH_FULLBAND;
 
     return OPUS_OK;
-
-failure:
-    opus_free(st);
-    return OPUS_INTERNAL_ERROR;
 }
 
 static unsigned char gen_toc(int mode, int framerate, int bandwidth, int silk_bandwidth, int channels)
@@ -326,7 +327,7 @@ static void hp_cutoff(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *ou
 #endif
 }
 
-OpusEncoder *opus_encoder_create(int Fs, int channels, int mode, int *error)
+OpusEncoder *opus_encoder_create(opus_int32 Fs, int channels, int mode, int *error)
 {
    int ret;
    OpusEncoder *st = (OpusEncoder *)opus_alloc(opus_encoder_get_size(channels));
@@ -374,6 +375,7 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
     int cutoff_Hz, hp_freq_smth1;
     int voice_est;
     opus_int32 equiv_rate;
+    int delay_compensation;
     ALLOC_STACK;
 
     st->rangeFinal = 0;
@@ -386,8 +388,15 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
     silk_enc = (char*)st+st->silk_enc_offset;
     celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
 
-    if (st->user_bitrate_bps==OPUS_BITRATE_AUTO)
+    if (st->lowdelay)
+       delay_compensation = 0;
+    else
+       delay_compensation = st->delay_compensation;
+
+    if (st->user_bitrate_bps==OPUS_AUTO)
         st->bitrate_bps = 60*st->Fs/frame_size + st->Fs*st->channels;
+    else if (st->user_bitrate_bps==OPUS_BITRATE_MAX)
+       st->bitrate_bps = max_data_bytes*8*st->Fs/frame_size;
     else
         st->bitrate_bps = st->user_bitrate_bps;
 
@@ -411,9 +420,9 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
        st->stream_channels = 3-st->stream_channels;
 #else
     /* Rate-dependent mono-stereo decision */
-    if (st->force_mono)
+    if (st->force_channels!=OPUS_AUTO && st->channels == 2)
     {
-        st->stream_channels = 1;
+        st->stream_channels = st->force_channels;
     } else if (st->channels == 2)
     {
        opus_int32 stereo_threshold;
@@ -444,12 +453,16 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
     }
 #else
     /* Mode selection depending on application and signal type */
+    if (st->lowdelay)
+    {
+       st->mode = MODE_CELT_ONLY;
+    } else if (st->user_forced_mode == OPUS_AUTO)
     {
        int chan;
        opus_int32 mode_voice, mode_music;
        opus_int32 threshold;
 
-       chan = (st->channels==2) && !st->force_mono;
+       chan = (st->channels==2) && st->force_channels!=1;
        mode_voice = mode_thresholds[chan][0];
        mode_music = mode_thresholds[chan][1];
        threshold = mode_music + ((voice_est*voice_est*(mode_voice-mode_music))>>14);
@@ -461,6 +474,8 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
            threshold += 4000;
 
        st->mode = (equiv_rate >= threshold) ? MODE_CELT_ONLY: MODE_SILK_ONLY;
+    } else {
+       st->mode = st->user_forced_mode;
     }
 #endif
 
@@ -502,7 +517,7 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
         opus_int32 bandwidth_thresholds[8];
         int bandwidth = OPUS_BANDWIDTH_FULLBAND;
 
-        if (st->channels==2 && !st->force_mono)
+        if (st->channels==2 && st->force_channels!=1)
         {
            voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds;
            music_bandwidth_thresholds = stereo_music_bandwidth_thresholds;
@@ -548,7 +563,7 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
     if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND)
         st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;
 
-    if (st->user_bandwidth != OPUS_BANDWIDTH_AUTO)
+    if (st->user_bandwidth != OPUS_AUTO)
         st->bandwidth = st->user_bandwidth;
 
     /* Can't support higher than wideband for >20 ms frames */
@@ -560,7 +575,7 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
         st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
 
     /* Chooses the appropriate mode for speech
-       *NEVER* switch to/from CELT-only mode here as this will */
+       *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */
     if (st->mode == MODE_SILK_ONLY && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)
         st->mode = MODE_HYBRID;
     if (st->mode == MODE_HYBRID && st->bandwidth <= OPUS_BANDWIDTH_WIDEBAND)
@@ -573,9 +588,9 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
 
     ec_enc_init(&enc, data, max_data_bytes-1);
 
-    ALLOC(pcm_buf, (st->delay_compensation+frame_size)*st->channels, opus_val16);
-    for (i=0;i<st->delay_compensation*st->channels;i++)
-       pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-st->delay_compensation)*st->channels+i];
+    ALLOC(pcm_buf, (delay_compensation+frame_size)*st->channels, opus_val16);
+    for (i=0;i<delay_compensation*st->channels;i++)
+       pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-delay_compensation)*st->channels+i];
 
     if (st->mode == MODE_CELT_ONLY)
        hp_freq_smth1 = SKP_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
@@ -590,10 +605,10 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
 
     if (st->application == OPUS_APPLICATION_VOIP)
     {
-       hp_cutoff(pcm, cutoff_Hz, &pcm_buf[st->delay_compensation*st->channels], st->hp_mem, frame_size, st->channels, st->Fs);
+       hp_cutoff(pcm, cutoff_Hz, &pcm_buf[delay_compensation*st->channels], st->hp_mem, frame_size, st->channels, st->Fs);
     } else {
        for (i=0;i<frame_size*st->channels;i++)
-          pcm_buf[st->delay_compensation*st->channels + i] = pcm[i];
+          pcm_buf[delay_compensation*st->channels + i] = pcm[i];
     }
 
     /* SILK processing */
@@ -666,10 +681,10 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
         }
 
 #ifdef FIXED_POINT
-        pcm_silk = pcm_buf+st->delay_compensation*st->channels;
+        pcm_silk = pcm_buf+delay_compensation*st->channels;
 #else
         for (i=0;i<frame_size*st->channels;i++)
-            pcm_silk[i] = FLOAT2INT16(pcm_buf[st->delay_compensation*st->channels + i]);
+            pcm_silk[i] = FLOAT2INT16(pcm_buf[delay_compensation*st->channels + i]);
 #endif
         ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 );
         if( ret ) {
@@ -723,7 +738,7 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
     if (st->mode != MODE_SILK_ONLY)
     {
         celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0));
-        celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(-1));
+        celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX));
         if (st->prev_mode == MODE_SILK_ONLY)
         {
             unsigned char dummy[10];
@@ -731,7 +746,7 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
             celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
             celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
             /* TODO: This wastes CPU a bit compared to just prefilling the buffer */
-            celt_encode_with_ec(celt_enc, &st->delay_buffer[(st->encoder_buffer-st->delay_compensation-st->Fs/400)*st->channels], st->Fs/400, dummy, 10, NULL);
+            celt_encode_with_ec(celt_enc, &st->delay_buffer[(st->encoder_buffer-delay_compensation-st->Fs/400)*st->channels], st->Fs/400, dummy, 10, NULL);
         } else {
             celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(2));
         }
@@ -763,8 +778,10 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
         nb_compr_bytes = 0;
     }
 
-    for (i=0;i<st->encoder_buffer*st->channels;i++)
-        st->delay_buffer[i] = pcm_buf[(frame_size+st->delay_compensation-st->encoder_buffer)*st->channels+i];
+    for (i=0;i<st->channels*(st->encoder_buffer-(frame_size+delay_compensation));i++)
+        st->delay_buffer[i] = st->delay_buffer[i+st->channels*frame_size];
+    for (;i<st->encoder_buffer*st->channels;i++)
+        st->delay_buffer[i] = pcm_buf[(frame_size+delay_compensation-st->encoder_buffer)*st->channels+i];
 
 
     if( st->mode == MODE_HYBRID && st->stream_channels == 2 ) {
@@ -791,22 +808,28 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
         }
     }
 
-    if (st->mode != MODE_CELT_ONLY)
+    if (st->mode != MODE_CELT_ONLY && ec_tell(&enc)+29+8*(st->mode == MODE_HYBRID) < 8*nb_compr_bytes)
     {
         /* Check if we have a redundant 0-8 kHz band */
         ec_enc_bit_logp(&enc, redundancy, 12);
         if (redundancy)
         {
+            int max_redundancy;
+            ec_enc_bit_logp(&enc, celt_to_silk, 1);
+            max_redundancy = nb_compr_bytes-((ec_tell(&enc)+7)>>3)-(st->mode == MODE_HYBRID);
             /* Target the same bit-rate for redundancy as for the rest,
                up to a max of 257 bytes */
-            redundancy_bytes = IMIN(257, st->bitrate_bps/1600);
-            ec_enc_bit_logp(&enc, celt_to_silk, 1);
+            redundancy_bytes = IMIN(max_redundancy, st->bitrate_bps/1600);
+            redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes));
             if (st->mode == MODE_HYBRID)
                 ec_enc_uint(&enc, redundancy_bytes-2, 256);
         }
-        start_band = 17;
+    } else {
+        redundancy = 0;
     }
 
+    if (st->mode != MODE_CELT_ONLY)start_band=17;
+
     if (st->mode == MODE_SILK_ONLY)
     {
         ret = (ec_tell(&enc)+7)>>3;
@@ -841,6 +864,8 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
     if (st->mode != MODE_SILK_ONLY)
     {
         ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc);
+        if (ret < 0)
+           return OPUS_INTERNAL_ERROR;
     }
 
     /* 5 ms redundant frame for SILK->CELT */
@@ -945,12 +970,14 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...)
         case OPUS_SET_BITRATE_REQUEST:
         {
             opus_int32 value = va_arg(ap, opus_int32);
-            if (value != OPUS_BITRATE_AUTO)
+            if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX)
             {
                 if (value <= 0)
                     goto bad_arg;
                 else if (value <= 500)
                     value = 500;
+                else if (value > (opus_int32)300000*st->channels)
+                    value = (opus_int32)300000*st->channels;
             }
             st->user_bitrate_bps = value;
         }
@@ -961,22 +988,22 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...)
             *value = st->bitrate_bps;
         }
         break;
-        case OPUS_SET_FORCE_MONO_REQUEST:
+        case OPUS_SET_FORCE_CHANNELS_REQUEST:
         {
             opus_int32 value = va_arg(ap, opus_int32);
-            st->force_mono = value;
+            st->force_channels = value;
         }
         break;
-        case OPUS_GET_FORCE_MONO_REQUEST:
+        case OPUS_GET_FORCE_CHANNELS_REQUEST:
         {
             opus_int32 *value = va_arg(ap, opus_int32*);
-            *value = !!st->force_mono;
+            *value = st->force_channels;
         }
         break;
         case OPUS_SET_BANDWIDTH_REQUEST:
         {
             opus_int32 value = va_arg(ap, opus_int32);
-            if (value < OPUS_BANDWIDTH_AUTO || value > OPUS_BANDWIDTH_FULLBAND)
+            if ((value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) && value != OPUS_AUTO)
                 return OPUS_BAD_ARG;
             st->user_bandwidth = value;
             if (st->user_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
@@ -1100,7 +1127,9 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...)
         case OPUS_GET_LOOKAHEAD_REQUEST:
         {
             opus_int32 *value = va_arg(ap, opus_int32*);
-            *value = st->delay_compensation+st->Fs/400;
+            *value = st->Fs/400;
+            if (!st->lowdelay)
+               *value += st->delay_compensation;
         }
         break;
         case OPUS_GET_FINAL_RANGE_REQUEST:
@@ -1116,7 +1145,7 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...)
            silk_enc = (char*)st+st->silk_enc_offset;
 
            OPUS_CLEAR((char*)&st->OPUS_ENCODER_RESET_START,
-                 opus_encoder_get_size(st->channels)-
+                 sizeof(OpusEncoder)-
                  ((char*)&st->OPUS_ENCODER_RESET_START - (char*)st));
 
            celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
@@ -1129,6 +1158,31 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...)
            st->variable_HP_smth2_Q15 = SKP_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
         }
         break;
+        case OPUS_SET_FORCE_MODE_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if (value < MODE_SILK_ONLY || value > MODE_CELT_ONLY)
+               goto bad_arg;
+            st->user_forced_mode = value;
+        }
+        break;
+        case OPUS_SET_RESTRICTED_LOWDELAY_REQUEST:
+        {
+            opus_int32 value = va_arg(ap, opus_int32);
+            if (!st->first && st->lowdelay != !!value)
+            {
+               ret = OPUS_BAD_ARG;
+               break;
+            }
+            st->lowdelay = !!value;
+        }
+        break;
+        case OPUS_GET_RESTRICTED_LOWDELAY_REQUEST:
+        {
+            opus_int32 *value = va_arg(ap, opus_int32*);
+            *value = st->lowdelay;
+        }
+        break;
         default:
             /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/
             ret = OPUS_UNIMPLEMENTED;