changeset 4424:8c830bde8006 libavcodec

Cook stereo (MONO_COOK2) bugfix, by Ian Braithwaite. ian at braithwaite dot dk.
author banan
date Sun, 28 Jan 2007 10:05:21 +0000
parents 96a09fef9a67
children aca324d5bd58
files cook.c
diffstat 1 files changed, 74 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/cook.c	Sat Jan 27 17:30:54 2007 +0000
+++ b/cook.c	Sun Jan 28 10:05:21 2007 +0000
@@ -277,16 +277,30 @@
 /**
  * Cook indata decoding, every 32 bits are XORed with 0x37c511f2.
  * Why? No idea, some checksum/error detection method maybe.
+ *
+ * Out buffer size: extra bytes are needed to cope with
+ * padding/missalignment.
+ * Subpackets passed to the decoder can contain two, consecutive
+ * half-subpackets, of identical but arbitrary size.
+ *          1234 1234 1234 1234  extraA extraB
+ * Case 1:  AAAA BBBB              0      0
+ * Case 2:  AAAA ABBB BB--         3      3
+ * Case 3:  AAAA AABB BBBB         2      2
+ * Case 4:  AAAA AAAB BBBB BB--    1      5
+ *
  * Nice way to waste CPU cycles.
  *
- * @param in        pointer to 32bit array of indata
- * @param bits      amount of bits
- * @param out       pointer to 32bit array of outdata
+ * @param inbuffer  pointer to byte array of indata
+ * @param out       pointer to byte array of outdata
+ * @param bytes     number of bytes
  */
+#define DECODE_BYTES_PAD1(bytes) (3 - ((bytes)+3) % 4)
+#define DECODE_BYTES_PAD2(bytes) ((bytes) % 4 + DECODE_BYTES_PAD1(2 * (bytes)))
 
-static inline void decode_bytes(uint8_t* inbuffer, uint8_t* out, int bytes){
-    int i;
-    uint32_t* buf = (uint32_t*) inbuffer;
+static inline int decode_bytes(uint8_t* inbuffer, uint8_t* out, int bytes){
+    int i, off;
+    uint32_t c;
+    uint32_t* buf;
     uint32_t* obuf = (uint32_t*) out;
     /* FIXME: 64 bit platforms would be able to do 64 bits at a time.
      * I'm too lazy though, should be something like
@@ -294,14 +308,14 @@
      *     (int64_t)out[i] = 0x37c511f237c511f2^be2me_64(int64_t)in[i]);
      * Buffer alignment needs to be checked. */
 
+    off = (uint32_t)inbuffer % 4;
+    buf = (uint32_t*) (inbuffer - off);
+    c = be2me_32((0x37c511f2 >> (off*8)) | (0x37c511f2 << (32-(off*8))));
+    bytes += 3 + off;
+    for (i = 0; i < bytes/4; i++)
+        obuf[i] = c ^ buf[i];
 
-    for(i=0 ; i<bytes/4 ; i++){
-#ifdef WORDS_BIGENDIAN
-        obuf[i] = 0x37c511f2^buf[i];
-#else
-        obuf[i] = 0xf211c537^buf[i];
-#endif
-    }
+    return off;
 }
 
 /**
@@ -948,6 +962,28 @@
 }
 
 /**
+ * First part of subpacket decoding:
+ *  decode raw stream bytes and read gain info.
+ *
+ * @param q                 pointer to the COOKContext
+ * @param inbuffer          pointer to raw stream data
+ * @param gain_ptr          array of current/prev gain pointers
+ */
+
+static inline void
+decode_bytes_and_gain(COOKContext *q, uint8_t *inbuffer, COOKgain *gain_ptr)
+{
+    int offset;
+
+    offset = decode_bytes(inbuffer, q->decoded_bytes_buffer,
+                          q->bits_per_subpacket/8);
+    init_get_bits(&q->gb, q->decoded_bytes_buffer + offset,
+                  q->bits_per_subpacket);
+    decode_gain_info(&q->gb, gain_ptr);
+}
+
+
+/**
  * Cook subpacket decoding. This function returns one decoded subpacket,
  * usually 1024 samples per channel.
  *
@@ -970,11 +1006,9 @@
 //    }
 //    av_log(NULL, AV_LOG_ERROR, "\n");
 
-    decode_bytes(inbuffer, q->decoded_bytes_buffer, sub_packet_size);
-    init_get_bits(&q->gb, q->decoded_bytes_buffer, sub_packet_size*8);
-    decode_gain_info(&q->gb, &q->gain_current);
+    if(q->nb_channels==2 && q->joint_stereo==1){
+        decode_bytes_and_gain(q, inbuffer, &q->gain_current);
 
-    if(q->nb_channels==2 && q->joint_stereo==1){
         joint_decode(q, q->decode_buf_ptr[0], q->decode_buf_ptr[2]);
 
         /* Swap buffer pointers. */
@@ -1014,6 +1048,8 @@
 
     } else if (q->nb_channels==2 && q->joint_stereo==0) {
             /* channel 0 */
+            decode_bytes_and_gain(q, inbuffer, &q->gain_current);
+
             mono_decode(q, q->decode_buf_ptr2[0]);
 
             tmp_ptr = q->decode_buf_ptr2[0];
@@ -1035,17 +1071,17 @@
                 value = lrintf(q->mono_mdct_output[j]);
                 if(value < -32768) value = -32768;
                 else if(value > 32767) value = 32767;
-                outbuffer[2*j+1] = value;
+                outbuffer[2*j] = value;
             }
 
             /* channel 1 */
             //av_log(NULL,AV_LOG_ERROR,"bits = %d\n",get_bits_count(&q->gb));
-            init_get_bits(&q->gb, q->decoded_bytes_buffer, sub_packet_size*8+q->bits_per_subpacket);
+            decode_bytes_and_gain(q, inbuffer + sub_packet_size/2,
+                                  &q->gain_channel2[0]);
 
             q->gain_now_ptr = &q->gain_channel2[0];
             q->gain_previous_ptr = &q->gain_channel2[1];
 
-            decode_gain_info(&q->gb, &q->gain_channel2[0]);
             mono_decode(q, q->decode_buf_ptr[0]);
 
             tmp_ptr = q->decode_buf_ptr[0];
@@ -1067,10 +1103,12 @@
                 value = lrintf(q->mono_mdct_output[j]);
                 if(value < -32768) value = -32768;
                 else if(value > 32767) value = 32767;
-                outbuffer[2*j] = value;
+                outbuffer[2*j+1] = value;
             }
 
     } else {
+        decode_bytes_and_gain(q, inbuffer, &q->gain_current);
+
         mono_decode(q, q->decode_buf_ptr[0]);
 
         /* Swap buffer pointers. */
@@ -1258,9 +1296,21 @@
     if(avctx->block_align >= UINT_MAX/2)
         return -1;
 
-    /* Pad the databuffer with FF_INPUT_BUFFER_PADDING_SIZE,
-       this is for the bitstreamreader. */
-    if ((q->decoded_bytes_buffer = av_mallocz((avctx->block_align+(4-avctx->block_align%4) + FF_INPUT_BUFFER_PADDING_SIZE)*sizeof(uint8_t)))  == NULL)
+    /* Pad the databuffer with:
+       DECODE_BYTES_PAD1 or DECODE_BYTES_PAD2 for decode_bytes(),
+       FF_INPUT_BUFFER_PADDING_SIZE, for the bitstreamreader. */
+    if (q->nb_channels==2 && q->joint_stereo==0) {
+        q->decoded_bytes_buffer =
+          av_mallocz(avctx->block_align/2
+                     + DECODE_BYTES_PAD2(avctx->block_align/2)
+                     + FF_INPUT_BUFFER_PADDING_SIZE);
+    } else {
+        q->decoded_bytes_buffer =
+          av_mallocz(avctx->block_align
+                     + DECODE_BYTES_PAD1(avctx->block_align)
+                     + FF_INPUT_BUFFER_PADDING_SIZE);
+    }
+    if (q->decoded_bytes_buffer == NULL)
         return -1;
 
     q->decode_buf_ptr[0] = q->decode_buffer_1;