changeset 18036:3406a28698cf

Fix RealAudio codecs (add descrambling)
author rtognimp
date Mon, 03 Apr 2006 19:41:17 +0000
parents cb43704389ff
children 3c8aa5261e80
files libmpdemux/demux_mkv.c
diffstat 1 files changed, 151 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/demux_mkv.c	Mon Apr 03 07:16:10 2006 +0000
+++ b/libmpdemux/demux_mkv.c	Mon Apr 03 19:41:17 2006 +0000
@@ -44,6 +44,24 @@
 #define MAX(a, b)	((a)>(b)?(a):(b))
 #endif
 
+static unsigned char sipr_swaps[38][2]={
+    {0,63},{1,22},{2,44},{3,90},{5,81},{7,31},{8,86},{9,58},{10,36},{12,68},
+    {13,39},{14,73},{15,53},{16,69},{17,57},{19,88},{20,34},{21,71},{24,46},
+    {25,94},{26,54},{28,75},{29,50},{32,70},{33,92},{35,74},{38,85},{40,56},
+    {42,87},{43,65},{45,59},{48,79},{49,93},{51,89},{55,95},{61,76},{67,83},
+    {77,80} };
+
+// Map flavour to bytes per second
+#define SIPR_FLAVORS 4
+#define ATRC_FLAVORS 8
+#define COOK_FLAVORS 34
+static int sipr_fl2bps[SIPR_FLAVORS] = {813, 1062, 625, 2000};
+static int atrc_fl2bps[ATRC_FLAVORS] = {8269, 11714, 13092, 16538, 18260, 22050, 33075, 44100};
+static int cook_fl2bps[COOK_FLAVORS] = {1000, 1378, 2024, 2584, 4005, 5513, 8010, 4005, 750, 2498,
+                                        4048, 5513, 8010, 11973, 8010, 2584, 4005, 2067, 2584, 2584,
+                                        4005, 4005, 5513, 5513, 8010, 12059, 1550, 8010, 12059, 5513,
+                                        12016, 16408, 22911, 33506};
+
 typedef struct
 {
   uint32_t order, type, scope;
@@ -82,6 +100,16 @@
   float rv_pts;  /* previous video timestamp */
   float ra_pts;  /* previous audio timestamp */
 
+  /** realaudio descrambling */
+  int sub_packet_size; ///< sub packet size, per stream
+  int sub_packet_h; ///< number of coded frames per block
+  int coded_framesize; ///< coded frame size, per stream
+  int audiopk_size; ///< audio packet size
+  unsigned char *audio_buf; ///< place to store reordered audio data
+  float *audio_timestamp; ///< timestamp for each audio packet
+  int sub_packet_cnt; ///< number of subpacket already received
+  int audio_filepos; ///< file position of first audio packet in block
+
   /* stuff for quicktime */
   int fix_i_bps;
   float qt_last_a_pts;
@@ -1947,25 +1975,57 @@
           src = (unsigned char *) (ra4p + 1);
           src += src[0] + 1;
           src += src[0] + 1;
+          track->sub_packet_size = be2me_16 (ra4p->sub_packet_size);
+          track->sub_packet_h = be2me_16 (ra4p->sub_packet_h);
+          track->coded_framesize = be2me_32 (ra4p->coded_frame_size);
+          track->audiopk_size = be2me_16 (ra4p->frame_size);
         }
       else
+        {
         src = (unsigned char *) (ra5p + 1);
+        track->sub_packet_size = be2me_16 (ra5p->sub_packet_size);
+        track->sub_packet_h = be2me_16 (ra5p->sub_packet_h);
+        track->coded_framesize = be2me_32 (ra5p->coded_frame_size);
+        track->audiopk_size = be2me_16 (ra5p->frame_size);
+        }
 
       src += 3;
       if (version == 5)
         src++;
       codecdata_length = be2me_32 (*(uint32_t *)src);
       src += 4;
-      sh_a->wf->cbSize = 10 + codecdata_length;
+      sh_a->wf->cbSize = codecdata_length;
       sh_a->wf = (WAVEFORMATEX *) realloc (sh_a->wf,
                                            sizeof (WAVEFORMATEX) +
                                            sh_a->wf->cbSize);
-      ((short *)(sh_a->wf + 1))[0] = be2me_16 (ra4p->sub_packet_size);
-      ((short *)(sh_a->wf + 1))[1] = be2me_16 (ra4p->sub_packet_h);
-      ((short *)(sh_a->wf + 1))[2] = be2me_16 (ra4p->flavor);
-      ((short *)(sh_a->wf + 1))[3] = be2me_32 (ra4p->coded_frame_size);
-      ((short *)(sh_a->wf + 1))[4] = codecdata_length;
-      memcpy(((char *)(sh_a->wf + 1)) + 10, src, codecdata_length);
+      memcpy(((char *)(sh_a->wf + 1)), src, codecdata_length);
+
+      switch (track->a_formattag) {
+        case mmioFOURCC('a', 't', 'r', 'c'):
+          sh_a->wf->nAvgBytesPerSec = atrc_fl2bps[be2me_16 (ra4p->flavor)];
+          sh_a->wf->nBlockAlign = track->sub_packet_size;
+          track->audio_buf = malloc(track->sub_packet_h * track->audiopk_size);
+          track->audio_timestamp = malloc(track->sub_packet_h * sizeof(float));
+          break;
+        case mmioFOURCC('c', 'o', 'o', 'k'):
+          sh_a->wf->nAvgBytesPerSec = cook_fl2bps[be2me_16 (ra4p->flavor)];
+          sh_a->wf->nBlockAlign = track->sub_packet_size;
+          track->audio_buf = malloc(track->sub_packet_h * track->audiopk_size);
+          track->audio_timestamp = malloc(track->sub_packet_h * sizeof(float));
+          break;
+        case mmioFOURCC('s', 'i', 'p', 'r'):
+          sh_a->wf->nAvgBytesPerSec = sipr_fl2bps[be2me_16 (ra4p->flavor)];
+          sh_a->wf->nBlockAlign = track->coded_framesize;
+          track->audio_buf = malloc(track->sub_packet_h * track->audiopk_size);
+          track->audio_timestamp = malloc(track->sub_packet_h * sizeof(float));
+          break;
+        case mmioFOURCC('2', '8', '_', '8'):
+          sh_a->wf->nAvgBytesPerSec = 3600;
+          sh_a->wf->nBlockAlign = track->coded_framesize;
+          track->audio_buf = malloc(track->sub_packet_h * track->audiopk_size);
+          track->audio_timestamp = malloc(track->sub_packet_h * sizeof(float));
+          break;
+      }
 
       track->realmedia = 1;
     }
@@ -2380,6 +2440,10 @@
                 free (mkv_d->tracks[i]->language);
               if (mkv_d->tracks[i]->private_data)
                 free (mkv_d->tracks[i]->private_data);
+              if (mkv_d->tracks[i]->audio_buf)
+                free (mkv_d->tracks[i]->audio_buf);
+              if (mkv_d->tracks[i]->audio_timestamp)
+                free (mkv_d->tracks[i]->audio_timestamp);
             }
           for (i=0; i < SUB_MAX_TEXT; i++)
             if (mkv_d->subs.text[i])
@@ -2772,9 +2836,85 @@
                   uint32_t size, int block_bref)
 {
   mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
-  demux_packet_t *dp = new_demux_packet (size);
-
-  memcpy (dp->buffer, buffer, size);
+  int sps = track->sub_packet_size;
+  int sph = track->sub_packet_h;
+  int cfs = track->coded_framesize;
+  int w = track->audiopk_size;
+  int spc = track->sub_packet_cnt;
+  demux_packet_t *dp;
+  int x;
+
+  if ((track->a_formattag == mmioFOURCC('2', '8', '_', '8')) ||
+      (track->a_formattag == mmioFOURCC('c', 'o', 'o', 'k')) ||
+      (track->a_formattag == mmioFOURCC('a', 't', 'r', 'c')) ||
+      (track->a_formattag == mmioFOURCC('s', 'i', 'p', 'r')))
+    {
+//      if(!block_bref)
+//        spc = track->sub_packet_cnt = 0;
+      switch (track->a_formattag) {
+        case mmioFOURCC('2', '8', '_', '8'):
+          for (x = 0; x < sph / 2; x++)
+            memcpy(track->audio_buf + x * 2 * w + spc * cfs, buffer + cfs * x, cfs);
+          break;
+        case mmioFOURCC('c', 'o', 'o', 'k'):
+        case mmioFOURCC('a', 't', 'r', 'c'):
+          for (x = 0; x < w / sps; x++)
+            memcpy(track->audio_buf + sps * (sph * x + ((sph + 1) / 2) * (spc & 1) + (spc >> 1)), buffer + sps * x, sps);
+          break;
+        case mmioFOURCC('s', 'i', 'p', 'r'):
+          memcpy(track->audio_buf + spc * w, buffer, w);
+          if (spc == sph - 1)
+            {
+              int n;
+              int bs = sph * w * 2 / 96;  // nibbles per subpacket
+              // Perform reordering
+              for(n=0; n < 38; n++)
+                {
+                  int j;
+                  int i = bs * sipr_swaps[n][0];
+                  int o = bs * sipr_swaps[n][1];
+                  // swap nibbles of block 'i' with 'o'      TODO: optimize
+                  for(j = 0;j < bs; j++)
+                    {
+                      int x = (i & 1) ? (track->audio_buf[i >> 1] >> 4) : (track->audio_buf[i >> 1] & 0x0F);
+                      int y = (o & 1) ? (track->audio_buf[o >> 1] >> 4) : (track->audio_buf[o >> 1] & 0x0F);
+                      if(o & 1)
+                        track->audio_buf[o >> 1] = (track->audio_buf[o >> 1] & 0x0F) | (x << 4);
+                      else
+                        track->audio_buf[o >> 1] = (track->audio_buf[o >> 1] & 0xF0) | x;
+                      if(i & 1)
+                        track->audio_buf[i >> 1] = (track->audio_buf[i >> 1] & 0x0F) | (y << 4);
+                      else
+                        track->audio_buf[i >> 1] = (track->audio_buf[i >> 1] & 0xF0) | y;
+                      ++i; ++o;
+                    }
+                }
+            }
+          break;
+      }
+      track->audio_timestamp[track->sub_packet_cnt] = (track->ra_pts == mkv_d->last_pts) ? 0 : (mkv_d->last_pts);
+      track->ra_pts = mkv_d->last_pts;
+      if (track->sub_packet_cnt == 0)
+        track->audio_filepos = demuxer->filepos;
+      if (++(track->sub_packet_cnt) == sph)
+        {
+           int apk_usize = ((WAVEFORMATEX*)((sh_audio_t*)demuxer->audio->sh)->wf)->nBlockAlign;
+           track->sub_packet_cnt = 0;
+           // Release all the audio packets
+           for (x = 0; x < sph*w/apk_usize; x++)
+             {
+               dp = new_demux_packet(apk_usize);
+               memcpy(dp->buffer, track->audio_buf + x * apk_usize, apk_usize);
+               /* Put timestamp only on packets that correspond to original audio packets in file */
+               dp->pts = (x * apk_usize % w) ? 0 : track->audio_timestamp[x * apk_usize / w];
+               dp->pos = track->audio_filepos; // all equal
+               dp->flags = x ? 0 : 0x10; // Mark first packet as keyframe
+               ds_add_packet(demuxer->audio, dp);
+             }
+        }
+   } else { // Not a codec that require reordering
+  dp = new_demux_packet (size);
+  memcpy(dp->buffer, buffer, size);
   if (track->ra_pts == mkv_d->last_pts && !mkv_d->a_skip_to_keyframe)
     dp->pts = 0;
   else
@@ -2784,6 +2924,7 @@
   dp->pos = demuxer->filepos;
   dp->flags = block_bref ? 0 : 0x10;
   ds_add_packet (demuxer->audio, dp);
+  }
 }
 
 /** Reorder timecodes and add cached demux packets to the queues.