public void Scan(TSAudioStream stream, TSStreamBuffer buffer, ref string tag, long?bitrate) { if (stream.IsInitialized) { return; } var sync = buffer.ReadBytes(2); if (sync == null || sync[0] != 0x0B || sync[1] != 0x77) { return; } var secondFrame = stream.ChannelCount > 0; uint srCode; uint frameSize = 0; uint frameSizeCode = 0; uint channelMode; uint lfeOn; uint dialNorm = 0; uint dialNormExt = 0; uint numBlocks = 0; var hdr = buffer.ReadBytes(4); var bsid = (uint)((hdr[3] & 0xF8) >> 3); buffer.Seek(-4, SeekOrigin.Current); if (bsid <= 10) { buffer.BSSkipBytes(2); srCode = buffer.ReadBits2(2); frameSizeCode = buffer.ReadBits2(6); bsid = buffer.ReadBits2(5); buffer.BSSkipBits(3); channelMode = buffer.ReadBits2(3); if ((channelMode & 0x1) > 0 && channelMode != 0x1) { buffer.BSSkipBits(2); } if ((channelMode & 0x4) > 0) { buffer.BSSkipBits(2); } if (channelMode == 0x2) { var dsurmod = buffer.ReadBits2(2); if (dsurmod == 0x2) { stream.AudioMode = TSAudioMode.Surround; } } lfeOn = buffer.ReadBits2(1); dialNorm = buffer.ReadBits2(5); if (buffer.ReadBool()) { buffer.BSSkipBits(8); } if (buffer.ReadBool()) { buffer.BSSkipBits(8); } if (buffer.ReadBool()) { buffer.BSSkipBits(7); } if (channelMode == 0) { buffer.BSSkipBits(5); if (buffer.ReadBool()) { buffer.BSSkipBits(8); } if (buffer.ReadBool()) { buffer.BSSkipBits(8); } if (buffer.ReadBool()) { buffer.BSSkipBits(7); } } buffer.BSSkipBits(2); if (bsid == 6) { if (buffer.ReadBool()) { buffer.BSSkipBits(14); } if (buffer.ReadBool()) { uint dsurexmod = buffer.ReadBits2(2); uint dheadphonmod = buffer.ReadBits2(2); if (dheadphonmod == 0x2) { // TODO } buffer.BSSkipBits(10); if (dsurexmod == 2) { stream.AudioMode = TSAudioMode.Extended; } } } } else { uint frameType = buffer.ReadBits2(2); buffer.BSSkipBits(3); frameSize = (buffer.ReadBits4(11) + 1) << 1; srCode = buffer.ReadBits2(2); if (srCode == 3) { srCode = buffer.ReadBits2(2); numBlocks = 3; } else { numBlocks = buffer.ReadBits2(2); } channelMode = buffer.ReadBits2(3); lfeOn = buffer.ReadBits2(1); bsid = buffer.ReadBits2(5); dialNormExt = buffer.ReadBits2(5); if (buffer.ReadBool()) { buffer.BSSkipBits(8); } if (channelMode == 0) // 1+1 { buffer.BSSkipBits(5); if (buffer.ReadBool()) { buffer.BSSkipBits(8); } } if (frameType == 1) //dependent stream { stream.CoreStream = (TSAudioStream)stream.Clone(); stream.CoreStream.StreamType = TSStreamType.AC3_AUDIO; if (buffer.ReadBool()) //channel remapping { var chanmap = buffer.ReadBits4(16); stream.ChannelCount = stream.CoreStream.ChannelCount; stream.ChannelCount += AC3ChanMap((int)chanmap); lfeOn = (uint)stream.CoreStream.LFE; } } var emdfFound = false; do { var emdfSync = buffer.ReadBits4(16); if (emdfSync == 0x5838) { emdfFound = true; break; } buffer.Seek(-2, SeekOrigin.Current); buffer.BSSkipBits(1); // skip 1 bit } while (buffer.Position < buffer.Length); if (emdfFound) { var emdfContainerSize = buffer.ReadBits4(16); var remainAfterEmdf = buffer.DataBitStreamRemain() - emdfContainerSize * 8; uint emdfVersion = buffer.ReadBits2(2); //emdf_version if (emdfVersion == 3) { emdfVersion += buffer.ReadBits2(2); } if (emdfVersion > 0) { buffer.BSSkipBits((int)(buffer.DataBitStreamRemain() - remainAfterEmdf)); } else { var temp = buffer.ReadBits2(3); if (temp == 0x7) { buffer.BSSkipBits(2); //skip 3 bits } var emdfPayloadID = buffer.ReadBits2(5); if (emdfPayloadID > 0 && emdfPayloadID < 16) { if (emdfPayloadID == 0x1F) { buffer.BSSkipBits(5); //skip 5 bits } EmdfPayloadConfig(buffer); var emdfPayloadSize = buffer.ReadBits2(8) * 8; buffer.BSSkipBits(emdfPayloadSize + 1); } while ((emdfPayloadID = buffer.ReadBits2(5)) != 14 && buffer.Position < buffer.Length) { if (emdfPayloadID == 0x1F) { buffer.BSSkipBits(5); //skip 5 bits } EmdfPayloadConfig(buffer); var emdfPayloadSize = buffer.ReadBits2(8) * 8; buffer.ReadBits4(emdfPayloadSize + 1); } if (buffer.Position < buffer.Length && emdfPayloadID == 14) { EmdfPayloadConfig(buffer); buffer.BSSkipBits(12); uint jocNumObjectsBits = buffer.ReadBits2(6); if (jocNumObjectsBits > 0) { stream.HasExtensions = true; } } } } } if (channelMode < 8 && stream.ChannelCount == 0) { stream.ChannelCount = AC3Channels[channelMode]; } if (stream.AudioMode == TSAudioMode.Unknown) { switch (channelMode) { case 0: // 1+1 stream.AudioMode = TSAudioMode.DualMono; break; case 2: // 2/0 stream.AudioMode = TSAudioMode.Stereo; break; default: stream.AudioMode = TSAudioMode.Unknown; break; } } switch (srCode) { case 0: stream.SampleRate = 48000; break; case 1: stream.SampleRate = 44100; break; case 2: stream.SampleRate = 32000; break; default: stream.SampleRate = 0; break; } if (bsid <= 10) { var fSize = frameSizeCode >> 1; if (fSize < 19) { stream.BitRate = AC3Bitrate[fSize] * 1000; } } else { stream.BitRate = (long)(4.0 * frameSize * stream.SampleRate / (numBlocks * 256)); if (stream.CoreStream != null) { stream.BitRate += stream.CoreStream.BitRate; } } stream.LFE = (int)lfeOn; if (stream.StreamType != TSStreamType.AC3_PLUS_SECONDARY_AUDIO) { if (stream.StreamType == TSStreamType.AC3_PLUS_AUDIO && bsid == 6 || stream.StreamType == TSStreamType.AC3_AUDIO) { stream.DialNorm = (int)dialNorm * -1; } else if (stream.StreamType == TSStreamType.AC3_PLUS_AUDIO && secondFrame) { stream.DialNorm = (int)dialNormExt * -1; } } stream.IsVBR = false; if (stream.StreamType == TSStreamType.AC3_PLUS_AUDIO && bsid == 6 && !secondFrame) { stream.IsInitialized = false; } else { stream.IsInitialized = true; } }
public static void Scan(TSAudioStream stream, TSStreamBuffer buffer, long bitrate, ref string tag) { if (stream.IsInitialized && (stream.StreamType == TSStreamType.DTS_HD_SECONDARY_AUDIO || (stream.CoreStream != null && stream.CoreStream.IsInitialized))) { return; } var syncFound = false; uint sync = 0; for (var i = 0; i < buffer.Length; i++) { sync = (sync << 8) + buffer.ReadByte(); if (sync == 0x64582025) { syncFound = true; break; } } if (!syncFound) { tag = "CORE"; if (stream.CoreStream == null) { stream.CoreStream = new TSAudioStream { StreamType = TSStreamType.DTS_AUDIO }; } if (!stream.CoreStream.IsInitialized) { buffer.BeginRead(); TSCodecDTS.Scan(stream.CoreStream, buffer, bitrate, ref tag); } return; } tag = "HD"; buffer.BSSkipBits(8); var nuSubStreamIndex = buffer.ReadBits4(2); var bBlownUpHeader = buffer.ReadBool(); buffer.BSSkipBits(bBlownUpHeader ? 32 : 24); var nuNumAssets = 1; var bStaticFieldsPresent = buffer.ReadBool(); if (bStaticFieldsPresent) { buffer.BSSkipBits(5); if (buffer.ReadBool()) { buffer.BSSkipBits(36); } var nuNumAudioPresent = buffer.ReadBits2(3) + 1; nuNumAssets = buffer.ReadBits2(3) + 1; var nuActiveExSsMask = new uint[nuNumAudioPresent]; for (var i = 0; i < nuNumAudioPresent; i++) { nuActiveExSsMask[i] = buffer.ReadBits4((int)(nuSubStreamIndex + 1)); //? } for (var i = 0; i < nuNumAudioPresent; i++) { for (var j = 0; j < nuSubStreamIndex + 1; j++) { if (((j + 1) % 2) == 1) { buffer.BSSkipBits(8); } } } if (buffer.ReadBool()) { buffer.BSSkipBits(2); var nuBits4MixOutMask = buffer.ReadBits2(2) * 4 + 4; var nuNumMixOutConfigs = buffer.ReadBits2(2) + 1; var nuMixOutChMask = new uint[nuNumMixOutConfigs]; for (var i = 0; i < nuNumMixOutConfigs; i++) { nuMixOutChMask[i] = buffer.ReadBits4(nuBits4MixOutMask); } } } var assetSizes = new uint[nuNumAssets]; for (var i = 0; i < nuNumAssets; i++) { if (bBlownUpHeader) { assetSizes[i] = buffer.ReadBits4(20) + 1; } else { assetSizes[i] = buffer.ReadBits4(16) + 1; } } for (var i = 0; i < nuNumAssets; i++) { buffer.BSSkipBits(12); if (bStaticFieldsPresent) { if (buffer.ReadBool()) { buffer.BSSkipBits(4); } if (buffer.ReadBool()) { buffer.BSSkipBits(24); } if (buffer.ReadBool()) { var nuInfoTextByteSize = buffer.ReadBits2(10) + 1; var infoText = new ushort[nuInfoTextByteSize]; for (var j = 0; j < nuInfoTextByteSize; j++) { infoText[j] = buffer.ReadBits2(8); } } var nuBitResolution = buffer.ReadBits2(5) + 1; int nuMaxSampleRate = buffer.ReadBits2(4); var nuTotalNumChs = buffer.ReadBits2(8) + 1; uint nuSpkrActivityMask = 0; if (buffer.ReadBool()) { if (nuTotalNumChs > 2) { buffer.BSSkipBits(1); } if (nuTotalNumChs > 6) { buffer.BSSkipBits(1); } if (buffer.ReadBool()) { int nuNumBits4SAMask = buffer.ReadBits2(2); nuNumBits4SAMask = nuNumBits4SAMask * 4 + 4; nuSpkrActivityMask = buffer.ReadBits4(nuNumBits4SAMask); } // TODO... } stream.SampleRate = SampleRates[nuMaxSampleRate]; stream.BitDepth = nuBitResolution; stream.LFE = 0; if ((nuSpkrActivityMask & 0x8) == 0x8) { ++stream.LFE; } if ((nuSpkrActivityMask & 0x1000) == 0x1000) { ++stream.LFE; } stream.ChannelCount = nuTotalNumChs - stream.LFE; } if (nuNumAssets > 1) { // TODO... break; } } uint temp2 = 0; while (buffer.Position < buffer.Length) { temp2 = (temp2 << 8) + buffer.ReadByte(); switch (temp2) { case 0x41A29547: // XLL Extended data case 0x655E315E: // XBR Extended data case 0x0A801921: // XSA Extended data case 0x1D95F262: // X96k case 0x47004A03: // XXch case 0x5A5A5A5A: // Xch int temp3 = 0; for (var i = (int)buffer.Position; i < buffer.Length; i++) { temp3 = (temp3 << 8) + buffer.ReadByte(); if (temp3 == 0x02000850) //DTS:X Pattern { stream.HasExtensions = true; break; } } break; } if (stream.HasExtensions) { break; } } // TODO if (stream.CoreStream != null) { var coreStream = (TSAudioStream)stream.CoreStream; if (coreStream.AudioMode == TSAudioMode.Extended && stream.ChannelCount == 5) { stream.AudioMode = TSAudioMode.Extended; } /* * if (coreStream.DialNorm != 0) * { * stream.DialNorm = coreStream.DialNorm; * } */ } if (stream.StreamType == TSStreamType.DTS_HD_MASTER_AUDIO) { stream.IsVBR = true; stream.IsInitialized = true; } else if (bitrate > 0) { stream.IsVBR = false; stream.BitRate = bitrate; if (stream.CoreStream != null) { stream.BitRate += stream.CoreStream.BitRate; stream.IsInitialized = true; } stream.IsInitialized = (stream.BitRate > 0); } }
public void Scan(TSAudioStream stream, TSStreamBuffer buffer, ref string tag, long?bitrate) { if (stream.IsInitialized && stream.CoreStream != null && stream.CoreStream.IsInitialized) { return; } var syncFound = false; uint sync = 0; for (var i = 0; i < buffer.Length; i++) { sync = (sync << 8) + buffer.ReadByte(); if (sync == 0xF8726FBA) { syncFound = true; break; } } if (!syncFound) { tag = "CORE"; stream.CoreStream ??= new TSAudioStream { StreamType = TSStreamType.AC3_AUDIO }; if (stream.CoreStream.IsInitialized) { return; } buffer.BeginRead(); (new TSCodecAC3()).Scan(stream.CoreStream, buffer, ref tag, bitrate); return; } tag = "HD"; int ratebits = buffer.ReadBits2(4); if (ratebits != 0xF) { stream.SampleRate = ((ratebits & 8) > 0 ? 44100 : 48000) << (ratebits & 7); } buffer.BSSkipBits(15); stream.ChannelCount = 0; stream.LFE = 0; if (buffer.ReadBool()) { stream.LFE += 1; } if (buffer.ReadBool()) { stream.ChannelCount += 1; } if (buffer.ReadBool()) { stream.ChannelCount += 2; } if (buffer.ReadBool()) { stream.ChannelCount += 2; } if (buffer.ReadBool()) { stream.ChannelCount += 1; } if (buffer.ReadBool()) { stream.ChannelCount += 1; } if (buffer.ReadBool()) { stream.ChannelCount += 2; } if (buffer.ReadBool()) { stream.ChannelCount += 2; } if (buffer.ReadBool()) { stream.ChannelCount += 2; } if (buffer.ReadBool()) { stream.ChannelCount += 2; } if (buffer.ReadBool()) { stream.LFE += 1; } if (buffer.ReadBool()) { stream.ChannelCount += 1; } if (buffer.ReadBool()) { stream.ChannelCount += 2; } buffer.BSSkipBits(49); var peakBitrate = buffer.ReadBits4(15); peakBitrate = (uint)((peakBitrate * stream.SampleRate) >> 4); var peakBitdepth = (double)peakBitrate / (stream.ChannelCount + stream.LFE) / stream.SampleRate; stream.BitDepth = peakBitdepth > 14 ? 24 : 16; buffer.BSSkipBits(79); var hasExtensions = buffer.ReadBool(); var numExtensions = buffer.ReadBits2(4) * 2 + 1; var hasContent = Convert.ToBoolean(buffer.ReadBits4(4)); if (hasExtensions) { for (var idx = 0; idx < numExtensions; ++idx) { if (Convert.ToBoolean(buffer.ReadBits2(8))) { hasContent = true; } } if (hasContent) { stream.HasExtensions = true; } } #if DEBUG Debug.WriteLine($"{stream.PID}\t{peakBitrate}\t{peakBitdepth:F2}"); #endif /* * // TODO: Get THD dialnorm from metadata * if (stream.CoreStream != null) * { * TSAudioStream coreStream = (TSAudioStream)stream.CoreStream; * if (coreStream.DialNorm != 0) * { * stream.DialNorm = coreStream.DialNorm; * } * } */ stream.IsVBR = true; if (stream.CoreStream != null && stream.CoreStream.IsInitialized) { stream.IsInitialized = true; } }