smart padding for better gapless playback
[fdkaac.git] / src / aacenc.c
index e622c62c0d6f1b7551bad75802b2a4b5086df24d..bf975d0778c67ce71cfbee8b97415a6e0782461c 100644 (file)
@@ -10,6 +10,7 @@
 #endif
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include "aacenc.h"
 
 int aacenc_is_sbr_active(const aacenc_param_t *params)
@@ -25,6 +26,68 @@ int aacenc_is_sbr_active(const aacenc_param_t *params)
     return 0;
 }
 
+static const unsigned aacenc_sampling_freq_tab[] = {
+    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 
+    16000, 12000, 11025, 8000, 7350, 0, 0, 0
+};
+
+static
+unsigned sampling_freq_index(unsigned rate)
+{
+    unsigned i;
+    for (i = 0; aacenc_sampling_freq_tab[i]; ++i)
+        if (aacenc_sampling_freq_tab[i] == rate)
+            return i;
+    return 0xf;
+}
+
+/*
+ * Append backward compatible SBR/PS signaling to implicit signaling ASC,
+ * if SBR/PS is present.
+ */
+int aacenc_mp4asc(const aacenc_param_t *params,
+                  const uint8_t *asc, uint32_t ascsize,
+                  uint8_t *outasc, uint32_t *outsize)
+{
+    unsigned asc_sfreq = aacenc_sampling_freq_tab[(asc[0]&0x7)<<1 |asc[1]>>7];
+
+    switch (params->profile) {
+    case AOT_SBR:
+    case AOT_PS:
+        if (*outsize < ascsize + 3)
+            return -1;
+        memcpy(outasc, asc, ascsize);
+        /* syncExtensionType:11 (value:0x2b7) */
+        outasc[ascsize+0] = 0x2b << 1;
+        outasc[ascsize+1] = 0x7 << 5;
+        /* extensionAudioObjectType:5 (value:5)*/
+        outasc[ascsize+1] |= 5;
+        /* sbrPresentFlag:1 (value:1) */
+        outasc[ascsize+2] = 0x80;
+        /* extensionSamplingFrequencyIndex:4 */
+        outasc[ascsize+2] |= sampling_freq_index(asc_sfreq << 1) << 3;
+        if (params->profile == AOT_SBR) {
+            *outsize = ascsize + 3;
+            break;
+        }
+        if (*outsize < ascsize + 5)
+            return -1;
+        /* syncExtensionType:11 (value:0x548) */
+        outasc[ascsize+2] |= 0x5;
+        outasc[ascsize+3] = 0x48;
+        /* psPresentFlag:1 (value:1) */
+        outasc[ascsize+4] = 0x80;
+        *outsize = ascsize + 5;
+        break;
+    default:
+        if (*outsize < ascsize)
+            return -1;
+        memcpy(outasc, asc, ascsize);
+        *outsize = ascsize;
+    }
+    return 0;
+}
+
 static
 int aacenc_channel_mode(const pcm_sample_description_t *format)
 {
@@ -97,7 +160,7 @@ int aacenc_init(HANDLE_AACENCODER *encoder, const aacenc_param_t *params,
     }
     if (aacEncoder_SetParam(*encoder, AACENC_SIGNALING_MODE,
                             params->sbr_signaling) != AACENC_OK) {
-        fprintf(stderr, "ERROR: unsupported transport format\n");
+        fprintf(stderr, "ERROR: failed to set SBR signaling mode\n");
         goto FAIL;
     }
     if (params->adts_crc_check)
@@ -142,7 +205,7 @@ int aac_encode_frame(HANDLE_AACENCODER encoder,
     unsigned channel_mode, obytes;
 
     channel_mode = aacEncoder_GetParam(encoder, AACENC_CHANNELMODE);
-    obytes = 6144 / 8 * channel_mode;
+    obytes = 6144 / 8 * channel_mode + 7;
     if (!*output || *osize < obytes) {
         *osize = obytes;
         *output = realloc(*output, obytes);
@@ -168,5 +231,5 @@ int aac_encode_frame(HANDLE_AACENCODER encoder,
         return -1;
     }
     *olen = oargs.numOutBytes;
-    return oargs.numInSamples;
+    return oargs.numInSamples / format->channels_per_frame;
 }
This page took 0.010788 seconds and 4 git commands to generate.