# HG changeset patch # User reimar # Date 1125688608 0 # Node ID 6f7428adc6ad985f37d9137e9ffd41ed45f912be # Parent 411601677547e70b4ee03ddea3213146de68fc56 Support de-/encoding of 24 and 32 bit PCM (from and to internal 16 bit). diff -r 411601677547 -r 6f7428adc6ad allcodecs.c --- a/allcodecs.c Fri Sep 02 17:12:16 2005 +0000 +++ b/allcodecs.c Fri Sep 02 19:16:48 2005 +0000 @@ -524,6 +524,15 @@ register_avcodec(& name ## _decoder); #endif +PCM_CODEC(CODEC_ID_PCM_S32LE, pcm_s32le); +PCM_CODEC(CODEC_ID_PCM_S32BE, pcm_s32be); +PCM_CODEC(CODEC_ID_PCM_U32LE, pcm_u32le); +PCM_CODEC(CODEC_ID_PCM_U32BE, pcm_u32be); +PCM_CODEC(CODEC_ID_PCM_S24LE, pcm_s24le); +PCM_CODEC(CODEC_ID_PCM_S24BE, pcm_s24be); +PCM_CODEC(CODEC_ID_PCM_U24LE, pcm_u24le); +PCM_CODEC(CODEC_ID_PCM_U24BE, pcm_u24be); +PCM_CODEC(CODEC_ID_PCM_S24DAUD, pcm_s24daud); PCM_CODEC(CODEC_ID_PCM_S16LE, pcm_s16le); PCM_CODEC(CODEC_ID_PCM_S16BE, pcm_s16be); PCM_CODEC(CODEC_ID_PCM_U16LE, pcm_u16le); diff -r 411601677547 -r 6f7428adc6ad avcodec.h --- a/avcodec.h Fri Sep 02 17:12:16 2005 +0000 +++ b/avcodec.h Fri Sep 02 19:16:48 2005 +0000 @@ -121,6 +121,15 @@ CODEC_ID_PCM_U8, CODEC_ID_PCM_MULAW, CODEC_ID_PCM_ALAW, + CODEC_ID_PCM_S32LE, + CODEC_ID_PCM_S32BE, + CODEC_ID_PCM_U32LE, + CODEC_ID_PCM_U32BE, + CODEC_ID_PCM_S24LE, + CODEC_ID_PCM_S24BE, + CODEC_ID_PCM_U24LE, + CODEC_ID_PCM_U24BE, + CODEC_ID_PCM_S24DAUD, /* various adpcm codecs */ CODEC_ID_ADPCM_IMA_QT= 0x11000, @@ -2097,6 +2106,15 @@ extern AVCodec name ## _decoder; \ extern AVCodec name ## _encoder +PCM_CODEC(CODEC_ID_PCM_S32LE, pcm_s32le); +PCM_CODEC(CODEC_ID_PCM_S32BE, pcm_s32be); +PCM_CODEC(CODEC_ID_PCM_U32LE, pcm_u32le); +PCM_CODEC(CODEC_ID_PCM_U32BE, pcm_u32be); +PCM_CODEC(CODEC_ID_PCM_S24LE, pcm_s24le); +PCM_CODEC(CODEC_ID_PCM_S24BE, pcm_s24be); +PCM_CODEC(CODEC_ID_PCM_U24LE, pcm_u24le); +PCM_CODEC(CODEC_ID_PCM_U24BE, pcm_u24be); +PCM_CODEC(CODEC_ID_PCM_S24DAUD, pcm_s24daud); PCM_CODEC(CODEC_ID_PCM_S16LE, pcm_s16le); PCM_CODEC(CODEC_ID_PCM_S16BE, pcm_s16be); PCM_CODEC(CODEC_ID_PCM_U16LE, pcm_u16le); diff -r 411601677547 -r 6f7428adc6ad pcm.c --- a/pcm.c Fri Sep 02 17:12:16 2005 +0000 +++ b/pcm.c Fri Sep 02 19:16:48 2005 +0000 @@ -23,6 +23,7 @@ */ #include "avcodec.h" +#include "bitstream.h" // for ff_reverse /* from g711.c by SUN microsystems (unrestricted use) */ @@ -128,6 +129,19 @@ } switch(avctx->codec->id) { + case CODEC_ID_PCM_S32LE: + case CODEC_ID_PCM_S32BE: + case CODEC_ID_PCM_U32LE: + case CODEC_ID_PCM_U32BE: + avctx->block_align = 4 * avctx->channels; + break; + case CODEC_ID_PCM_S24LE: + case CODEC_ID_PCM_S24BE: + case CODEC_ID_PCM_U24LE: + case CODEC_ID_PCM_U24BE: + case CODEC_ID_PCM_S24DAUD: + avctx->block_align = 3 * avctx->channels; + break; case CODEC_ID_PCM_S16LE: case CODEC_ID_PCM_S16BE: case CODEC_ID_PCM_U16LE: @@ -170,6 +184,29 @@ return 0; } +/** + * \brief convert samples from 16 bit + * \param bps byte per sample for the destination format, must be >= 2 + * \param le 0 for big-, 1 for little-endian + * \param samples input samples + * \param dst output samples + * \param n number of samples in samples buffer. + */ +static inline void encode_from16(int bps, int le, int us, + short **samples, uint8_t **dst, int n) { + if (bps > 2) + memset(*dst, 0, n * bps); + if (le) *dst += bps - 2; + for(;n>0;n--) { + register int v = *(*samples)++; + if (us) v += 0x8000; + (*dst)[le] = v >> 8; + (*dst)[1 - le] = v; + *dst += bps; + } + if (le) *dst -= bps - 2; +} + static int pcm_encode_frame(AVCodecContext *avctx, unsigned char *frame, int buf_size, void *data) { @@ -178,6 +215,19 @@ unsigned char *dst; switch(avctx->codec->id) { + case CODEC_ID_PCM_S32LE: + case CODEC_ID_PCM_S32BE: + case CODEC_ID_PCM_U32LE: + case CODEC_ID_PCM_U32BE: + sample_size = 4; + break; + case CODEC_ID_PCM_S24LE: + case CODEC_ID_PCM_S24BE: + case CODEC_ID_PCM_U24LE: + case CODEC_ID_PCM_U24BE: + case CODEC_ID_PCM_S24DAUD: + sample_size = 3; + break; case CODEC_ID_PCM_S16LE: case CODEC_ID_PCM_S16BE: case CODEC_ID_PCM_U16LE: @@ -193,6 +243,43 @@ dst = frame; switch(avctx->codec->id) { + case CODEC_ID_PCM_S32LE: + encode_from16(4, 1, 0, &samples, &dst, n); + break; + case CODEC_ID_PCM_S32BE: + encode_from16(4, 0, 0, &samples, &dst, n); + break; + case CODEC_ID_PCM_U32LE: + encode_from16(4, 1, 1, &samples, &dst, n); + break; + case CODEC_ID_PCM_U32BE: + encode_from16(4, 0, 1, &samples, &dst, n); + break; + case CODEC_ID_PCM_S24LE: + encode_from16(3, 1, 0, &samples, &dst, n); + break; + case CODEC_ID_PCM_S24BE: + encode_from16(3, 0, 0, &samples, &dst, n); + break; + case CODEC_ID_PCM_U24LE: + encode_from16(3, 1, 1, &samples, &dst, n); + break; + case CODEC_ID_PCM_U24BE: + encode_from16(3, 0, 1, &samples, &dst, n); + break; + case CODEC_ID_PCM_S24DAUD: + for(;n>0;n--) { + uint32_t tmp = ff_reverse[*samples >> 8] + + (ff_reverse[*samples & 0xff] << 8); + tmp <<= 4; // sync flags would go here + dst[2] = tmp & 0xff; + tmp >>= 8; + dst[1] = tmp & 0xff; + dst[0] = tmp >> 8; + samples++; + dst += 3; + } + break; case CODEC_ID_PCM_S16LE: for(;n>0;n--) { v = *samples++; @@ -287,6 +374,26 @@ return 0; } +/** + * \brief convert samples to 16 bit + * \param bps byte per sample for the source format, must be >= 2 + * \param le 0 for big-, 1 for little-endian + * \param src input samples + * \param samples output samples + * \param src_len number of bytes in src + */ +static inline void decode_to16(int bps, int le, int us, + uint8_t **src, short **samples, int src_len) +{ + register int n = src_len / bps; + if (le) *src += bps - 2; + for(;n>0;n--) { + *(*samples)++ = ((*src)[le] << 8 | (*src)[1 - le]) - (us?0x8000:0); + *src += bps; + } + if (le) *src -= bps - 2; +} + static int pcm_decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size) @@ -303,6 +410,40 @@ buf_size = AVCODEC_MAX_AUDIO_FRAME_SIZE/2; switch(avctx->codec->id) { + case CODEC_ID_PCM_S32LE: + decode_to16(4, 1, 0, &src, &samples, buf_size); + break; + case CODEC_ID_PCM_S32BE: + decode_to16(4, 0, 0, &src, &samples, buf_size); + break; + case CODEC_ID_PCM_U32LE: + decode_to16(4, 1, 1, &src, &samples, buf_size); + break; + case CODEC_ID_PCM_U32BE: + decode_to16(4, 0, 1, &src, &samples, buf_size); + break; + case CODEC_ID_PCM_S24LE: + decode_to16(3, 1, 0, &src, &samples, buf_size); + break; + case CODEC_ID_PCM_S24BE: + decode_to16(3, 0, 0, &src, &samples, buf_size); + break; + case CODEC_ID_PCM_U24LE: + decode_to16(3, 1, 1, &src, &samples, buf_size); + break; + case CODEC_ID_PCM_U24BE: + decode_to16(3, 0, 1, &src, &samples, buf_size); + break; + case CODEC_ID_PCM_S24DAUD: + n = buf_size / 3; + for(;n>0;n--) { + uint32_t v = src[0] << 16 | src[1] << 8 | src[2]; + v >>= 4; // sync flags are here + *samples++ = ff_reverse[(v >> 8) & 0xff] + + (ff_reverse[v & 0xff] << 8); + src += 3; + } + break; case CODEC_ID_PCM_S16LE: n = buf_size >> 1; for(;n>0;n--) { @@ -382,6 +523,15 @@ pcm_decode_frame, \ } +PCM_CODEC(CODEC_ID_PCM_S32LE, pcm_s32le); +PCM_CODEC(CODEC_ID_PCM_S32BE, pcm_s32be); +PCM_CODEC(CODEC_ID_PCM_U32LE, pcm_u32le); +PCM_CODEC(CODEC_ID_PCM_U32BE, pcm_u32be); +PCM_CODEC(CODEC_ID_PCM_S24LE, pcm_s24le); +PCM_CODEC(CODEC_ID_PCM_S24BE, pcm_s24be); +PCM_CODEC(CODEC_ID_PCM_U24LE, pcm_u24le); +PCM_CODEC(CODEC_ID_PCM_U24BE, pcm_u24be); +PCM_CODEC(CODEC_ID_PCM_S24DAUD, pcm_s24daud); PCM_CODEC(CODEC_ID_PCM_S16LE, pcm_s16le); PCM_CODEC(CODEC_ID_PCM_S16BE, pcm_s16be); PCM_CODEC(CODEC_ID_PCM_U16LE, pcm_u16le); diff -r 411601677547 -r 6f7428adc6ad utils.c --- a/utils.c Fri Sep 02 17:12:16 2005 +0000 +++ b/utils.c Fri Sep 02 19:16:48 2005 +0000 @@ -828,6 +828,19 @@ /* for PCM codecs, compute bitrate directly */ switch(enc->codec_id) { + case CODEC_ID_PCM_S32LE: + case CODEC_ID_PCM_S32BE: + case CODEC_ID_PCM_U32LE: + case CODEC_ID_PCM_U32BE: + bitrate = enc->sample_rate * enc->channels * 32; + break; + case CODEC_ID_PCM_S24LE: + case CODEC_ID_PCM_S24BE: + case CODEC_ID_PCM_U24LE: + case CODEC_ID_PCM_U24BE: + case CODEC_ID_PCM_S24DAUD: + bitrate = enc->sample_rate * enc->channels * 24; + break; case CODEC_ID_PCM_S16LE: case CODEC_ID_PCM_S16BE: case CODEC_ID_PCM_U16LE: