Esempio n. 1
0
        public void TestVideoIndexerSerialization()
        {
            var frameFingerPrint = new FrameFingerPrintWrapper
            {
                FrameNumber        = 0,
                PHashCode          = 0x1010,
                EdgeGrayScaleThumb = new byte[] { 0, 1, 0 },
            };

            var videoFingerPrint = new VideoFingerPrintWrapper
            {
                FilePath     = "test.mkv",
                FingerPrints = new[] { frameFingerPrint },
            };

            var database = new VideoFingerPrintDatabaseWrapper
            {
                VideoFingerPrints = new[] { videoFingerPrint },
            };

            using (var memoryStream = new MemoryStream())
            {
                VideoFingerPrintDatabaseSaver.Save(database, memoryStream);
                byte[] savedDatabase = memoryStream.ToArray();
                VideoFingerPrintDatabaseWrapper reloadedDatabase = VideoFingerPrintDatabaseLoader.Load(savedDatabase);

                Assert.AreEqual(database, reloadedDatabase);
            }
        }
Esempio n. 2
0
        private static void IndexImpl(string databaseMetaTablePath, IEnumerable <string> videoPaths, int numThreads, long maxMemory)
        {
            IEnumerable <string> knownHashes = GetKnownDatabaseEntries(databaseMetaTablePath);
            var skippedFiles = new ConcurrentBag <string>();

            using (ChangeErrorMode _ = new ChangeErrorMode(ChangeErrorMode.ErrorModes.FailCriticalErrors | ChangeErrorMode.ErrorModes.NoGpFaultErrorBox))
                using (FingerPrintStore store = new FingerPrintStore(databaseMetaTablePath))
                {
                    long maxMemoryPerIndexJob = (long)Math.Round((double)maxMemory / numThreads);
                    Parallel.ForEach(
                        videoPaths.Except(knownHashes),
                        new ParallelOptions {
                        MaxDegreeOfParallelism = numThreads
                    },
                        videoPath =>
                    {
                        string fileName = Path.GetFileName(videoPath);
                        try
                        {
                            if (videoPath.Length > 260) // Max file path that mediainfo can handle
                            {
                                Console.WriteLine("File path is too long. Skipping: " + fileName);
                                return;
                            }

                            VideoFingerPrintWrapper videoFingerPrint = Video.VideoIndexer.IndexVideo(videoPath, maxMemoryPerIndexJob);
                            store.AddFingerPrint(videoFingerPrint);
                        }
                        catch (InvalidOperationException e)
                        {
                            Console.WriteLine(string.Format("Unable to hash file {0}. Reason: {1}. Skipping", fileName, e.Message));
                            skippedFiles.Add(videoPath);
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(string.Format("Unable to hash file {0}. Reason: {1}. Skipping", fileName, e.Message));
                        }
                    }
                        );

                    // Attempting to index skipped files
                    foreach (string skippedFile in skippedFiles)
                    {
                        Console.WriteLine("Attempting to hash skipped file: " + skippedFile);
                        try
                        {
                            VideoFingerPrintWrapper videoFingerPrint = Video.VideoIndexer.IndexVideo(skippedFile, maxMemory);
                            store.AddFingerPrint(videoFingerPrint);
                        }
                        catch (InvalidOperationException)
                        {
                            Console.WriteLine(string.Format("Unable to hash file {0} for the second time. Giving up", skippedFile));
                        }
                    }

                    store.Shutdown();
                    store.Wait();
                }
        }
Esempio n. 3
0
        private static void ExecuteCheckDatabase(string[] args)
        {
            string maxMemoryArg          = GetMaxMemory(args);
            string databaseMetaTablePath = GetDatabaseMetaTable(args);

            if (string.IsNullOrWhiteSpace(databaseMetaTablePath))
            {
                PrintHelp("Database metatable path not provided");
                return;
            }

            if (File.Exists(databaseMetaTablePath) == false)
            {
                PrintHelp("Database MetaTable does not exist");
                return;
            }

            if (string.IsNullOrWhiteSpace(maxMemoryArg))
            {
                PrintHelp("--max-memory must be set");
                return;
            }

            long maxMemory = 0;

            if (long.TryParse(maxMemoryArg, out maxMemory) == false)
            {
                PrintHelp("--max-memory could not be parsed");
                return;
            }

            VideoFingerPrintDatabaseMetaTableWrapper metaTable = VideoFingerPrintDatabaseMetaTableLoader.Load(databaseMetaTablePath);
            var random = new Random();

            foreach (string databasePath in metaTable.DatabaseMetaTableEntries.Select(e => e.FileName))
            {
                VideoFingerPrintDatabaseWrapper database = VideoFingerPrintDatabaseLoader.Load(databasePath);
                int videoFingerPrintSampleCount          = (int)Math.Round(database.VideoFingerPrints.Length / 3.0);
                IEnumerable <VideoFingerPrintWrapper> videoFingerPrints = from fingerPrint in database.VideoFingerPrints
                                                                          where random.Next() % 2 == 0
                                                                          select fingerPrint;

                foreach (VideoFingerPrintWrapper videoFingerPrint in videoFingerPrints.Take(videoFingerPrintSampleCount))
                {
                    VideoFingerPrintWrapper actualVideoFingerPrint = Video.VideoIndexer.IndexVideo(videoFingerPrint.FilePath, maxMemory);

                    if (Equals(videoFingerPrint, actualVideoFingerPrint) == false)
                    {
                        Console.WriteLine("{0} Fingerprint does not match", Path.GetFileName(videoFingerPrint.FilePath));
                    }
                }
            }
        }
Esempio n. 4
0
        private static WritableLockBitImage GetFrameFromVideo(VideoFingerPrintWrapper video, int frameNumber)
        {
            using (MediaInfoProcess mediaInfoProcess = new MediaInfoProcess(video.FilePath))
            {
                MediaInfo mediaInfo = mediaInfoProcess.Execute();
                if (mediaInfo.GetFramerate().Numerator == 0)
                {
                    throw new Exception("Did not get valid frame rate");
                }

                int width  = mediaInfo.GetWidth();
                int height = mediaInfo.GetHeight();
                var ffmpegProcessSettings = new FFMPEGProcessVideoSettings(
                    video.FilePath,
                    mediaInfo.GetFramerate().Numerator,
                    mediaInfo.GetFramerate().Denominator * 4,
                    FFMPEGMode.SeekFrame
                    );

                ffmpegProcessSettings.TargetFrame = frameNumber;
                byte[] frameBytes = new byte[width * height * 3];
                int    offset     = 0;
                using (
                    var ffmpegProcess = new FFMPEGProcess(
                        ffmpegProcessSettings,
                        (stdoutBytes, numBytes) =>
                {
                    Buffer.BlockCopy(stdoutBytes, 0, frameBytes, offset, numBytes);
                    offset += numBytes;
                },
                        false
                        )
                    )
                {
                    ffmpegProcess.Execute();
                    if (offset != 3 * width * height)
                    {
                        throw new Exception("Did not get all bytes to produce valid frame");
                    }

                    WritableLockBitImage videoFrame = new WritableLockBitImage(width, height, frameBytes);
                    videoFrame.Lock();
                    return(videoFrame);
                }
            }
        }
Esempio n. 5
0
        private static IDictionary <string, ISet <PhotoFingerPrintWrapper> > MapPhotosToVideos(
            PhotoFingerPrintDatabaseWrapper photoDatabase,
            VideoFingerPrintDatabaseMetaTableWrapper metatable
            )
        {
            IDictionary <string, ISet <PhotoFingerPrintWrapper> > resultMap = new Dictionary <string, ISet <PhotoFingerPrintWrapper> >();
            IDictionary <string, VideoFingerPrintWrapper>         fileNameToVideoFingerPrintMap = MetaTableUtils.EnumerateVideoFingerPrints(metatable).ToDictionary(e => e.FilePath);
            BKTree <FrameMetricWrapper> bktree = ModelMetricUtils.CreateBKTree(metatable);

            foreach (PhotoFingerPrintWrapper photo in photoDatabase.PhotoFingerPrints)
            {
                // 1. Find bucket of possible candidates
                IDictionary <FrameMetricWrapper, int> treeResults = bktree.Query(
                    new PhotoMetricWrapper
                {
                    Photo = photo,
                },
                    DefaultMetricThreshold
                    );

                IDictionary <string, ISet <FrameMetricWrapper> > collapsedTreeResults = ModelMetricUtils.CollapseTreeResults(treeResults);

                // 2. Find most likely result and add it to the bucket
                if (treeResults.Count > 0)
                {
                    VideoFingerPrintWrapper mostLikelyVideo = FindMostLikelyVideo(photo, collapsedTreeResults, fileNameToVideoFingerPrintMap);

                    // In the case where we didn't get any results, we just skip this photo and move alone
                    if (mostLikelyVideo == null)
                    {
                        continue;
                    }

                    ISet <PhotoFingerPrintWrapper> bucket;
                    string videoFileName = mostLikelyVideo.FilePath;
                    if (resultMap.TryGetValue(videoFileName, out bucket) == false)
                    {
                        bucket = new HashSet <PhotoFingerPrintWrapper>();
                        resultMap.Add(videoFileName, bucket);
                    }
                }
            }

            return(resultMap);
        }
Esempio n. 6
0
        private static VideoFingerPrintWrapper FindMostLikelyVideo(
            PhotoFingerPrintWrapper photo,
            IDictionary <string, ISet <FrameMetricWrapper> > treeResults,
            IDictionary <string, VideoFingerPrintWrapper> nameToVideoMap
            )
        {
            if (treeResults.Count() == 1)
            {
                return(treeResults.First().Value.First().Video);
            }

            using (WritableLockBitImage photoAsLockBitImage = new WritableLockBitImage(Image.FromFile(photo.FilePath)))
            {
                // Filter on grayscale results first
                List <FrameMetricWrapper> filteredOnGrayScaleResults = (from videoFrameResults in treeResults
                                                                        from frameMetricWrapper in videoFrameResults.Value
                                                                        where DistanceCalculator.CalculateHammingDistance(photo.EdgeGrayScaleThumb, frameMetricWrapper.Frame.EdgeGrayScaleThumb) < 2
                                                                        select frameMetricWrapper).ToList();

                if (filteredOnGrayScaleResults.Count == 1)
                {
                    return(filteredOnGrayScaleResults.First().Video);
                }

                double currentBestSSIM = 0.0;
                VideoFingerPrintWrapper currentBestVideo = null;
                foreach (FrameMetricWrapper FrameMetricWrapper in filteredOnGrayScaleResults)
                {
                    // Calculate SSIM
                    using (WritableLockBitImage videoFrame = GetFrameFromVideo(FrameMetricWrapper.Video, FrameMetricWrapper.Frame.FrameNumber))
                    {
                        double possibleBestSSIM = SSIMCalculator.Compute(photoAsLockBitImage, videoFrame);
                        // SSIM must be at least good enough for us to consider
                        if (possibleBestSSIM > currentBestSSIM)
                        {
                            currentBestSSIM  = possibleBestSSIM;
                            currentBestVideo = FrameMetricWrapper.Video;
                        }
                    }
                }

                return(currentBestVideo);
            }
        }
        private static Offset <FrameFingerPrint>[] CreateFrameFingerPrintArray(FlatBufferBuilder builder, VideoFingerPrintWrapper videoFingerPrint)
        {
            int frameFingerPrintCounter = 0;
            var frameFingerPrintArray   = new Offset <FrameFingerPrint> [videoFingerPrint.FingerPrints.Length];

            foreach (FrameFingerPrintWrapper frameFingerPrint in videoFingerPrint.FingerPrints)
            {
                VectorOffset grayScaleImageOffset = FrameFingerPrint.CreateEdgeGrayScaleThumbVector(builder, frameFingerPrint.EdgeGrayScaleThumb);

                FrameFingerPrint.StartFrameFingerPrint(builder);
                FrameFingerPrint.AddFrameNumber(builder, frameFingerPrint.FrameNumber);
                FrameFingerPrint.AddPHash(builder, frameFingerPrint.PHashCode);
                FrameFingerPrint.AddEdgeGrayScaleThumb(builder, grayScaleImageOffset);

                frameFingerPrintArray[frameFingerPrintCounter] = FrameFingerPrint.EndFrameFingerPrint(builder);
                frameFingerPrintCounter++;
            }

            return(frameFingerPrintArray);
        }
Esempio n. 8
0
 public void AddFingerPrint(VideoFingerPrintWrapper fingerprint)
 {
     _workItems.Add(fingerprint);
 }