video-hash

Generates unique fingerprints for video files

Usage no npm install needed!

<script type="module">
  import videoHash from 'https://cdn.skypack.dev/video-hash';
</script>

README

video-hash

npm npm David Travis Coveralls license Beerpay

Algorithm to fingerprint videos with relatively high accuracy and returns a hash. Achieved by capturing screenshots at particular intervals, hashing the pixels of each screenshot and creating a single hash from all of the generated pixel hashes. This package uses FFmpeg to take screenshots and FFprobe to retrieve metadata. Please note that this package is going to be slow depending on the size of video you are fingerprinting.

Usage

Requirements

In order to use this package, you must have the following requirements met:

  1. FFmpeg installed and in your PATH or a local binary.
    • You can use a package like ffmpeg-installer to provide precompiled binaries for your OS.
  2. FFprobe installed and in your PATH or a local binary.
    • You can use a package like ffprobe-installer to provide precompiled binaries for your OS.

Install

npm install --save video-hash

Quick Start

This example shows how to get started using precompiled binaries:

npm install --save video-hash @ffmpeg-installer/ffmpeg @ffprobe-installer/ffprobe
const ffmpeg = require('@ffmpeg-installer/ffmpeg');
const ffprobe = require('@ffprobe-installer/ffprobe');

const vHash = require('video-hash')({
    ffmpegPath: ffmpeg.path,
    ffprobePath: ffprobe.path
});

async createFingerprint(videoPath) {
    const video = vHash.video(videoPath);
    
    try {
        let hash = await video.hash();
        return hash;
    } catch(err) {
        throw err;
    }
}

API Documentation

video-hash

VideoHash([options]) ⇒ this

Function exported from this module. Call with options object. May be called with or without new.

Kind: Exported function

Param Type Default Description
[options] Object {} Optional options to pass into the module.
[options.ffmpegPath] String Overrides the path to the ffmpeg binary. If not provided, it will attempt to locate on the system.
[options.ffprobePath] String Overrides the path to the ffprobe binary. If not provided, it will attempt to locate on the system.
[options.hashAlgorithm] String 'sha256' The hashing algorithm to use when generating the hash. Must be one of the available from crypto.createHash.
[options.tempDir] String os.tmpdir() Overrides the temp directory where various metadata during hashing is stored.
[options.hashBits] Number 12 Hash length when generating hashes of screenshots. The longer the value, the more unique. See imghash.hash.
[options.strength] Number 2 The strength of the generated video hash. Must be a number between 0.1 and 10. Determines the percentage in which each screenshot is taken based on the video duration. Setting this option to a higher value will provide a stronger fingerprint, but will take longer to generate the hash.

Example

// Using default options:
const vHash = require('video-hash')();

// With options:
const vHash = require('video-hash')({
    // options...
});

vHash.video(videoPath) ⇒ Video

Prepares a video for hashing at the provided videoPath. Returns a new instance of Video.

Kind: instance method of VideoHash
Returns: Video - New instance of Video.
Throws:

  • Error If videoPath is not provided.
Param Type Description
videoPath String Path to video file to load for hashing.

Example

const video = vHash.video('/path/to/some-video.mp4');
// => Video { ... }

vHash.options : Object

Compiled options object. All options except ffmpegPath and ffprobePath can be changed at any time.

Kind: static property of VideoHash

Video

Kind: global class

new Video(options, video)

Creates an instance of Video. This constructor cannot be called directly.

Param Type Description
options Object Options passed from VideoHash.
video FfmpegCommand Instance of FfmpegCommand from fluent-ffmpeg for the video.

video.hash() ⇒ Promise.<String>

Generates the hash/fingerprint for a single video.

Kind: instance method of Video
Returns: Promise.<String> - The generated hash/fingerprint for the video.
Example

const vHash = require('video-hash')({
    // options...
});

async function hashVideo(videoPath) {
    const video = vHash.video(videoPath);

    try {
        let hash = await video.hash();
        return hash;
    } catch(err) {
        throw err;
    }

video.metadata() ⇒ Promise.<Object>

Returns basic metadata for a single video from ffprobe.

Kind: instance method of Video
Returns: Promise.<Object> - The format metadata object for the video. See metadata.
Example

async function getMetadata(videoPath) {
    const video = vHash.video(videoPath);
    let metadata = await video.metadata();
}

Algorithm

Video Hash uses a basic algorithm to generate a hash for a video that will provide consistent results each time for the same provided options. This works by taking captures at percentage-based intervals based off of the duration of the video. The module generates a number of captures to take from the video using an equation like:

⌈(⌈duration⌉ * strength)⌉

To simplify, the video duration is rounded up to the nearest whole number and multiplied by the provided strength option. The resulting number is then rounded up to the nearest whole number. From there, the dependency fluent-ffmpeg will generate an array of percentages based on the duration of the video for when FFmpeg shoud capture a screenshot. If the duration of the video does not change, neither will the hash.

After all of the captures are taken by FFmpeg, each one is hashed using perceptual hashing and stored. Once the hashes are generated, all are combined and a final hash (SHA256 by default) is generated and returned.

Tests

To run tests locally, ensure you have all of the requirements installed and run:

npm test

Contributing

When contributing to this package, please follow the guidelines below:

  1. Ensure the there are no ESLint errors in the code, following the .eslintrc.yml file in the repo.
  2. Write or update tests for any changes. I strive for 100% coverage, but 95% or higher is acceptable.
  3. Run the tests locally and ensure they pass.
  4. Commits must use the conventional commits spec. If you do not, your commit will fail.
  5. Submit a pull request.

License

MIT License