[MPlayer-dev-eng] [PATCH] improved AIFF PCM Audio support - take 5

Jake Luck mplay at 10k.org
Fri Dec 10 20:57:28 CET 2004


> > > > +      stream_skip(s,-4);
> > > > +      break;
> > > 
> > > I didn't read the patch closely, but is it possible to avoid that
> > > backwards-seek? If yes, please do so, because then e.g. playing from
> > > stdin will work (even without -cache).
> > 
> > I used stream_skip(s, -4) to follow the same mental model suggested by the
> > existing processing code in demux_audio.c. Currently, WAVE, FLAC and MP3
> > all perform backseek to reset the stream and then carry out a full header
> > parse. One advantage from this approach is that one no longer needs to
> > maintain a separate partial header parser.
> 
> That is not (completely) true (and also those 4 bytes are still in the
> hdr variable). This approach is only necessary when the codec needs the
> data - and even then it is done in line 348 (except for fLaC, where I
> was too lazy to fix it). I know I reworked the MP3 part so that it will
> work without any backwards seeking at all (by skipping a few frames
> though). The WAVE code only seeks backwards when detection failed, that
> should rarely happen at that point and I don't think it really matters
> if that fails... The only case where it is done is for fLaC, and that
> can't be eliminated (easily) because the codec (stupidly?) needs the
> data to start with "fLaC". If that is not the case with your decoder you
> should be able to avoid the seeking.
> 
> > I feel that if we do choose to eliminate backward-seek we should consider
> > doing it globally across all codecs to ensure consistency in both code
> > organization and user behavior.
> 
> Would be nice, but is a lot of work, especially in a way that will be
> accepted (not really such an important feature). At the moment my
> strategy is trying to avoid it (when it's not too much work) in new
> code, keeping everything else for some undetermined moment in the future
> ;-)

Reimar, 

Thank you for the clarification. Attached is the revised patch which
eliminates the backward-seek. Please review and accept. Thank you

jake
-------------- next part --------------
diff -Nrup main/etc/codecs.conf main-aiff/etc/codecs.conf
--- main/etc/codecs.conf	2004-12-07 17:05:04.000000000 -0500
+++ main-aiff/etc/codecs.conf	2004-12-08 18:35:22.000000000 -0500
@@ -2122,6 +2122,7 @@ audiocodec pcm
   format 0x74776f73  ; "sowt" (MOV files)
   format 0x32336c66  ; "fl32" (MOV files)
   format 0x454e4f4e  ; "NONE" (MOV files from Kodak CX6320)
+  format 0x66666961  ; "aiff"
 ;;;; these are for hardware support only:  (alaw,ulaw,ima-adpcm,mpeg,ac3)
 ;  format 0x6
 ;  format 0x7
diff -Nrup main/libmpcodecs/ad_pcm.c main-aiff/libmpcodecs/ad_pcm.c
--- main/libmpcodecs/ad_pcm.c	2004-11-27 10:39:38.000000000 -0500
+++ main-aiff/libmpcodecs/ad_pcm.c	2004-12-08 18:26:04.000000000 -0500
@@ -61,6 +61,13 @@ static int init(sh_audio_t *sh_audio)
        sh_audio->sample_format=AFMT_AF_FLAGS | AF_FORMAT_BE | AF_FORMAT_F;
        sh_audio->samplesize=4;
        break;
+    case 0x66666961: // 'aiff', big endian 
+        switch (sh_audio->samplesize)
+        {
+            case 2: sh_audio->sample_format = AFMT_S16_BE; break;
+            case 1: sh_audio->sample_format = AFMT_S8;     break;
+        }
+        break;
     default: if(sh_audio->samplesize!=2) sh_audio->sample_format=AFMT_U8;
   }
   return 1;
diff -Nrup main/libmpdemux/Makefile main-aiff/libmpdemux/Makefile
--- main/libmpdemux/Makefile	2004-11-20 09:46:22.000000000 -0500
+++ main-aiff/libmpdemux/Makefile	2004-12-08 18:26:10.000000000 -0500
@@ -3,7 +3,7 @@ LIBNAME = libmpdemux.a
 
 include ../config.mak
 
-SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_ty.c demux_ty_osd.c demux_pva.c demux_viv.c demuxer.c dvdnav_stream.c open.c parse_es.c stream.c stream_file.c stream_netstream.c stream_vcd.c stream_null.c stream_ftp.c tv.c tvi_dummy.c tvi_v4l.c tvi_v4l2.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_alsa1x.c ai_oss.c audio_in.c demux_smjpeg.c demux_lmlm4.c cue_read.c extension.c demux_gif.c demux_ts.c demux_realaud.c url.c muxer_rawvideo.c demux_lavf.c demux_nsv.c
+SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_ty.c demux_ty_osd.c demux_pva.c demux_viv.c demuxer.c dvdnav_stream.c open.c parse_es.c stream.c stream_file.c stream_netstream.c stream_vcd.c stream_null.c stream_ftp.c tv.c tvi_dummy.c tvi_v4l.c tvi_v4l2.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_alsa1x.c ai_oss.c audio_in.c demux_smjpeg.c demux_lmlm4.c cue_read.c extension.c demux_gif.c demux_ts.c demux_realaud.c url.c muxer_rawvideo.c demux_lavf.c demux_nsv.c aiff.c
 ifeq ($(XMMS_PLUGINS),yes)
 SRCS += demux_xmms.c
 endif 
diff -Nrup main/libmpdemux/aiff.c main-aiff/libmpdemux/aiff.c
--- main/libmpdemux/aiff.c	1969-12-31 19:00:00.000000000 -0500
+++ main-aiff/libmpdemux/aiff.c	2004-12-09 15:51:08.000000000 -0500
@@ -0,0 +1,170 @@
+/*
+    AIFF Audio Utilities
+    
+    Copyright (c) 2004, Jake Luck <mplay at 10k.org>
+    All rights reserved.
+    BSD License
+    http://www.opensource.org/licenses/bsd-license.php
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "stream.h"
+#include "aiff.h"
+#include "bswap.h"
+
+AIFF_HEADER * 
+get_aiff_header(stream_t *s)
+{
+    AIFF_HEADER             *h;
+    AIFF_FORMCHUNK          *fc;
+    AIFF_COMMONCHUNK        *cc;
+    AIFF_SOUNDDATACHUNK     *sc;
+    
+    h = (AIFF_HEADER *)malloc(sizeof(AIFF_HEADER));
+    if (h == NULL)      goto abort;
+
+    fc = &(h->f);
+    cc = &(h->c);
+    sc = &(h->s);
+
+    memcpy(fc->fId, "FORM", 4);
+    
+    /* read form chunk */
+    if ( stream_read(s, (char *)&(fc->fSize), 4) != 4)     goto abort;
+    if ( stream_read(s, (char *)&(fc->fFormat), 4) != 4)   goto abort;
+    
+    /* read common chunk */
+    if ( stream_read(s, (char *)&(cc->cId), 4) != 4)               goto abort;
+    if ( stream_read(s, (char *)&(cc->cSize), 4) != 4)             goto abort;
+    if ( stream_read(s, (char *)&(cc->cNumChannels), 2) != 2)      goto abort;
+    if ( stream_read(s, (char *)&(cc->cSampleFrames), 4) != 4)     goto abort;
+    if ( stream_read(s, (char *)&(cc->cSampleSize), 2) != 2)       goto abort;
+    if ( stream_read(s, (char *)&(cc->cSampleRate[0]), 4) != 4)    goto abort;
+    if ( stream_read(s, (char *)&(cc->cSampleRate[4]), 4) != 4)    goto abort;
+    if ( stream_read(s, (char *)&(cc->cPadd), 2) != 2)             goto abort;
+    
+    /* read sound data chunk */
+    if ( stream_read(s, (char *)&(sc->sId), 4) != 4)           goto abort;
+    if ( stream_read(s, (char *)&(sc->sSize), 4) != 4)         goto abort;
+    if ( stream_read(s, (char *)&(sc->sOffset), 4) != 4)       goto abort;
+    if ( stream_read(s, (char *)&(sc->sAlignSize), 4) != 4)    goto abort;
+    
+    /* fix endian issue */
+    fc->fSize        = be2me_32(fc->fSize);
+
+    cc->cSize        = be2me_32(cc->cSize);
+    cc->cNumChannels = be2me_16(cc->cNumChannels);
+    cc->cSampleFrames= be2me_32(cc->cSampleFrames);
+    cc->cSampleSize  = be2me_16(cc->cSampleSize);
+
+    sc->sSize        = be2me_32(sc->sSize);
+    sc->sOffset      = be2me_32(sc->sOffset);
+    sc->sAlignSize   = be2me_32(sc->sAlignSize);
+
+    return h;
+        
+abort:
+    if (h != NULL)  free(h);
+    return NULL;
+}
+
+/*
+    demuxer->movi_end uses absolute file location
+    
+    ssnd chunksize already includes
+        its offset field (4 bytes)
+        its align field (4 bytes)
+    
+    hence 
+    sounddata_end = ssnd_chunksize - partial ssnd header + headersize
+*/
+off_t   
+endpos_aiff_pcm(AIFF_HEADER *h)
+{
+    AIFF_FORMCHUNK          *f;
+    AIFF_COMMONCHUNK        *c;
+    AIFF_SOUNDDATACHUNK     *s;
+    int         n;
+    off_t       w;
+    
+    f = &(h->f);
+    c = &(h->c);
+    s = &(h->s);
+    
+    w = s->sSize - 8 + 54;
+    
+    return w;
+}
+
+/*  
+    convert the extended 8 byte sample rate to int
+*/
+int
+samplerate_aiff_pcm(unsigned char *sr)
+{
+    int     r;
+    
+    if      ( memcmp(sr, "\x40\x0E\xAC\x44\x00\x00\x00\x00", 8) == 0 )
+        r = 44100;
+    else if ( memcmp(sr, "\x40\x0E\xBB\x80\x00\x00\x00\x00", 8) == 0 )
+        r = 48000;    
+    else if ( memcmp(sr, "\x40\x0D\xFA\x00\x00\x00\x00\x00", 8) == 0 )
+        r = 32000; 
+    else if ( memcmp(sr, "\x40\x0D\xBB\x80\x00\x00\x00\x00", 8) == 0 )
+        r = 24000; 
+    else if ( memcmp(sr, "\x40\x0D\xAC\x44\x00\x00\x00\x00", 8) == 0 )
+        r = 22050; 
+    else if ( memcmp(sr, "\x40\x0C\xFA\x00\x00\x00\x00\x00", 8) == 0 )
+        r = 16000; 
+    else if ( memcmp(sr, "\x40\x0C\xAC\x44\x00\x00\x00\x00", 8) == 0 )
+        r = 11025; 
+    else if ( memcmp(sr, "\x40\x0B\xFA\x00\x00\x00\x00\x00", 8) == 0 )
+        r = 8000; 
+        
+    return r;
+}
+
+void 
+print_aiff_header(AIFF_HEADER *h)
+{
+    AIFF_FORMCHUNK          *f;
+    AIFF_COMMONCHUNK        *c;
+    AIFF_SOUNDDATACHUNK     *s;
+    int     n;
+    
+    f = &(h->f);
+    c = &(h->c);
+    s = &(h->s);
+
+    printf("---------------------------------------\n");
+    printf("FORM id %c%c%c%c\n", f->fId[0], f->fId[1], f->fId[2], f->fId[3]);
+    printf("FORM size : %d\n",f->fSize);
+    printf("FORM format %c%c%c%c\n\n", f->fFormat[0], f->fFormat[1], 
+                                       f->fFormat[2], f->fFormat[3]);
+    
+    printf("COMMON id %c%c%c%c\n", c->cId[0], c->cId[1], c->cId[2], c->cId[3]);
+    printf("COMMON size : %d\n", c->cSize);
+    printf("COMMON channel: %d\n", c->cNumChannels);
+    printf("COMMON sample frames : %d\n", c->cSampleFrames);
+    printf("COMMON sample size : %d\n", c->cSampleSize);
+    printf("COMMON sample rate : %08X %08X\n", *((unsigned int *)(&(c->cSampleRate[0]))),
+                                               *((unsigned int *)(&(c->cSampleRate[4]))));
+    printf("COMMON pad %c%c\n\n", c->cPadd[0], c->cPadd[1]);
+    
+    printf("SSND id %c%c%c%c\n", s->sId[0], s->sId[1], s->sId[2], s->sId[3]);
+    printf("SSND size : %d\n", s->sSize);
+    printf("SSND offset : %d\n", s->sOffset);
+    printf("SSND alignsize : %d\n", s->sAlignSize);
+    printf("---------------------------------------\n");
+    printf("SSND  sample bytes: %d\n", s->sSize - 8);
+    printf("Total sample bytes: %d\n", c->cNumChannels * c->cSampleFrames * 
+                                       c->cSampleSize>>3);
+
+}
+
diff -Nrup main/libmpdemux/aiff.h main-aiff/libmpdemux/aiff.h
--- main/libmpdemux/aiff.h	1969-12-31 19:00:00.000000000 -0500
+++ main-aiff/libmpdemux/aiff.h	2004-12-08 18:41:09.000000000 -0500
@@ -0,0 +1,50 @@
+/*
+    AIFF Audio Header
+    based on the Apple specification documented at 
+    http://developer.apple.com/documentation/QuickTime/INMAC/SOUND/imsoundmgr.36.htm
+    
+    Copyright (c) 2004, Jake Luck <mplay at 10k.org>
+    All rights reserved.
+    BSD License
+    http://www.opensource.org/licenses/bsd-license.php
+*/
+
+#ifndef __AIFF_HEADER_H
+#define __AIFF_HEADER_H 1
+
+typedef struct __attribute__((__packed__)) aiffformchunk_tag {
+    unsigned char   fId[4];
+    unsigned long   fSize;
+    unsigned char   fFormat[4];
+} AIFF_FORMCHUNK;   /* 12 bytes */
+
+typedef struct __attribute__((__packed__)) aiffcommonchunk_tag {
+    unsigned char   cId[4];
+    unsigned long   cSize;
+    unsigned short  cNumChannels;
+    unsigned long   cSampleFrames;
+    unsigned short  cSampleSize;
+    unsigned char   cSampleRate[8];
+    unsigned char   cPadd[2];
+} AIFF_COMMONCHUNK; /* 26 bytes */
+
+typedef struct __attribute__((__packed__)) aiffsounddatachunk_tag {
+    unsigned char   sId[4];
+    unsigned long   sSize;
+    unsigned long   sOffset;
+    unsigned long   sAlignSize;
+} AIFF_SOUNDDATACHUNK;  /* 16 bytes */
+
+
+typedef struct __attribute__((__packed__)) aiffheader_tag {
+    AIFF_FORMCHUNK          f;
+    AIFF_COMMONCHUNK        c;
+    AIFF_SOUNDDATACHUNK     s;
+} AIFF_HEADER;      /* 54 bytes */
+
+AIFF_HEADER *get_aiff_header(stream_t *s);
+void    print_aiff_header(AIFF_HEADER *h);
+off_t   endpos_aiff_pcm(AIFF_HEADER *h);
+int     samplerate_aiff_pcm(unsigned char *sr);
+
+#endif
diff -Nrup main/libmpdemux/demux_audio.c main-aiff/libmpdemux/demux_audio.c
--- main/libmpdemux/demux_audio.c	2004-09-28 13:05:44.000000000 -0400
+++ main-aiff/libmpdemux/demux_audio.c	2004-12-09 15:51:09.000000000 -0500
@@ -9,6 +9,7 @@
 #include "stheader.h"
 #include "genres.h"
 #include "mp3_hdr.h"
+#include "aiff.h"
 
 #include <string.h>
 #ifdef MP_DEBUG
@@ -18,6 +19,7 @@
 #define MP3 1
 #define WAV 2
 #define fLaC 3
+#define AIFF 4
 
 
 #define HDR_SIZE 4
@@ -167,6 +169,9 @@ int demux_audio_open(demuxer_t* demuxer)
       frmt = fLaC;
       stream_skip(s,-4);
       break;
+    } else if( hdr[0] == 'F' && hdr[1] == 'O' && hdr[2] == 'R' && hdr[3] == 'M' ) {
+      frmt = AIFF;
+      break;
     }
     // Add here some other audio format detection
     if(step < HDR_SIZE)
@@ -330,6 +335,36 @@ int demux_audio_open(demuxer_t* demuxer)
 	    demuxer->movi_start = stream_tell(s);
 	    demuxer->movi_end = s->end_pos;
 	    break;
+  case AIFF: 
+    {
+        sh_audio->ah = get_aiff_header(s);
+        
+        if(verbose>0) print_aiff_header(sh_audio->ah);
+        
+        sh_audio->format = 0x66666961;      // "aiff"
+        sh_audio->channels = sh_audio->ah->c.cNumChannels;
+        sh_audio->samplerate = samplerate_aiff_pcm(sh_audio->ah->c.cSampleRate);
+        sh_audio->samplesize = sh_audio->ah->c.cSampleSize;
+        sh_audio->i_bps = sh_audio->channels * sh_audio->samplerate * sh_audio->samplesize>>3;
+        
+        WAVEFORMATEX* w;
+        w = (WAVEFORMATEX*)malloc(sizeof(WAVEFORMATEX));
+        w->wFormatTag = sh_audio->format;
+        w->nChannels = sh_audio->channels;
+        w->nSamplesPerSec = sh_audio->samplerate;
+        w->wBitsPerSample = sh_audio->samplesize;
+        w->nAvgBytesPerSec = sh_audio->i_bps;
+        w->nBlockAlign = (sh_audio->channels * sh_audio->samplesize)>>3;
+        w->cbSize = 0;
+        
+        sh_audio->wf = w;
+        
+        if(verbose>0) print_wave_header(w);
+        
+        demuxer->movi_start = stream_tell(s);
+        demuxer->movi_end = endpos_aiff_pcm(sh_audio->ah);
+    }
+    break;
   }
 
   priv = (da_priv_t*)malloc(sizeof(da_priv_t));
@@ -423,6 +458,16 @@ int demux_audio_fill_buffer(demux_stream
     ds_add_packet(ds,dp);
     return 1;
   }
+  case AIFF : {
+    int l = sh_audio->i_bps;
+    demux_packet_t*  dp = new_demux_packet(l);
+    l = stream_read(s,dp->buffer,l);
+    resize_demux_packet(dp, l);
+    priv->last_pts = priv->last_pts < 0 ? 0 : priv->last_pts + l/(float)sh_audio->i_bps;
+    ds->pts = priv->last_pts - (ds_tell_pts(demux->audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
+    ds_add_packet(ds,dp);
+    return 1;
+  }
   default:
     printf("Audio demuxer : unknown format %d\n",priv->frmt);
   }
diff -Nrup main/libmpdemux/demuxer.c main-aiff/libmpdemux/demuxer.c
--- main/libmpdemux/demuxer.c	2004-11-25 17:24:00.000000000 -0500
+++ main-aiff/libmpdemux/demuxer.c	2004-12-08 18:26:10.000000000 -0500
@@ -102,6 +102,7 @@ sh_audio_t* new_sh_audio(demuxer_t *demu
 void free_sh_audio(sh_audio_t* sh){
     mp_msg(MSGT_DEMUXER,MSGL_DBG2,"DEMUXER: freeing sh_audio at %p\n",sh);
     if(sh->wf) free(sh->wf);
+    if(sh->ah) free(sh->ah);
     free(sh);
 }
 
diff -Nrup main/libmpdemux/extension.c main-aiff/libmpdemux/extension.c
--- main/libmpdemux/extension.c	2004-08-21 15:17:17.000000000 -0400
+++ main-aiff/libmpdemux/extension.c	2004-12-08 18:26:10.000000000 -0500
@@ -36,6 +36,7 @@ static struct {
         { "y4m", DEMUXER_TYPE_Y4M },
         { "mp3", DEMUXER_TYPE_AUDIO },
         { "wav", DEMUXER_TYPE_AUDIO },
+        { "aif", DEMUXER_TYPE_AUDIO },
         { "flac", DEMUXER_TYPE_AUDIO },
         { "fla", DEMUXER_TYPE_AUDIO },
         { "ogg", DEMUXER_TYPE_OGG },
diff -Nrup main/libmpdemux/stheader.h main-aiff/libmpdemux/stheader.h
--- main/libmpdemux/stheader.h	2004-04-28 06:18:33.000000000 -0400
+++ main-aiff/libmpdemux/stheader.h	2004-12-08 18:51:39.000000000 -0500
@@ -3,6 +3,7 @@
 
 #include "aviheader.h"
 #include "ms_hdr.h"
+#include "aiff.h"
 
 // Stream headers:
 
@@ -41,6 +42,8 @@ typedef struct {
   // win32-compatible codec parameters:
   AVIStreamHeader audio;
   WAVEFORMATEX* wf;
+  // aiff codec parameters:
+  AIFF_HEADER *ah;
   // codec-specific:
   void* context; // codec-specific stuff (usually HANDLE or struct pointer)
   unsigned char* codecdata; // extra header data passed from demuxer to codec


More information about the MPlayer-dev-eng mailing list