]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/pcm.c
Move the ratecontrol related code from mpegvideo.h to a separate header file.
[ffmpeg] / libavcodec / pcm.c
index 8e57d11a1c50db07590a5197544e80c7a5946d6d..0b4dd1c86bc3d4f5876683d17dd101fd412c5898 100644 (file)
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
+
 /**
  * @file pcm.c
  * PCM codecs
  */
+
 #include "avcodec.h"
+#include "bitstream.h" // for ff_reverse
 
 /* from g711.c by SUN microsystems (unrestricted use) */
 
-#define        SIGN_BIT        (0x80)          /* Sign bit for a A-law byte. */
-#define        QUANT_MASK      (0xf)           /* Quantization field mask. */
-#define        NSEGS           (8)             /* Number of A-law segments. */
-#define        SEG_SHIFT       (4)             /* Left shift for segment number. */
-#define        SEG_MASK        (0x70)          /* Segment field mask. */
+#define         SIGN_BIT        (0x80)      /* Sign bit for a A-law byte. */
+#define         QUANT_MASK      (0xf)       /* Quantization field mask. */
+#define         NSEGS           (8)         /* Number of A-law segments. */
+#define         SEG_SHIFT       (4)         /* Left shift for segment number. */
+#define         SEG_MASK        (0x70)      /* Segment field mask. */
 
-#define        BIAS            (0x84)          /* Bias for linear code. */
+#define         BIAS            (0x84)      /* Bias for linear code. */
 
 /*
  * alaw2linear() - Convert an A-law value to 16-bit linear PCM
  *
  */
-static int alaw2linear(unsigned char   a_val)
+static int alaw2linear(unsigned char a_val)
 {
-       int             t;
-       int             seg;
+        int t;
+        int seg;
 
-       a_val ^= 0x55;
+        a_val ^= 0x55;
 
-       t = a_val & QUANT_MASK;
-       seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
-       if(seg) t= (t + t + 1 + 32) << (seg + 2);
-       else    t= (t + t + 1     ) << 3;
+        t = a_val & QUANT_MASK;
+        seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
+        if(seg) t= (t + t + 1 + 32) << (seg + 2);
+        else    t= (t + t + 1     ) << 3;
 
-       return ((a_val & SIGN_BIT) ? t : -t);
+        return ((a_val & SIGN_BIT) ? t : -t);
 }
 
-static int ulaw2linear(unsigned char   u_val)
+static int ulaw2linear(unsigned char u_val)
 {
-       int             t;
+        int t;
 
-       /* Complement to obtain normal u-law value. */
-       u_val = ~u_val;
+        /* Complement to obtain normal u-law value. */
+        u_val = ~u_val;
 
-       /*
-        * Extract and bias the quantization bits. Then
-        * shift up by the segment number and subtract out the bias.
-        */
-       t = ((u_val & QUANT_MASK) << 3) + BIAS;
-       t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
+        /*
+         * Extract and bias the quantization bits. Then
+         * shift up by the segment number and subtract out the bias.
+         */
+        t = ((u_val & QUANT_MASK) << 3) + BIAS;
+        t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
 
-       return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
+        return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
 }
 
 /* 16384 entries per table */
@@ -77,9 +78,9 @@ static int linear_to_alaw_ref = 0;
 static uint8_t *linear_to_ulaw = NULL;
 static int linear_to_ulaw_ref = 0;
 
-static void build_xlaw_table(uint8_t *linear_to_xlaw, 
+static void build_xlaw_table(uint8_t *linear_to_xlaw,
                              int (*xlaw2linear)(unsigned char),
-                             int mask) 
+                             int mask)
 {
     int i, j, v, v1, v2;
 
@@ -126,8 +127,21 @@ static int pcm_encode_init(AVCodecContext *avctx)
     default:
         break;
     }
-    
+
     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:
@@ -146,7 +160,7 @@ static int pcm_encode_init(AVCodecContext *avctx)
 
     avctx->coded_frame= avcodec_alloc_frame();
     avctx->coded_frame->key_frame= 1;
-    
+
     return 0;
 }
 
@@ -170,14 +184,51 @@ 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)
+                            unsigned char *frame, int buf_size, void *data)
 {
     int n, sample_size, v;
     short *samples;
     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,9 +375,30 @@ 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)
+                            void *data, int *data_size,
+                            uint8_t *buf, int buf_size)
 {
     PCMDecode *s = avctx->priv_data;
     int n;
@@ -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--) {
@@ -366,9 +509,9 @@ AVCodec name ## _encoder = {                    \
     CODEC_TYPE_AUDIO,                           \
     id,                                         \
     0,                                          \
-    pcm_encode_init,                           \
-    pcm_encode_frame,                          \
-    pcm_encode_close,                          \
+    pcm_encode_init,                            \
+    pcm_encode_frame,                           \
+    pcm_encode_close,                           \
     NULL,                                       \
 };                                              \
 AVCodec name ## _decoder = {                    \
@@ -376,12 +519,21 @@ AVCodec name ## _decoder = {                    \
     CODEC_TYPE_AUDIO,                           \
     id,                                         \
     sizeof(PCMDecode),                          \
-    pcm_decode_init,                           \
+    pcm_decode_init,                            \
     NULL,                                       \
     NULL,                                       \
     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);