private Int64 GetClusterClock(EbmlElement cluster) { Int64 clock = -1; if (cluster.Id != Constants.MKVCLUSTER_START) { throw new FormatException("Bad cluster ID - Invalid/Corrupted MKV file"); } EbmlElement[] children = cluster.Children; foreach (EbmlElement time in children) { if (time.Id == Constants.MKVTIMECODE_START) { clock = 0; Stream s = time.DataStream; for (Int64 i = 0; i < time.Size; i++) { clock <<= 8; clock |= (byte)fs.ReadByte(); } break; } } if (-1 == clock) { throw new FormatException("Could not find timecode in cluster."); } return(clock); }
public TrackInfo(ushort pid, string codec, byte[] data, EbmlElement info) { this.pid = pid; this.codec = codec; this.data = data; this.info = info; }
public static EbmlElement ParseEbml(Stream fs) { Int64 pos = fs.Position; EbmlElement ebml = null; if (null == fs || fs.Length == 0) { return(null); } int b = fs.ReadByte(); if (b == -1) { goto cleanup; } int len = VintLength((byte)b); if ((fs.Length - fs.Position) < (Int64)len) { goto cleanup; } fs.Position -= 1; Int64 id = 0; for (int i = 0; i < len; i++) { id <<= 8; id |= (byte)fs.ReadByte(); } b = fs.ReadByte(); if (b == -1) { goto cleanup; } len = VintLength((byte)b); if ((fs.Length - fs.Position) < (Int64)len) { goto cleanup; } fs.Position -= 1; Int64 size = VintToInt64(fs); if ((fs.Length - fs.Position) < size) { goto cleanup; } ebml = new EbmlElement(id, size, fs.Position, fs); cleanup: fs.Position = pos; return(ebml); }
public override PesPacket[] GetNextPesPackets() { 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()); }
protected override void GetInitialValues() { fs.Seek(0, SeekOrigin.Begin); UInt32 header = 0xffffffff; EbmlElement mkv = null; byte b = 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"); } b = (byte)(ib & 0xff); header <<= 8; header |= b; if (header == Constants.MKVSEGMENT_START) { fs.Seek(-4, SeekOrigin.Current); mkv = EbmlElement.ParseEbml(fs); if (null == mkv) { throw new FormatException("Invalid/Corrupted MKV file"); } break; } } EbmlElement[] clusts = mkv.Children; foreach (EbmlElement clust in clusts) { ReportProgress((int)(50 * clust.DataStream.Position / clust.DataStream.Length)); if (clust.Id == Constants.MKVCLUSTER_START) { Clusters.Add(GetClusterClock(clust), clust); } else if (clust.Id == Constants.MKVTRACKINFO_START) { EbmlElement[] tracks = clust.Children; ushort id = 0; List <StreamInfo> mkvStreams = new List <StreamInfo>(); foreach (EbmlElement track in tracks) { if (track.Id == 0xae) { EbmlElement[] trackAttributes = track.Children; string codec = null; ushort pid = 0; UInt64 uid = 0; byte[] data = null; EbmlElement elementaryInfo = null; foreach (EbmlElement trackAtt in trackAttributes) { switch (trackAtt.Id) { case 0xd7: // Track number for (Int64 i = 0; i < trackAtt.Size; i++) { pid <<= 8; pid |= (byte)fs.ReadByte(); } break; case 0x86: // Codec ID byte[] cid = new byte[(int)trackAtt.Size]; trackAtt.DataStream.Read(cid, 0, (int)trackAtt.Size); codec = Encoding.ASCII.GetString(cid); break; case 0x63a2: // Coded Private data = new byte[(int)trackAtt.Size]; trackAtt.DataStream.Read(data, 0, (int)trackAtt.Size); break; case 0x73c5: // Track UID for (Int64 i = 0; i < trackAtt.Size; i++) { uid <<= 8; uid |= (byte)fs.ReadByte(); } break; case 0xe0: // Video elementary stream info elementaryInfo = trackAtt; break; case 0xe1: // Audio elementary stream info elementaryInfo = trackAtt; break; } } if (codec == null || pid == 0) { throw new FormatException("Track info is invalid"); } if (0 == string.Compare(codec, "V_MPEG2", true, CultureInfo.InvariantCulture) || 0 == string.Compare(codec, "V_MPEG4/ISO/AVC", true, CultureInfo.InvariantCulture) || 0 == string.Compare(codec, "V_MS/VFW/FOURCC", true, CultureInfo.InvariantCulture) || 0 == string.Compare(codec, "A_AC3", true, CultureInfo.InvariantCulture) || 0 == string.Compare(codec, "A_DTS", true, CultureInfo.InvariantCulture)) { id++; TrackInfo ti = new TrackInfo(id, codec, data, elementaryInfo); TrackList.Add(id, ti); StreamInfo si = null; if (0 == string.Compare(codec, "V_MPEG2", true, CultureInfo.InvariantCulture)) { si = new StreamInfo(ElementaryStreamTypes.VIDEO_STREAM_MPEG2, id); } else if (0 == string.Compare(codec, "V_MPEG4/ISO/AVC", true, CultureInfo.InvariantCulture)) { si = new StreamInfo(ElementaryStreamTypes.VIDEO_STREAM_H264, id); } else if (0 == string.Compare(codec, "V_MS/VFW/FOURCC", true, CultureInfo.InvariantCulture)) { si = new StreamInfo(ElementaryStreamTypes.VIDEO_STREAM_VC1, id); } else if (0 == string.Compare(codec, "A_AC3", true, CultureInfo.InvariantCulture)) { si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_AC3, id); } else if (0 == string.Compare(codec, "A_DTS", true, CultureInfo.InvariantCulture)) { si = new StreamInfo(ElementaryStreamTypes.AUDIO_STREAM_DTS, id); } mkvStreams.Add(si); } } } if (mkvStreams.Count > 0) { sis = mkvStreams.ToArray(); } } } GetTimeStamps(); CurrentIndex = 0; }
private Int64 GetClusterClock(EbmlElement cluster) { Int64 clock = -1; if(cluster.Id != Constants.MKVCLUSTER_START) throw new FormatException("Bad cluster ID - Invalid/Corrupted MKV file"); EbmlElement[] children = cluster.Children; foreach (EbmlElement time in children) { if (time.Id == Constants.MKVTIMECODE_START) { clock = 0; Stream s = time.DataStream; for (Int64 i = 0; i < time.Size; i++) { clock <<= 8; clock |= (byte)fs.ReadByte(); } break; } } if (-1 == clock) throw new FormatException("Could not find timecode in cluster."); return clock; }
public static EbmlElement ParseEbml(Stream fs) { Int64 pos = fs.Position; EbmlElement ebml = null; if (null == fs || fs.Length == 0) return null; int b = fs.ReadByte(); if (b == -1) goto cleanup; int len = VintLength((byte)b); if ((fs.Length - fs.Position) < (Int64)len) goto cleanup; fs.Position -= 1; Int64 id = 0; for (int i = 0; i < len; i++) { id <<= 8; id |= (byte)fs.ReadByte(); } b = fs.ReadByte(); if (b == -1) goto cleanup; len = VintLength((byte)b); if ((fs.Length - fs.Position) < (Int64)len) goto cleanup; fs.Position -= 1; Int64 size = VintToInt64(fs); if ((fs.Length - fs.Position) < size) goto cleanup; ebml = new EbmlElement(id, size, fs.Position, fs); cleanup: fs.Position = pos; return ebml; }