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

Reimar Döffinger Reimar.Doeffinger
Thu Sep 1 19:13:58 CEST 2005


Hi,
On Wed, Aug 31, 2005 at 12:55:32PM +0200, Reimar D?ffinger wrote:
> Ok, I did a quick hack to show what I am thinking about. It is not
> finished and will not yet work, but before spending more time on it I
> want to get some comments.

No reply :-(. Well, I finished it. If you have better suggestions for
the names, please go ahead.
Any other suggestions for improvement are welcome, too.
The macros I introduced in pcm.c are just a suggestion too, especially
since the one for encoding do not set the lower bits to 0 for the the 24
and 32 bit formats.

Greetings,
Reimar D??ffinger
-------------- next part --------------
Index: etc/codecs.conf
===================================================================
RCS file: /cvsroot/mplayer/main/etc/codecs.conf,v
retrieving revision 1.428
diff -u -r1.428 codecs.conf
--- etc/codecs.conf	25 Aug 2005 15:54:44 -0000	1.428
+++ etc/codecs.conf	31 Aug 2005 23:02:47 -0000
@@ -2314,6 +2330,13 @@
   format 0x2033504D  ; "MP3 " (used in .nsv files)
   driver mp3lib
 
+audiocodec ffpcms24daud
+  info "D-Cinema audio (FFmpeg)"
+  status untested
+  format 0x6d6e6364
+  driver ffmpeg
+  dll "pcm_s24daud"
+
 audiocodec ffwmav1
   info "DivX audio v1 (FFmpeg)"
   status untested
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	31 Aug 2005 23:06:20 -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	31 Aug 2005 23:06:28 -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	31 Aug 2005 23:06:40 -0000
@@ -128,6 +128,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:
@@ -178,6 +191,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:
@@ -192,40 +218,72 @@
     samples = data;
     dst = frame;
 
+// rely a bit on compiler optimization
+// low bits are not initialized, maybe use memset before?
+#define TO_PCM(bps, le, us) \
+  if (le) dst += bps - 2; \
+  for(;n>0;n--) { \
+    v = *samples++; \
+    if (us) v += 0x8000; \
+    dst[le] = v >> 8; \
+    dst[1 - le] = v & 0xff; \
+    dst += bps; \
+  }
+
     switch(avctx->codec->id) {
-    case CODEC_ID_PCM_S16LE:
-        for(;n>0;n--) {
-            v = *samples++;
-            dst[0] = v & 0xff;
-            dst[1] = v >> 8;
-            dst += 2;
+    case CODEC_ID_PCM_S32LE:
+        TO_PCM(4, 1, 0);
+        break;
+    case CODEC_ID_PCM_S32BE:
+        TO_PCM(4, 0, 0);
+        break;
+    case CODEC_ID_PCM_U32LE:
+        TO_PCM(4, 1, 1);
+        break;
+    case CODEC_ID_PCM_U32BE:
+        TO_PCM(4, 0, 1);
+        break;
+    case CODEC_ID_PCM_S24LE:
+        TO_PCM(3, 1, 0);
+        break;
+    case CODEC_ID_PCM_S24BE:
+        TO_PCM(3, 0, 0);
+        break;
+    case CODEC_ID_PCM_U24LE:
+        TO_PCM(3, 1, 1);
+        break;
+    case CODEC_ID_PCM_U24BE:
+        TO_PCM(3, 0, 1);
+        break;
+    case CODEC_ID_PCM_S24DAUD:
+        for(;n>0;n--) {
+            uint32_t tmp2 = 0;
+            uint16_t tmp = *samples++;
+            int i;
+            for (i = 0; i < 16; i++) {
+              tmp2 <<= 1;
+              tmp2 |= (tmp & 1);
+              tmp >>= 1;
+            }
+            tmp2 <<= 4; // sync flags would go here
+            dst[2] = tmp2 & 0xff;
+            tmp2 >>= 8;
+            dst[1] = tmp2 & 0xff;
+            dst[0] = tmp2 >> 8;
+            dst += 3;
         }
         break;
+    case CODEC_ID_PCM_S16LE:
+        TO_PCM(2, 1, 0);
+        break;
     case CODEC_ID_PCM_S16BE:
-        for(;n>0;n--) {
-            v = *samples++;
-            dst[0] = v >> 8;
-            dst[1] = v;
-            dst += 2;
-        }
+        TO_PCM(2, 0, 0);
         break;
     case CODEC_ID_PCM_U16LE:
-        for(;n>0;n--) {
-            v = *samples++;
-            v += 0x8000;
-            dst[0] = v & 0xff;
-            dst[1] = v >> 8;
-            dst += 2;
-        }
+        TO_PCM(2, 1, 1);
         break;
     case CODEC_ID_PCM_U16BE:
-        for(;n>0;n--) {
-            v = *samples++;
-            v += 0x8000;
-            dst[0] = v >> 8;
-            dst[1] = v;
-            dst += 2;
-        }
+        TO_PCM(2, 0, 1);
         break;
     case CODEC_ID_PCM_S8:
         for(;n>0;n--) {
@@ -302,34 +360,69 @@
     if(buf_size > AVCODEC_MAX_AUDIO_FRAME_SIZE/2)
         buf_size = AVCODEC_MAX_AUDIO_FRAME_SIZE/2;
 
+// general purpose PCM conversion macro, hopefully
+// the compiler will optimize out the parts that
+// are not used in the special instance
+#define FROM_PCM(bps, le, us) \
+  n = buf_size / bps; \
+  if (le) src += bps - 2; \
+  for(;n>0;n--) { \
+    *samples++ = (src[le] << 8) | src[1 - le] - (us)?0x8000:0; \
+    src += bps; \
+  }
+
     switch(avctx->codec->id) {
-    case CODEC_ID_PCM_S16LE:
-        n = buf_size >> 1;
-        for(;n>0;n--) {
-            *samples++ = src[0] | (src[1] << 8);
-            src += 2;
+    case CODEC_ID_PCM_S32LE:
+        FROM_PCM(4, 1, 0);
+        break;
+    case CODEC_ID_PCM_S32BE:
+        FROM_PCM(4, 0, 0);
+        break;
+    case CODEC_ID_PCM_U32LE:
+        FROM_PCM(4, 1, 1);
+        break;
+    case CODEC_ID_PCM_U32BE:
+        FROM_PCM(4, 0, 1);
+        break;
+    case CODEC_ID_PCM_S24LE:
+        FROM_PCM(3, 1, 0);
+        break;
+    case CODEC_ID_PCM_S24BE:
+        FROM_PCM(3, 0, 0);
+        break;
+    case CODEC_ID_PCM_U24LE:
+        FROM_PCM(3, 1, 1);
+        break;
+    case CODEC_ID_PCM_U24BE:
+        FROM_PCM(3, 0, 1);
+        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];
+          int i;
+          v >>= 4; // sync flags are here
+          *samples = 0;
+          for (i = 0; i < 16; i++) {
+            *samples <<= 1;
+            *samples |= (v & 1);
+            v >>= 1;
+          }
+          samples++;
+          src += 3;
         }
         break;
+    case CODEC_ID_PCM_S16LE:
+        FROM_PCM(2, 1, 0);
+        break;
     case CODEC_ID_PCM_S16BE:
-        n = buf_size >> 1;
-        for(;n>0;n--) {
-            *samples++ = (src[0] << 8) | src[1];
-            src += 2;
-        }
+        FROM_PCM(2, 0, 0);
         break;
     case CODEC_ID_PCM_U16LE:
-        n = buf_size >> 1;
-        for(;n>0;n--) {
-            *samples++ = (src[0] | (src[1] << 8)) - 0x8000;
-            src += 2;
-        }
+        FROM_PCM(2, 1, 1);
         break;
     case CODEC_ID_PCM_U16BE:
-        n = buf_size >> 1;
-        for(;n>0;n--) {
-            *samples++ = ((src[0] << 8) | src[1]) - 0x8000;
-            src += 2;
-        }
+        FROM_PCM(2, 0, 1);
         break;
     case CODEC_ID_PCM_S8:
         n = buf_size;
@@ -382,6 +475,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	31 Aug 2005 23:06:44 -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	31 Aug 2005 23:06:45 -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	31 Aug 2005 23:06:46 -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	31 Aug 2005 23:06:49 -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	31 Aug 2005 23:06:49 -0000
@@ -0,0 +1,68 @@
+/*
+ * 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 = 0x6d6e6364;
+  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(&s->pb))
+    return AVERROR_IO;
+  size = get_be16(pb);
+  get_be16(pb); // unknown
+  if (av_new_packet(pkt, size))
+    return AVERROR_IO;
+  pkt->stream_index = 0;
+  ret = get_buffer(pb, pkt->data, pkt->size);
+  if (ret < 0)
+    av_free_packet(pkt);
+  pkt->size = ret;
+  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;
+}
+



More information about the ffmpeg-devel mailing list