예제 #1
0
        protected override void OnDoWork(DoWorkEventArgs e)
        {
            IFragment   fragment = e.Argument as IFragment;
            IResultNode results  = null;

            try
            {
                results = GetResults(fragment, this);
            }
            catch (FileNotFoundException fileNotFoundException)
            {
                ExceptionHandling.HandleFileNotFoundException(fileNotFoundException);
            }
            catch (IOException ioException)
            {
                ExceptionHandling.HandleIOException(ioException, fragment == null ? string.Empty : fragment.InputFile.Name);
            }
            catch (FrameworkException frameworkException)
            {
                ExceptionHandling.HandleFrameworkException(frameworkException);
            }

            // Return cancellation state
            if (CancellationPending)
            {
                e.Cancel = true;
            }
            else
            {
                e.Result = results;
            }

            base.OnDoWork(e);
        }
예제 #2
0
        private static string GetExtraDataCodecStreamName(IResultNode headerDataAtom)
        {
            QtAtom track             = FindParentAtom(headerDataAtom, AtomName.Track);
            QtAtom sampleDescription = FindParentAtom(headerDataAtom, AtomName.SampleDescription);

            return(GetCodecStreamName(track, sampleDescription, true));
        }
예제 #3
0
        public IDataPacket FindReferenceHeader(IDataReader dataReader, ICodecParametersSpec codecParameters)
        {
            while (dataReader.State == DataReaderState.Ready)
            {
                IScanContext scanContext = new ReferenceHeaderScanContext {
                    Detectors = new[] { this }
                };

                var dataBlock = _carver.Carve(new BitStreamDataReader(dataReader), new ReferenceHeaderDataBlockBuilder(), scanContext);
                if (dataBlock == null)
                {
                    break;                     // No (more) data blocks detected
                }

                IResultNode sequenceHeader = scanContext.Results.FindChild(SequenceHeader.Name);
                if (sequenceHeader != null)
                {
                    return(CreateReferenceHeader(dataBlock.DataFormat, sequenceHeader, codecParameters));
                }

                // Sequence header is missing: Continue scanning after current data block ...
                dataReader.Position = dataBlock.EndOffset;
            }

            return(null);            // No reference header detected
        }
 public void SelectPacketInTree(IResultNode resultNode, Control parentControl)
 {
     if (_keyframeSourceTree != null)
     {
         _keyframeSourceTree.SelectedItem = resultNode;
     }
 }
예제 #5
0
        public IDataPacket GetVideoHeaders(IResultNode headerPacket)
        {
            IResultNode pictureNode = GetPictureNode(headerPacket);

            IDataPacket data = null;

            for (IResultNode node = pictureNode.Parent; node != null; node = node.Parent)
            {
                if (node.Name == SequenceHeader.Name)
                {
                    // Check for 'SequenceExtension', required for MPEG2
                    foreach (IResultNode childNode in node.Children)
                    {
                        if (childNode.Name == SequenceExtension.Name)
                        {
                            data = data.Prepend(childNode);
                        }
                    }
                }
                if (node.Length > 0)
                {
                    // Add parent node
                    data = data.Prepend(node);
                }
            }
            return(data);
        }
        public void TestSubstDETMultipleDetectors()
        {
            String parameters = "-a [DET]";

            IResultNode top1   = MockRepository.GenerateStub <IResultNode>();
            IResultNode top2   = MockRepository.GenerateStub <IResultNode>();
            IResultNode child1 = MockRepository.GenerateStub <IResultNode>();

            top1.Stub(t => t.Children).Return(new IResultNode[] { child1 });
            child1.Stub(c => c.Children).Return(new IResultNode[0]);
            top2.Stub(t => t.Children).Return(new IResultNode[0]);
            _selection.Stub(s => s.Results).Return(new IResultNode[] { top1, top2 });

            ICodecDetector okDetector = MockRepository.GenerateStub <ICodecDetector>();

            okDetector.Stub(d => d.Name).Return("ok detector");
            IDetector notOkDetector = MockRepository.GenerateStub <IDetector>();

            notOkDetector.Stub(d => d.Name).Return("not ok detector");

            top1.Stub(t => t.Detectors).Return(new IDetector[] { okDetector });
            top2.Stub(t => t.Detectors).Return(new IDetector[] { notOkDetector });
            child1.Stub(t => t.Detectors).Return(new IDetector[] { okDetector });

            String subst = _checker.Substitute(parameters, _selection, _dataPacket, outputFilename);

            Assert.AreEqual(subst, "-a \"ok detector\"");
        }
        public void TestSubstLISTO()
        {
            String parameters = "-z [LISTO]";

            IResultNode top1   = MockRepository.GenerateStub <IResultNode>();
            IResultNode child1 = MockRepository.GenerateStub <IResultNode>();
            IResultNode child2 = MockRepository.GenerateStub <IResultNode>();

            top1.Stub(t => t.Children).Return(new IResultNode[] { child1, child2 });
            child1.Stub(c => c.Children).Return(new IResultNode[0]);
            child2.Stub(c => c.Children).Return(new IResultNode[0]);

            IResultNode top2 = MockRepository.GenerateStub <IResultNode>();

            top2.Stub(t => t.Children).Return(new IResultNode[0]);

            _selection.Stub(s => s.Results).Return(new IResultNode[] { top1, top2 });

            top1.Stub(t => t.Length).Return(8);
            top1.Stub(t => t.StartOffset).Return(1);
            top2.Stub(t => t.Length).Return(17);
            top2.Stub(t => t.StartOffset).Return(2);
            child1.Stub(c => c.Length).Return(99);
            child1.Stub(c => c.StartOffset).Return(3);
            child2.Stub(c => c.Length).Return(66);
            child2.Stub(c => c.StartOffset).Return(4);

            String subst = _checker.Substitute(parameters, _selection, _dataPacket, outputFilename);

            Assert.AreEqual(subst, "-z 1 8 3 99 4 66 2 17");
        }
예제 #8
0
        /// <summary>
        /// Adds columns for the dropped detectors.
        /// Normaly this is done by Workpad.AddFragments, but the drop doesn't use this method.
        /// </summary>
        /// <param name="sender">Event sender</param>
        /// <param name="e">Drop event row data</param>
        private void headerTree_RowDrop(object sender, RowDropEventArgs e)
        {
            if (!headerTree.IsWorkpad)
            {
                return;
            }
            Row[] rows = (Row[])e.Data.GetData(typeof(Row[]));

            // For each detector in the data blocks,
            // add the column names to the column chooser
            List <IDetector> detectors = new List <IDetector>(); // List to keep track of the handled detectors

            foreach (Row row in rows)
            {
                IResultNode resultNode = row.Item as IResultNode;

                if (resultNode != null)
                {
                    foreach (IDetector detector in resultNode.Detectors.Where(d => (!detectors.Contains(d))))
                    {
                        detectors.Add(detector);
                        AddColumns(detector);
                    }
                }
            }
        }
        public override IDataPacket GetVideoHeaders(IResultNode headerPacket)
        {
            IDataPacket data = null;

            IResultNode parentNode = headerPacket.Parent;

            if (parentNode is GroupOfVop)
            {
                parentNode = parentNode.Parent;
            }
            if (parentNode != null)
            {
                // Add parent parent node (required WHEN available)
                IResultNode parentParentNode = parentNode.Parent;
                if ((parentParentNode != null) && (parentParentNode.Length > 0))
                {
                    data = parentParentNode;
                }

                // Add parent node (required)
                if (parentNode.Length > 0)
                {
                    data = (data == null) ? parentNode : data.Append(parentNode);
                }
            }
            return(data);
        }
        public void TestReaderGetDataBlocksVerifyContents()
        {
            IInputFile         inputFile  = _project.GetInputFiles()[0];
            IList <IDataBlock> dataBlocks = _project.GetDataBlocks(inputFile);

            Assert.AreEqual(inputFile, dataBlocks[0].InputFile, "DataBlock.InputFile");
            Assert.AreEqual(0, dataBlocks[0].StartOffset, "DataBlock.StartOffset");
            Assert.AreEqual(268, dataBlocks[0].Length, "DataBlock.Length");
            Assert.AreEqual(false, dataBlocks[0].IsFullFile, "DataBlock.IsFullFile");
            IResultNode results = TestFramework.GetResults(dataBlocks[0]);

            Assert.AreEqual(1, results.Children[0].Length, "DataBlock.StartResult.Length");
            Assert.AreEqual("correct type 1", results.Children[0].Name, "DataBlock.StartResult.Name");
            Assert.AreEqual(true, results.Children[0].Children != null && results.Children[0].Children.Count > 0, "DataBlock.StartResult.HasChildren");
            Assert.AreEqual(2, results.Children[0].Attributes.Count, "DataBlock.StartResult.Attributes.Count");

            Assert.AreEqual(inputFile, dataBlocks[1].InputFile, "DataBlock.InputFile");
            Assert.AreEqual(517, dataBlocks[1].StartOffset, "DataBlock.StartOffset");
            Assert.AreEqual(1, dataBlocks[1].Length, "DataBlock.Length");
            Assert.AreEqual(true, dataBlocks[1].IsFullFile, "DataBlock.IsFullFile");
            results = TestFramework.GetResults(dataBlocks[1]);
            Assert.AreEqual(1, results.Children[0].Length, "DataBlock.StartResult.Length");
            Assert.AreEqual("correct type 1", results.Children[0].Name, "DataBlock.StartResult.Name");
            Assert.AreEqual(false, results.Children[0].Children != null && results.Children[0].Children.Count > 0, "DataBlock.StartResult.HasChildren");
            Assert.AreEqual(2, results.Children[0].Attributes.Count, "DataBlock.StartResult.Attributes.Count");
        }
        private static bool IsSuitableSibling(IResultNode prev, IResultNode next)
        {
            if (prev == null)
            {
                return(true);                // (broken) H.264 streams can start with any NAL unit
            }
            if (IsUnparsableSlice(next) && !CheckFirstMacroblockInSliceSequence(prev, next))
            {
                return(false);
            }

            // TODO: implement these rules

            //switch (next.Name)
            //{
            //    case SequenceParameterSet.Name:
            //        return IsSlice(prev) || (prev.Name == EndOfSequence.Name);

            //    case PictureParameterSet.Name:
            //        return prev.Name == SequenceParameterSet.Name;

            //    case EndOfSequence.Name:
            //        return IsSlice(prev);

            //    case EndOfStream.Name:
            //        return (prev.Name == EndOfSequence.Name);

            //    case IdrPictureSlice.Name:
            //    case NonIdrPictureSlice.Name:
            //        return IsSlice(prev) || (prev.Name == PictureParameterSet.Name);
            //}

            return(true);
        }
예제 #12
0
        public void Test2804()
        {
            var file        = TestFramework.CreateInputFile(_fileName);
            var dataReader  = TestFramework.CreateDataReader(file);
            var scanContext = TestFramework.CreateScanContext(_project);

            //File begins with VOPs
            IDataBlock        vopBlock;
            IDataBlockBuilder vopBuilder;

            Assert.IsTrue(GetNextDataBlock(file, dataReader, scanContext, out vopBlock, out vopBuilder));
            Assert.IsNotNull(vopBlock);

            Assert.AreEqual(vopBlock.EndOffset, dataReader.Position);
            Assert.AreEqual(file.Length, dataReader.Length);

            //Next valid datablock is a VOL
            IDataBlock        volBlock;
            IDataBlockBuilder volBuilder;

            Assert.IsTrue(GetNextDataBlock(file, dataReader, scanContext, out volBlock, out volBuilder));
            Assert.IsNotNull(volBlock);
            Assert.IsNotNull(volBuilder);

            IResultNode volResult = scanContext.Results;

            Assert.IsNotNull(volResult);

            var expectedVol = volResult.GetLastDescendant();

            Assert.AreEqual("VideoObjectLayer", expectedVol.Name);
        }
        private static IResultNode GetPreviousResult(IResultNode node)
        {
            if (node == null)
            {
                return(null);
            }

            IResultNode parentNode = node.Parent;

            if (parentNode == null)
            {
                return(null);
            }

            var children = parentNode.Children;

            for (int i = 0; i < children.Count; i++)
            {
                if (children[i] == node)
                {
                    if (i == 0)
                    {
                        return(GetPreviousResult(parentNode));
                    }

                    return(children[i - 1].GetLastDescendant());
                }
            }
            return(null);
        }
        private bool IsValidResult(IResultNode rootResultNode)
        {
            if (_state.ParsedHeaderCount < 2)
            {
                return(false);                // Less than two headers: Invalid!
            }
            if (!_falseHitReduction)
            {
                return(true);                // No further checks performed
            }

            if (HasResultNode(rootResultNode, r => IsSlice(r) && r.Valid))
            {
                return(true);                // At least one validated slice
            }
            if (HasResultNode(rootResultNode, r => (r.Name == SequenceParameterSet.Name) && r.Valid) &&
                HasResultNode(rootResultNode, r => (r.Name == PictureParameterSet.Name) && r.Valid))
            {
                return(true);                // At least a valid SPS and PPS
            }

            uint validSliceCount = GetValidSliceCount(rootResultNode);

            if (validSliceCount >= 4)
            {
                return(true);                // At least 4 slices that are likely valid
            }
            if (validSliceCount >= 2)
            {
                return(!HasResultNode(rootResultNode, r => IsSlice(r) && IsPotentialFalseHit(r)));
            }

            return(false);            // Dropping false hit
        }
        private static bool IsPotentialFalseHit(IResultNode resultNode)
        {
            if (resultNode.Length < 0x200)
            {
                return(true);
            }

            var firstMacroblockInSlice = resultNode.FindAttributeByName(FirstMacroblockInSliceName);

            if (firstMacroblockInSlice == null)
            {
                return(true);
            }

            var pictureParamaterSetId = resultNode.FindAttributeByName(PictureParameterSetIdName);

            if (pictureParamaterSetId == null)
            {
                return(true);
            }

            var sliceType = resultNode.FindAttributeByName(SliceTypeName);

            if (sliceType == null)
            {
                return(true);
            }

            return(H264Utils.ComputeFalseHitLikelihoodScore((uint)firstMacroblockInSlice.Value, (uint)pictureParamaterSetId.Value, (SliceType)(int)sliceType.Value) >= 1);
        }
        public void TestReaderGetResultsResultVerifyContents()
        {
            IList <IDataBlock> dataBlocks = _project.GetDataBlocks(_project.GetInputFiles()[0]);
            IResultNode        results    = TestFramework.GetResults(dataBlocks[0]);

            results = results.Children[0];
            Assert.AreEqual(255, results.Children[0].StartOffset, "Result.Offset");
            Assert.AreEqual(2, results.Children[0].Length, "Result.Length");
            Assert.AreEqual("correct type 2", results.Children[0].Name, "Result.Name");
            Assert.AreEqual(true, results.Children[0].Children != null && results.Children[0].Children.Count > 0, "Result.HasChildren");
            Assert.AreEqual(4, results.Children[0].Attributes.Count, "Result.Attributes.Count");
            Assert.AreEqual("type2 first", results.Children[0].Attributes[0].Value, "Result.Attributes[0]");

            results = results.Children[0];
            Assert.AreEqual(260, results.Children[0].StartOffset, "Result.Offset");
            Assert.AreEqual(3, results.Children[0].Length, "Result.Length");
            Assert.AreEqual("correct type 1", results.Children[0].Name, "Result.Name");
            Assert.AreEqual(false, results.Children[0].Children != null && results.Children[0].Children.Count > 0, "Result.HasChildren");
            Assert.AreEqual(2, results.Children[0].Attributes.Count, "Result.Attributes.Count");
            Assert.AreEqual("type1 first", results.Children[0].Attributes[0].Value, "Result.Attributes[0]");

            Assert.AreEqual(264, results.Children[1].StartOffset, "Result.Offset");
            Assert.AreEqual(4, results.Children[1].Length, "Result.Length");
            Assert.AreEqual("correct type 2", results.Children[1].Name, "Result.Name");
            Assert.AreEqual(false, results.Children[1].Children != null && results.Children[1].Children.Count > 0, "Result.HasChildren");
            Assert.AreEqual(4, results.Children[1].Attributes.Count, "Result.Attributes.Count");
            Assert.AreEqual("type2 unique second", results.Children[1].Attributes[1].Value, "Result.Attributes[1]");
        }
        public override IDataPacket FindReferenceHeader(IDataReader dataReader, ICodecParametersSpec codecParameters)
        {
            // Note: Loop to detect reference headers preceeded by a block of video frames
            //       (e.g. for 3GP files with 'mdat' before the 'moov' atom, so that the slices are located before the SPS/PPS pair)
            while (dataReader.State == DataReaderState.Ready)
            {
                IScanContext scanContext = new ReferenceHeaderScanContext {
                    Detectors = new[] { this }
                };

                var dataBlock = Carve(dataReader, new ReferenceHeaderDataBlockBuilder(), scanContext);
                if (dataBlock == null)
                {
                    break;                     // No (more) data blocks detected
                }

                IResultNode videoObject = scanContext.Results.FindChild(VideoObjectName);
                if ((videoObject != null) && videoObject.HasChildren())
                {
                    IResultNode videoObjectLayer = videoObject.GetFirstChild();
                    if (videoObjectLayer.Name == VideoObjectLayerName)
                    {
                        return(CreateReferenceHeader(dataBlock.DataFormat, videoObject, videoObjectLayer, codecParameters));
                    }
                }

                // VideoObject or VideoObjectLayer is missing: Continue scanning after current data block ...
                dataReader.Position = dataBlock.EndOffset;
            }

            return(null);            // No reference header detected
        }
        private IDataBlock DetectData1(IDataReader dataReader, IDataBlockBuilder dataBlockBuilder, IScanContext context)
        {
            if ((dataReader.Position + 51) > dataReader.Length)
            {
                return(null);
            }

            IResultNode root   = new MockResult(this);
            IResultNode parent = root;
            int         i      = (int)(dataReader.GetDataPacket(0, 1).StartOffset + (dataReader.Position) / 51);

            for (int j = 0; j < 3; j++)
            {
                long       offset = dataReader.Position;
                const long length = 17;
                parent = new MockResult(parent, dataReader, offset, length, "result: " + i + ", " + j);
                dataReader.Position += length;
            }
            context.Results = root;
            var firstChild = ((MockResult)context.Results.Children[0]);

            dataBlockBuilder.StartOffset = firstChild.Offset;
            var lastChild = ((MockResult)context.Results.GetLastDescendant());

            dataBlockBuilder.EndOffset = (lastChild.Offset + lastChild.Length);
            return(dataBlockBuilder.Build());
        }
예제 #19
0
        public void TestSaveRandomResultsMultiProject()
        {
            IInputFile         inputFile1  = Util.FindInputFile(_project1.GetInputFiles(), _testDataFile1);
            IInputFile         inputFile2  = Util.FindInputFile(_project1.GetInputFiles(), _testDataFile2);
            IInputFile         inputFile3  = Util.FindInputFile(_project2.GetInputFiles(), _testDataFile3);
            IList <IDataBlock> dataBlocks1 = _project1.GetDataBlocks(inputFile1);
            IList <IDataBlock> dataBlocks2 = _project1.GetDataBlocks(inputFile2);
            IList <IDataBlock> dataBlocks3 = _project2.GetDataBlocks(inputFile3);
            IResultNode        results12   = TestFramework.GetResults(dataBlocks1[2]);
            IResultNode        results20   = TestFramework.GetResults(dataBlocks2[0]);
            IResultNode        results30   = TestFramework.GetResults(dataBlocks3[0]);

            IResultNode[] results = new IResultNode[5];
            results[0] = results30.Children[4].ShallowCopy();
            results[1] = results20.Children[0].ShallowCopy();
            results[2] = results12.Children[0].ShallowCopy();
            results[3] = results30.Children[1].ShallowCopy();
            results[4] = results20.Children[0].ShallowCopy();
            TestFramework.WriteResults(results, _testOutputFile);
            byte[] contents = new byte[57];
            Array.Copy(_fullFile3, 60, contents, 0, 15);
            Array.Copy(_fullFile2, 0, contents, 15, 5);
            Array.Copy(_fullFile1, 102, contents, 20, 17);
            Array.Copy(_fullFile3, 15, contents, 37, 15);
            Array.Copy(_fullFile2, 0, contents, 52, 5);
            Util.AssertArrayEqualsFile(contents, _testOutputFile);
        }
예제 #20
0
        public void TestWriteRandomResultsFile1()
        {
            IInputFile         inputFile  = Util.FindInputFile(_project1.GetInputFiles(), _testDataFile1);
            IList <IDataBlock> dataBlocks = _project1.GetDataBlocks(inputFile);
            IResultNode        results0   = TestFramework.GetResults(dataBlocks[0]);
            IResultNode        results1   = TestFramework.GetResults(dataBlocks[1]);
            IResultNode        results2   = TestFramework.GetResults(dataBlocks[2]);
            IResultNode        results3   = TestFramework.GetResults(dataBlocks[3]);
            IResultNode        results4   = TestFramework.GetResults(dataBlocks[4]);

            IResultNode[] results = new IResultNode[5];
            results[0] = results0.Children[0].ShallowCopy();
            results[1] = results2.Children[0].ShallowCopy();
            results[2] = results4.Children[0].ShallowCopy();
            results[3] = results3.Children[0].ShallowCopy();
            results[4] = results1.Children[0].ShallowCopy();
            TestFramework.WriteResults(results, _testOutputFile);
            byte[] contents = new byte[85];
            Array.Copy(_fullFile1, 0, contents, 0, 17);
            Array.Copy(_fullFile1, 102, contents, 17, 17);
            Array.Copy(_fullFile1, 204, contents, 34, 17);
            Array.Copy(_fullFile1, 153, contents, 51, 17);
            Array.Copy(_fullFile1, 51, contents, 68, 17);
            Util.AssertArrayEqualsFile(contents, _testOutputFile);
        }
        public MockResult(IResultNode parent, IDataReader dataReader, long offset, long length, string name)
        {
            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }
            if (dataReader == null)
            {
                throw new ArgumentNullException("dataReader");
            }
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (length <= 0)
            {
                throw new ArgumentOutOfRangeException("length");
            }
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }

            _name       = name;
            _attributes = new List <IResultAttribute>();
            _dataPacket = dataReader.GetDataPacket(offset, length);
            _detector   = parent.Detectors.First();
            Offset      = offset;

            parent.AddChild(this);
        }
예제 #22
0
        private static bool IsIntraSlice(IResultNode resultNode)
        {
            if (!IsSlice(resultNode) || (resultNode.Name != IdrPictureSlice.Name))
            {
                return(false);
            }

            var sliceTypeAttribute = resultNode.FindAttributeByName(SliceTypeName);

            if (sliceTypeAttribute == null)
            {
                return(false);
            }

            if ((int)sliceTypeAttribute.Value == (int)SliceType.I)
            {
                return(true);
            }
            if ((int)sliceTypeAttribute.Value == (int)SliceType.OnlyI)
            {
                return(true);
            }

            return(false);
        }
예제 #23
0
 private static IResultNode Last(IResultNode result)
 {
     if (result.Children.Count > 0)
     {
         return(Last(result.Children[result.Children.Count - 1]));
     }
     return(result);
 }
예제 #24
0
 public void ClearWindow()
 {
     if (_previewWindow != null)
     {
         _previewWindow.UpdateResult(null);
         _activeFrameSourceNode = null;
     }
 }
예제 #25
0
 public void AddNewFFmpegConvertItem(IResultNode resultNode)
 {
     if (_previewWindow == null)
     {
         return;
     }
     _ffmpegManager.AddToConvertQueue(resultNode, this, true);
 }
예제 #26
0
 public void FFmpegDataConverted(FFmpegResult ffmpegResult)
 {
     if (_previewWindow != null)
     {
         _previewWindow.UpdateResult(ffmpegResult);
         _activeFrameSourceNode = ffmpegResult.SourcePacket;
     }
 }
 public MockResult(MockResult mockResult)
 {
     _name       = mockResult._name;
     _attributes = mockResult._attributes;
     _dataPacket = mockResult._dataPacket;
     _detector   = mockResult._detector;
     _parent     = null;
 }
 /// <summary>
 /// Creates a copy of <paramref name="result"/> without its children.
 /// </summary>
 /// <param name="result">the result to copy</param>
 /// <return>the shallow copy</return>
 public static IResultNode ShallowCopy(this IResultNode result)
 {
     if (result == null)
     {
         throw new ArgumentNullException("result");
     }
     return(new ResultNodeCopy(result));
 }
 public MockResult2(IResultNode parent, IDataReader dataReader, long offset, long length)
     : base(parent, dataReader, offset, length, "correct type 2")
 {
     Attributes.Add(new FormattedAttribute <string, string>("General first", "type2 first"));
     Attributes.Add(new FormattedAttribute <string, string>("Type2 specific second", "type2 unique second"));
     Attributes.Add(new FormattedAttribute <string, string>("General third", "type2 unique second"));
     Attributes.Add(new FormattedAttribute <string, string>("General fourth", "type2 unique second"));
 }
        public override IDataPacket GetVideoData(IResultNode resultNode)
        {
            // Mpeg4 doesn't require other data (frames) to make itself visible.
            IDataPacket dataPacket = resultNode;

            // Duplicate the frame data, because otherwise, FFmpeg won't decode it.
            return(dataPacket.Append(dataPacket));
        }