diff --git a/CUETools.Codecs.BDLPCM/BDLPCMReader.cs b/CUETools.Codecs.BDLPCM/BDLPCMReader.cs new file mode 100644 index 0000000..23e5e2f --- /dev/null +++ b/CUETools.Codecs.BDLPCM/BDLPCMReader.cs @@ -0,0 +1,713 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace CUETools.Codecs.BDLPCM +{ + [AudioDecoderClass("cuetools", "m2ts", 2)] + public class BDLPCMReader : IAudioSource + { + public unsafe BDLPCMReader(string path, Stream IO) + { + _path = path; + _IO = IO != null ? IO : new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000); + streams = new Dictionary(); + frameBuffer = new byte[192]; + streamId = 0; + demuxer_channel = 0; + _samplePos = 0; + _sampleLen = -1; + demux_ts_packets(null, 0); + } + + public void Close() + { + //if (_br != null) + //{ + // _br.Close(); + // _br = null; + //} + _IO = null; + } + + public long Length + { + get + { + return _sampleLen; + } + } + + public long Remaining + { + get + { + return _sampleLen - _samplePos; + } + } + + public unsafe int StreamId + { + get + { + return streamId; + } + set + { + streamId = value; + chosenStream = null; + foreach (var s in streams) + { + if (s.Value.is_opened && s.Value.streamId == streamId) + { + chosenStream = s.Value; + if (chosenStream.pcm == null) + { + demux_ts_packets(null, 0); + } + break; + } + } + } + } + + public unsafe int StreamIds + { + get + { + int res = 0; + foreach (var s in streams) + if (s.Value.is_opened) + res++; + return res; + } + } + + public long Position + { + get + { + return _samplePos; + } + set + { + if (_samplePos == value) + { + return; + } + + throw new NotSupportedException(); + } + } + + public AudioPCMConfig PCM { get { return chosenStream.pcm; } } + + public string Path { get { return _path; } } + + public unsafe int Read(AudioBuffer buff, int maxLength) + { + if (chosenStream == null) throw new InvalidOperationException("chosenStream == null"); + buff.Prepare(this, maxLength); + int sampleCount; + fixed (byte* dest = &buff.Bytes[0]) + sampleCount = demux_ts_packets(dest, buff.Length); + buff.Length = sampleCount; + _samplePos += sampleCount; + return sampleCount; + } + + unsafe int demux_ts_packets(byte* dest, int maxSamples) + { + int byteOffset = 0; + int samplesOffset = 0; + while (true) + { + if (chosenStream != null && chosenStream.pcm != null) + { + int samplesInBuffer = chosenStream.savedBufferSize / chosenStream.pcm.BlockAlign; + if (samplesInBuffer > 0) + { + int chunkSamples = Math.Min(samplesInBuffer, maxSamples - samplesOffset); + int chunkLen = chunkSamples * chosenStream.pcm.BlockAlign; + fixed (byte* psrc_start = &chosenStream.savedBuffer[0]) + remux( + dest + byteOffset, + psrc_start + chosenStream.savedBufferOffset, + chunkSamples, chosenStream.pcm); + byteOffset += chunkLen; + samplesOffset += chunkSamples; + chosenStream.savedBufferOffset += chunkLen; + chosenStream.savedBufferSize -= chunkLen; + } + + if (chosenStream.savedBufferSize > 0 && chosenStream.savedBufferOffset + chosenStream.pcm.BlockAlign > chosenStream.savedBuffer.Length) + { + Buffer.BlockCopy(chosenStream.savedBuffer, chosenStream.savedBufferOffset, chosenStream.savedBuffer, 0, chosenStream.savedBufferSize); + chosenStream.savedBufferOffset = 0; + } + + if (samplesOffset >= maxSamples) return samplesOffset; + } + + int read = _IO.Read(frameBuffer, 0, 192); + if (read != 192) + break; + //if (frameBuffer[0] == 0x47 && frameBuffer[4] != 0x47) + // throw new FormatException("TS, not M2TS"); + //if (frameBuffer[0] == 0x47 || frameBuffer[4] != 0x47) + // throw new FormatException("unknown stream type"); + + fixed (byte* ptr = &frameBuffer[0]) + { + var fr = new FrameReader(ptr, ptr + 192); + TsStream s; + demux_ts_packet(fr, out s); + int dataLen = (int) fr.Length; + if (dataLen > 0 && s != null) + { + int dataOffset = (int)(fr.Ptr - ptr); + if (s.savedBufferSize > 0) + { + int blockLen = s.pcm.BlockAlign; + int chunkLen = Math.Min(dataLen, blockLen - s.savedBufferSize); + // fr.read_bytes(svptr + s.savedBufferOffset + s.savedBufferSize, chunkLen); + Buffer.BlockCopy(frameBuffer, dataOffset, s.savedBuffer, s.savedBufferOffset + s.savedBufferSize, chunkLen); + dataOffset += chunkLen; + dataLen -= chunkLen; + chosenStream.savedBufferSize += chunkLen; + if (chosenStream.savedBufferSize == blockLen) + { + fixed (byte* psrc = &s.savedBuffer[s.savedBufferOffset]) + remux(dest + byteOffset, psrc, 1, s.pcm); + byteOffset += blockLen; + samplesOffset += 1; + chosenStream.savedBufferOffset = 0; + chosenStream.savedBufferSize = 0; + } + } + if (dataLen > 0) + { + var tmp = s.savedBuffer; + s.savedBuffer = frameBuffer; + s.savedBufferOffset = dataOffset; + s.savedBufferSize = dataLen; + frameBuffer = tmp; + if (dest == null) return 0; + } + } + } + } + + return samplesOffset; + } + + unsafe static void remux(byte* pdest, byte* psrc, int samples, AudioPCMConfig pcm) + { + if (pcm.BitsPerSample == 24) + { + for (int i = 0; i < samples * pcm.ChannelCount; i++) + { + byte p0 = *(psrc++); + byte p1 = *(psrc++); + byte p2 = *(psrc++); + *(pdest++) = p2; + *(pdest++) = p1; + *(pdest++) = p0; + } + // if (0 != (pcm.ChannelCount & 1)) channels are padded with one extra unused channel! is it the same for wav? + } + else + throw new NotSupportedException(); + } + + unsafe void process_psi_pat(TsStream s, FrameReader fr) + { + long len = fr.Length - 4; + long n = len / 4; + if (len < 0 || 0 != (len % 4)) + throw new NotSupportedException(); + + for (int i = 0; i < n; i++) + { + ushort channel = fr.read_ushort(); + ushort pid = fr.read_ushort(); + if ((pid & 0xe000) != 0xe000) + throw new NotSupportedException(); + + pid &= 0x1fff; + + if (demuxer_channel == 0 || demuxer_channel == channel) + { + if (!streams.ContainsKey(pid)) + streams.Add(pid, new TsStream()); + TsStream ss = streams[pid]; + ss.channel = channel; + ss.type = 0xff; + } + } + } + + unsafe void process_psi_pmt(TsStream s, FrameReader fr) + { + // PMT (Program Map Table) + ushort pcr_pid = fr.read_ushort(); + ushort info_len = (ushort)(fr.read_ushort() & 0x0fff); + + fr.skip(info_len); + + // CRC + fr.Length -= 4; + + while (fr.Length > 0) + { + byte type = fr.read_byte(); + ushort es_pid = fr.read_ushort(); + + if ((es_pid & 0xe000) != 0xe000) + throw new IndexOutOfRangeException(); + + es_pid &= 0x1fff; + + info_len = (ushort)(fr.read_ushort() & 0x0fff); + + while (info_len > 0) + { + byte tag = fr.read_byte(); + switch (tag) + { + case 0x05: // registration descriptor + { + byte len = fr.read_byte(); + uint rid = fr.read_uint(); + if (rid == 0x48444D56 /* "HDMV" */ && type == 0x80 /* LPCM */) + { + if (!streams.ContainsKey(es_pid)) + { + streams.Add(es_pid, new TsStream()); + TsStream ss = streams[es_pid]; + if (ss.channel != s.channel || ss.type != type) + { + ss.channel = s.channel; + ss.type = type; + ss.streamId = s.streamId; + ss.is_opened = true; + s.streamId++; + } + } + } + fr.skip(len - 4); + info_len -= (ushort)(len + 2); + break; + } + default: + { + fr.skip(info_len - 1); + info_len = 0; + break; + } + } + } + } + + if (fr.Length > 0) + throw new IndexOutOfRangeException(); + } + + unsafe void process_psi(TsStream s, FrameReader fr, UInt16 pid, int table) + { + if (0 == pid) + { + process_psi_pat(s, fr); // Program Association Table + return; + } + //if (1 == pid) + //{ + // process_cat(s, ptr, end_ptr); // Conditional Access Table + // return; + //} + //if (0x11 == pid) + //{ + // process_sdt(s, ptr, end_ptr); + // return; + //} + + if (table == 0x02) + { + process_psi_pmt(s, fr); // Program Map Table + return; + } + } + + unsafe void process_pes_header(TsStream s, FrameReader fr) + { + // Packet start code prefix + if (fr.read_byte() != 0 || fr.read_byte() != 0 || fr.read_byte() != 1) + throw new NotSupportedException(); + + s.ts_stream_id = fr.read_byte(); + + int pes_len = (int)fr.read_ushort(); + int pes_type = (fr.read_byte() >> 6) & 3; + + // pes_type == 2; /* mpeg2 PES */ + + byte flags1 = fr.read_byte(); + s.frame_size = fr.read_byte(); + s.frame_num++; + s.at_packet_header = true; + + switch (flags1 & 0xc0) + { + case 0x80: // PTS only + { + ulong pts = fr.read_pts(); + + if (s.dts > 0 && pts > s.dts) + s.frame_length = (uint)(pts - s.dts); + s.dts = pts; + + if (pts > s.last_pts) + s.last_pts = pts; + + if (s.first_pts == 0) + s.first_pts = pts; + } + break; + case 0xc0: // PTS,DTS + { + ulong pts = fr.read_pts(); + ulong dts = fr.read_pts(); + + if (s.dts > 0 && dts > s.dts) + s.frame_length = (uint)(dts - s.dts); + s.dts = dts; + + if (pts > s.last_pts) + s.last_pts = pts; + + if (s.first_dts == 0) + s.first_dts = dts; + } + break; + } + } + + unsafe void BdHeader(TsStream s, FrameReader fr) + { + uint h = fr.read_uint(); + int pi_channels; + int pi_channels_padding; + int pi_bits; + int pi_rate; + //uint[] pi_channels_in; + +//static const uint32_t pi_8channels_in[] = +//{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER, +// AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, +// AOUT_CHAN_MIDDLERIGHT, AOUT_CHAN_LFE, 0 }; + +//static const uint32_t pi_7channels_in[] = +//{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER, +// AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, +// AOUT_CHAN_MIDDLERIGHT, 0 }; + +//static const uint32_t pi_6channels_in[] = +//{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER, +// AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_LFE, 0 }; + +//static const uint32_t pi_5channels_in[] = +//{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER, +// AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, 0 }; + +//static const uint32_t pi_4channels_in[] = +//{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, +// AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 }; + +//static const uint32_t pi_3channels_in[] = +//{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, +// AOUT_CHAN_CENTER, 0 }; + + switch( ( h & 0xf000) >> 12 ) + { + case 1: + pi_channels = 1; + //pi_original_channels = AOUT_CHAN_CENTER; + break; + case 3: + pi_channels = 2; + //pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; + break; + case 4: + pi_channels = 3; + //pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER; + //pi_channels_in = pi_3channels_in; + break; + case 5: + pi_channels = 3; + //pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER; + break; + case 6: + pi_channels = 4; + //pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | + // AOUT_CHAN_REARCENTER; + break; + case 7: + pi_channels = 4; + //pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | + // AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; + //pi_channels_in = pi_4channels_in; + break; + case 8: + pi_channels = 5; + //pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | + // AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; + //pi_channels_in = pi_5channels_in; + break; + case 9: + pi_channels = 6; + //pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | + // AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | + // AOUT_CHAN_LFE; + //pi_channels_in = pi_6channels_in; + break; + case 10: + pi_channels = 7; + //*pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | + // AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | + // AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT; + //pi_channels_in = pi_7channels_in; + break; + case 11: + pi_channels = 8; + //pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | + // AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | + // AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT | + // AOUT_CHAN_LFE; + //pi_channels_in = pi_8channels_in; + break; + + default: + throw new NotSupportedException(); + } + pi_channels_padding = pi_channels & 1; + + switch( (h >> 6) & 0x03 ) + { + case 1: + pi_bits = 16; + break; + case 2: /* 20 bits but samples are stored on 24 bits */ + case 3: /* 24 bits */ + pi_bits = 24; + break; + default: + throw new NotSupportedException(); + } + + switch( (h >> 8) & 0x0f ) + { + case 1: + pi_rate = 48000; + break; + case 4: + pi_rate = 96000; + break; + case 5: + pi_rate = 192000; + break; + default: + throw new NotSupportedException(); + } + + if (s.pcm == null) + s.pcm = new AudioPCMConfig(pi_bits, pi_channels, pi_rate); + + //if( pi_channels_in ) + //{ + // p_sys->i_chans_to_reorder = + // aout_CheckChannelReorder( pi_channels_in, NULL, + // *pi_original_channels, + // p_sys->pi_chan_table ); + //} + } + + unsafe void demux_ts_packet(FrameReader fr, out TsStream dataStream) + { + dataStream = null; + + uint timecode = fr.read_uint() & 0x3fffffff; + + byte sync = fr.read_byte(); // ts sync byte + if (sync != 0x47) throw new FormatException("invalid packet"); + + ushort pid = fr.read_ushort(); + bool transport_error = (pid & 0x8000) != 0; + bool payload_unit_start_indicator = (pid & 0x4000) != 0; + pid &= 0x1fff; + if (transport_error) + throw new FormatException("invalid packet "); + + byte flags = fr.read_byte(); + bool adaptation_field_exist = (flags & 0x20) != 0; + bool payload_data_exist = (flags & 0x10) != 0; + byte continuity_counter = (byte)(flags & 0x0f); + + if (pid == 0x1fff || !payload_data_exist) + { + return; + } + + // skip adaptation field + if (adaptation_field_exist) + { + fr.skip(fr.read_byte()); + } + + if (!streams.ContainsKey(pid)) + streams.Add(pid, new TsStream()); + TsStream s = streams[pid]; + + if (0 == pid || (s.channel != 0xffff && s.type == 0xff)) + { + // PSI (Program Specific Information) + if (payload_unit_start_indicator) + { + // begin of PSI table + byte pointerLen = fr.read_byte(); + fr.skip(pointerLen); + byte tableId = fr.read_byte(); + ushort sectionHeader = fr.read_ushort(); + bool syntaxFlag = ((sectionHeader >> 15) & 1) != 0; + bool privateFlag = ((sectionHeader >> 14) & 1) != 0; + int reservedBits = (sectionHeader >> 12) & 3; + if (reservedBits != 3) throw new NotSupportedException(); + int l = sectionHeader & 0x0fff; + if (syntaxFlag) + { + ushort extId = fr.read_ushort(); + byte tmp8 = fr.read_byte(); + int reserved3 = (tmp8 >> 6); + int version = (tmp8 >> 1) & 31; + bool current_flag = (tmp8 & 1) != 0; + byte section_num = fr.read_byte(); + byte last_section_num = fr.read_byte(); + l -= 5; + } + + int len = (int)fr.Length; + if (l <= len) + { + fr.Length = l; + process_psi(s, fr, pid, tableId); + return; + } + + if (l > s.psi.Length) + throw new FormatException("invalid packet "); + fixed (byte* psip = &s.psi[0]) + fr.read_bytes(psip, len); + s.psi_offset = len; + s.psi_table = tableId; + s.psi_len = l; + return; + } + + // next part of PSI + if (0 == s.psi_offset) + throw new FormatException("invalid packet "); + + { + int len = (int)fr.Length; + if (len > s.psi.Length - s.psi_offset) + throw new FormatException("invalid packet "); + fixed (byte* psip = &s.psi[s.psi_offset]) + fr.read_bytes(psip, len); + s.psi_offset += len; + } + + if (s.psi_offset < s.psi_len) + return; + fixed (byte* psip = &s.psi[0]) + { + var psiFr = new FrameReader(psip, psip + s.psi_len); + process_psi(s, psiFr, pid, s.psi_table); + } + return; + } + + if (s.type != 0xff) + { + // PES + + if (payload_unit_start_indicator) + { + s.psi_offset = 0; + s.psi_len = 9; + } + + while (s.psi_offset < s.psi_len) + { + int len = Math.Min((int)fr.Length, s.psi_len - s.psi_offset); + if (len <= 0) return; + fixed (byte* psip = &s.psi[s.psi_offset]) + fr.read_bytes(psip, len); + s.psi_offset += len; + if (s.psi_len == 9) + s.psi_len += s.psi[8]; + } + + if (s.psi_len != 0) + { + fixed (byte* psip = &s.psi[0]) + { + var pesFr = new FrameReader(psip, psip + s.psi_len); + process_pes_header(s, pesFr); + } + + s.psi_len = 0; + s.psi_offset = 0; + } + + if (s.frame_num == 0) + return; + + //if(es_parse) + //{ + // switch(s.type) + // { + // case 0x1b: + // s.frame_num_h264.parse(fr); + // break; + // case 0x06: + // case 0x81: + // case 0x83: + // s.frame_num_ac3.parse(fr); + // break; + // } + //} + + if (s.is_opened && streamId == s.streamId) + { + if (s.at_packet_header) + { + BdHeader(s, fr); + s.at_packet_header = false; + } + + dataStream = s; + } + } + } + + string _path; + Stream _IO; + Dictionary streams; + byte[] frameBuffer; + + int demuxer_channel; + int streamId; + TsStream chosenStream; + long _samplePos, _sampleLen; + } +} diff --git a/CUETools.Codecs.BDLPCM/CUETools.Codecs.BDLPCM.csproj b/CUETools.Codecs.BDLPCM/CUETools.Codecs.BDLPCM.csproj new file mode 100644 index 0000000..8e9e8fb --- /dev/null +++ b/CUETools.Codecs.BDLPCM/CUETools.Codecs.BDLPCM.csproj @@ -0,0 +1,99 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {E75F7CCD-4266-42E1-A039-DC7EB5EDD8F6} + Library + Properties + CUETools.Codecs.BDLPCM + CUETools.Codecs.BDLPCM + + + 3.5 + + + v2.0 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\bin\Debug\plugins\ + DEBUG;TRACE + prompt + 4 + true + AllRules.ruleset + + + pdbonly + true + ..\bin\Release\plugins\ + TRACE + prompt + 4 + true + AllRules.ruleset + + + + + + + + + + + + + + + {6458A13A-30EF-45A9-9D58-E5031B17BEE2} + CUETools.Codecs + False + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/CUETools.Codecs.BDLPCM/FrameReader.cs b/CUETools.Codecs.BDLPCM/FrameReader.cs new file mode 100644 index 0000000..002d84c --- /dev/null +++ b/CUETools.Codecs.BDLPCM/FrameReader.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CUETools.Codecs.BDLPCM +{ + internal unsafe class FrameReader + { + internal FrameReader(byte* ptr, byte* end) + { + ptr_m = ptr; + end_m = end; + } + + internal FrameReader(byte* ptr, long len) + { + ptr_m = ptr; + end_m = ptr + len; + } + + internal void read_bytes(byte* dst, int len) + { + if (ptr_m + len > end_m) throw new IndexOutOfRangeException(); + AudioSamples.MemCpy(dst, ptr_m, len); + ptr_m += len; + } + + internal byte read_byte() + { + if (ptr_m + 1 > end_m) throw new IndexOutOfRangeException(); + return *(ptr_m++); + } + + internal ushort read_ushort() + { + if (ptr_m + 2 > end_m) throw new IndexOutOfRangeException(); + ushort n = (ushort)(*(ptr_m++)); + n <<= 8; n += (ushort)(*(ptr_m++)); + return n; + } + + internal uint read_uint() + { + if (ptr_m + 4 > end_m) throw new IndexOutOfRangeException(); + uint n = (uint)(*(ptr_m++)); + n <<= 8; n += (uint)(*(ptr_m++)); + n <<= 8; n += (uint)(*(ptr_m++)); + n <<= 8; n += (uint)(*(ptr_m++)); + return n; + } + + internal ulong read_pts() + { + if (ptr_m + 5 > end_m) throw new IndexOutOfRangeException(); + ulong pts + = ((ulong)(*(ptr_m++) & 0x0e) << 29); + pts |= ((ulong)(*(ptr_m++) & 0xff) << 22); + pts |= ((ulong)(*(ptr_m++) & 0xfe) << 14); + pts |= ((ulong)(*(ptr_m++) & 0xff) << 7); + pts |= ((ulong)(*(ptr_m++) & 0xfe) >> 1); + return pts; + } + + internal void skip(long bytes) + { + if (ptr_m + bytes > end_m) throw new IndexOutOfRangeException(); + ptr_m += bytes; + } + + internal long Length + { + get + { + return end_m - ptr_m; + } + set + { + end_m = ptr_m + value; + } + } + + internal byte* Ptr + { + get + { + return ptr_m; + } + } + + byte* ptr_m; + byte* end_m; + } +} diff --git a/CUETools.Codecs.BDLPCM/Properties/AssemblyInfo.cs b/CUETools.Codecs.BDLPCM/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2f6bb08 --- /dev/null +++ b/CUETools.Codecs.BDLPCM/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CUETools.Codecs.BDLPCM")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CUETools.Codecs.BDLPCM")] +[assembly: AssemblyCopyright("Copyright © 2018 Grigory Chudov")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("671d2a00-4ce2-452b-830e-18c30a7Cb168")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("2.1.6.0")] +[assembly: AssemblyFileVersion("2.1.6.0")] diff --git a/CUETools.Codecs.BDLPCM/TsStream.cs b/CUETools.Codecs.BDLPCM/TsStream.cs new file mode 100644 index 0000000..6fcce7b --- /dev/null +++ b/CUETools.Codecs.BDLPCM/TsStream.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CUETools.Codecs.BDLPCM +{ + internal class TsStream + { + internal UInt16 channel; // channel number (1,2 ...) + internal int streamId; // stream number in channel + internal byte type; // 0xff - not ES + internal AudioPCMConfig pcm; + internal byte[] savedBuffer; + internal int savedBufferOffset; + internal int savedBufferSize; + + internal byte[] psi; // PAT,PMT cache (only for PSI streams) + internal int psi_len; + internal int psi_offset; + internal int psi_table; + internal bool at_packet_header; + + internal byte ts_stream_id; // MPEG stream id + + internal bool is_opened; + + internal UInt64 dts; // current MPEG stream DTS (presentation time for audio, decode time for video) + internal UInt64 first_dts; + internal UInt64 first_pts; + internal UInt64 last_pts; + internal UInt32 frame_length; // frame length in ticks (90 ticks = 1 ms, 90000/frame_length=fps) + internal UInt32 frame_size; // frame size in bytes + internal UInt64 frame_num; // frame counter + + internal TsStream() + { + is_opened = false; + psi = new byte[512]; + psi_len = 0; + psi_offset = 0; + psi_table = 0; + channel = 0xffff; + streamId = 0; + type = 0xff; + ts_stream_id = 0; + dts = 0; + first_dts = 0; + first_pts = 0; + last_pts = 0; + frame_length = 0; + frame_size = 0; + frame_num = 0; + pcm = null; + savedBuffer = new byte[192]; + savedBufferOffset = 0; + savedBufferSize = 0; + } + }; +}