mirror of https://git.ffmpeg.org/ffmpeg.git
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:
parent
16beae15f3
commit
b461b3bc4a
13
ffmpeg.c
13
ffmpeg.c
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
150
libavcodec/pcm.c
150
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,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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue