diff options
Diffstat (limited to 'src/libffmpeg/libavcodec/pcm.c')
-rw-r--r-- | src/libffmpeg/libavcodec/pcm.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/libffmpeg/libavcodec/pcm.c b/src/libffmpeg/libavcodec/pcm.c index 8e57d11a1..e3a81a590 100644 --- a/src/libffmpeg/libavcodec/pcm.c +++ b/src/libffmpeg/libavcodec/pcm.c @@ -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 @@ static int pcm_encode_init(AVCodecContext *avctx) } 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,30 @@ static int pcm_encode_close(AVCodecContext *avctx) 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 us 0 for signed, 1 for unsigned output + * \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 +216,19 @@ static int pcm_encode_frame(AVCodecContext *avctx, 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 +244,43 @@ static int pcm_encode_frame(AVCodecContext *avctx, 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 +375,27 @@ static int pcm_decode_init(AVCodecContext * avctx) 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 us 0 for signed, 1 for unsigned input + * \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 +412,40 @@ static int pcm_decode_frame(AVCodecContext *avctx, 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 +525,15 @@ AVCodec name ## _decoder = { \ 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); |