/// <summary> /// Load the entire partition from disk (when not yet loaded) /// </summary> public void Load() { if (!this.IsLoaded) { MXFKLVFactory klvFactory = new MXFKLVFactory(); using (MXFReader reader = new MXFReader(this.File.Filename)) { // Seek just after this partition reader.Seek(this.DataOffset + this.Length); while (!reader.EOF) { MXFKLV klv = klvFactory.CreateObject(reader, this); if (klv.Key.Type == KeyType.Partition || klv.Key.Type == KeyType.RIP || klv.Key.Type == KeyType.PrimerPack) { break; // Next partition or other segment, quit reading } if (!this.Children.Any(a => a.Offset == klv.Offset)) { // Normal, just add the new child this.AddChild(klv); } // Next KLV please reader.Seek(klv.DataOffset + klv.Length); } } this.IsLoaded = true; } }
/// <summary> /// /// </summary> /// <param name="reader"></param> private void Initialize(MXFReader reader) { // Make sure we read at the data position reader.Seek(this.DataOffset); // Read all local tags long klvEnd = this.DataOffset + this.Length; while (reader.Position + 4 < klvEnd) { MXFLocalTag tag = new MXFLocalTag(reader); long next = tag.DataOffset + tag.Size; AddRefKeyFromPrimerPack(tag); // Allow derived classes to handle the data if (!ParseLocalTag(reader, tag)) { // Not processed, use default tag.Parse(reader); // Add to the collection AddChild(tag); } reader.Seek(next); } // Allow derived classes to do some final work PostInitialize(); }
/// <summary> /// /// </summary> /// <param name="reader"></param> private void Initialize(MXFReader reader) { // Make sure we read at the data position reader.Seek(this.DataOffset); // Read all local tags long klvEnd = this.DataOffset + this.Length; while (reader.Position + 4 < klvEnd) { MXFLocalTag tag = new MXFLocalTag(reader); long next = tag.DataOffset + tag.Size; if (tag.Tag == 0x3C0A) { // Generic instance UID this.InstanceUID = reader.ReadKey(); } else { if (tag.Tag > 0x7FFF) { // Find the tag in the primerpack's keys if (this.Partition != null && this.Partition.PrimerKeys != null) { if (this.Partition.PrimerKeys.ContainsKey(tag.Tag)) { MXFEntryPrimer entry = this.Partition.PrimerKeys[tag.Tag]; tag.Name = entry.AliasUID.Key.Name; } } } // Allow derived classes to handle the data if (!ParseLocalTag(reader, tag)) { // Not processed, use default tag.Parse(reader); // Add to the collection AddChild(tag); } } reader.Seek(next); } // Allow derived classes to do some final work PostInitialize(); }
public MXFPackageMetaData(MXFReader reader, MXFKLV headerKLV) : base(headerKLV, "PackageMetadata", KeyType.PackageMetaDataSet) { this.m_eType = MXFObjectType.Essence; // I will count this as essence data if (this.Key[5] == 0x63) { nofSizeSize = 4; } switch (this.Key[14]) { case 0x02: this.Key.Name = "Package Metadata set"; break; case 0x03: this.Key.Name = "Picture Metadata set"; break; case 0x04: this.Key.Name = "Sound Metadata set"; break; case 0x05: this.Key.Name = "Data Metadata set"; break; case 0x06: this.Key.Name = "Control Metadata set"; break; } reader.Seek(this.DataOffset); // Seek to the start of the data long end = this.DataOffset + this.Length; while (reader.Position < end) { byte type = reader.ReadB(); UInt32 size = 0; if (nofSizeSize == 2) { size = reader.ReadW(); } else { size = reader.ReadD(); } long startPos = reader.Position; if (m_itemTypes.ContainsKey(type)) { this.AddChild(new MXFData(m_itemTypes[type], reader, size)); } reader.Seek(startPos + size); } }
public MXFSystemItem(MXFReader reader, MXFKLV headerKLV) : base(headerKLV, "SystemItem (CP)", KeyType.SystemItem) { this.m_eType = MXFObjectType.SystemItem; if (this.Key[12] == 0x14) { this.Key.Name = "SystemItem (GC)"; } reader.Seek(this.DataOffset); // Seek to the start of the data // Parse system bitmap this.SystemBitmap = (SystemBitmap)reader.ReadByte(); // Parse Content package rate byte rate = reader.ReadByte(); int rateIndex = (rate & 0x1E) >> 1; int[] rates = new int[16] { 0, 24, 25, 30, 48, 50, 60, 72, 75, 90, 96, 100, 120, 0, 0, 0 }; int rateNonDrop = 1; if (rateIndex < 16) { rateNonDrop = rates[rateIndex]; } this.PackageRate = rateNonDrop; if ((rate & 0x01) == 0x01) // 1.001 divider active? { this.PackageRate = this.PackageRate / 1.001; } // Parse Content Package Type byte type = reader.ReadByte(); this.StreamStatus = (SystemStreamStatus)((type & 0xE0) >> 5); this.LowLatencyMode = ((type & 0x10) == 0x10); this.TransferMode = (SystemTransferMode)((type & 0x0C) >> 2); this.TimingMode = (SystemTimingMode)(type & 0x03); this.ChannelHandle = reader.ReadUInt16(); this.ContinuityCount = reader.ReadUInt16(); this.SMPTE = reader.ReadULKey(); // Always read even if zero MXFTimeStamp creationTimeStamp = reader.ReadBCDTimeCode(this.PackageRate); this.CreationDate = creationTimeStamp.ToString(); this.UserDate = reader.ReadBCDTimeCode(this.PackageRate); this.UserDateFullFrameNb = this.UserDate.GetString(true); }
/// <summary> /// Try to locate the RIP /// </summary> private bool ReadRIP(MXFKLVFactory klvFactory) { if (this.RIP == null) { // Read the last 4 bytes of the file m_reader.Seek(this.Filesize - 4); uint ripSize = m_reader.ReadD(); if (ripSize < this.Filesize && ripSize >= 4) // At least 4 bytes { m_reader.Seek(this.Filesize - ripSize); MXFKLV klv = klvFactory.CreateObject(m_reader, null); if (klv.Key.Type == KeyType.RIP) { // Yes, RIP found this.AddChild(klv); this.RIP = klv as MXFRIP; return(true); } } } return(false); }
private void Initialize(MXFReader reader) { // Make sure we read at the data position reader.Seek(this.DataOffset); // Read all local tags long klvEnd = this.DataOffset + this.Length; while (reader.Position + 12 < klvEnd) { // Add to the collection AddChild(new MXFEntryRIP(reader)); } }
public MXFPartition(MXFReader reader, MXFKLV headerKLV) : base(headerKLV, "Partition", KeyType.Partition) { this.m_eType = MXFObjectType.Partition; this.IsLoaded = false; // Determine the partition type switch (this.Key[13]) { case 2: this.PartitionType = PartitionType.Header; break; case 3: this.PartitionType = PartitionType.Body; break; case 4: this.PartitionType = PartitionType.Footer; break; default: this.PartitionType = PartitionType.Unknown; Log(MXFLogType.Error, "unknown partition type"); break; } this.Closed = (this.PartitionType == PartitionType.Footer) || (this.Key[14] & 0x01) == 0x00; this.Complete = (this.Key[14] > 2); // Make sure we read at the data position reader.Seek(this.DataOffset); this.MajorVersion = reader.ReadUInt16(); this.MinorVersion = reader.ReadUInt16(); this.KagSize = reader.ReadUInt32(); this.ThisPartition = reader.ReadUInt64(); this.PreviousPartition = reader.ReadUInt64(); this.FooterPartition = reader.ReadUInt64(); this.HeaderByteCount = reader.ReadUInt64(); this.IndexByteCount = reader.ReadUInt64(); this.IndexSID = reader.ReadUInt32(); this.BodyOffset = reader.ReadUInt64(); this.BodySID = reader.ReadUInt32(); this.OP = reader.ReadULKey(); MXFObject essenceContainers = reader.ReadAUIDSet("Essence Containers", "Essence Container"); this.AddChild(essenceContainers); }
/// <summary> /// Partially Parse an MXF file, skip all data /// </summary> protected void ParsePartial(BackgroundWorker worker) { Stopwatch sw = Stopwatch.StartNew(); MXFKLVFactory klvFactory = new MXFKLVFactory(); MXFPartition currentPartition = null; int previousPercentage = 0; Dictionary <UInt16, MXFEntryPrimer> allPrimerKeys = null; int[] counters = new int[Enum.GetNames(typeof(KeyType)).Length]; PartialSeekMode seekMode = PartialSeekMode.Unknown; using (m_reader = new MXFReader(this.Filename)) { this.Filesize = m_reader.Size; MXFObject partitions = new MXFNamedObject("Partitions", 0); this.AddChild(partitions); // Start with trying to find the RIP bool ripFound = ReadRIP(klvFactory); if (ripFound) { seekMode = PartialSeekMode.UsingRIP; } m_reader.Seek(0); // Start at the beginning // Start by reading the first partition int partitionNumber = 0; // For easy partition identification while (!m_reader.EOF && seekMode != PartialSeekMode.Backwards) // Eof and NOT searching backwards { MXFKLV klv = klvFactory.CreateObject(m_reader, currentPartition); // Update overall counters if (klv.Key.Type == KeyType.None) { counters[(int)klv.Key.Type]++; } if (klv.Key.Type == KeyType.Partition && seekMode == PartialSeekMode.Backwards) { if (this.Partitions.Exists(a => a.Offset == klv.Offset)) { // A new partition has been found that we already found, quit the main loop break; } } // Process the new KLV ProcessKLVObject(klv, partitions, ref currentPartition, ref partitionNumber, ref allPrimerKeys); // If we found the second partition long nextSeekPosition = klv.DataOffset + klv.Length; if (partitionNumber >= 2) // Header fully read, now busy with the second partition { switch (seekMode) { case PartialSeekMode.UsingRIP: // And we already found the RIP if (currentPartition.FirstSystemItem != null) // And we found the first system item { MXFEntryRIP ripEntry = this.RIP.GetPartition(partitionNumber); if (ripEntry != null) { // Mark the current partition as not-completely read currentPartition.IsLoaded = false; // Start at the next partition nextSeekPosition = (long)ripEntry.PartitionOffset; } } break; case PartialSeekMode.Backwards: // NO RIP, searching backwards // Backwards, jump to the PREVIOUS partition if (currentPartition.FirstSystemItem != null) // And we found the first system item { // Jump to the previous partition if (currentPartition.PreviousPartition != 0) { // And we haven't found this partition yet if (!this.Partitions.Exists(a => a.ThisPartition == currentPartition.PreviousPartition)) { nextSeekPosition = (long)currentPartition.PreviousPartition; // Jump to previous } } } break; case PartialSeekMode.Unknown: // No RIP.... // Hmmm, RIP is not found, check if we have a footer partition somewhere MXFPartition part = this.Partitions.Where(a => a.FooterPartition != 0).FirstOrDefault(); if (part != null) { // If we are already at the footer, don't bother to seek if (currentPartition.Offset != (long)part.FooterPartition) { nextSeekPosition = (long)part.FooterPartition; // Start at the footer seekMode = PartialSeekMode.Backwards; } } break; } } // Next KLV please m_reader.Seek(nextSeekPosition); // Only report progress when the percentage has changed int currentPercentage = (int)((m_reader.Position * 90) / m_reader.Size); if (currentPercentage != previousPercentage) { worker.ReportProgress(currentPercentage, "Partial Parsing MXF file"); previousPercentage = currentPercentage; } } } // Progress should now be 90% // Update all type descriptions klvFactory.UpdateAllTypeDescriptions(allPrimerKeys); Debug.WriteLine("Finished parsing file '{0}' in {1} ms", this.Filename, sw.ElapsedMilliseconds); sw.Restart(); // Create a list with all UID keys worker.ReportProgress(91, "Creating key list"); Dictionary <string, MXFObject> allKeys = new Dictionary <string, MXFObject>(); CreateKeyList(allKeys, this); // Resolve the references worker.ReportProgress(92, "Resolving references"); ResolveReferences(allKeys, this); Debug.WriteLine("Finished resolving references in {0} ms", sw.ElapsedMilliseconds); sw.Restart(); this.FlatList = new List <MXFObject>(); worker.ReportProgress(93, "Creating flat list"); this.AddToList(this.FlatList); Debug.WriteLine("Flatlist created in {0} ms", sw.ElapsedMilliseconds); sw.Restart(); // Create the logical tree worker.ReportProgress(94, "Creating logical tree"); CreateLogicalTree(); Debug.WriteLine("Logical tree created in {0} ms", sw.ElapsedMilliseconds); sw.Restart(); // And Execute FAST tests this.ExecuteValidationTest(worker, false); // Finished worker.ReportProgress(100, "Finished"); }
/// <summary> /// Fully Parse an MXF file /// </summary> protected void ParseFull(BackgroundWorker worker) { Stopwatch sw = Stopwatch.StartNew(); MXFKLVFactory klvFactory = new MXFKLVFactory(); MXFPartition currentPartition = null; int previousPercentage = 0; Dictionary <UInt16, MXFEntryPrimer> allPrimerKeys = null; int[] counters = new int[Enum.GetNames(typeof(KeyType)).Length]; using (m_reader = new MXFReader(this.Filename)) { this.Filesize = m_reader.Size; MXFObject partitions = new MXFNamedObject("Partitions", 0); this.AddChild(partitions); int partitionNumber = 0; // For easy partition identification while (!m_reader.EOF) { MXFKLV klv = klvFactory.CreateObject(m_reader, currentPartition); // Update overall counters if (klv.Key.Type == KeyType.None) { counters[(int)klv.Key.Type]++; } // Process the new KLV ProcessKLVObject(klv, partitions, ref currentPartition, ref partitionNumber, ref allPrimerKeys); // Next KLV please m_reader.Seek(klv.DataOffset + klv.Length); // Only report progress when the percentage has changed int currentPercentage = (int)((m_reader.Position * 90) / m_reader.Size); if (currentPercentage != previousPercentage) { worker.ReportProgress(currentPercentage, "Parsing MXF file"); previousPercentage = currentPercentage; } } } // Progress should now be 90% // Update all type descriptions klvFactory.UpdateAllTypeDescriptions(allPrimerKeys); worker.ReportProgress(91, "Creating key list"); Debug.WriteLine("Finished parsing file '{0}' in {1} ms", this.Filename, sw.ElapsedMilliseconds); sw.Restart(); // Create a list with all UID keys Dictionary <string, MXFObject> allKeys = new Dictionary <string, MXFObject>(); CreateKeyList(allKeys, this); worker.ReportProgress(92, "Creating resolving references"); // Resolve the references ResolveReferences(allKeys, this); Debug.WriteLine("Finished resolving references in {0} ms", sw.ElapsedMilliseconds); sw.Restart(); worker.ReportProgress(93, "Resolving flatlist"); this.FlatList = new List <MXFObject>(); this.AddToList(this.FlatList); Debug.WriteLine("Flatlist created in {0} ms", sw.ElapsedMilliseconds); sw.Restart(); worker.ReportProgress(94, "Creating Logical tree"); // Create the logical tree CreateLogicalTree(); Debug.WriteLine("Logical tree created in {0} ms", sw.ElapsedMilliseconds); sw.Restart(); // And Execute ALL test this.ExecuteValidationTest(worker, true); // Finished worker.ReportProgress(100, "Finished"); }
private void Initialize(MXFReader reader) { // Make sure we read at the data position reader.Seek(this.DataOffset); ItemValue_ISO7 = reader.ReadUTF8String((int)this.Length); }
/// <summary> /// Overridden method to process local tags /// </summary> /// <param name="localTag"></param> protected override bool ParseLocalTag(MXFReader reader, MXFLocalTag localTag) { switch (localTag.Tag) { case 0x3F05: this.EditUnitByteCount = reader.ReadUInt32(); return(true); case 0x3F06: this.IndexSID = reader.ReadUInt32(); return(true); case 0x3F07: this.BodySID = reader.ReadUInt32(); return(true); case 0x3F08: this.SliceCount = reader.ReadByte(); return(true); case 0x3F0C: this.IndexStartPosition = reader.ReadUInt64(); return(true); case 0x3F0D: this.IndexDuration = reader.ReadUInt64(); return(true); case 0x3F0E: this.PosTableCount = reader.ReadByte(); return(true); case 0x3F0F: this.ExtStartOffset = reader.ReadUInt64(); return(true); case 0x3F10: this.VBEByteCount = reader.ReadUInt64(); return(true); case 0x3F11: this.SingleIndexLocation = reader.ReadBool(); return(true); case 0x3F12: this.SingleEssenceLocation = reader.ReadBool(); return(true); case 0x3F13: this.ForwardIndexDirection = reader.ReadBool(); return(true); case 0x3F0B: this.IndexEditRate = reader.ReadRational(); return(true); case 0x3F0A: // Index entry array { UInt32 NbIndexEntries = reader.ReadUInt32(); UInt32 entryLength = reader.ReadUInt32(); if (NbIndexEntries > 0) { this.IndexEntries = new List <MXFEntryIndex>(); MXFObject indexCollection = new MXFNamedObject("IndexEntries", reader.Position, MXFObjectType.Index); for (UInt64 i = 0; i < NbIndexEntries; i++) { long next = reader.Position + entryLength; MXFEntryIndex newEntry = new MXFEntryIndex((ulong)this.IndexStartPosition + i, reader, this.SliceCount, this.PosTableCount, entryLength); this.IndexEntries.Add(newEntry); // Also add this entry to the local list // And to the child collection indexCollection.AddChild(newEntry); reader.Seek(next); } this.AddChild(indexCollection); } } return(true); case 0x3F09: // Delta entry array { UInt32 NbDeltaEntries = reader.ReadUInt32(); UInt32 entryLength = reader.ReadUInt32(); if (NbDeltaEntries > 0) { MXFObject deltaCollection = new MXFNamedObject("DeltaEntries", reader.Position, MXFObjectType.Index); for (int i = 0; i < NbDeltaEntries; i++) { long next = reader.Position + entryLength; deltaCollection.AddChild(new MXFEntryDelta(reader, entryLength)); reader.Seek(next); } this.AddChild(deltaCollection); } } return(true); } return(base.ParseLocalTag(reader, localTag)); }
// Add all meta data see spec: SMPTE ST 331:2011 private void ParseElements(MXFReader reader) { reader.Seek(this.DataOffset); // Seek to the start of the data long end = this.DataOffset + this.Length; byte[] byteArray; while (reader.Position < end) { var(Tag, Size) = GetTag(reader); var pos = reader.Position; switch (Tag) { // Metadata link case 0x80: byteArray = reader.ReadArray(reader.ReadByte, (int)Size); this.AddChild(new MXFWrapperObject <byte[]>(byteArray, "Metadata link", pos, Size)); break; // SMPTE 12M time-code case 0x81: byteArray = reader.ReadArray(reader.ReadByte, (int)Size); this.AddChild(new MXFWrapperObject <byte[]>(byteArray, "SMPTE 12M time-code", pos, Size)); break; // SMPTE 309M date-time stamp case 0x82: byteArray = reader.ReadArray(reader.ReadByte, (int)Size); this.AddChild(new MXFWrapperObject <byte[]>(byteArray, "SMPTE 309M date-time stamp", pos, Size)); break; // UMID case 0x83: byteArray = reader.ReadArray(reader.ReadByte, (int)Size); if (Size == 64) { var umid = new MXFExtendedUMID(byteArray); this.AddChild(new MXFWrapperObject <MXFExtendedUMID>(umid, "ExtendedUMID", pos, Size)); } else if (Size == 32) { var umid = new MXFUMID(byteArray); this.AddChild(new MXFWrapperObject <MXFUMID>(umid, "UMID", pos, Size)); } else { Debug.WriteLine("Invalid tag size for UMID. Must be 32 bytes or 64 for extended UMID"); } break; // MPEG-2 picture editing case 0x84: byteArray = reader.ReadArray(reader.ReadByte, (int)Size); this.AddChild(new MXFWrapperObject <byte[]>(byteArray, "MPEG-2 picture editing", pos, Size)); break; // 8-channel AES3 editing case 0x85: byteArray = reader.ReadArray(reader.ReadByte, (int)Size); this.AddChild(new MXFWrapperObject <byte[]>(byteArray, "8-channel AES3 editing", pos, Size)); break; // Picture bit-stream splicing case 0x86: byteArray = reader.ReadArray(reader.ReadByte, (int)Size); this.AddChild(new MXFWrapperObject <byte[]>(byteArray, "Picture bit-stream splicing", pos, Size)); break; // MPEG decoder buffer delay case 0x87: byteArray = reader.ReadArray(reader.ReadByte, (int)Size); this.AddChild(new MXFWrapperObject <byte[]>(byteArray, "MPEG decoder buffer delay", pos, Size)); break; // KLV metadata case 0x88: var obj = new MXFKLVFactory().CreateObject(reader, this.Partition); this.AddChild(obj); break; // AES3 non-audio metadata case 0x89: byteArray = reader.ReadArray(reader.ReadByte, (int)Size); this.AddChild(new MXFWrapperObject <byte[]>(byteArray, "AES3 non-audio metadata", pos, Size)); break; default: break; } // seek to next tag position reader.Seek(pos + Size); } }
/// <summary> /// Fully Parse an MXF file /// </summary> protected void ParseFull(BackgroundWorker worker) { Stopwatch sw = Stopwatch.StartNew(); MXFKLVFactory klvFactory = new MXFKLVFactory(); MXFPartition currentPartition = null; int previousPercentage = 0; Dictionary <UInt16, MXFEntryPrimer> allPrimerKeys = null; //int[] counters = new int[Enum.GetNames(typeof(KeyType)).Length]; using (m_reader = new MXFReader(this.Filename)) { this.Filesize = m_reader.Size; MXFObject partitions = new MXFNamedObject("Partitions", 0); this.AddChild(partitions); int partitionNumber = 0; // For easy partition identification while (!m_reader.EOF) { try { MXFKLV klv = klvFactory.CreateObject(m_reader, currentPartition); //// Update overall counters //if (klv.Key.Type == KeyType.None) // counters[(int)klv.Key.Type]++; // Process the new KLV ProcessKLVObject(klv, partitions, ref currentPartition, ref partitionNumber, ref allPrimerKeys); // Next KLV please m_reader.Seek(klv.DataOffset + klv.Length); } catch (Exception e) { m_reader.SeekForNextPotentialKey(); } // Only report progress when the percentage has changed int currentPercentage = (int)((m_reader.Position * 90) / m_reader.Size); if (currentPercentage != previousPercentage) { worker.ReportProgress(currentPercentage, "Parsing MXF file"); previousPercentage = currentPercentage; } } } Debug.WriteLine("Finished parsing file '{0}' in {1} ms", this.Filename, sw.ElapsedMilliseconds); // Progress should now be 90% DoPostWork(worker, sw, allPrimerKeys); // And Execute ALL test sw.Restart(); this.ExecuteValidationTest(worker, true); Debug.WriteLine("Tests executed in {0} ms", sw.ElapsedMilliseconds); // Finished worker.ReportProgress(100, "Finished"); }