OSDN Git Service

implement PesFile::OpenFile() in TsToPes
authorcocot <cocot@users.sourceforge.jp>
Sat, 4 Apr 2009 13:53:39 +0000 (22:53 +0900)
committercocot <cocot@users.sourceforge.jp>
Sat, 4 Apr 2009 13:53:39 +0000 (22:53 +0900)
src/Mkv.cc
src/TsToPes.cc
src/TsToPes.h
src/Utils.h

index d870d05..d3541ea 100644 (file)
@@ -70,17 +70,95 @@ Int64 EbmlElement::VintToInt64(boost::shared_ptr<Stream> fs)
 
 MkvPesFile::MkvPesFile(BackgroundWorker& bw)
 {
-    return;
+       Clusters = new SortedList<long, EbmlElement>();
+       TrackList = new Dictionary<ushort, TrackInfo>();
+       CurrentIndex = -1;
 }
 
 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(Int32 pcr)
index 446af5f..d36bc9b 100644 (file)
 
 namespace TsRemux
 {
-  static const char PesTemplate[] = { 0x00, 0x00, 0x01, 0xbd};
+static const char PesTemplate[] = { 0x00, 0x00, 0x01, 0xbd};
 
 
+       
+public abstract class PesFile
+{
+                       protected PesFile(BackgroundWorker openWorker)
+                       {
+                               fs = null;
+                               tsior = null;
+                               fileType = TsFileType.UNKNOWN;
+                               startPcr = -1;
+                               endPcr = -1;
+                               sis = null;
+                               pcrDelegate = null;
+                               ptsDelegate = null;
+                               this.openWorker = openWorker;
+                               lastPercent = 0;
+                       }
+                       
+                       protected void ReportProgress(int percent)
+                       {
+                               if (openWorker.CancellationPending)
+                                       {
+                                               throw new ApplicationException("Opening file canceled");
+                                       }
+                               if (lastPercent != percent && percent > 0 && percent <= 100)
+                                       {
+                                               lastPercent = percent;
+                                               openWorker.ReportProgress(percent);
+                                       }
+                       }
+                       
+                       public void SetPcrDelegate(PcrChanged pcr)
+                       {
+                               pcrDelegate = pcr;
+                       }
+                       
+                       public Int64 StartPcr
+                       {
+                               get { return startPcr; }
+                       }
+                       
+                       public Int64 EndPcr
+                       {
+                               get { return endPcr; }
+                       }
+                       
+                       public void SetPtsDelegate(PtsChanged pts)
+                       {
+                               ptsDelegate = pts;
+                       }
+                       
+                       public StreamInfo GetStreamInfo(ushort pid)
+                       {
+                               foreach (StreamInfo si in sis)
+                if (si.ElementaryPID == pid)
+                    return si;
+                               return null;
+                       }
+                       
+                       private void ParseElementaryStreams()
+                       {
+                               Seek(-1);
+                               for (int i = 0; i < 300;)
+                                       {
+                                               ReportProgress(50 + ((50 * i) / 300));
+                                               PesPacket[] ppa = GetNextPesPackets();
+                                               if(ppa == null)
+                                                       goto done;
+                                               foreach (PesPacket pp in ppa)
+                                               {
+                                                       if (null != pp)
+                                                               {
+                                                                       byte[] payload = pp.GetPayload();
+                                                                       StreamInfo si = GetStreamInfo(pp.PID);
+                                                                       if (si != null)
+                                                                               ParseStream(si, payload);
+                                                                       i++;
+                                                               }
+                                                       else
+                                                               goto done;
+                                               }
+                                       }
+                       done:
+                               Seek(-1);
+                       }
+                       
+                       private void ParseStream(StreamInfo si, byte[] payload)
+                       {
+                               switch (si.StreamType)
+                               {
+                                       case ElementaryStreamTypes.VIDEO_STREAM_VC1:
+                                               if ((si.ElementaryDescriptors == null) ||
+                                                       si.FrameRate == FrameRate.Reserved ||
+                                                       si.VideoFormat == VideoFormat.Reserved ||
+                                                       si.AspectRatio == AspectRatio.Reserved)
+                                                       {
+                                                               VC1SequenceInfo sq = new VC1SequenceInfo(payload, 0);
+                                                               if (sq.Valid)
+                                                                       {
+                                                                               if (sq.AspectRatio != AspectRatio.Reserved)
+                                                                                       si.AspectRatio = sq.AspectRatio;
+                                                                               if (sq.FrameRate != FrameRate.Reserved)
+                                                                                       si.FrameRate = sq.FrameRate;
+                                                                               if (sq.VideoFormat != VideoFormat.Reserved)
+                                                                                       si.VideoFormat = sq.VideoFormat;
+                                                                               if (si.ElementaryDescriptors == null)
+                                                                                       si.ElementaryDescriptors = Constants.vc1_descriptor;
+                                                                       }
+                                                       }
+                                               break;
+                                       case ElementaryStreamTypes.AUDIO_STREAM_AC3:
+                                               if ((si.ElementaryDescriptors == null) ||
+                                                       si.AudioPresentationType == AudioPresentationType.Reserved ||
+                                                       si.SamplingFrequency == SamplingFrequency.Reserved)
+                                                       {
+                                                               AC3Info ac3 = new AC3Info(payload, 0);
+                                                               if (ac3.Valid)
+                                                                       {
+                                                                               if (ac3.AudioPresentationType != AudioPresentationType.Reserved)
+                                                                                       si.AudioPresentationType = ac3.AudioPresentationType;
+                                                                               if (ac3.SamplingFrequency != SamplingFrequency.Reserved)
+                                                                                       si.SamplingFrequency = ac3.SamplingFrequency;
+                                                                               if (si.ElementaryDescriptors == null)
+                                                                                       si.ElementaryDescriptors = ac3.ElementaryDescriptors;
+                                                                               if (ac3.SyntaxType == Ac3SyntaxType.Enhanced)
+                                                                                       si.StreamType = ElementaryStreamTypes.AUDIO_STREAM_AC3_PLUS;
+                                                                       }
+                                                       }
+                                               break;
+                                       case ElementaryStreamTypes.AUDIO_STREAM_AC3_PLUS:
+                                               if (si.AudioPresentationType == AudioPresentationType.Reserved ||
+                                                       si.SamplingFrequency == SamplingFrequency.Reserved)
+                                                       {
+                                                               AC3Info ac3 = new AC3Info(payload, 0);
+                                                               if (ac3.Valid)
+                                                                       {
+                                                                               if (ac3.AudioPresentationType != AudioPresentationType.Reserved)
+                                                                                       si.AudioPresentationType = ac3.AudioPresentationType;
+                                                                               if (ac3.SamplingFrequency != SamplingFrequency.Reserved)
+                                                                                       si.SamplingFrequency = ac3.SamplingFrequency;
+                                                                               if (si.ElementaryDescriptors == null)
+                                                                                       si.ElementaryDescriptors = ac3.ElementaryDescriptors;
+                                                                       }
+                                                       }
+                                               break;
+                                       case ElementaryStreamTypes.AUDIO_STREAM_AC3_TRUE_HD:
+                                               if (si.AudioPresentationType == AudioPresentationType.Reserved ||
+                                                       si.SamplingFrequency == SamplingFrequency.Reserved)
+                                                       {
+                                                               MlpInfo ac3 = new MlpInfo(payload, 0);
+                                                               if (ac3.Valid)
+                                                                       {
+                                                                               if (ac3.AudioPresentationType != AudioPresentationType.Reserved)
+                                                                                       si.AudioPresentationType = ac3.AudioPresentationType;
+                                                                               if (ac3.SamplingFrequency != SamplingFrequency.Reserved)
+                                                                                       si.SamplingFrequency = ac3.SamplingFrequency;
+                                                                               if (si.ElementaryDescriptors == null)
+                                                                                       si.ElementaryDescriptors = ac3.ElementaryDescriptors;
+                                                                       }
+                                                       }
+                                               break;
+                                       case ElementaryStreamTypes.VIDEO_STREAM_H264:
+                                               if ((si.ElementaryDescriptors == null) ||
+                                                       si.FrameRate == FrameRate.Reserved ||
+                                                       si.VideoFormat == VideoFormat.Reserved ||
+                                                       si.AspectRatio == AspectRatio.Reserved)
+                                                       {
+                                                               H264Info h264 = new H264Info(payload, 0);
+                                                               if(h264.Valid)
+                                                                       {
+                                                                               if (h264.AspectRatio != AspectRatio.Reserved)
+                                                                                       si.AspectRatio = h264.AspectRatio;
+                                                                               if (h264.FrameRate != FrameRate.Reserved)
+                                                                                       si.FrameRate = h264.FrameRate;
+                                                                               if (h264.VideoFormat != VideoFormat.Reserved)
+                                                                                       si.VideoFormat = h264.VideoFormat;
+                                                                               if (si.ElementaryDescriptors == null)
+                                                                                       si.ElementaryDescriptors = h264.ElementaryDescriptors;
+                                                                       }
+                                                       }
+                                               break;
+                                       case ElementaryStreamTypes.AUDIO_STREAM_DTS:
+                                       case ElementaryStreamTypes.AUDIO_STREAM_DTS_HD:
+                                       case ElementaryStreamTypes.AUDIO_STREAM_DTS_HD_MASTER_AUDIO:
+                                               if (si.AudioPresentationType == AudioPresentationType.Reserved ||
+                                                       si.SamplingFrequency == SamplingFrequency.Reserved)
+                                                       {
+                                                               DtsInfo dts = new DtsInfo(payload, 0);
+                                                               if (dts.Valid)
+                                                                       {
+                                                                               if (dts.AudioPresentationType != AudioPresentationType.Reserved)
+                                                                                       si.AudioPresentationType = dts.AudioPresentationType;
+                                                                               if (dts.SamplingFrequency != SamplingFrequency.Reserved)
+                                                                                       si.SamplingFrequency = dts.SamplingFrequency;
+                                                                       }
+                                                       }
+                                               break;
+                                       case ElementaryStreamTypes.VIDEO_STREAM_MPEG2:
+                                               if ((si.ElementaryDescriptors == null) ||
+                                                       si.FrameRate == FrameRate.Reserved ||
+                                                       si.VideoFormat == VideoFormat.Reserved ||
+                                                       si.AspectRatio == AspectRatio.Reserved)
+                                                       {
+                                                               Mpeg2Info mpeg2 = new Mpeg2Info(payload, 0);
+                                                               if (mpeg2.Valid)
+                                                                       {
+                                                                               if (mpeg2.AspectRatio != AspectRatio.Reserved)
+                                                                                       si.AspectRatio = mpeg2.AspectRatio;
+                                                                               if (mpeg2.FrameRate != FrameRate.Reserved)
+                                                                                       si.FrameRate = mpeg2.FrameRate;
+                                                                               if (mpeg2.VideoFormat != VideoFormat.Reserved)
+                                                                                       si.VideoFormat = mpeg2.VideoFormat;
+                                                                               if (si.ElementaryDescriptors == null)
+                                                                                       si.ElementaryDescriptors = mpeg2.ElementaryDescriptors;
+                                                                       }
+                                                       }
+                                               break;
+                               }
+                       }
+                       
+TsFileType PesFile::GetFileType(FileStream fs)
+{
+       pByte inBuff = pByte(new byte[Constant::STRIDE_SIZE * 7]);
+       int offset;
+       fs.Seek(0, SeekOrigin.Begin);
+       
+       if (fs.Read(inBuff, 0, sizeof(inBuff.get())) != sizeof(inBuff.get()))
+               throw std::invalid_argument("The specified file is too short");
+       
+       // try ts
+       for (offset = 0; offset < Constants::STRIDE_SIZE; offset++)
+       {
+               if (inBuff[offset] == Constants::SYNC_BYTE)
+               {
+                       if (inBuff[offset + Constants::TS_SIZE] == Constants::SYNC_BYTE &&
+                               inBuff[offset + (Constants::TS_SIZE * 2)] == Constants::SYNC_BYTE &&
+                               inBuff[offset + (Constants::TS_SIZE * 3)] == Constants::SYNC_BYTE &&
+                               inBuff[offset + (Constants::TS_SIZE * 4)] == Constants::SYNC_BYTE &&
+                               inBuff[offset + (Constants::TS_SIZE * 5)] == Constants::SYNC_BYTE)
+                               return TsFileType::TS;
+                       else if (inBuff[offset + Constants::STRIDE_SIZE] == Constants::SYNC_BYTE &&
+                                        inBuff[offset + (Constants::STRIDE_SIZE * 2)] == Constants::SYNC_BYTE &&
+                                        inBuff[offset + (Constants::STRIDE_SIZE * 3)] == Constants::SYNC_BYTE &&
+                                        inBuff[offset + (Constants::STRIDE_SIZE * 4)] == Constants::SYNC_BYTE &&
+                                        inBuff[offset + (Constants::STRIDE_SIZE * 5)] == Constants::SYNC_BYTE)
+                               return TsFileTyp::M2TS;
+               }
+       }
+       // try SUP
+       if ((inBuff[0] == (byte)'P' || inBuff[0] == (byte)'p') &&
+               (inBuff[1] == (byte)'G' || inBuff[1] == (byte)'g'))
+               return TsFileType::SUP_ELEMENTARY;
+       // try EVOB
+       UInt32 marker = 0xffffffff;
+       int stuffing = 0;
+       bool packstart = false;
+       for (int i = 0; i < sizeof(inBuff.get()); i++)
+       {
+               marker = marker << 8;
+               marker &= 0xffffff00;
+               marker += inBuff[i];
+               if ((marker & 0xffffff00) == 0x00000100)
+               {
+                       switch (marker & 0xff)
+                       {
+                       case 0xba:
+                               // pack start code
+                               if (sizeof(inBuff.get()) < i + 11)
+                               {
+                                       i = sizeof(inBuff.get());
+                                       break;
+                               }
+                               i += 10;
+                               stuffing = inBuff[i] & 0x7;
+                               if (sizeof(inBuff.get()) < i + stuffing + 1)
+                               {
+                                       i = sizeof(inBuff.get());
+                                       break;
+                               }
+                               i += stuffing;
+                               stuffing = 0;
+                               marker = 0xffffffff;
+                               packstart = true;
+                               break;
+                       default:
+                               // other PES packet
+                               if (sizeof(inBuff.get()) < i + 3)
+                               {
+                                       i = sizeof(inBuff.get());
+                                       break;
+                               }
+                               stuffing = (inBuff[i + 1] << 8) + inBuff[i + 2];
+                               i += 2;
+                               if (sizeof(inBuff.get()) < i + stuffing)
+                                       {
+                                               i = sizeof(inBuff.get());
+                                               break;
+                                       }
+                               i += stuffing;
+                               stuffing = 0;
+                               marker = 0xffffffff;
+                               break;
+                       }
+               }
+       }
+       if (packstart)
+               return TsFileType::EVOB;
+       // try MKV
+       marker = 0xffffffff;
+       for (int i = 0; i < sizeof(inBuff.get()); i++)
+       {
+               marker = marker << 8;
+               marker &= 0xffffff00;
+               marker += inBuff[i];
+               if (marker == Constants::MKVFILE_START)
+                       return TsFileType::MKV;
+       }
+       throw std::invalid_argument("The specified file is not a valid TS/M2TS/EVOB/MKV file");
+}
+                       
+boost::shared_ptr<PesFile> PesFile::OpenFile(string path, bool useAsync, BackgroundWorker openWorker)
+{
+       PesFile pf = null;
+       FileStream fs = null;
+       // pending
+       //      fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, Constant::DISK_BUFFER, useAsync); 
+       try
+       {
+               TsIo tsior = new TsIo(fs, null, Constants::DISK_BUFFER ); 
+               TsFileType fileType = GetFileType(fs);
+               switch (fileType)
+               {
+               case TsFileType::EVOB:
+                       pf = new EvoPesFile(openWorker);
+                       break;
+               case TsFileType::M2TS:
+                       pf = new TsPesFile(openWorker,4);
+                       break;
+               case TsFileType::TS:
+                       pf = new TsPesFile(openWorker,0);
+                       break;
+               case TsFileType::SUP_ELEMENTARY:
+                       pf = new SupPesFile(openWorker);
+                       break;
+               case TsFileType::MKV:
+                       pf = new MkvPesFile(openWorker);
+                       break;
+               }
+               pf.fileType = fileType;
+               pf.fs = fs;
+               pf.tsior = tsior;
+               pf.GetInitialValues();
+               pf.ParseElementaryStreams();
+       }
+       catch (Exception)
+       {
+               fs.Close();
+               throw;
+       }
+       return pf;
+}
+                       
+                       public void CloseFile()
+                       {
+                               fs.Close();
+                               fs = null;
+                               tsior = null;
+                       }
+                       
+                       public void Clear()
+                       {
+                               tsior.Clear();
+                       }
+                       
+                       public TsFileType FileType
+                       {
+                               get { return fileType; }
+                       }
+                       
+                       public StreamInfo[] StreamInfos
+                       {
+                               get { return sis; }
+                       }
+                       
+                       public TimeSpan VideoLength
+                       {
+                               get
+                               {
+                                       Int64 span = endPcr - startPcr;
+                                       if (span < 0)
+                                               span += Constants.MAX_MPEG2TS_CLOCK;
+                                       return new TimeSpan((span * 10) / 27);
+                               }
+                       }
+                       
+                       public abstract PesPacket[] GetNextPesPackets();
+                       public abstract void Seek(Int64 pcr);
+                       public abstract DTCP_Descriptor DtcpInfo { get; }
+                       protected abstract void GetInitialValues();
+               }
+       
+    public class EvoPesFile : PesFile
+               {
+                       private Dictionary<ushort, List<byte>> soundFrames;
+                       private Int64 lastPcr;
+                       
+                       public EvoPesFile(BackgroundWorker bw)
+            : base(bw)
+                       {
+                               soundFrames = new Dictionary<ushort, List<byte>>();
+                               lastPcr = 0 - Constants.MPEG2TS_CLOCK_RATE;
+                       }
+                       
+                       public override DTCP_Descriptor DtcpInfo
+                       {
+                               get { return null; }
+                       }
+                       
+                       protected override void GetInitialValues()
+                       {
+                               GetTimeStamps();
+                               
+                               Dictionary<byte, StreamInfo> evoStreams = new Dictionary<byte, StreamInfo>();
+                               fs.Seek(0, SeekOrigin.Begin);
+                               byte[] inBuff = new byte[Constants.DISK_BUFFER]; // 72MB IS TOO BIG! CAUSES FAILURE: << 2]; note this was line 463
+                               int Length = fs.Read(inBuff, 0, inBuff.Length);
+                               UInt32 marker = 0xffffffff;
+                               int stuffing = 0;
+                               for (int i = 0; i < Length; i++)
+                                       {
+                                               ReportProgress(50 * i / Length);
+                                               marker = marker << 8;
+                                               marker &= 0xffffff00;
+                                               marker += inBuff[i];
+                                               if ((marker & 0xffffff00) == 0x00000100)
+                                                       {
+                                                               switch (marker & 0xff)
+                                                               {
+                                                                       case 0xba:
+                                                                               // pack start code
+                                                                               if (Length <= i + 10)
+                                                                                       {
+                                                                                               i = Length;
+                                                                                               break;
+                                                                                       }
+                                                                               i += 10;
+                                                                               stuffing = inBuff[i] & 0x7;
+                                                                               if (Length <= i + stuffing)
+                                                                                       {
+                                                                                               i = Length;
+                                                                                               break;
+                                                                                       }
+                                                                               i += stuffing;
+                                                                               stuffing = 0;
+                                                                               break;
+                                                                       default:
+                                                                               if (inBuff[i] == Constants.PES_PRIVATE1)
+                                                                                       {
+                                                                                               // skip to the end of the header
+                                                                                               int endOfHeader = i + 6 + inBuff[i + 5];
+                                                                                               if (inBuff.Length > endOfHeader + 4)
+                                                                                                       {
+                                                                                                               if ((inBuff[endOfHeader] & 0xe0) == Constants.PES_PRIVATE_SUBTITLE)
+                                                                                                                       {
+                                                                                                                               byte subid = inBuff[endOfHeader];
+                                                                                                                               if (evoStreams.ContainsKey(subid) == false)
+                                                                                                                                       {
+                                                                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.PRESENTATION_GRAPHICS_STREAM, subid);
+                                                                                                                                               evoStreams.Add(subid, si);
+                                                                                                                                       }
+                                                                                                                       }
+                                                                                                               else if ((inBuff[endOfHeader] & 0xf8) == Constants.PES_PRIVATE_AC3)
+                                                                                                                       {
+                                                                                                                               byte subid = inBuff[endOfHeader];
+                                                                                                                               if (evoStreams.ContainsKey(subid) == false)
+                                                                                                                                       {
+                                                                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_AC3, subid);
+                                                                                                                                               evoStreams.Add(subid, si);
+                                                                                                                                       }
+                                                                                                                       }
+                                                                                                               else if ((inBuff[endOfHeader] & 0xf8) == Constants.PES_PRIVATE_DTS_HD)
+                                                                                                                       {
+                                                                                                                               byte subid = inBuff[endOfHeader];
+                                                                                                                               if (evoStreams.ContainsKey(subid) == false)
+                                                                                                                                       {
+                                                                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_DTS_HD, subid);
+                                                                                                                                               evoStreams.Add(subid, si);
+                                                                                                                                       }
+                                                                                                                       }
+                                                                                                               else if ((inBuff[endOfHeader] & 0xf0) == Constants.PES_PRIVATE_AC3_PLUS)
+                                                                                                                       {
+                                                                                                                               byte subid = inBuff[endOfHeader];
+                                                                                                                               if (evoStreams.ContainsKey(subid) == false)
+                                                                                                                                       {
+                                                                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_AC3_PLUS, subid);
+                                                                                                                                               evoStreams.Add(subid, si);
+                                                                                                                                       }
+                                                                                                                       }
+                                                                                                               else if ((inBuff[endOfHeader] & 0xf8) == Constants.PES_PRIVATE_LPCM)
+                                                                                                                       {
+                                                                                                                               byte subid = inBuff[endOfHeader];
+                                                                                                                               if (evoStreams.ContainsKey(subid) == false)
+                                                                                                                                       {
+                                                                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_LPCM, subid);
+                                                                                                                                               evoStreams.Add(subid, si);
+                                                                                                                                       }
+                                                                                                                       }
+                                                                                                               else if ((inBuff[endOfHeader] & 0xf8) == Constants.PES_PRIVATE_AC3_TRUE_HD)
+                                                                                                                       {
+                                                                                                                               byte subid = inBuff[endOfHeader];
+                                                                                                                               if (evoStreams.ContainsKey(subid) == false)
+                                                                                                                                       {
+                                                                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_AC3_TRUE_HD, subid);
+                                                                                                                                               evoStreams.Add(subid, si);
+                                                                                                                                       }
+                                                                                                                       }
+                                                                                                       }
+                                                                                       }
+                                                                               else if ((inBuff[i] & 0xe0) == Constants.PES_AUDIO_MPEG)
+                                                                                       {
+                                                                                               byte subid = inBuff[i];
+                                                                                               if (evoStreams.ContainsKey(subid) == false)
+                                                                                                       {
+                                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_MPEG2, subid);
+                                                                                                               evoStreams.Add(subid, si);
+                                                                                                       }
+                                                                                       }
+                                                                               else if ((inBuff[i] & 0xf0) == Constants.PES_VIDEO)
+                                                                                       {
+                                                                                               byte subid = inBuff[i];
+                                                                                               if (evoStreams.ContainsKey(subid) == false)
+                                                                                                       {
+                                                                                                               // need to differenciate between H.264 and MPEG2
+                                                                                                               if (Length <= i + 5)
+                                                                                                                       {
+                                                                                                                               i = Length;
+                                                                                                                               break;
+                                                                                                                       }
+                                                                                                               ElementaryStreamTypes videoFormat = ElementaryStreamTypes.INVALID;
+                                                                                                               int startIndex = i + 6 + inBuff[i + 5];
+                                                                                                               if (Length <= startIndex + 3)
+                                                                                                                       {
+                                                                                                                               i = Length;
+                                                                                                                               break;
+                                                                                                                       }
+                                                                                                               UInt32 format = (UInt32)inBuff[startIndex] << 24;
+                                                                                                               format += (UInt32)inBuff[startIndex + 1] << 16;
+                                                                                                               format += (UInt32)inBuff[startIndex + 2] << 8;
+                                                                                                               format += inBuff[startIndex + 3];
+                                                                                                               if ((format & 0xffff) == 0x1)
+                                                                                                                       {
+                                                                                                                               videoFormat = ElementaryStreamTypes.VIDEO_STREAM_H264;
+                                                                                                                               StreamInfo si = new StreamInfo(videoFormat, subid);
+                                                                                                                               evoStreams.Add(subid, si);
+                                                                                                                       }
+                                                                                                               else if ((format & 0xffffff00) == 0x100)
+                                                                                                                       {
+                                                                                                                               videoFormat = ElementaryStreamTypes.VIDEO_STREAM_MPEG2;
+                                                                                                                               StreamInfo si = new StreamInfo(videoFormat, subid);
+                                                                                                                               evoStreams.Add(subid, si);
+                                                                                                                       }
+                                                                                                       }
+                                                                                       }
+                                                                               else if (inBuff[i] == Constants.PES_VIDEO_VC1)
+                                                                                       {
+                                                                                               byte subid = GetVC1SubstreamId(inBuff, i + 3);
+                                                                                               if (subid != 0 && evoStreams.ContainsKey(subid) == false)
+                                                                                                       {
+                                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.VIDEO_STREAM_VC1, subid);
+                                                                                                               si.ElementaryDescriptors = Constants.vc1_descriptor;
+                                                                                                               evoStreams.Add(subid, si);
+                                                                                                       }
+                                                                                       }
+                                                                               
+                                                                               // other PES packet
+                                                                               if (Length < i + 3)
+                                                                                       {
+                                                                                               i = Length;
+                                                                                               break;
+                                                                                       }
+                                                                               stuffing = (inBuff[i + 1] << 8) + inBuff[i + 2];
+                                                                               i += 2;
+                                                                               if (Length < i + stuffing)
+                                                                                       {
+                                                                                               i = Length;
+                                                                                               break;
+                                                                                       }
+                                                                               i += stuffing;
+                                                                               stuffing = 0;
+                                                                               break;
+                                                               }
+                                                               marker = 0xffffffff;
+                                                       }
+                                       }
+                               if (evoStreams.Count > 0)
+                                       {
+                                               sis = new StreamInfo[evoStreams.Values.Count];
+                                               evoStreams.Values.CopyTo(sis, 0);
+                                       }
+                       }
+                       
+                       public override PesPacket[] GetNextPesPackets()
+                       {
+                               // there was a big optimization opportunity here:
+                               // this method added to partial packets one byte at a time
+                               // the calls to PesPacket.AddData used about 40% of total CPU 
+                               byte[] inData = new byte[1];
+                               byte[] inData2 = new byte[128]; 
+                               int bytesRead = 0;
+                               int bytesToRead = 0;
+                               int bytesToGo = 0;
+                               UInt32 marker = 0xffffffff;
+                               PesPacket pp = null;
+                               PesPacket partial = null;
+                               int i = 0;
+                               while (tsior.Read(inData, 0, inData.Length) == inData.Length)
+                                       {
+                                               marker = marker << 8;
+                                               marker &= 0xffffff00;
+                                               marker += inData[0];
+                                               if ((marker & 0xffffff00) == 0x00000100)
+                                                       {
+                                                               if ((marker & 0xff) == Constants.PACK_ID)
+                                                                       {
+                                                                               // pack start code
+                                                                               UInt64 header = 0;
+                                                                               for (i = 4; i < 10; i++)
+                                                                                       {
+                                                                                               if (tsior.Read(inData, 0, inData.Length) != inData.Length)
+                                                                                                       goto done;
+                                                                                               header <<= 8;
+                                                                                               header |= inData[0];
+                                                                                       }
+                                                                               for (i = 10; i < 14; i++) // skip mux rate etc.
+                                                                                       {
+                                                                                               if (tsior.Read(inData, 0, inData.Length) != inData.Length)
+                                                                                                       goto done;
+                                                                                       }
+                                                                               Int64 pcr = (Int64)((header & 0x380000000000) >> 13);
+                                                                               pcr |= (Int64)((header & 0x3fff8000000) >> 12);
+                                                                               pcr |= (Int64)((header & 0x3fff800) >> 11);
+                                                                               pcr *= 300;
+                                                                               pcr |= (Int64)((header & 0x3fe) >> 1);
+                                                                               Int64 delta = pcr - lastPcr;
+                                                                               if (delta > Constants.MPEG2TS_CLOCK_RATE / 9)
+                                                                                       {
+                                                                                               if (pcrDelegate != null)
+                                                                                                       pcrDelegate(pcr);
+                                                                                               lastPcr = pcr;
+                                                                                       }
+                                                                       }
+                                                               else if (((marker & 0xff) == Constants.SYS_ID)
+                                                                                || ((marker & 0xff) == Constants.MAP_ID)
+                                                                                || ((marker & 0xff) == Constants.PAD_ID)
+                                                                                || ((marker & 0xff) == Constants.DIR_ID))
+                                                                       {
+                                                                               ushort Length = 0;
+                                                                               for (i = 4; i < 6; i++)
+                                                                                       {
+                                                                                               if (tsior.Read(inData, 0, inData.Length) != inData.Length)
+                                                                                                       goto done;
+                                                                                               Length <<= 8;
+                                                                                               Length |= inData[0];
+                                                                                       }
+                                                                               Length += 6;
+                                                                               for (i = 6; i < Length; i++)
+                                                                                       {
+                                                                                               if (tsior.Read(inData, 0, inData.Length) != inData.Length)
+                                                                                                       goto done;
+                                                                                       }
+                                                                       }
+                                                               else
+                                                                       {
+                                                                               byte end = inData[0];
+                                                                               inData[0] = 0;
+                                                                               partial = new PesPacket(inData, 0, 1, 0);
+                                                                               partial.AddData(inData, 0, 1);
+                                                                               inData[0] = 1;
+                                                                               partial.AddData(inData, 0, 1);
+                                                                               inData[0] = end;
+                                                                               partial.AddData(inData, 0, 1);
+                                                                               ushort Length = 0;
+                                                                               for (i = 4; i < 6; i++)
+                                                                                       {
+                                                                                               if (tsior.Read(inData, 0, inData.Length) != inData.Length)
+                                                                                                       goto done;
+                                                                                               partial.AddData(inData, 0, 1);
+                                                                                               Length <<= 8;
+                                                                                               Length |= inData[0];
+                                                                                       }
+                                                                               Length += 6;
+                                                                               // we don't need this byte-by-byte loop here, as we have just gotten the length:
+                                                                               /*
+                                                                                for (i = 6; i < Length; i++)
+                                                                                {
+                                                                                if (tsior.Read(inData, 0, inData.Length) != inData.Length)
+                                                                                goto done;
+                                                                                partial.AddData(inData, 0, 1);
+                                                                                }
+                                                                                */
+                                                                               bytesToGo = Length - 6;
+                                                                               while (bytesToGo > 0)
+                                                                                       {
+                                                                                               bytesToRead = (bytesToGo > inData2.Length) ? inData2.Length : bytesToGo;
+                                                                                               if ((bytesRead = tsior.Read(inData2, 0, bytesToRead)) != bytesToRead)
+                                                                                                       goto done;
+                                                                                               partial.AddData(inData2, 0, bytesRead);
+                                                                                               bytesToGo -= bytesRead;
+                                                                                       }
+                                                                               pp = partial;
+                                                                               PesHeader ph = partial.GetHeader();
+                                                                               if (partial.BaseId == Constants.PES_PRIVATE1)
+                                                                                       {
+                                                                                               if ((partial.ExtendedId & 0xf0) == Constants.PES_PRIVATE_AC3_PLUS ||
+                                                                                                       (partial.ExtendedId & 0xf8) == Constants.PES_PRIVATE_AC3)
+                                                                                                       {
+                                                                                                               if (soundFrames.ContainsKey(partial.ExtendedId) == false)
+                                                                                                                       soundFrames.Add(partial.ExtendedId, new List<byte>());
+                                                                                                               byte[] tempd = partial.GetPayload();
+                                                                                                               for (int j = 4; j < tempd.Length; j++)
+                                                                                                                       soundFrames[partial.ExtendedId].Add(tempd[j]);
+                                                                                                               tempd = soundFrames[partial.ExtendedId].ToArray();
+                                                                                                               int len = 0;
+                                                                                                               ushort mk2 = 0xffff;
+                                                                                                               if (tempd.Length > 2 && tempd[0] == (byte)(Constants.AC3_SYNC >> 8) &&
+                                                                                                                       tempd[1] == (byte)(Constants.AC3_SYNC & 0xff))
+                                                                                                                       {
+                                                                                                                               pp = null;
+                                                                                                                               while (tempd.Length > 2 && tempd[0] == (byte)(Constants.AC3_SYNC >> 8)
+                                                                                                                                          && tempd[1] == (byte)(Constants.AC3_SYNC & 0xff))
+                                                                                                                                       {
+                                                                                                                                               AC3Info ac3 = new AC3Info(tempd, 0);
+                                                                                                                                               if (ac3.Valid == false || ac3.FrameLength == 0 || tempd.Length < ac3.FrameLength)
+                                                                                                                                                       break;
+                                                                                                                                               if (pp == null)
+                                                                                                                                                       pp = new PesPacket(partial.GetData(), 0, ph.TotalHeaderLength, partial.ExtendedId);
+                                                                                                                                               pp.AddData(tempd, 0, ac3.FrameLength);
+                                                                                                                                               soundFrames[partial.ExtendedId].RemoveRange(0, ac3.FrameLength);
+                                                                                                                                               tempd = soundFrames[partial.ExtendedId].ToArray();
+                                                                                                                                       }
+                                                                                                                               if (pp != null)
+                                                                                                                                       {
+                                                                                                                                               pp.Complete = true;
+                                                                                                                                               goto done;
+                                                                                                                                       }
+                                                                                                                       }
+                                                                                                               for (int j = 2; j < tempd.Length; j++)
+                                                                                                                       {
+                                                                                                                               mk2 <<= 8;
+                                                                                                                               mk2 |= tempd[j];
+                                                                                                                               if (mk2 == Constants.AC3_SYNC)
+                                                                                                                                       {
+                                                                                                                                               len = j - 1;
+                                                                                                                                               mk2 = 0xffff;
+                                                                                                                                               break;
+                                                                                                                                       }
+                                                                                                                       }
+                                                                                                               if (len == 0)
+                                                                                                                       len = tempd.Length;
+                                                                                                               soundFrames[partial.ExtendedId].RemoveRange(0, len);
+                                                                                                               pp = new PesPacket(partial.GetData(), 0, ph.TotalHeaderLength, partial.ExtendedId);
+                                                                                                               pp.AddData(tempd, 0, len);
+                                                                                                               pp.Complete = true;
+                                                                                                       }
+                                                                                               else if ((partial.ExtendedId & 0xf8) == Constants.PES_PRIVATE_AC3_TRUE_HD)
+                                                                                                       {
+                                                                                                               if (soundFrames.ContainsKey(partial.ExtendedId) == false)
+                                                                                                                       soundFrames.Add(partial.ExtendedId, new List<byte>());
+                                                                                                               byte[] tempd = partial.GetPayload();
+                                                                                                               for (int j = 5; j < tempd.Length; j++)
+                                                                                                                       soundFrames[partial.ExtendedId].Add(tempd[j]);
+                                                                                                               tempd = soundFrames[partial.ExtendedId].ToArray();
+                                                                                                               int len = tempd.Length;
+                                                                                                               /*
+                                                                                                                UInt32 mk2 = 0xffffffff;
+                                                                                                                for (int j = 5; j < tempd.Length; j++)
+                                                                                                                {
+                                                                                                                mk2 <<= 8;
+                                                                                                                mk2 |= tempd[j];
+                                                                                                                if (mk2 == Constants.MLP_SYNC)
+                                                                                                                {
+                                                                                                                len = j - 3;
+                                                                                                                mk2 = 0xffffffff;
+                                                                                                                }
+                                                                                                                }
+                                                                                                                if (len == 0)
+                                                                                                                {
+                                                                                                                len = tempd.Length;
+                                                                                                                }
+                                                                                                                */
+                                                                                                               soundFrames[partial.ExtendedId].RemoveRange(0, len);
+                                                                                                               pp = new PesPacket(partial.GetData(), 0, ph.TotalHeaderLength, partial.ExtendedId);
+                                                                                                               pp.AddData(tempd, 0, len);
+                                                                                                               pp.Complete = true;
+                                                                                                       }
+                                                                                               else if ((partial.ExtendedId & 0xf8) == Constants.PES_PRIVATE_LPCM)
+                                                                                                       {
+                                                                                                               if (soundFrames.ContainsKey(partial.ExtendedId) == false)
+                                                                                                                       soundFrames.Add(partial.ExtendedId, new List<byte>());
+                                                                                                               byte[] tempd = partial.GetPayload();
+                                                                                                               for (int j = 7; j < tempd.Length; j++)
+                                                                                                                       soundFrames[partial.ExtendedId].Add(tempd[j]);
+                                                                                                               tempd = soundFrames[partial.ExtendedId].ToArray();
+                                                                                                               int len = tempd.Length;
+                                                                                                               /*
+                                                                                                                UInt32 mk2 = 0xffffffff;
+                                                                                                                for (int j = 5; j < tempd.Length; j++)
+                                                                                                                {
+                                                                                                                mk2 <<= 8;
+                                                                                                                mk2 |= tempd[j];
+                                                                                                                if (mk2 == Constants.MLP_SYNC)
+                                                                                                                {
+                                                                                                                len = j - 3;
+                                                                                                                mk2 = 0xffffffff;
+                                                                                                                }
+                                                                                                                }
+                                                                                                                if (len == 0)
+                                                                                                                {
+                                                                                                                len = tempd.Length;
+                                                                                                                }
+                                                                                                                */
+                                                                                                               soundFrames[partial.ExtendedId].RemoveRange(0, len);
+                                                                                                               pp = new PesPacket(partial.GetData(), 0, ph.TotalHeaderLength, partial.ExtendedId);
+                                                                                                               pp.AddData(tempd, 0, len);
+                                                                                                               pp.Complete = true;
+                                                                                                       }
+                                                                                               else if ((partial.ExtendedId & 0xf8) == Constants.PES_PRIVATE_DTS_HD)
+                                                                                                       {
+                                                                                                               if (soundFrames.ContainsKey(partial.ExtendedId) == false)
+                                                                                                                       soundFrames.Add(partial.ExtendedId, new List<byte>());
+                                                                                                               byte[] tempd = partial.GetPayload();
+                                                                                                               for (int j = 4; j < tempd.Length; j++)
+                                                                                                                       soundFrames[partial.ExtendedId].Add(tempd[j]);
+                                                                                                               tempd = soundFrames[partial.ExtendedId].ToArray();
+                                                                                                               int len = 0;
+                                                                                                               UInt32 mk2 = 0xffffffff;
+                                                                                                               for (int j = 4; j < tempd.Length; j++)
+                                                                                                                       {
+                                                                                                                               mk2 <<= 8;
+                                                                                                                               mk2 |= tempd[j];
+                                                                                                                               if (mk2 == Constants.DTS_SYNC)
+                                                                                                                                       {
+                                                                                                                                               len = j - 3;
+                                                                                                                                               mk2 = 0xffffffff;
+                                                                                                                                       }
+                                                                                                                       }
+                                                                                                               if (len == 0)
+                                                                                                                       {
+                                                                                                                               DtsInfo dts = new DtsInfo(tempd, 0);
+                                                                                                                               if (dts.Valid && (int)dts.FrameSize < tempd.Length &&
+                                                                                                                                       (tempd.Length - (int)dts.FrameSize < 4))
+                                                                                                                                       len = (int)dts.FrameSize;
+                                                                                                                               else
+                                                                                                                                       len = tempd.Length;
+                                                                                                                       }
+                                                                                                               soundFrames[partial.ExtendedId].RemoveRange(0, len);
+                                                                                                               pp = new PesPacket(partial.GetData(), 0, ph.TotalHeaderLength, partial.ExtendedId);
+                                                                                                               pp.AddData(tempd, 0, len);
+                                                                                                               pp.Complete = true;
+                                                                                                       }
+                                                                                               else
+                                                                                                       pp.PID = pp.ExtendedId;
+                                                                                       }
+                                                                               else if (pp.BaseId == Constants.PES_PADDING || pp.BaseId == Constants.PES_PRIVATE2)
+                                                                                       {
+                                                                                               marker = 0xffffffff;
+                                                                                               continue;
+                                                                                       }
+                                                                               else if (((pp.BaseId & 0xe0) == Constants.PES_AUDIO_MPEG)
+                                                                                                || ((pp.BaseId & 0xf0) == Constants.PES_VIDEO))
+                                                                                       pp.PID = pp.BaseId;
+                                                                               else if (pp.BaseId == Constants.PES_VIDEO_VC1 && ph != null)
+                                                                                       pp.PID = ph.Extention2;
+                                                                               if (ph != null && ph.HasPts)
+                                                                                       {
+                                                                                               if (ptsDelegate != null)
+                                                                                                       ptsDelegate(ph.Pts, pp.PID);
+                                                                                       }
+                                                                               goto done;
+                                                                       }
+                                                               marker = 0xffffffff;
+                                                       }
+                                       }
+                       done:
+                               if (null != pp)
+                                       {
+                                               PesPacket[] ppa = new PesPacket[1];
+                                               ppa[0] = pp;
+                                               return ppa;
+                                       }
+                               else
+                                       return null;
+                       }
+                       
+                       public override void Seek(long pcr)
+                       {
+                               tsior.Clear();
+                               
+                               if (pcr == -1)
+                                       {
+                                               fs.Seek(0, SeekOrigin.Begin);
+                                               return;
+                                       }
+                               
+                               int packetSize = sizeof(byte);
+                               Int64 span = endPcr - startPcr;
+                               if (span < 0)
+                                       span += Constants.MAX_MPEG2TS_CLOCK;
+                               Int64 pcrPerByte = span / fs.Length;
+                               Int64 seek = pcr - startPcr;
+                               if (seek < 0)
+                                       seek += Constants.MAX_MPEG2TS_CLOCK;
+                               Int64 length = seek / pcrPerByte;
+                               length /= packetSize;
+                               length *= packetSize;
+                               if (length > fs.Length)
+                                       length = fs.Length;
+                               fs.Seek(length, SeekOrigin.Begin);
+                               bool found = false;
+                               
+                               while (found == false)
+                                       {
+                                               Int64 offset = GetCurrentPcrFromFile();
+                                               if (-1 == offset)
+                                                       offset = endPcr;
+                                               offset -= pcr;
+                                               if (offset > Constants.MAX_MPEG2TS_CLOCK / 2)
+                                                       offset -= Constants.MAX_MPEG2TS_CLOCK;
+                                               else if (offset < (0 - (Constants.MAX_MPEG2TS_CLOCK / 2)))
+                                                       offset += Constants.MAX_MPEG2TS_CLOCK;
+                                               Int64 target = offset / Constants.MPEG2TS_CLOCK_RATE;
+                                               if (target > 0)
+                                                       {
+                                                               offset /= pcrPerByte;
+                                                               offset >>= 2;
+                                                               offset /= packetSize;
+                                                               offset *= packetSize;
+                                                               fs.Seek(0 - offset, SeekOrigin.Current);
+                                                       }
+                                               else if (target < 0)
+                                                       {
+                                                               offset /= pcrPerByte;
+                                                               offset >>= 2;
+                                                               offset /= packetSize;
+                                                               offset *= packetSize;
+                                                               fs.Seek(0 - offset, SeekOrigin.Current);
+                                                       }
+                                               else
+                                                       break;
+                                       }
+                       }
+                       
+                       private void GetTimeStamps()
+                       {
+                               fs.Seek(0, SeekOrigin.Begin);
+                               UInt64 header = 0xffffffff;
+                               byte b = 0;
+                               int packsize_reading = -1;
+                               for (int i = 0; i < Constants.DISK_BUFFER; i++)
+                                       {
+                                               int ib = fs.ReadByte();
+                                               if (ib == -1)
+                                                       throw new FormatException("The specified file is too short");
+                                               b = (byte)(ib & 0xff);
+                                               header <<= 8;
+                                               header |= b;
+                                               if ((header & 0xffffffff) == 0x000001ba)
+                                                       {
+                                                               // pack start code
+                                                               packsize_reading = 5;
+                                                       }
+                                               else if (packsize_reading > 0)
+                                                       packsize_reading--;
+                                               else if (packsize_reading == 0)
+                                                       {
+                                                               startPcr = (Int64)((header & 0x380000000000) >> 13);
+                                                               startPcr |= (Int64)((header & 0x3fff8000000) >> 12);
+                                                               startPcr |= (Int64)((header & 0x3fff800) >> 11);
+                                                               startPcr *= 300;
+                                                               startPcr |= (Int64)((header & 0x3fe) >> 1);
+                                                               break;
+                                                       }
+                                       }
+                               int lseek = -15;
+                               fs.Seek(lseek, SeekOrigin.End);
+                               header = 0xffffffff;
+                               b = 0;
+                               packsize_reading = -1;
+                               for (int i = 0; i < Constants.DISK_BUFFER; i++)
+                                       {
+                                               for (int j = 0; j < 12; j++)
+                                                       {
+                                                               int ib = fs.ReadByte();
+                                                               if (ib == -1)
+                                                                       throw new FormatException("The specified file is too short");
+                                                               b = (byte)(ib & 0xff);
+                                                               header <<= 8;
+                                                               header |= b;
+                                                               if ((header & 0xffffffff) == 0x000001ba)
+                                                                       {
+                                                                               // pack start code
+                                                                               packsize_reading = 5;
+                                                                       }
+                                                               else if (packsize_reading > 0)
+                                                                       packsize_reading--;
+                                                               else if (packsize_reading == 0)
+                                                                       {
+                                                                               endPcr = (Int64)((header & 0x380000000000) >> 13);
+                                                                               endPcr |= (Int64)((header & 0x3fff8000000) >> 12);
+                                                                               endPcr |= (Int64)((header & 0x3fff800) >> 11);
+                                                                               endPcr *= 300;
+                                                                               endPcr |= (Int64)((header & 0x3fe) >> 1);
+                                                                               break;
+                                                                       }
+                                                       }
+                                               if (packsize_reading == 0)
+                                                       break;
+                                               lseek--;
+                                               fs.Seek(lseek, SeekOrigin.End);
+                                               
+                                       }
+                       }
+                       
+                       private byte GetVC1SubstreamId(byte[] buff, int offset)
+                       {
+                               if (buff.Length <= offset + 3)
+                                       return 0;
+                               if ((buff[offset] & 0xc0) != 0x80)
+                                       return 0; // first two bits must be '10'
+                               byte PTS_DTS_flags = (byte)(buff[offset + 1] & 0xc0);
+                               byte ESCR_flag = (byte)(buff[offset + 1] & 0x20);
+                               byte ES_rate_flag = (byte)(buff[offset + 1] & 0x10);
+                               byte DSM_trick_mode_flag = (byte)(buff[offset + 1] & 0x08);
+                               byte additional_copy_info_flag = (byte)(buff[offset + 1] & 0x04);
+                               byte PES_CRC_flag = (byte)(buff[offset + 1] & 0x02);
+                               byte PES_extension_flag = (byte)(buff[offset + 1] & 0x01);
+                               if (buff[offset + 2] == 0)
+                                       return 0;
+                               int length = offset + buff[offset + 2] + 3;
+                               if (buff.Length < length)
+                                       return 0;
+                               offset += 3;
+                               if (PTS_DTS_flags == 0x80)
+                                       offset += 5;
+                               if (PTS_DTS_flags == 0xc0)
+                                       offset += 10;
+                               if (ESCR_flag > 0)
+                                       offset += 6;
+                               if (ES_rate_flag > 0)
+                                       offset += 3;
+                               if (DSM_trick_mode_flag > 0)
+                                       offset += 1;
+                               if (additional_copy_info_flag > 0)
+                                       offset += 1;
+                               if (PES_CRC_flag > 0)
+                                       offset += 2;
+                               if (PES_extension_flag == 0)
+                                       return 0;
+                               byte PES_private_data_flag = (byte)(buff[offset] & 0x80);
+                               byte pack_header_field_flag = (byte)(buff[offset] & 0x40);
+                               byte program_packet_sequence_counter_flag = (byte)(buff[offset] & 0x20);
+                               byte PSTD_buffer_flag = (byte)(buff[offset] & 0x10);
+                               byte PES_extension_flag_2 = (byte)(buff[offset] & 0x01);
+                               offset++;
+                               if (PES_private_data_flag > 0)
+                                       offset += 25;
+                               if (pack_header_field_flag > 0)
+                                       offset += (buff[offset] + 1);
+                               if (program_packet_sequence_counter_flag > 0)
+                                       offset += 2;
+                               if (PSTD_buffer_flag > 0)
+                                       offset += 2;
+                               if (PES_extension_flag_2 == 0)
+                                       return 0;
+                               if (buff[offset] != 0x81)
+                                       return 0;
+                               return buff[offset + 1];
+                       }
+                       
+                       private Int64 GetCurrentPcrFromFile()
+                       {
+                               UInt64 header = 0xffffffff;
+                               byte b = 0;
+                               int packsize_reading = -1;
+                               for (int i = 0; i < Constants.DISK_BUFFER; i++)
+                                       {
+                                               int ib = fs.ReadByte();
+                                               if (ib == -1)
+                                                       return -1;
+                                               b = (byte)(ib & 0xff);
+                                               header <<= 8;
+                                               header |= b;
+                                               if ((header & 0xffffffff) == 0x000001ba)
+                                                       {
+                                                               // pack start code
+                                                               packsize_reading = 5;
+                                                       }
+                                               else if (packsize_reading > 0)
+                                                       packsize_reading--;
+                                               else if (packsize_reading == 0)
+                                                       {
+                                                               Int64 pcr = (Int64)((header & 0x380000000000) >> 13);
+                                                               pcr |= (Int64)((header & 0x3fff8000000) >> 12);
+                                                               pcr |= (Int64)((header & 0x3fff800) >> 11);
+                                                               pcr *= 300;
+                                                               pcr |= (Int64)((header & 0x3fe) >> 1);
+                                                               return pcr;
+                                                       }
+                                       }
+                               return -1;
+                       }
+               }
+       
+    public class SupPesFile : PesFile
+               {
+                       private static readonly byte[] PesTemplate = new byte[4] {
+            0x00, 0x00, 0x01, 0xbd};
+                       
+                       public SupPesFile(BackgroundWorker bw) : base(bw) { }
+                       
+                       public override DTCP_Descriptor DtcpInfo
+                       {
+                               get { return null; }
+                       }
+                       
+                       protected override void GetInitialValues()
+                       {
+                               GetTimeStamps();
+                               this.sis = new StreamInfo[1];
+                               this.sis[0] = new StreamInfo(ElementaryStreamTypes.PRESENTATION_GRAPHICS_STREAM, Constants.DEFAULT_PRESENTATION_GRAPHICS_PID);
+                       }
+                       
+                       public override PesPacket[] GetNextPesPackets()
+                       {
+                               byte b0 = 0;
+                               byte b1 = 0;
+                               byte[] inData = new byte[1];
+                               byte[] pgHeader = new byte[3];
+                               
+                               while (tsior.Read(inData, 0, inData.Length) == inData.Length)
+                                       {
+                                               b0 = b1;
+                                               b1 = inData[0];
+                                               if ((b0 == (byte)'P' || b0 == (byte)'p') &&
+                                                       (b1 == (byte)'G' || b1 == (byte)'g'))
+                                                       {
+                                                               Int64 Pts = 0;
+                                                               Int64 Dts = 0;
+                                                               ushort len = 0;
+                                                               for (int k = 0; k < 4; k++)
+                                                                       {
+                                                                               if (0 == tsior.Read(inData, 0, inData.Length))
+                                                                                       return null;
+                                                                               Pts <<= 8;
+                                                                               Pts |= inData[0];
+                                                                       }
+                                                               Pts <<= 1;
+                                                               if (ptsDelegate != null)
+                                                                       ptsDelegate(Pts, sis[0].ElementaryPID);
+                                                               for (int k = 0; k < 4; k++)
+                                                                       {
+                                                                               if (0 == tsior.Read(inData, 0, inData.Length))
+                                                                                       return null;
+                                                                               Dts <<= 8;
+                                                                               Dts |= inData[0];
+                                                                       }
+                                                               Dts <<= 1;
+                                                               for (int k = 0; k < 3; k++)
+                                                                       {
+                                                                               if (0 == tsior.Read(inData, 0, inData.Length))
+                                                                                       return null;
+                                                                               pgHeader[k] = inData[0];
+                                                                               if (k > 0)
+                                                                                       {
+                                                                                               len <<= 8;
+                                                                                               len |= inData[0];
+                                                                                       }
+                                                                       }
+                                                               byte hlen = (byte)(Dts == 0 ? 0x05 : 0x0a);
+                                                               ushort plen = (ushort)(6 + hlen + len);
+                                                               PesPacket pp = new PesPacket(PesTemplate, 0, PesTemplate.Length, sis[0].ElementaryPID);
+                                                               inData[0] = (byte)((plen >> 8) & 0xff);
+                                                               pp.AddData(inData, 0, 1);
+                                                               inData[0] = (byte)(plen & 0xff);
+                                                               pp.AddData(inData, 0, 1);
+                                                               inData[0] = 0x81;
+                                                               pp.AddData(inData, 0, 1);
+                                                               inData[0] = (byte)(Dts == 0 ? 0x80 : 0xc0);
+                                                               pp.AddData(inData, 0, 1);
+                                                               inData[0] = hlen;
+                                                               pp.AddData(inData, 0, 1);
+                                                               byte old = (byte)(Dts == 0 ? 0x21 : 0x31);
+                                                               inData[0] = (byte)(((Pts & 0x1C0000000) >> 29) | old);
+                                                               pp.AddData(inData, 0, 1);
+                                                               inData[0] = (byte)((Pts & 0x3fC00000) >> 22);
+                                                               pp.AddData(inData, 0, 1);
+                                                               inData[0] = (byte)(((Pts & 0x3f8000) >> 14) | 0x01);
+                                                               pp.AddData(inData, 0, 1);
+                                                               inData[0] = (byte)((Pts & 0x7f80) >> 7);
+                                                               pp.AddData(inData, 0, 1);
+                                                               inData[0] = (byte)(((Pts & 0x7f) << 1) | 0x01);
+                                                               pp.AddData(inData, 0, 1);
+                                                               if (Dts != 0)
+                                                                       {
+                                                                               inData[0] = (byte)(((Dts & 0x1C0000000) >> 29) | 0x11);
+                                                                               pp.AddData(inData, 0, 1);
+                                                                               inData[0] = (byte)((Dts & 0x3fC00000) >> 22);
+                                                                               pp.AddData(inData, 0, 1);
+                                                                               inData[0] = (byte)(((Dts & 0x3f8000) >> 14) | 0x01);
+                                                                               pp.AddData(inData, 0, 1);
+                                                                               inData[0] = (byte)((Dts & 0x7f80) >> 7);
+                                                                               pp.AddData(inData, 0, 1);
+                                                                               inData[0] = (byte)(((Dts & 0x7f) << 1) | 0x01);
+                                                                               pp.AddData(inData, 0, 1);
+                                                                       }
+                                                               pp.AddData(pgHeader, 0, pgHeader.Length);
+                                                               for (int k = 0; k < len; k++)
+                                                                       {
+                                                                               if (0 == tsior.Read(inData, 0, inData.Length))
+                                                                                       return null;
+                                                                               pp.AddData(inData, 0, 1);
+                                                                       }
+                                                               PesPacket[] ppa = new PesPacket[1];
+                                                               ppa[0] = pp;
+                                                               return ppa;
+                                                       }
+                                       }
+                               return null;
+                       }
+                       
+                       public override void Seek(long pcr)
+                       {
+                               tsior.Clear();
+                               
+                               if (pcr == -1)
+                                       {
+                                               fs.Seek(0, SeekOrigin.Begin);
+                                               return;
+                                       }
+                               
+                               int packetSize = sizeof(byte);
+                               Int64 span = endPcr - startPcr;
+                               if (span < 0)
+                                       span += Constants.MAX_MPEG2TS_CLOCK;
+                               Int64 pcrPerByte = span / fs.Length;
+                               Int64 seek = pcr - startPcr;
+                               if (seek < 0)
+                                       seek += Constants.MAX_MPEG2TS_CLOCK;
+                               Int64 length = seek / pcrPerByte;
+                               length /= packetSize;
+                               length *= packetSize;
+                               if (length > fs.Length)
+                                       length = fs.Length;
+                               fs.Seek(length, SeekOrigin.Begin);
+                               bool found = false;
+                               
+                               while (found == false)
+                                       {
+                                               Int64 offset = GetCurrentPcrFromFile();
+                                               if (-1 == offset)
+                                                       offset = endPcr;
+                                               offset -= pcr;
+                                               if (offset > Constants.MAX_MPEG2TS_CLOCK / 2)
+                                                       offset -= Constants.MAX_MPEG2TS_CLOCK;
+                                               else if (offset < (0 - (Constants.MAX_MPEG2TS_CLOCK / 2)))
+                                                       offset += Constants.MAX_MPEG2TS_CLOCK;
+                                               Int64 target = offset / Constants.MPEG2TS_CLOCK_RATE;
+                                               if (target > 0)
+                                                       {
+                                                               offset /= pcrPerByte;
+                                                               offset >>= 2;
+                                                               offset /= packetSize;
+                                                               offset *= packetSize;
+                                                               fs.Seek(0 - offset, SeekOrigin.Current);
+                                                       }
+                                               else if (target < 0)
+                                                       {
+                                                               offset /= pcrPerByte;
+                                                               offset >>= 2;
+                                                               offset /= packetSize;
+                                                               offset *= packetSize;
+                                                               fs.Seek(0 - offset, SeekOrigin.Current);
+                                                       }
+                                               else
+                                                       break;
+                                       }
+                       }
+                       
+                       private Int64 GetCurrentPcrFromFile()
+                       {
+                               byte b0 = 0;
+                               byte b1 = 0;
+                               Int64 pcr = 0;
+                               while (true)
+                                       {
+                                               int ib = fs.ReadByte();
+                                               if (ib == -1)
+                                                       return -1;
+                                               b0 = b1;
+                                               b1 = (byte)(ib & 0xff);
+                                               if ((b0 == (byte)'P' || b0 == (byte)'p') &&
+                                                       (b1 == (byte)'G' || b1 == (byte)'g'))
+                                                       {
+                                                               pcr = 0;
+                                                               for (int k = 0; k < 4; k++)
+                                                                       {
+                                                                               ib = fs.ReadByte();
+                                                                               if (ib == -1)
+                                                                                       return -1;
+                                                                               b1 = (byte)(ib & 0xff);
+                                                                               pcr <<= 8;
+                                                                               pcr |= b1;
+                                                                       }
+                                                               pcr *= (Constants.MPEG2TS_CLOCK_RATE / Constants.PTS_CLOCK_RATE);
+                                                               break;
+                                                       }
+                                       }
+                               return pcr;
+                       }
+                       
+                       private void GetTimeStamps()
+                       {
+                               fs.Seek(0, SeekOrigin.Begin);
+                               byte b0 = 0;
+                               byte b1 = 0;
+                               for (int i = 0; i < Constants.DISK_BUFFER; i++)
+                                       {
+                                               int ib = fs.ReadByte();
+                                               if (ib == -1)
+                                                       throw new FormatException("The specified file is too short");
+                                               b0 = b1;
+                                               b1 = (byte)(ib & 0xff);
+                                               if ((b0 == (byte)'P' || b0 == (byte)'p') &&
+                                                       (b1 == (byte)'G' || b1 == (byte)'g'))
+                                                       {
+                                                               startPcr = 0;
+                                                               for (int k = 0; k < 4; k++)
+                                                                       {
+                                                                               ib = fs.ReadByte();
+                                                                               if (ib == -1)
+                                                                                       throw new FormatException("The specified file is too short");
+                                                                               b1 = (byte)(ib & 0xff);
+                                                                               startPcr <<= 8;
+                                                                               startPcr |= b1;
+                                                                       }
+                                                               startPcr *= (Constants.MPEG2TS_CLOCK_RATE / Constants.PTS_CLOCK_RATE);
+                                                               break;
+                                                       }
+                                       }
+                               int lseek = -10;
+                               fs.Seek(lseek, SeekOrigin.End);
+                               b0 = b1 = 0;
+                               bool found = false;
+                               for (int i = 0; i < Constants.DISK_BUFFER; i++)
+                                       {
+                                               for (int j = 0; j < 2; j++)
+                                                       {
+                                                               int ib = fs.ReadByte();
+                                                               if (ib == -1)
+                                                                       throw new FormatException("The specified file is too short");
+                                                               b0 = b1;
+                                                               b1 = (byte)(ib & 0xff);
+                                                               if ((b0 == (byte)'P' || b0 == (byte)'p') &&
+                                                                       (b1 == (byte)'G' || b1 == (byte)'g'))
+                                                                       {
+                                                                               endPcr = 0;
+                                                                               for (int k = 0; k < 4; k++)
+                                                                                       {
+                                                                                               ib = fs.ReadByte();
+                                                                                               if (ib == -1)
+                                                                                                       throw new FormatException("The specified file is too short");
+                                                                                               b1 = (byte)(ib & 0xff);
+                                                                                               endPcr <<= 8;
+                                                                                               endPcr |= b1;
+                                                                                       }
+                                                                               endPcr *= (Constants.MPEG2TS_CLOCK_RATE / Constants.PTS_CLOCK_RATE);
+                                                                               found = true;
+                                                                               break;
+                                                                       }
+                                                       }
+                                               if (found)
+                                                       break;
+                                               lseek--;
+                                               fs.Seek(lseek, SeekOrigin.End);
+                                       }
+                       }
+               }
+       
+    public class TsPesFile : PesFile
+               {
+                       private int stride;
+                       private byte[] tsPack;
+                       TsPacket ts;
+                       private Dictionary<ushort, PesPacket> PesPackets;
+                       private DTCP_Descriptor dt;
+                       private ushort pcrPID;
+                       
+                       public TsPesFile(BackgroundWorker bw, int offset)
+            : base(bw)
+                       {
+                               stride = offset;
+                               tsPack = new byte[Constants.TS_SIZE + offset];
+                               ts = new TsPacket();
+                               PesPackets = new Dictionary<ushort, PesPacket>();
+                               dt = null;
+                               pcrPID = 0xffff;
+                       }
+                       
+                       public override DTCP_Descriptor DtcpInfo
+                       {
+                               get { return dt; }
+                       }
+                       
+                       public override PesPacket[] GetNextPesPackets()
+                       {
+                               int i;
+                               while (true)
+                                       {
+                                               for (i = tsior.Read(tsPack, 0, 1 + stride); (i > 0) && (tsPack[stride] != Constants.SYNC_BYTE); i = tsior.Read(tsPack, stride, 1))
+                                                       ; // ensure a good sync byte
+                                               if (i == 0)
+                                                       {
+                                                               List<PesPacket> ppa = new List<PesPacket>();
+                                                               foreach (ushort pd in PesPackets.Keys)
+                                                               {
+                                                                       PesPacket pp = PesPackets[pd];
+                                                                       pp.Complete = true;
+                                                                       ppa.Add(pp);
+                                                               }
+                                                               PesPackets.Clear();
+                                                               if (ppa.Count == 0)
+                                                                       return null; // end of stream
+                                                               else
+                                                                       {
+                                                                               return ppa.ToArray();
+                                                                       }
+                                                       }
+                                               i = tsior.Read(tsPack, stride + 1, tsPack.Length - (stride + 1));
+                                               if (i < tsPack.Length - (stride + 1))
+                                                       {
+                                                               List<PesPacket> ppa = new List<PesPacket>();
+                                                               foreach (ushort pd in PesPackets.Keys)
+                                                               {
+                                                                       PesPacket pp = PesPackets[pd];
+                                                                       pp.Complete = true;
+                                                                       ppa.Add(pp);
+                                                               }
+                                                               PesPackets.Clear();
+                                                               if (ppa.Count == 0)
+                                                                       return null; // end of stream
+                                                               else
+                                                                       return ppa.ToArray();
+                                                       }
+                                               ts.SetData(tsPack, stride);
+                                               ushort pid = ts.PID;
+                                               byte[] payload = ts.Payload;
+                                               if (ts.HasPcr)
+                                                       {
+                                                               if (null != pcrDelegate && pcrPID == pid)
+                                                                       pcrDelegate(ts.Pcr);
+                                                       }
+                                               if (ts.HasPesHeader)
+                                                       {
+                                                               if (payload != null && payload.Length > 3 && payload[0] == 0x00
+                                                                       && payload[1] == 0x00 && payload[2] == 0x01)
+                                                                       {
+                                                                               PesPacket newpp = new PesPacket(payload, 0, payload.Length, pid);
+                                                                               newpp.Priority = ts.Priority;
+                                                                               PesHeader ph = newpp.GetHeader();
+                                                                               if (ph != null && ph.HasPts)
+                                                                                       {
+                                                                                               if (ptsDelegate != null)
+                                                                                                       ptsDelegate(ph.Pts, pid);
+                                                                                       }
+                                                                               if (PesPackets.ContainsKey(pid))
+                                                                                       {
+                                                                                               PesPacket pp = PesPackets[ts.PID];
+                                                                                               pp.Complete = true;
+                                                                                               PesPackets[ts.PID] = newpp;
+                                                                                               PesPacket[] ppa = new PesPacket[1];
+                                                                                               ppa[0] = pp;
+                                                                                               return ppa;
+                                                                                       }
+                                                                               else
+                                                                                       {
+                                                                                               if (newpp.Complete == true)
+                                                                                                       {
+                                                                                                               PesPacket[] ppa = new PesPacket[1];
+                                                                                                               ppa[0] = newpp;
+                                                                                                               return ppa;
+                                                                                                       }
+                                                                                               PesPackets[ts.PID] = newpp;
+                                                                                       }
+                                                                       }
+                                                               else
+                                                                       {
+                                                                               throw new InvalidDataException("invalid stream");
+                                                                       }
+                                                       }
+                                               else if (PesPackets.ContainsKey(pid))
+                                                       {
+                                                               PesPacket pp = PesPackets[ts.PID];
+                                                               if (payload != null)
+                                                                       {
+                                                                               pp.AddData(payload, 0, payload.Length);
+                                                                               if (pp.Complete)
+                                                                                       {
+                                                                                               PesPackets.Remove(pid);
+                                                                                               PesPacket[] ppa = new PesPacket[1];
+                                                                                               ppa[0] = pp;
+                                                                                               return ppa;
+                                                                                       }
+                                                                       }
+                                                       }
+                                       }
+                       }
+                       
+                       private void GetTimestamps()
+                       {
+                               int i = 0;
+                               
+                               startPcr = -1;
+                               endPcr = -1;
+                               if(null != tsior)
+                                       tsior.Clear();
+                               fs.Seek(0, SeekOrigin.Begin);
+                               
+                               while (true)
+                                       {
+                                               for (i = tsior.Read(tsPack, 0, 1 + stride); (i > 0) && (tsPack[stride] != Constants.SYNC_BYTE); i = tsior.Read(tsPack, stride, 1))
+                                                       ; // ensure a good sync byte
+                                               if (i == 0)
+                                                       return; // end of stream
+                                               i = tsior.Read(tsPack, stride + 1, tsPack.Length - (stride + 1));
+                                               if (i < tsPack.Length - (stride + 1))
+                                                       return; // end of stream
+                                               ts.SetData(tsPack, stride);
+                                               if (ts.HasPcr)
+                                                       {
+                                                               startPcr = ts.Pcr;
+                                                               pcrPID = ts.PID;
+                                                               break;
+                                                       }
+                                               if (fs.Position > (Constants.DISK_BUFFER << 1))
+                                                       return;
+                                       }
+                               tsior.Clear();
+                               int packSize = Constants.TS_SIZE + stride;
+                               fs.Seek(0, SeekOrigin.End);
+                               for (i = packSize; (fs.Length - fs.Position) < Constants.DISK_BUFFER; i += packSize)
+                                       {
+                                               fs.Seek(0 - i, SeekOrigin.End);
+                                               if (fs.Read(tsPack, 0, packSize) == packSize)
+                                                       {
+                                                               if (tsPack[stride] != Constants.SYNC_BYTE)
+                                                                       {
+                                                                               i++;
+                                                                               i -= packSize;
+                                                                               continue;
+                                                                       }
+                                                               ts.SetData(tsPack, stride);
+                                                               if (ts.HasPcr && pcrPID == ts.PID)
+                                                                       {
+                                                                               endPcr = ts.Pcr;
+                                                                               Seek(-1);
+                                                                               return;
+                                                                       }
+                                                       }
+                                               else
+                                                       break;
+                                       }
+                               endPcr = startPcr = -1;
+                       }
+                       
+                       protected override void  GetInitialValues()
+                       {
+                               GetTimestamps();
+                               Seek(-1);
+                               PatPacket pp = null;
+                               PmtPacket pm = null;
+                               bool bluray = false;
+                               bool validPmt = false;
+                               ushort pmtPid = 0;
+                               int i = 0;
+                               Dictionary<ushort, StreamInfo> streams = new Dictionary<ushort, StreamInfo>();
+                               while (true)
+                                       {
+                                               for (i = tsior.Read(tsPack, 0, 1 + stride); (i > 0) && (tsPack[stride] != Constants.SYNC_BYTE); i = tsior.Read(tsPack, stride, 1))
+                                                       ; // ensure a good sync byte
+                                               if (i == 0)
+                                                       break; // end of stream
+                                               i = tsior.Read(tsPack, stride + 1, tsPack.Length - (stride + 1));
+                                               if (i < tsPack.Length - (stride + 1))
+                                                       break; // end of stream
+                                               ts.SetData(tsPack, stride);
+                                               if (ts.PID == Constants.PAT_PID)
+                                                       {
+                                                               pp = new PatPacket(ts.GetData());
+                                                               ProgramInfo[] pi = pp.Programs;
+                                                               if (null != pi && pi.Length == 2)
+                                                                       {
+                                                                               if ((pi[0].ProgramNumber == 0 && pi[0].ProgramPID == 0x001f && pi[1].ProgramNumber == 1 && pi[1].ProgramPID == 0x0100)
+                                                                                       || (pi[1].ProgramNumber == 0 && pi[1].ProgramPID == 0x001f && pi[0].ProgramNumber == 1 && pi[0].ProgramPID == 0x0100))
+                                                                                       {
+                                                                                               bluray = true;
+                                                                                       }
+                                                                       }
+                                                               else if (null != pi && pi[0] != null && pi[0].ProgramNumber == 1)
+                                                                       pmtPid = pi[0].ProgramPID;
+                                                       }
+                                               else if (bluray && ts.PID == 0x0100)
+                                                       {
+                                                               if (pm == null)
+                                                                       pm = new PmtPacket(ts.GetData());
+                                                               else if (pm.Complete == false)
+                                                                       pm.AddData(ts.Payload, 0, ts.Payload.Length);
+                                                               if (pm.Complete)
+                                                                       {
+                                                                               sis = pm.ElementaryStreams;
+                                                                               dt = pm.DtcpInfo;
+                                                                               return;
+                                                                       }
+                                                       }
+                                               else if (ts.PID == pmtPid)
+                                                       {
+                                                               pm = new PmtPacket(ts.GetData());
+                                                               sis = pm.ElementaryStreams;
+                                                               dt = pm.DtcpInfo;
+                                                       }
+                                               else if (streams.ContainsKey(ts.PID) == false && ts.HasPesHeader)
+                                                       {
+                                                               byte[] payload = ts.Payload;
+                                                               PesHeader ph = new PesHeader(ts.Payload);
+                                                               PesPacket pes = new PesPacket(payload, 0, payload.Length, ts.PID);
+                                                               if (ph.StreamId == Constants.PES_PRIVATE1)
+                                                                       {
+                                                                               byte[] audio = pes.GetPayload();
+                                                                               AC3Info ac3 = new AC3Info(audio, 0);
+                                                                               DtsInfo dts = new DtsInfo(audio, 0);
+                                                                               MlpInfo mlp = new MlpInfo(audio, 0);
+                                                                               if (ac3.Valid)
+                                                                                       {
+                                                                                               if (ac3.SyntaxType == Ac3SyntaxType.Standard || ac3.SyntaxType == Ac3SyntaxType.Alternative)
+                                                                                                       {
+                                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_AC3, ts.PID);
+                                                                                                               streams.Add(ts.PID, si);
+                                                                                                       }
+                                                                                               else if (ac3.SyntaxType == Ac3SyntaxType.Enhanced)
+                                                                                                       {
+                                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_AC3_PLUS, ts.PID);
+                                                                                                               streams.Add(ts.PID, si);
+                                                                                                       }
+                                                                                       }
+                                                                               else if (dts.Valid)
+                                                                                       {
+                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_DTS_HD, ts.PID);
+                                                                                               streams.Add(ts.PID, si);
+                                                                                       }
+                                                                               else if (mlp.Valid)
+                                                                                       {
+                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_AC3_TRUE_HD, ts.PID);
+                                                                                               streams.Add(ts.PID, si);
+                                                                                       }
+                                                                               else if ((pes.ExtendedId & 0xf8) == Constants.PES_PRIVATE_LPCM)
+                                                                                       {
+                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_LPCM, ts.PID);
+                                                                                               streams.Add(ts.PID, si);
+                                                                                       }
+                                                                       }
+                                                               else if ((ph.StreamId & 0xe0) == Constants.PES_AUDIO_MPEG)
+                                                                       {
+                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_MPEG2, ts.PID);
+                                                                               streams.Add(ts.PID, si);
+                                                                       }
+                                                               else if ((ph.StreamId & 0xf0) == Constants.PES_VIDEO)
+                                                                       {
+                                                                               UInt32 format = pes.ExtendedType;
+                                                                               if ((format & 0xffff) == 0x1)
+                                                                                       {
+                                                                                       }
+                                                                               else if ((format & 0xffffff00) == 0x100)
+                                                                                       {
+                                                                                       }
+                                                                               
+                                                                               H264Info h264 = new H264Info(payload, 0);
+                                                                               Mpeg2Info mpg2 = new Mpeg2Info(payload, 0);
+                                                                               if (h264.Valid)
+                                                                                       {
+                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.VIDEO_STREAM_H264, ts.PID);
+                                                                                               streams.Add(ts.PID, si);
+                                                                                       }
+                                                                               else if (mpg2.Valid)
+                                                                                       {
+                                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.VIDEO_STREAM_MPEG2, ts.PID);
+                                                                                               streams.Add(ts.PID, si);
+                                                                                       }
+                                                                       }
+                                                               else if (ph.StreamId == Constants.PES_VIDEO_VC1)
+                                                                       {
+                                                                               StreamInfo si = new StreamInfo(ElementaryStreamTypes.VIDEO_STREAM_VC1, ts.PID);
+                                                                               streams.Add(ts.PID, si);
+                                                                       }
+                                                       }
+                                               if (sis != null)
+                                                       {
+                                                               validPmt = true;
+                                                               foreach (StreamInfo si in sis)
+                                                               {
+                                                                       if (streams.ContainsKey(si.ElementaryPID) == false)
+                                                                               {
+                                                                                       validPmt = false;
+                                                                                       break;
+                                                                               }
+                                                               }
+                                                               if (validPmt)
+                                                                       return;
+                                                       }
+                                               if (fs.Position > (Constants.DISK_BUFFER << 1))
+                                                       break;
+                                       }
+                               sis = new StreamInfo[streams.Values.Count];
+                               streams.Values.CopyTo(sis, 0);
+                       }
+                       
+                       private Int64 GetCurrentPcrFromFile()
+                       {
+                               int packetSize = 0;
+                               if (fileType == TsFileType.TS)
+                                       packetSize = Constants.TS_SIZE;
+                               else if (fileType == TsFileType.M2TS)
+                                       packetSize = Constants.STRIDE_SIZE;
+                               byte[] inBuff = new byte[packetSize];
+                               TsPacket tp = new TsPacket();
+                               Int64 filePos = fs.Position;
+                               
+                               while (fs.Read(inBuff, 0, packetSize) == packetSize && fs.Position < (filePos + 1000000))
+                                       {
+                                               if (packetSize == Constants.STRIDE_SIZE)
+                                                       tp.SetData(inBuff, 4);
+                                               else if (packetSize == Constants.TS_SIZE)
+                                                       tp.SetData(inBuff, 0);
+                                               if (tp.HasPcr)
+                                                       {
+                                                               fs.Seek(filePos, SeekOrigin.Begin);
+                                                               return tp.Pcr;
+                                                       }
+                                       }
+                               return -1;
+                       }
+                       
+                       public override void Seek(Int64 pcr)
+                       {
+                               tsior.Clear();
+                               PesPackets.Clear();
+                               
+                               if (pcr == -1)
+                                       {
+                                               fs.Seek(0, SeekOrigin.Begin);
+                                               return;
+                                       }
+                               
+                               int packetSize = 0;
+                               if (fileType == TsFileType.TS)
+                                       packetSize = Constants.TS_SIZE;
+                               else if (fileType == TsFileType.M2TS)
+                                       packetSize = Constants.STRIDE_SIZE;
+                               else
+                                       packetSize = sizeof(byte);
+                               Int64 span = endPcr - startPcr;
+                               if (span < 0)
+                                       span += Constants.MAX_MPEG2TS_CLOCK;
+                               Int64 pcrPerByte = span / fs.Length;
+                               Int64 seek = pcr - startPcr;
+                               if (seek < 0)
+                                       seek += Constants.MAX_MPEG2TS_CLOCK;
+                               Int64 length = seek / pcrPerByte;
+                               length /= packetSize;
+                               length *= packetSize;
+                               if (length > fs.Length)
+                                       length = fs.Length;
+                               fs.Seek(length, SeekOrigin.Begin);
+                               
+                               for(int i = 0; i < 100; i++)
+                                       {
+                                               Int64 offset = GetCurrentPcrFromFile();
+                                               if (-1 == offset)
+                                                       offset = endPcr;
+                                               offset -= pcr;
+                                               if (offset > Constants.MAX_MPEG2TS_CLOCK / 2)
+                                                       offset -= Constants.MAX_MPEG2TS_CLOCK;
+                                               else if (offset < (0 - (Constants.MAX_MPEG2TS_CLOCK / 2)))
+                                                       offset += Constants.MAX_MPEG2TS_CLOCK;
+                                               Int64 target = offset / Constants.MPEG2TS_CLOCK_RATE;
+                                               if (target > 0)
+                                                       {
+                                                               offset /= pcrPerByte;
+                                                               offset >>= 2;
+                                                               offset /= packetSize;
+                                                               offset *= packetSize;
+                                                               fs.Seek(0 - offset, SeekOrigin.Current);
+                                                       }
+                                               else if (target < 0)
+                                                       {
+                                                               offset /= pcrPerByte;
+                                                               offset >>= 2;
+                                                               offset /= packetSize;
+                                                               offset *= packetSize;
+                                                               fs.Seek(0 - offset, SeekOrigin.Current);
+                                                       }
+                                               else
+                                                       break;
+                                       }
+                       }
+               }
+       
+public class TsIo
+{
+TsIo::TsIo(FileStream read, FileStream write)
+{
+       init(read, write, Constants::DISK_BUFFER);
+}
+                       
+TsIo::TsIo(FileStream read, FileStream write, int buffsize)
+{
+       init(read, write, buffsize);
+}
+                       
+TsIo::init(FileStream read, FileStream write, int buffsize)
+{
+       fsr = read;
+       fsw = write;
+       if (fsr != null)
+       {
+               ReadBuffer1 = pByte(new byte[buffsize]);
+               ReadBuffer2 = pByte(new byte[buffsize]);
+               ReadBuffer = ReadBuffer1;
+       }
+       else
+       {
+               ReadBuffer.reset();
+               ReadBuffer1.reset();
+               ReadBuffer2.reset();
+       }
+       if (fsw != null)
+       {
+               WriteBuffer1 = pByte(new byte[buffsize]);
+               WriteBuffer2 = pByte(new byte[buffsize]);
+               WriteBuffer = WriteBuffer1;
+       }
+       else
+       {
+               WriteBuffer.reset();
+               WriteBuffer1.reset();
+               WriteBuffer2.reset();
+       }
+       readIndex = 0;
+       readSize = 0;
+       writeIndex = 0;
+       asyncRead = null;
+       asyncWrite = null;
+}
+                       
+int TsIo::Read(byte[] target, int offset, int count)
+                       {
+                               if (readIndex == readSize)
+                                       {
+                                               // this buffer is finished, get next one
+                                               if (asyncRead != null)
+                                                       {
+                                                               if (asyncRead.IsCompleted == false)
+                                                                       GC.Collect(); // garbage collection during spare cycles
+                                                               readSize = fsr.EndRead(asyncRead);
+                                                               if (ReadBuffer == ReadBuffer1)
+                                                                       ReadBuffer = ReadBuffer2;
+                                                               else ReadBuffer = ReadBuffer1;
+                                                               readIndex = 0;
+                                                               if (readSize == 0)
+                                                                       {
+                                                                               asyncRead = null;
+                                                                               return 0; // end of file
+                                                                       }
+                                                       }
+                                               else
+                                                       {
+                                                               // one time init - prepopulate buffer
+                                                               readSize = fsr.Read(ReadBuffer, 0, ReadBuffer.Length);
+                                                               if (readSize == 0)
+                                                                       return 0;
+                                                               readIndex = 0;
+                                                       }
+                                               if (ReadBuffer == ReadBuffer1)
+                                                       asyncRead = fsr.BeginRead(ReadBuffer2, 0, ReadBuffer2.Length, null, null);
+                                               else
+                                                       asyncRead = fsr.BeginRead(ReadBuffer1, 0, ReadBuffer1.Length, null, null);
+                                       }
+                               if (readIndex < readSize)
+                                       {
+                                               int len = count;
+                                               while (len > (readSize - readIndex))
+                                                       {
+                                                               int ret = Read(target, offset, (int)(readSize - readIndex));
+                                                               offset += ret;
+                                                               len -= ret;
+                                                               if (ret == 0)
+                                                                       break;
+                                                       }
+                                               if (len <= (readSize - readIndex))
+                                                       {
+                                                               // this optimization saves a LOT of time in PS files
+                                                               if (len == 1)
+                                                                       target[offset] = ReadBuffer[readIndex];
+                                                               else
+                                                                       Array.Copy(ReadBuffer, readIndex, target, offset, len);
+                                                               readIndex += len;
+                                                               return count;
+                                                       }
+                                               else
+                                                       {
+                                                               return count - len;
+                                                       }
+                                       }
+                               throw new ArgumentException("read index out of bounds");
+                       }
+                       
+                       public void Write(byte[] target, int offset, int count)
+                       {
+                               if (writeIndex == WriteBuffer.Length)
+                                       {
+                                               // this buffer is finished, get next one
+                                               if (asyncWrite != null)
+                                                       {
+                                                               if (asyncWrite.IsCompleted == false)
+                                                                       GC.Collect(); // garbage collection during spare cycles
+                                                               fsw.EndWrite(asyncWrite);
+                                                       }
+                                               asyncWrite = fsw.BeginWrite(WriteBuffer, 0, WriteBuffer.Length, null, null);
+                                               if (WriteBuffer == WriteBuffer1)
+                                                       WriteBuffer = WriteBuffer2;
+                                               else
+                                                       WriteBuffer = WriteBuffer1;
+                                               writeIndex = 0;
+                                       }
+                               if (writeIndex < WriteBuffer.Length)
+                                       {
+                                               while (count > (int)(WriteBuffer.Length - writeIndex))
+                                                       {
+                                                               int diff = (int)(WriteBuffer.Length - writeIndex);
+                                                               Write(target, offset, diff);
+                                                               offset += diff;
+                                                               count -= diff;
+                                                       }
+                                               Array.Copy(target, offset, WriteBuffer, writeIndex, count);
+                                               writeIndex += count;
+                                               return;
+                                       }
+                               throw new ArgumentException("write index out of bounds");
+                       }
+                       
+                       public void Flush()
+                       {
+                               if (asyncWrite != null)
+                                       {
+                                               fsw.EndWrite(asyncWrite);
+                                               asyncWrite = null;
+                                       }
+                               if (writeIndex > 0)
+                                       {
+                                               fsw.Write(WriteBuffer, 0, (int)writeIndex);
+                                               writeIndex = 0;
+                                       }
+                       }
+                       
+                       public void Clear()
+                       {
+                               if (asyncRead != null)
+                                       {
+                                               fsr.EndRead(asyncRead);
+                                               asyncRead = null;
+                                       }
+                               readIndex = readSize = 0;
+                       }
+               }
+}
+                                                                                                                               
 }
 
index bedb5bd..71d06a1 100644 (file)
@@ -1,74 +1,66 @@
 #ifndef TSREMUXCPP_TSTOPES_H_
 #define TSREMUXCPP_TSTOPES_H_
 
-#include <string>
-#include <list>
 #include "Utils.h"
-#include "define_temporary.h"
-#include "define_stream.h"
-#include "define_backgroundworker.h"
-#include "define_iasyncresult.h"
-#include "define_pcrchanged.h"
-#include "define_ptschanged.h"
 
 namespace TsRemux {
 class TsIo {
  public:
   TsIo(FileStream read, FileStream write);
-  TsIo(FileStream read, FileStream write, signed int buffersize);
-  void init(FileStream read, FileStream write, signed int buffersize);
-  int Read(char target[], int offset, int count);
-  void Write(char target[], int offset, int count);
+  TsIo(FileStream read, FileStream write, Int32 buffersize);
+  void init(FileStream read, FileStream write, Int32 buffersize);
+  int Read(pByte target, int offset, int count);
+  void Write(pByte target, int offset, int count);
   void Flush(void);
   void Clear(void);
  protected:
  private:
   FileStream fsr;
   FileStream fsw;
-  char ReadBuffer1[];
-  char ReadBuffer2[];
-  char ReadBuffer[];
-  char WriteBuffer1[];
-  char WriteBuffer2[];
-  char WriteBuffer[];
-  signed long long readIndex;
-  signed long long readSize;
-  signed long long writeIndex;
+  pByte ReadBuffer1;
+  pByte ReadBuffer2;
+  pByte ReadBuffer;
+  pByte WriteBuffer1;
+  pByte WriteBuffer2;
+  pByte WriteBuffer;
+  Int64 readIndex;
+  Int64 readSize;
+  Int64 writeIndex;
   IAsyncResult asyncRead;
   IAsyncResult asyncWrite;
 };
 class PesFile {
  public:
   void SetPcrDelegate(PcrChanged pcr);
-  signed long long StartPcr;
-  signed long long EndPcr;
+  Int64 StartPcr;
+  Int64 EndPcr;
   void SetPtsDelegate(PtsChanged pts);
-  StreamInfo GetStreamInfo(unsigned short pid);
+  StreamInfo GetStreamInfo(ushort pid);
   void CloseFile(void);
   void Clear(void);
-  TsFileType FileType;
-  StreamInfo StreamInfos[];
-  time_t VideoLength;
-  PesPacket* GetNextPesPackets(void);
-  void Seek(signed long long pcr);
+  TsFileType GetFileType(FileStream fs)throw(std::invalid_argument);
+  std::vector<boost::shared_ptr<StreamInfo> > StreamInfos;
+  TimeSpan VideoLength;
+  boost::shared_ptr<PesPacket> GetNextPesPackets(void);
+  void Seek(Int64 pcr);
   DTCP_Descriptor DtcpInfo;
  protected:
   PesFile(BackgroundWorker openWorker);
-  void ReportProgress(signed int percent);
+  void ReportProgress(Int32 percent);
   void GetInitialValues(void);
   FileStream fs;
   TsIo tsior;
   TsFileType fileTpe;
-  signed long long startPcr;
-  signed long long endPcr;
-  StreamInfo sis[];
+  Int64 startPcr;
+  Int64 endPcr;
+  std::vector<boost::shared_ptr<StreamInfo> > sis;
   PcrChanged pcrDelegate;
   PtsChanged ptsDelegate;
   BackgroundWorker openWorker;
-  signed int lastPercent;
+  Int32 lastPercent;
  private:
   void ParseElementaryStreams(void);
-  void ParseStream(StreamInfo si, char payload[]);
+  void ParseStream(StreamInfo si, pByte payload);
   static PesFile OpenFile(std::string path, bool useAsync, BackgroundWorker openWorker);
 };
 
@@ -81,23 +73,23 @@ class EvoPesFile {
  protected:
   void GetInitialValues(void);
  private:
-  Dictionary<unsigned short, std::list<char> > soundFrames;
-  signed long long GetCurrentPcrFromFile(void);
+  Dictionary<ushort, pByte> soundFrames;
+  Int64 GetCurrentPcrFromFile(void);
   void GetTimeStamps(void);
-  char GetVC1SubstreamId(char buff[], signed int offset);
-  signed long long lastPcr;
+  char GetVC1SubstreamId(pByte buff, Int32 offset);
+  Int64 lastPcr;
 };
 
 class SupPesFile {
  public:
   SupPesFile(BackgroundWorker bw);
   DTCP_Descriptor DtcpInfo;
-  PesPacket* GetNextPesPackets(void);
-  void Seek(signed long pcr);
+  boost::shared_ptr<PesPacket> GetNextPesPackets(void);
+  void Seek(Int32 pcr);
  protected:
   void GetInitialValues(void);
  private:
-  signed long long GetCurrentPcrFromFile(void);
+  Int64 GetCurrentPcrFromFile(void);
   void GetTimeStamps(void);
 };
 
@@ -105,19 +97,18 @@ class TsPesFile {
  public:
   TsPesFile(BackgroundWorker bw);
   DTCP_Descriptor DtcpInfo;
-  PesPacket* GetNextPesPackets(void);
-  void Seek(signed long pcr);
+  boost::shared_ptr<PesPacket> GetNextPesPackets(void);
+  void Seek(Int32 pcr);
  protected:
   void GetInitialValues(void);
  private:
-  signed long long GetCurrentPcrFromFile(void);
+  Int64 GetCurrentPcrFromFile(void);
   void GetTimeStamps(void);
-  signed int stride;
-  char tsPack[];
-  Dictionary<unsigned short, PesPacket> PesPackets;
+  Int32 stride;
+  pByte tsPack;
+  Dictionary<ushort, PesPacket> PesPackets;
   DTCP_Descriptor dt;
-  unsigned short pcrPID;
+  ushort pcrPID;
 };
 }
 #endif
-
index bb92317..830756e 100755 (executable)
@@ -12,6 +12,7 @@
 #include <boost/shared_array.hpp>
 #include <boost/filesystem.hpp>
 #include <boost/iostreams/stream.hpp>
+#include <boost/thread.hpp>
 
 #define readonly const
 
@@ -27,6 +28,8 @@ typedef unsigned long long UInt64;
 typedef signed long long Int64;
 typedef boost::posix_time::time_duration TimeSpan;
 typedef boost::shared_array<byte> pByte;
+typedef boost::thread BackgroundWorker;
+typedef std::map Dictionary;
     
 class Stream {
  public: