Example #1
0
 /// <summary>
 /// Copy constructor
 /// </summary>
 /// <param name="reader"></param>
 public MXFKLV(MXFKLV klv)
 {
     this.Offset     = klv.Offset;
     this.Key        = klv.Key;
     this.Length     = klv.Length;
     this.DataOffset = klv.DataOffset;
     this.Partition  = klv.Partition;
 }
Example #2
0
 /// <summary>
 /// Copy constructor
 /// </summary>
 /// <param name="reader"></param>
 public MXFKLV(MXFKLV klv, string name, KeyType type)
 {
     this.Offset     = klv.Offset;
     this.Key        = klv.Key;
     this.Key.Name   = name;
     this.Key.Type   = type;
     this.Length     = klv.Length;
     this.DataOffset = klv.DataOffset;
     this.Partition  = klv.Partition;
 }
Example #3
0
        /// <summary>
        /// Check if the RIP is present and valid
        /// </summary>
        /// <param name="this.File"></param>
        /// <param name="results"></param>
        public override void OnExecuteTest(ref List <MXFValidationResult> results)
        {
            MXFValidationResult valResult = new MXFValidationResult("Random Index Pack Test");

            results.Add(valResult);
            valResult.Category = "Random Index Pack";

            Stopwatch sw = Stopwatch.StartNew();

            if (this.File.RIP == null)
            {
                valResult.SetError(string.Format("Error! No RIP found."));
                return;
            }

            if (this.File.RIPEntryCount != this.File.PartitionCount)
            {
                valResult.SetError(string.Format("Error! Number of RIP entries is not equal to the number of partitions ({0} vs {1}).", this.File.RIPEntryCount, this.File.PartitionCount));
                return;
            }

            int ripErrorCount = 0;

            for (int n = 0; n < this.File.RIPEntryCount; n++)
            {
                MXFEntryRIP rip = this.File.RIP.Children[n] as MXFEntryRIP;
                if (rip != null)
                {
                    MXFPartition part = this.File.Partitions.Where(a => (ulong)a.Offset == rip.PartitionOffset).FirstOrDefault();
                    if (part == null)
                    {
                        ripErrorCount++;
                        valResult.AddError(string.Format("Error! RIP entry {0} not pointing to a valid partion.", n));
                        return;
                    }
                }
            }
            if (ripErrorCount > 0)
            {
                valResult.SetError(string.Format("Error! {0} RIP entries are not pointing to a valid partion.", ripErrorCount));
                return;
            }

            valResult.SetSuccess("Random Index Pack (RIP) is valid.");

            LogInfo("Validation completed in {0} msec", sw.ElapsedMilliseconds);
        }
Example #4
0
        /// <summary>
        /// Create a new MXF object based on the KLV key
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="currentPartition"></param>
        /// <returns></returns>
        public MXFKLV CreateObject(MXFReader reader, MXFPartition currentPartition)
        {
            MXFKLV klv = new MXFKLV(reader);

            klv.Partition = currentPartition; // Pass the current partition through to the classes

            if (dict.TryGetValue(klv.Key, out Type foundType))
            {
                return((MXFKLV)Activator.CreateInstance(foundType, reader, klv));
            }
            else
            {
                // TODO what if the key cannot be found, i.e. it is not known?
            }

            return(klv);
        }
Example #5
0
        /// <summary>
        /// Create a new MXF object based on the KLV key
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="currentPartition"></param>
        /// <returns></returns>
        public MXFKLV CreateObject(MXFReader reader, MXFPartition currentPartition)
        {
            MXFKLV klv = new MXFKLV(reader);

            klv.Partition = currentPartition;             // Pass the current partition through to the classes
            foreach (MXFKey knownKey in MXFKLVFactory.m_allKeys)
            {
                if (klv.Key == knownKey)
                {
                    if (knownKey.ObjectType != null)
                    {
                        return((MXFKLV)Activator.CreateInstance(knownKey.ObjectType, reader, klv));
                    }
                    klv.Key.Name = knownKey.Name;
                    klv.Key.Type = knownKey.Type;
                    break;
                }
            }
            return(klv);
        }
Example #6
0
 public static bool IsPartitionClosedAndComplete(this MXFPartition p)
 {
     return(!(p.Closed && p.Complete));
 }
Example #7
0
 public static bool IsPartitionDurationBetween(this MXFPartition partition, long min, long max)
 {
     return(partition.CountPictureEssences() >= min &&
            partition.CountPictureEssences() <= max);
 }
Example #8
0
 public static long CountPictureEssences(this MXFPartition partition)
 {
     return(partition.Children.OfType <MXFEssenceElement>().Count(e => e.IsPicture));
 }
Example #9
0
        /// <summary>
        /// Process a new KLV object
        /// </summary>
        /// <param name="klv"></param>
        /// <param name="partitions"></param>
        /// <param name="currentPartition"></param>
        /// <param name="partitionNumber"></param>
        /// <param name="allPrimerKeys"></param>
        private void ProcessKLVObject(MXFKLV klv, MXFObject partitions, ref MXFPartition currentPartition, ref int partitionNumber, ref Dictionary <UInt16, MXFEntryPrimer> allPrimerKeys)
        {
            // Is this a header, add to the partitions
            switch (klv.Key.Type)
            {
            case KeyType.Partition:
                currentPartition                 = klv as MXFPartition;
                currentPartition.File            = this;
                currentPartition.PartitionNumber = partitionNumber;
                this.Partitions.Add(currentPartition);
                partitions.AddChild(currentPartition);
                partitionNumber++;
                break;

            case KeyType.PrimerPack:
                if (currentPartition != null)
                {
                    MXFPrimerPack primer = klv as MXFPrimerPack;
                    if (primer != null)                             // Just to be sure
                    {
                        // Let the partition know all primer keys
                        allPrimerKeys = primer.AllKeys;
                        currentPartition.PrimerKeys = primer.AllKeys;
                    }
                    currentPartition.AddChild(klv);                             // Add the primer
                }
                break;

            case KeyType.RIP:
                // Only add the RIP when not yet present
                if (this.RIP == null)
                {
                    this.AddChild(klv);
                    this.RIP = klv as MXFRIP;
                }
                break;

            case KeyType.SystemItem:
                if (currentPartition != null)
                {
                    // Store the first system item for every partition
                    // (required to calculate essence positions)
                    if (currentPartition.FirstSystemItem == null)
                    {
                        currentPartition.FirstSystemItem = klv as MXFSystemItem;
                    }
                    currentPartition.AddChild(klv);
                }
                else
                {
                    this.AddChild(klv);
                }

                // Store the first and the last system item
                if (this.FirstSystemItem == null)
                {
                    this.FirstSystemItem = klv as MXFSystemItem;
                }
                this.LastSystemItem = klv as MXFSystemItem;
                break;


            case KeyType.Essence:
                if (currentPartition != null)
                {
                    // Store the first system item for every partition
                    // (required to calculate essence positions)
                    MXFEssenceElement ee = klv as MXFEssenceElement;
                    if (ee.IsPicture && currentPartition.FirstPictureEssenceElement == null)
                    {
                        currentPartition.FirstPictureEssenceElement = ee;
                    }
                    currentPartition.AddChild(klv);
                }
                else
                {
                    this.AddChild(klv);
                }
                break;

            case KeyType.Preface:
                this.LogicalBase = new MXFLogicalObject(klv, klv.ToString());
                // Normal
                if (currentPartition != null)
                {
                    currentPartition.AddChild(klv);
                }
                else
                {
                    this.AddChild(klv);
                }
                break;

            default:
                // Normal
                if (currentPartition != null)
                {
                    currentPartition.AddChild(klv);
                }
                else
                {
                    this.AddChild(klv);
                }
                break;
            }
        }
Example #10
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 #11
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 #12
0
        /// <summary>
        /// Check if all partitions are valid
        /// </summary>
        /// <param name="results"></param>
        public override void OnExecuteTest(ref List <MXFValidationResult> results)
        {
            this.Task = "Validating partitions";

            MXFValidationResult valResult = new MXFValidationResult("Partition Test");

            results.Add(valResult);
            valResult.Category = "Partitions";

            Stopwatch sw = Stopwatch.StartNew();

            if (this.File.Partitions == null || this.File.Partitions.Count == 0)
            {
                valResult.SetError(string.Format("Error! No partitions present."));
                return;
            }


            // Check if only a single header is present
            if (this.File.Partitions.Where(a => a.PartitionType == PartitionType.Header).Count() > 1)
            {
                valResult.SetError(string.Format("Error! More then 1 header partion present!"));
                return;
            }
            MXFPartition header = this.File.Partitions.Where(a => a.PartitionType == PartitionType.Header).FirstOrDefault();

            if (header == null)
            {
                valResult.SetError(string.Format("Error! No header partition present!"));
                return;
            }

            // Check if only a single footer is present
            if (this.File.Partitions.Where(a => a.PartitionType == PartitionType.Footer).Count() > 1)
            {
                valResult.SetError(string.Format("Error! More then 1 footer partion present!"));
                return;
            }
            MXFPartition footer         = this.File.Partitions.Where(a => a.PartitionType == PartitionType.Footer).FirstOrDefault();
            long         footerExpected = 0;

            if (footer == null)
            {
                valResult.SetWarning(string.Format("Error! No footer partition present!"));
                footerExpected = 0;
            }
            else
            {
                footerExpected = footer.Offset;
            }

            // Check if all partitions point to the previous partition and check the this pointer
            // Note that this is more serious and less likely to go wrong then the footer check
            for (int n = 0; n < this.File.Partitions.Count(); n++)
            {
                if (this.File.Partitions[n].ThisPartition != (ulong)this.File.Partitions[n].Offset)
                {
                    valResult.SetError(string.Format("Error! Partition[{0}] has an invalid 'ThisPartition' pointer.", n));
                    return;
                }

                if (n > 0)
                {
                    if (this.File.Partitions[n].PreviousPartition != (ulong)this.File.Partitions[n - 1].Offset)
                    {
                        valResult.SetError(string.Format("Error! Partition[{0}] has no valid link to the previous partition.", n));
                        return;
                    }
                }
            }

            // Check if all partitions point to the footer
            int errorCount = 0;

            for (int n = 0; n < this.File.Partitions.Count(); n++)
            {
                if (this.File.Partitions[n].Closed && this.File.Partitions[n].FooterPartition != (ulong)footerExpected)
                {
                    errorCount++;
                }
            }
            if (errorCount > 0)
            {
                valResult.SetWarning(string.Format("There are {0} partitions that do not point to the footer partition.", errorCount));
                return;
            }

            valResult.SetSuccess("Partition structure is valid.");

            LogInfo("Validation completed in {0} msec", sw.ElapsedMilliseconds);
        }
Example #13
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");
        }