Support de-/encoding of 24 and 32 bit PCM (from and to internal 16 bit).

Originally committed as revision 4548 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Reimar Döffinger 2005-09-02 19:16:48 +00:00
parent 16beae15f3
commit b461b3bc4a
7 changed files with 232 additions and 0 deletions

View File

@ -599,6 +599,19 @@ static void do_audio_out(AVFormatContext *s,
/* output a pcm frame */
/* XXX: change encoding codec API to avoid this ? */
switch(enc->codec->id) {
case CODEC_ID_PCM_S32LE:
case CODEC_ID_PCM_S32BE:
case CODEC_ID_PCM_U32LE:
case CODEC_ID_PCM_U32BE:
size_out = size_out << 1;
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:
size_out = size_out / 2 * 3;
break;
case CODEC_ID_PCM_S16LE:
case CODEC_ID_PCM_S16BE:
case CODEC_ID_PCM_U16LE:

View File

@ -524,6 +524,15 @@ void avcodec_register_all(void)
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);

View File

@ -121,6 +121,15 @@ enum CodecID {
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 libgsm_decoder;
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);

View File

@ -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,29 @@ 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 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 @@ 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 +243,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 +374,26 @@ 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 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 @@ 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 +523,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);

View File

@ -828,6 +828,19 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
/* 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:

View File

@ -643,6 +643,23 @@ static int get_audio_frame_size(AVCodecContext *enc, int size)
/* specific hack for pcm codecs because no frame size is
provided */
switch(enc->codec_id) {
case CODEC_ID_PCM_S32LE:
case CODEC_ID_PCM_S32BE:
case CODEC_ID_PCM_U32LE:
case CODEC_ID_PCM_U32BE:
if (enc->channels == 0)
return -1;
frame_size = size / (4 * enc->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:
if (enc->channels == 0)
return -1;
frame_size = size / (3 * enc->channels);
break;
case CODEC_ID_PCM_S16LE:
case CODEC_ID_PCM_S16BE:
case CODEC_ID_PCM_U16LE:

View File

@ -25,6 +25,8 @@ const CodecTag codec_wav_tags[] = {
{ CODEC_ID_AC3, 0x2000 },
{ CODEC_ID_PCM_S16LE, 0x01 },
{ CODEC_ID_PCM_U8, 0x01 }, /* must come after s16le in this list */
{ CODEC_ID_PCM_S24LE, 0x01 },
{ CODEC_ID_PCM_S32LE, 0x01 },
{ CODEC_ID_PCM_ALAW, 0x06 },
{ CODEC_ID_PCM_MULAW, 0x07 },
{ CODEC_ID_ADPCM_MS, 0x02 },
@ -68,6 +70,10 @@ int put_wav_header(ByteIOContext *pb, AVCodecContext *enc)
bps = 0;
} else if (enc->codec_id == CODEC_ID_ADPCM_IMA_WAV || enc->codec_id == CODEC_ID_ADPCM_MS || enc->codec_id == CODEC_ID_ADPCM_G726 || enc->codec_id == CODEC_ID_ADPCM_YAMAHA) { //
bps = 4;
} else if (enc->codec_id == CODEC_ID_PCM_S24LE) {
bps = 24;
} else if (enc->codec_id == CODEC_ID_PCM_S32LE) {
bps = 32;
} else {
bps = 16;
}
@ -82,6 +88,8 @@ int put_wav_header(ByteIOContext *pb, AVCodecContext *enc)
} else
blkalign = enc->channels*bps >> 3;
if (enc->codec_id == CODEC_ID_PCM_U8 ||
enc->codec_id == CODEC_ID_PCM_S24LE ||
enc->codec_id == CODEC_ID_PCM_S32LE ||
enc->codec_id == CODEC_ID_PCM_S16LE) {
bytespersec = enc->sample_rate * blkalign;
} else {
@ -179,6 +187,10 @@ int wav_codec_get_id(unsigned int tag, int bps)
/* handle specific u8 codec */
if (id == CODEC_ID_PCM_S16LE && bps == 8)
id = CODEC_ID_PCM_U8;
if (id == CODEC_ID_PCM_S16LE && bps == 24)
id = CODEC_ID_PCM_S24LE;
if (id == CODEC_ID_PCM_S16LE && bps == 32)
id = CODEC_ID_PCM_S32LE;
return id;
}