namespace TsRemux
{
- static const signed long long vsint_subtr[] = {
+ static const Int64 vsint_subtr[] = {
0x3fLL, 0x1ffffLL, 0xfffffLL, 0x7ffffffLL, 0x3ffffffffLL,
0x1ffffffffffLL, 0xffffffffffffffLL, 0x7fffffffffffffLL };
-EbmlElement::EbmlElement(signed long long id, signed long long size, signed long long pos, Stream& fs)
+EbmlElement::EbmlElement(Int64 id, Int64 size, Int64 pos, boost::shared_ptr<Stream> fs)
{
- return;
+ SetId(id);
+ SetSize(size);
+ SetPos(pos);
+ SetStream(fs);
}
-EbmlElement* EbmlElement::ParseEbml(Stream& fs)
-{
-
- return NULL;
+boost::shared_ptr<EbmlElement> EbmlElement::ParseEbml(boost::shared_ptr<Stream> fs)
+{
+ Int64 pos = fs.get()->Position;
+ EbmlElement ebml = null;
+ if (!fs || fs.Length == 0)
+ return null;
+ int b = fs.ReadByte();
+ if (b == -1)
+ goto cleanup;
+ int len = VintLength((byte)b);
+ if ((fs.Length - fs.Position) < (Int64)len)
+ goto cleanup;
+ fs.Position -= 1;
+ Int64 id = 0;
+ for (int i = 0; i < len; i++)
+ {
+ id <<= 8;
+ id |= (byte)fs.ReadByte();
+ }
+ b = fs.ReadByte();
+ if (b == -1)
+ goto cleanup;
+ len = VintLength((byte)b);
+ if ((fs.Length - fs.Position) < (Int64)len)
+ goto cleanup;
+ fs.Position -= 1;
+ Int64 size = VintToInt64(fs);
+ if ((fs.Length - fs.Position) < size)
+ goto cleanup;
+ ebml = new EbmlElement(id, size, fs.Position, fs);
+
+cleanup:
+ fs.Position = pos;
+ return ebml;
}
-char EbmlElement::VintLength(char vint)
+byte EbmlElement::VintLength(byte vint)
{
- return 'A';
+ byte len = 1;
+ for (int i = 7; (((vint >> i) & 0x01) == 0) && i >= 0; i--)
+ len++;
+ return len;
}
-signed long long EbmlElement::VintToInt64(Stream& fs)
+Int64 EbmlElement::VintToInt64(boost::shared_ptr<Stream> fs)
{
- return 1;
+ byte b = (byte)fs.ReadByte();
+ int len = VintLength(b);
+ Int64 ret = (((1 << (8 - len)) - 1) & b) << (8 * (len - 1));
+ for (int i = 1; i < len; i++)
+ ret += (((byte)fs.ReadByte()) << (8 * (len - 1 - i)));
+ return ret;
}
MkvPesFile::MkvPesFile(BackgroundWorker& bw)
{
- return;
+ Clusters = new SortedList<long, EbmlElement>();
+ TrackList = new Dictionary<ushort, TrackInfo>();
+ CurrentIndex = -1;
}
-TrackInfo::TrackInfo(unsigned short pid, std::string codec, char* data, EbmlElement& info)
+TrackInfo::TrackInfo(ushort pid, std::string codec, pByte data, EbmlElement& info)
{
- return;
+ this.pid = pid;
+ this.codec = codec;
+ this.data = data;
+ this.info = info;
}
PesPacket* MkvPesFile::GetNextPesPackets(void)
{
- return NULL;
+ if (CurrentIndex >= Clusters.Keys.Count)
+ return null;
+ EbmlElement cluster = Clusters[Clusters.Keys[CurrentIndex]];
+ EbmlElement[] blocks = cluster.Children;
+ List<PesPacket> packList = new List<PesPacket>();
+ Int64 clock = GetClusterClock(cluster);
+ if (pcrDelegate != null)
+ pcrDelegate(clock * (Constants.MPEG2TS_CLOCK_RATE / 1000));
+ foreach (EbmlElement bl in blocks)
+ {
+ EbmlElement block = null;
+ switch (bl.Id)
+ {
+ case 0xa0: // block group
+ EbmlElement[] cbls = bl.Children;
+ foreach (EbmlElement bl2 in cbls)
+ if (bl2.Id == 0xa1)
+ {
+ block = bl2;
+ break;
+ }
+ break;
+ case 0xa3:
+ block = bl;
+ break;
+ }
+ if (null != block)
+ {
+ Stream stm = block.DataStream;
+ Int64 endPos = stm.Position + block.Size;
+ Int64 track = EbmlElement.VintToInt64(stm);
+ Int16 time = (short)stm.ReadByte();
+ time <<= 8;
+ time += (short)stm.ReadByte();
+ Int64 pts = clock + time;
+ pts *= 90;
+ byte flags = (byte)stm.ReadByte();
+ LacingType lacing = (LacingType)((flags >> 1) & 0x03);
+ if (lacing != LacingType.NoLacing && lacing != LacingType.FixedSizeLacing)
+ throw new FormatException("Variable lacing is not yet supported");
+ if (lacing == LacingType.FixedSizeLacing)
+ stm.Position += 1;
+ byte[] data = new byte[endPos - stm.Position];
+ stm.Read(data, 0, (int)(endPos - stm.Position));
+ if (data.Length > 0 && TrackList.ContainsKey((ushort)track))
+ {
+ TrackInfo ti = TrackList[(ushort)track];
+ if (ptsDelegate != null)
+ ptsDelegate(pts, ti.pid);
+ switch (sis[(ushort)track - 1].StreamType)
+ {
+ case ElementaryStreamTypes.AUDIO_STREAM_AC3:
+ packList.Add(BuildAc3Pes(pts, data, ti.pid));
+ break;
+ case ElementaryStreamTypes.AUDIO_STREAM_DTS:
+ packList.Add(BuildDtsPes(pts, data, ti.pid));
+ break;
+ case ElementaryStreamTypes.VIDEO_STREAM_MPEG2:
+ packList.Add(BuildMpeg2Pes(pts, data, ti.pid));
+ break;
+ case ElementaryStreamTypes.VIDEO_STREAM_H264:
+ packList.Add(BuildAvcPes(pts, data, ti.pid));
+ break;
+ case ElementaryStreamTypes.VIDEO_STREAM_VC1:
+ packList.Add(BuildVc1Pes(pts, data, ti.pid));
+ break;
+ }
+ }
+ }
+ }
+ CurrentIndex++;
+ if(packList.Count == 0)
+ return null;
+ return packList.ToArray();
}
-void MkvPesFile::Seek(signed long pcr)
+void MkvPesFile::Seek(Int32 pcr)
{
return;
}
return 1;
}
-PesPacket MkvPesFile::BuildAc3Pes(signed long long timestamp, char data[], unsigned short pid)
+PesPacket MkvPesFile::BuildAc3Pes(Int64 timestamp, pByte data, ushort pid)
{
PesPacket ret;
return ret;
}
-PesPacket MkvPesFile::BuildMpeg2Pes(signed long long timestamp, char data[], unsigned short pid)
+PesPacket MkvPesFile::BuildMpeg2Pes(Int64 timestamp, pByte data, ushort pid)
{
PesPacket ret;
return ret;
}
-PesPacket MkvPesFile::BuildAvcPes(signed long long timestamp, char data[], unsigned short pid)
+PesPacket MkvPesFile::BuildAvcPes(Int64 timestamp, pByte data, ushort pid)
{
PesPacket ret;
return ret;
}
-PesPacket MkvPesFile::BuildVc1Pes(signed long long timestamp, char data[], unsigned short pid)
+PesPacket MkvPesFile::BuildVc1Pes(Int64 timestamp, pByte data, ushort pid)
{
PesPacket ret;
return ret;