|
|
@@ -187,7 +187,65 @@ public class FlvPacketizer {
|
|
|
codecInfo.pcmAccum = new short[1024 * codecInfo.aacChannels];
|
|
|
}
|
|
|
|
|
|
- // 初始化AAC编码器
|
|
|
+ // 如果负载类型本身就是 AAC(例如原始 AAC 帧或 ADTS),直接封装为 FLV 的 AAC 原始包
|
|
|
+ if (codecInfo.payloadAudio == JttConstants.PAYLOAD_TYPE_AAC
|
|
|
+ || codecInfo.payloadAudio == JttConstants.PAYLOAD_TYPE_AACLC
|
|
|
+ || codecInfo.payloadAudio == JttConstants.PAYLOAD_TYPE_MP4AUDIO
|
|
|
+ || codecInfo.payloadAudio == JttConstants.PAYLOAD_TYPE_HEAAC) {
|
|
|
+
|
|
|
+ byte[] rawAac = audioBytes;
|
|
|
+ // 检测 ADTS(syncword 0xFFF)并解析 header 以获取采样率/声道以及去掉 ADTS 头
|
|
|
+ if (rawAac.length >= 2 && (rawAac[0] & 0xFF) == 0xFF && (rawAac[1] & 0xF0) == 0xF0) {
|
|
|
+ int protectionAbsent = rawAac[1] & 0x01;
|
|
|
+ int adtsHeaderLen = (protectionAbsent == 0) ? 9 : 7;
|
|
|
+ if (rawAac.length >= adtsHeaderLen) {
|
|
|
+ int samplingIndex = (rawAac[2] & 0x3C) >> 2;
|
|
|
+ int channelConfig = ((rawAac[2] & 0x01) << 2) | ((rawAac[3] & 0xC0) >> 6);
|
|
|
+
|
|
|
+ int[] rates = new int[] {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,7350};
|
|
|
+ int sampleRate = 44100;
|
|
|
+ if (samplingIndex >= 0 && samplingIndex < rates.length) sampleRate = rates[samplingIndex];
|
|
|
+
|
|
|
+ codecInfo.aacSampleRate = sampleRate;
|
|
|
+ codecInfo.aacChannels = Math.max(1, channelConfig);
|
|
|
+
|
|
|
+ int payloadLen = rawAac.length - adtsHeaderLen;
|
|
|
+ if (payloadLen > 0) {
|
|
|
+ byte[] tmp = new byte[payloadLen];
|
|
|
+ System.arraycopy(rawAac, adtsHeaderLen, tmp, 0, payloadLen);
|
|
|
+ rawAac = tmp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成/获取 AAC 序列头(若尚未生成)
|
|
|
+ byte[] seq = new byte[0];
|
|
|
+ if (!codecInfo.aacSequenceHeaderGenerated) {
|
|
|
+ seq = createAacSequenceHeader(codecInfo.aacSampleRate, codecInfo.aacChannels, timestamp);
|
|
|
+ codecInfo.aacSequenceHeaderTag = seq;
|
|
|
+ codecInfo.aacSequenceHeaderGenerated = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建 AAC 原始数据的 FLV 音频 Tag (AACPacketType = 1)
|
|
|
+ byte[] rawTag = createAudioTag(JttConstants.AAC_SEQUENCE_DATA, rawAac, timestamp);
|
|
|
+
|
|
|
+ // 若本次刚生成序列头,则返回序列头+本帧;否则只返回本帧
|
|
|
+ if (seq != null && seq.length > 0) {
|
|
|
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
|
|
+ try {
|
|
|
+ bout.write(seq);
|
|
|
+ bout.write(rawTag);
|
|
|
+ return bout.toByteArray();
|
|
|
+ } catch (IOException e) {
|
|
|
+ logger.error("合并 AAC 序列头与原始帧失败", e);
|
|
|
+ return new byte[0];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return rawTag;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化AAC编码器(仅当需要把其他编码解码并编码为 AAC 时使用)
|
|
|
if (codecInfo.aacHandle == 0) {
|
|
|
try {
|
|
|
codecInfo.aacHandle = AacEncoderNative.initEncoder(
|