[Spice-devel] [spice-common opus support 2/6 (take 3)] Add support for the Opus codec.

Christophe Fergeau cfergeau at redhat.com
Wed Nov 20 08:51:36 PST 2013


ACK

On Tue, Nov 12, 2013 at 03:52:36PM -0600, Jeremy White wrote:
> Signed-off-by: Jeremy White <jwhite at codeweavers.com>
> ---
>  common/Makefile.am |    2 +
>  common/snd_codec.c |  136 +++++++++++++++++++++++++++++++++++++++++++++++++---
>  common/snd_codec.h |   20 ++++++--
>  configure.ac       |    4 ++
>  spice.proto        |    1 +
>  spice1.proto       |    1 +
>  6 files changed, 153 insertions(+), 11 deletions(-)
> 
> diff --git a/common/Makefile.am b/common/Makefile.am
> index c79f596..73703fc 100644
> --- a/common/Makefile.am
> +++ b/common/Makefile.am
> @@ -84,6 +84,7 @@ AM_CPPFLAGS =				\
>  	$(GL_CFLAGS)			\
>  	$(PIXMAN_CFLAGS)		\
>  	$(CELT051_CFLAGS)		\
> +	$(OPUS_CFLAGS)		        \
>  	$(PROTOCOL_CFLAGS)		\
>  	$(SMARTCARD_CFLAGS)		\
>  	$(VISIBILITY_HIDDEN_CFLAGS)	\
> @@ -92,6 +93,7 @@ AM_CPPFLAGS =				\
>  	$(NULL)
>  
>  libspice_common_la_LIBADD =				\
> +	$(OPUS_LIBS)		                        \
>  	$(CELT051_LIBS)
>  
>  MARSHALLERS_DEPS =					\
> diff --git a/common/snd_codec.c b/common/snd_codec.c
> index 2d13183..f737432 100644
> --- a/common/snd_codec.c
> +++ b/common/snd_codec.c
> @@ -48,6 +48,11 @@ typedef struct
>      CELTEncoder *celt_encoder;
>      CELTDecoder *celt_decoder;
>  #endif
> +
> +#if HAVE_OPUS
> +    OpusEncoder *opus_encoder;
> +    OpusDecoder *opus_decoder;
> +#endif
>  } SndCodecInternal;
>  
>  
> @@ -80,7 +85,7 @@ static int snd_codec_create_celt051(SndCodecInternal *codec, int encode, int dec
>      int celt_error;
>  
>      codec->celt_mode = celt051_mode_create(codec->frequency,
> -                                           SND_CODEC_CELT_PLAYBACK_CHAN,
> +                                           SND_CODEC_PLAYBACK_CHAN,
>                                             SND_CODEC_CELT_FRAME_SIZE, &celt_error);
>      if (! codec->celt_mode)
>      {
> @@ -119,7 +124,7 @@ error:
>  static int snd_codec_encode_celt051(SndCodecInternal *codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size)
>  {
>      int n;
> -    if (in_size != SND_CODEC_CELT_FRAME_SIZE * SND_CODEC_CELT_PLAYBACK_CHAN * 2)
> +    if (in_size != SND_CODEC_CELT_FRAME_SIZE * SND_CODEC_PLAYBACK_CHAN * 2)
>          return SND_CODEC_INVALID_ENCODE_SIZE;
>      n = celt051_encode(codec->celt_encoder, (celt_int16_t *) in_ptr, NULL, out_ptr, *out_size);
>      if (n < 0) {
> @@ -138,12 +143,93 @@ static int snd_codec_decode_celt051(SndCodecInternal *codec, uint8_t *in_ptr, in
>          spice_printerr("celt051_decode failed %d\n", n);
>          return SND_CODEC_DECODE_FAILED;
>      }
> -    *out_size = SND_CODEC_CELT_FRAME_SIZE * SND_CODEC_CELT_PLAYBACK_CHAN * 2 /* 16 fmt */;
> +    *out_size = SND_CODEC_CELT_FRAME_SIZE * SND_CODEC_PLAYBACK_CHAN * 2 /* 16 fmt */;
>      return SND_CODEC_OK;
>  }
>  #endif
>  
>  
> +/* Opus support routines */
> +#if HAVE_OPUS
> +static void snd_codec_destroy_opus(SndCodecInternal *codec)
> +{
> +    if (codec->opus_decoder)
> +    {
> +        opus_decoder_destroy(codec->opus_decoder);
> +        codec->opus_decoder = NULL;
> +    }
> +
> +    if (codec->opus_encoder)
> +    {
> +        opus_encoder_destroy(codec->opus_encoder);
> +        codec->opus_encoder = NULL;
> +    }
> +
> +}
> +
> +static int snd_codec_create_opus(SndCodecInternal *codec, int encode, int decode)
> +{
> +    int opus_error;
> +
> +    if (encode)
> +    {
> +        codec->opus_encoder = opus_encoder_create(codec->frequency,
> +                                SND_CODEC_PLAYBACK_CHAN,
> +                                OPUS_APPLICATION_AUDIO, &opus_error);
> +        if (! codec->opus_encoder)
> +        {
> +            spice_printerr("create opus encoder failed; error %d", opus_error);
> +            goto error;
> +        }
> +    }
> +
> +    if (decode)
> +    {
> +        codec->opus_decoder = opus_decoder_create(codec->frequency,
> +                                SND_CODEC_PLAYBACK_CHAN, &opus_error);
> +        if (! codec->opus_decoder)
> +        {
> +            spice_printerr("create opus decoder failed; error %d", opus_error);
> +            goto error;
> +        }
> +    }
> +
> +    codec->mode = SPICE_AUDIO_DATA_MODE_OPUS;
> +    return SND_CODEC_OK;
> +
> +error:
> +    snd_codec_destroy_opus(codec);
> +    return SND_CODEC_UNAVAILABLE;
> +}
> +
> +static int snd_codec_encode_opus(SndCodecInternal *codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size)
> +{
> +    int n;
> +    if (in_size != SND_CODEC_OPUS_FRAME_SIZE * SND_CODEC_PLAYBACK_CHAN * 2)
> +        return SND_CODEC_INVALID_ENCODE_SIZE;
> +    n = opus_encode(codec->opus_encoder, (opus_int16 *) in_ptr, SND_CODEC_OPUS_FRAME_SIZE, out_ptr, *out_size);
> +    if (n < 0) {
> +        spice_printerr("opus_encode failed %d\n", n);
> +        return SND_CODEC_ENCODE_FAILED;
> +    }
> +    *out_size = n;
> +    return SND_CODEC_OK;
> +}
> +
> +static int snd_codec_decode_opus(SndCodecInternal *codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size)
> +{
> +    int n;
> +    n = opus_decode(codec->opus_decoder, in_ptr, in_size, (opus_int16 *) out_ptr,
> +                *out_size / SND_CODEC_PLAYBACK_CHAN / 2, 0);
> +    if (n < 0) {
> +        spice_printerr("opus_decode failed %d\n", n);
> +        return SND_CODEC_DECODE_FAILED;
> +    }
> +    *out_size = n * SND_CODEC_PLAYBACK_CHAN * 2 /* 16 fmt */;
> +    return SND_CODEC_OK;
> +}
> +#endif
> +
>  
>  /*----------------------------------------------------------------------------
>  **          PUBLIC INTERFACE
> @@ -155,14 +241,23 @@ static int snd_codec_decode_celt051(SndCodecInternal *codec, uint8_t *in_ptr, in
>        use the given codec, FALSE otherwise.
>     mode must be a SPICE_AUDIO_DATA_MODE_XXX enum from spice/enum.h
>   */
> -int snd_codec_is_capable(int mode)
> +int snd_codec_is_capable(int mode, int frequency)
>  {
>  #if HAVE_CELT051
>      if (mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1)
>          return TRUE;
> -#else
> -    return FALSE;
>  #endif
> +
> +#if HAVE_OPUS
> +    if (mode == SPICE_AUDIO_DATA_MODE_OPUS &&
> +         (frequency == SND_CODEC_ANY_FREQUENCY ||
> +          frequency == 48000 || frequency == 24000 ||
> +          frequency == 16000 || frequency == 12000 ||
> +          frequency == 8000) )
> +        return TRUE;
> +#endif
> +
> +    return FALSE;
>  }
>  
>  /*
> @@ -191,6 +286,11 @@ int snd_codec_create(SndCodec *codec, int mode, int frequency, int encode, int d
>          rc = snd_codec_create_celt051(*c, encode, decode);
>  #endif
>  
> +#if HAVE_OPUS
> +    if (mode == SPICE_AUDIO_DATA_MODE_OPUS)
> +        rc = snd_codec_create_opus(*c, encode, decode);
> +#endif
> +
>      return rc;
>  }
>  
> @@ -208,6 +308,10 @@ void snd_codec_destroy(SndCodec *codec)
>      snd_codec_destroy_celt051(*c);
>  #endif
>  
> +#if HAVE_OPUS
> +    snd_codec_destroy_opus(*c);
> +#endif
> +
>      free(*c);
>      *c = NULL;
>  }
> @@ -225,6 +329,10 @@ int snd_codec_frame_size(SndCodec codec)
>      if (c && c->mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1)
>          return SND_CODEC_CELT_FRAME_SIZE;
>  #endif
> +#if HAVE_OPUS
> +    if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
> +        return SND_CODEC_OPUS_FRAME_SIZE;
> +#endif
>      return SND_CODEC_MAX_FRAME_SIZE;
>  }
>  
> @@ -251,7 +359,18 @@ int snd_codec_encode(SndCodec codec, uint8_t *in_ptr, int in_size, uint8_t *out_
>      SndCodecInternal *c = (SndCodecInternal *) codec;
>  #if HAVE_CELT051
>      if (c && c->mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1)
> +    {
> +        /* The output buffer size in celt determines the compression,
> +            and so is essentially mandatory to use a certain value (47) */
> +        if (*out_size > SND_CODEC_CELT_COMPRESSED_FRAME_BYTES)
> +            *out_size = SND_CODEC_CELT_COMPRESSED_FRAME_BYTES;
>          return snd_codec_encode_celt051(c, in_ptr, in_size, out_ptr, out_size);
> +    }
> +#endif
> +
> +#if HAVE_OPUS
> +    if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
> +        return snd_codec_encode_opus(c, in_ptr, in_size, out_ptr, out_size);
>  #endif
>  
>      return SND_CODEC_ENCODER_UNAVAILABLE;
> @@ -281,5 +400,10 @@ int snd_codec_decode(SndCodec codec, uint8_t *in_ptr, int in_size, uint8_t *out_
>          return snd_codec_decode_celt051(c, in_ptr, in_size, out_ptr, out_size);
>  #endif
>  
> +#if HAVE_OPUS
> +    if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
> +        return snd_codec_decode_opus(c, in_ptr, in_size, out_ptr, out_size);
> +#endif
> +
>      return SND_CODEC_DECODER_UNAVAILABLE;
>  }
> diff --git a/common/snd_codec.h b/common/snd_codec.h
> index 069356f..e1edfe9 100644
> --- a/common/snd_codec.h
> +++ b/common/snd_codec.h
> @@ -24,6 +24,10 @@
>  #include <celt051/celt.h>
>  #endif
>  
> +#if HAVE_OPUS
> +#include  <opus.h>
> +#endif
> +
>  /* Spice uses a very fixed protocol when transmitting CELT audio;
>     audio must be transmitted in frames of 256, and we must compress
>     data down to a fairly specific size (47, computation below).
> @@ -33,14 +37,20 @@
>  #define SND_CODEC_CELT_FRAME_SIZE       256
>  #define SND_CODEC_CELT_BIT_RATE         (64 * 1024)
>  #define SND_CODEC_CELT_PLAYBACK_FREQ    44100
> -#define SND_CODEC_CELT_PLAYBACK_CHAN    2
>  #define SND_CODEC_CELT_COMPRESSED_FRAME_BYTES (SND_CODEC_CELT_FRAME_SIZE * SND_CODEC_CELT_BIT_RATE / \
>                                          SND_CODEC_CELT_PLAYBACK_FREQ / 8)
>  
> +#define SND_CODEC_OPUS_FRAME_SIZE       480
> +#define SND_CODEC_OPUS_PLAYBACK_FREQ    48000
> +#define SND_CODEC_OPUS_COMPRESSED_FRAME_BYTES 480
> +
> +#define SND_CODEC_PLAYBACK_CHAN         2
> +
> +#define SND_CODEC_MAX_FRAME_SIZE        (MAX(SND_CODEC_CELT_FRAME_SIZE, SND_CODEC_OPUS_FRAME_SIZE))
> +#define SND_CODEC_MAX_FRAME_BYTES       (SND_CODEC_MAX_FRAME_SIZE * SND_CODEC_PLAYBACK_CHAN * 2 /* FMT_S16 */)
> +#define SND_CODEC_MAX_COMPRESSED_BYTES  MAX(SND_CODEC_CELT_COMPRESSED_FRAME_BYTES, SND_CODEC_OPUS_COMPRESSED_FRAME_BYTES)
>  
> -#define SND_CODEC_MAX_FRAME_SIZE        SND_CODEC_CELT_FRAME_SIZE
> -#define SND_CODEC_MAX_FRAME_BYTES       (SND_CODEC_MAX_FRAME_SIZE * SND_CODEC_CELT_PLAYBACK_CHAN * 2 /* FMT_S16 */)
> -#define SND_CODEC_MAX_COMPRESSED_BYTES  SND_CODEC_CELT_COMPRESSED_FRAME_BYTES
> +#define SND_CODEC_ANY_FREQUENCY        -1
>  
>  #define SND_CODEC_OK                    0
>  #define SND_CODEC_UNAVAILABLE           1
> @@ -54,7 +64,7 @@ SPICE_BEGIN_DECLS
>  
>  typedef struct SndCodecInternal * SndCodec;
>  
> -int  snd_codec_is_capable(int mode);
> +int  snd_codec_is_capable(int mode, int frequency);
>  
>  int  snd_codec_create(SndCodec *codec, int mode, int frequency, int encode, int decode);
>  void snd_codec_destroy(SndCodec *codec);
> diff --git a/configure.ac b/configure.ac
> index 3443334..273d935 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -67,6 +67,10 @@ fi
>  AM_CONDITIONAL([HAVE_CELT051], [test "x$have_celt051" = "xyes"])
>  AM_COND_IF([HAVE_CELT051], AC_DEFINE([HAVE_CELT051], 1, [Define if we have celt051 codec]))
>  
> +PKG_CHECK_MODULES([OPUS], [opus >= 0.9.14], have_opus=yes, have_opus=no)
> +AM_CONDITIONAL([HAVE_OPUS], [test "x$have_opus" = "xyes"])
> +AM_COND_IF([HAVE_OPUS], AC_DEFINE([HAVE_OPUS], 1, [Define if we have Opus]))
> +
>  AC_ARG_ENABLE([opengl],
>    AS_HELP_STRING([--enable-opengl=@<:@yes/no@:>@],
>                   [Enable opengl support (not recommended) @<:@default=no@:>@]),
> diff --git a/spice.proto b/spice.proto
> index 04e7ea4..67b3803 100644
> --- a/spice.proto
> +++ b/spice.proto
> @@ -1067,6 +1067,7 @@ enum16 audio_data_mode {
>      INVALID,
>      RAW,
>      CELT_0_5_1,
> +    OPUS,
>  };
>  
>  enum16 audio_fmt {
> diff --git a/spice1.proto b/spice1.proto
> index 2d22cdf..67eb0e6 100644
> --- a/spice1.proto
> +++ b/spice1.proto
> @@ -876,6 +876,7 @@ enum32 audio_data_mode {
>      INVALID,
>      RAW,
>      CELT_0_5_1,
> +    OPUS,
>  };
>  
>  enum32 audio_fmt {
> -- 
> 1.7.10.4
> 
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/spice-devel/attachments/20131120/d72e3b6d/attachment.pgp>


More information about the Spice-devel mailing list