[Ffmpeg-devel] [RFC] More PCM formats (was: [PATCH] demuxer for dcinema audio)

Reimar Döffinger Reimar.Doeffinger
Fri Sep 2 20:24:59 CEST 2005


Hi,
On Fri, Sep 02, 2005 at 01:00:40PM +0200, Michael Niedermayer wrote:
> yes, feel free to apply it

Unfortunately found a few bugs in final testing with ffmpeg.
Changes against last patch:
1) size_out and frame_size calculation for new formats (ffmpeg.c and
libavformat/utils.c).
2) make libavutil/wav.c recognize the new formats
3) fixes to the en/decode_from/to16 function (a missing () and "fixing"
the dst and src pointers after processing for little-endian).

Greetings,
Reimar D??ffinger
-------------- next part --------------
Index: ffmpeg.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/ffmpeg.c,v
retrieving revision 1.343
diff -u -r1.343 ffmpeg.c
--- ffmpeg.c	21 Aug 2005 20:27:00 -0000	1.343
+++ ffmpeg.c	2 Sep 2005 18:12:48 -0000
@@ -599,6 +599,19 @@
         /* 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:
Index: libavcodec/allcodecs.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/allcodecs.c,v
retrieving revision 1.109
diff -u -r1.109 allcodecs.c
--- libavcodec/allcodecs.c	17 Jul 2005 00:28:11 -0000	1.109
+++ libavcodec/allcodecs.c	2 Sep 2005 18:12:51 -0000
@@ -524,6 +536,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);
Index: libavcodec/avcodec.h
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/avcodec.h,v
retrieving revision 1.415
diff -u -r1.415 avcodec.h
--- libavcodec/avcodec.h	21 Aug 2005 22:31:01 -0000	1.415
+++ libavcodec/avcodec.h	2 Sep 2005 18:12:59 -0000
@@ -121,6 +122,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 +2113,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);
Index: libavcodec/pcm.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/pcm.c,v
retrieving revision 1.15
diff -u -r1.15 pcm.c
--- libavcodec/pcm.c	13 Feb 2005 23:36:04 -0000	1.15
+++ libavcodec/pcm.c	2 Sep 2005 18:13:09 -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);
Index: libavcodec/utils.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/utils.c,v
retrieving revision 1.148
diff -u -r1.148 utils.c
--- libavcodec/utils.c	21 Aug 2005 19:50:22 -0000	1.148
+++ libavcodec/utils.c	2 Sep 2005 18:13:13 -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:
Index: libavformat/Makefile
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/Makefile,v
retrieving revision 1.98
diff -u -r1.98 Makefile
--- libavformat/Makefile	13 Aug 2005 13:45:42 -0000	1.98
+++ libavformat/Makefile	2 Sep 2005 18:13:14 -0000
@@ -17,7 +17,7 @@
       yuv4mpeg.o 4xm.o flvenc.o flvdec.o movenc.o psxstr.o idroq.o ipmovie.o \
       nut.o wc3movie.o mp3.o westwood.o segafilm.o idcin.o flic.o \
       sierravmd.o matroska.o sol.o electronicarts.o nsvdec.o asf.o asf-enc.o \
-      ogg2.o oggparsevorbis.o oggparsetheora.o oggparseflac.o
+      ogg2.o oggparsevorbis.o oggparsetheora.o oggparseflac.o daud.o
 AMROBJS=
 ifeq ($(AMR_NB),yes)
 AMROBJS= amr.o
Index: libavformat/allformats.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/allformats.c,v
retrieving revision 1.48
diff -u -r1.48 allformats.c
--- libavformat/allformats.c	15 Jul 2005 12:50:00 -0000	1.48
+++ libavformat/allformats.c	2 Sep 2005 18:13:14 -0000
@@ -109,6 +109,7 @@
     sol_init();
     ea_init();
     nsvdec_init();
+    daud_init();
 
 #ifdef CONFIG_ENCODERS
     /* image formats */
Index: libavformat/avformat.h
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/avformat.h,v
retrieving revision 1.132
diff -u -r1.132 avformat.h
--- libavformat/avformat.h	21 Aug 2005 22:31:00 -0000	1.132
+++ libavformat/avformat.h	2 Sep 2005 18:13:17 -0000
@@ -546,6 +546,9 @@
 /* nsvdec.c */
 int nsvdec_init(void);
 
+/* daud.c */
+int daud_init(void);
+
 #include "rtp.h"
 
 #include "rtsp.h"
Index: libavformat/daud.c
===================================================================
RCS file: libavformat/daud.c
diff -N libavformat/daud.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libavformat/daud.c	2 Sep 2005 18:13:17 -0000
@@ -0,0 +1,63 @@
+/*
+ * D-Cinema audio decoder.
+ * Copyright (c) 2005 Reimar D?ffinger.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * 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
+ */
+#include "avformat.h"
+
+static int daud_header(AVFormatContext *s, AVFormatParameters *ap) {
+    AVStream *st = av_new_stream(s, 0);
+    st->codec->codec_type = CODEC_TYPE_AUDIO;
+    st->codec->codec_id = CODEC_ID_PCM_S24DAUD;
+    st->codec->codec_tag = MKTAG('d', 'a', 'u', 'd');
+    st->codec->channels = 6;
+    st->codec->sample_rate = 96000;
+    st->codec->bit_rate = 3 * 6 * 96000 * 8;
+    st->codec->block_align = 3 * 6;
+    st->codec->bits_per_sample = 24;
+    return 0;
+}
+
+static int daud_packet(AVFormatContext *s, AVPacket *pkt) {
+    ByteIOContext *pb = &s->pb;
+    int ret, size;
+    if (url_feof(pb))
+        return AVERROR_IO;
+    size = get_be16(pb);
+    get_be16(pb); // unknown
+    ret = av_get_packet(pb, pkt, size);
+    pkt->stream_index = 0;
+    return ret;
+}
+
+static AVInputFormat daud_iformat = {
+    "daud",
+    "D-Cinema audio format",
+    0,
+    NULL,
+    daud_header,
+    daud_packet,
+    NULL,
+    NULL,
+    .extensions = "302",
+};
+
+int daud_init(void)
+{
+    av_register_input_format(&daud_iformat);
+    return 0;
+}
+
Index: libavformat/utils.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/utils.c,v
retrieving revision 1.164
diff -u -r1.164 utils.c
--- libavformat/utils.c	15 Aug 2005 15:58:21 -0000	1.164
+++ libavformat/utils.c	2 Sep 2005 18:13:27 -0000
@@ -643,6 +643,23 @@
         /* 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:
Index: libavformat/wav.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/wav.c,v
retrieving revision 1.53
diff -u -r1.53 wav.c
--- libavformat/wav.c	17 Jul 2005 22:24:36 -0000	1.53
+++ libavformat/wav.c	2 Sep 2005 18:13:28 -0000
@@ -25,6 +25,8 @@
     { 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 @@
         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 @@
     } 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 @@
     /* 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;
 }
 



More information about the ffmpeg-devel mailing list