Example #1
0
        /// <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();
        }
Example #4
0
        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);
            }
        }
Example #5
0
        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);
        }
Example #6
0
 /// <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);
 }
Example #7
0
        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));
            }
        }
Example #8
0
        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);
        }
Example #9
0
        /// <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");
        }
Example #10
0
        /// <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");
        }
Example #11
0
 private void Initialize(MXFReader reader)
 {
     // Make sure we read at the data position
     reader.Seek(this.DataOffset);
     ItemValue_ISO7 = reader.ReadUTF8String((int)this.Length);
 }
Example #12
0
        /// <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));
        }
Example #13
0
        // 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);
            }
        }
Example #14
0
        /// <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");
        }