# AI Video Defect Scanner (Black, Frozen, Silent, Corrupted) (`gaocun/ai-video-defect-scanner`) Actor

Check a batch of video URLs before you publish them. Find black frames, frozen frames, silent or missing audio, wrong resolution and corrupted data, with the exact second of each problem. Check loudness, true peak, frame rate and black bars. Made for AI-generated video.

- **URL**: https://apify.com/gaocun/ai-video-defect-scanner.md
- **Developed by:** [gaocun](https://apify.com/gaocun) (community)
- **Categories:** Videos, AI, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 scanned videos

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## AI Video Defect Scanner

### What does AI Video Defect Scanner do?

**AI Video Defect Scanner** checks a batch of video URLs before you publish or deliver them. It finds **black frames, frozen frames, silent or missing audio, wrong resolution, and corrupted files**, and it gives the **exact second** of each problem. It also checks **delivery specs**: loudness, true peak, frame rate, and black bars.

Video models sometimes return a black clip, a frozen clip, a clip with silent audio, or a clip at the wrong size. A person who checks hundreds of clips by eye misses these defects. This Actor checks them automatically.

To try it, click **Start**. The prefilled example scans two short sample videos in a few seconds.

- **Eleven checks** in one decode pass, with start and end seconds for each defect.
- **Delivery specs.** Set a target loudness (for example -14 LUFS for YouTube) and a frame rate. The Actor measures loudness and true peak for each video.
- **Made for AI-generated video.** The thresholds come from tests on real AI video output, so static shots are not reported as frozen.
- **Batch scans.** Give hundreds of URLs in one run. The Actor downloads up to 4 videos at the same time.
- **Share links work.** You can use Dropbox and Google Drive share links.
- **Fair billing.** You pay only for videos that the Actor scanned. A link that does not open is free. A repeated link is scanned and charged once.
- **All Apify platform features:** API access, schedules, webhooks, and integrations with Make, Zapier, and other tools.

#### Who uses AI Video Defect Scanner?

- Teams that generate video with AI models and must reject broken clips before they edit or publish.
- Agencies and studios that check delivered files before they send them to a client.
- Developers who add a quality gate to a video pipeline through the API.

### How to use AI Video Defect Scanner

1. Put links to your video files in **Video URLs**, one link per line. Use a direct file link, or a Dropbox or Google Drive share link.
2. Turn off **Audio track is required** if your videos have no sound on purpose.
3. Optional: set **Expected resolution**, for example `1080x1920` or `720p`.
4. Optional: set the delivery specs: **Target loudness**, **Expected frame rate**, and **Black bars are a defect**.
5. Click **Start**.
6. When the run ends, open the **Output** tab. Filter for `ok: false` to see the broken videos.

### How much does it cost to scan videos?

The Actor uses the **pay per event + usage** model:

- **$0.005 per scanned video** (event `video-scanned`). 1,000 videos cost $5.
- **Platform usage** for the run. The default run uses 2048 MB of memory. In our test, 3 short videos used 0.004 compute units. Longer videos take longer to decode and use more. The price of a compute unit depends on your Apify plan.

A URL that cannot be downloaded or opened is not charged.

### What does the scanner find?

| Code | Meaning |
| --- | --- |
| `BLACK_FRAMES` | The picture is black for 0.1 s or longer. |
| `FROZEN_FRAMES` | Identical frames repeat for 0.5 s or longer. |
| `NO_AUDIO` | The file has no audio track. You can turn off this check. |
| `SILENT_AUDIO` | The file has an audio track, but 95% or more of it is silent (below -50 dB). Off when `requireAudio` is `false`. |
| `RESOLUTION_MISMATCH` | The size is not the size you expect. This check is optional. |
| `CORRUPTED` | The decoder stops on broken data. |
| `NO_VIDEO_STREAM` | The file has no video stream. |
| `LOUDNESS_MISMATCH` | The integrated loudness is more than 1 LU from the target. Only when you set `targetLoudness`. |
| `TRUE_PEAK_HIGH` | The true peak is above -1 dBTP. Only when you set `targetLoudness`. |
| `FRAME_RATE_MISMATCH` | The frame rate is not the rate you expect. Only when you set `expectedFrameRate`. |
| `BLACK_BARS` | Every frame has black bars on its edges (letterbox or pillarbox). Only when `rejectBlackBars` is `true`. |

The thresholds come from tests on real AI video output:

- A static shot (a still landscape, a person who stands still) is **not** reported as frozen. Its frames differ by sensor noise and compression. A real freeze repeats identical frames.
- A black section is reported once, as `BLACK_FRAMES`, and not again as `FROZEN_FRAMES`.
- Silent sections are measured and returned in `silentSegments`. Short silent sections do not fail a video, because quiet speech and pauses are normal. Only a track that is almost fully silent is `SILENT_AUDIO`.
- A silent track is reported once, as `SILENT_AUDIO`, and not again as `LOUDNESS_MISMATCH`.
- A frame rate of 24 also accepts 23.976, and 30 also accepts 29.97. The tolerance is 0.5%.
- Black bars are reported only when they are on the edges of every frame and take 2% or more of the width or the height. A dark scene does not count.
- A phone video with a rotation flag is measured upright. A portrait video shows as `1080x1920`, not `1920x1080`.

### Input

| Field | Required | Description |
| --- | --- | --- |
| `videoUrls` | Yes | Direct http(s) links to video files (mp4, mov, webm, mkv, and other formats), or Dropbox and Google Drive share links. Maximum size is 2 GB per file. A repeated link is scanned and charged once. |
| `requireAudio` | No | Report `NO_AUDIO` and `SILENT_AUDIO`. Default is `true`. |
| `expectedResolution` | No | For example `1080x1920`, `1920x1080`, or `720p`. |
| `targetLoudness` | No | Integrated loudness in LUFS, for example `-14` (YouTube, Spotify, TikTok), `-16` (Apple), `-23` (EBU R128), or `-24` (ATSC A/85). |
| `expectedFrameRate` | No | Frames per second, for example `24`, `25`, `30`, or `60`. |
| `rejectBlackBars` | No | Report `BLACK_BARS`. Default is `false`. |

```json
{
  "videoUrls": [
    "https://example.com/clip-017.mp4",
    "https://example.com/clip-018.mp4"
  ],
  "requireAudio": true,
  "expectedResolution": "1080x1920",
  "targetLoudness": -14,
  "expectedFrameRate": 30
}
```

### Output

The Actor writes one dataset item for each URL. Items can be in a different order than the input.

```json
[
  {
    "url": "https://example.com/clip-017.mp4",
    "ok": false,
    "issues": [
      { "code": "LOUDNESS_MISMATCH", "detail": "Integrated loudness is -21.4 LUFS, expected -14 LUFS" },
      { "code": "FROZEN_FRAMES", "detail": "Identical frames for 2.04 s", "startSeconds": 0.96, "endSeconds": 3.0 }
    ],
    "durationSeconds": 3.0,
    "width": 1080,
    "height": 1920,
    "hasAudio": true,
    "frameRate": 30.0,
    "loudnessLufs": -21.4,
    "truePeakDb": -3.2,
    "blackSegments": [],
    "frozenSegments": [{ "startSeconds": 0.96, "endSeconds": 3.0 }],
    "silentSegments": []
  },
  {
    "url": "https://example.com/clip-018.mp4",
    "ok": null,
    "error": "The server returned HTTP 404."
  }
]
```

- `ok: true`: no defect was found.
- `ok: false`: see `issues`.
- `ok: null`: the file could not be downloaded or opened. The `error` field gives the reason. This item is not charged.
- `loudnessLufs` and `truePeakDb` are always measured when the video has audio. They are `null` for digital silence.

### How does the scan work?

The Actor downloads each file and decodes it once with FFmpeg. The black, freeze, silence, and EBU R128 loudness filters run in the same pass. The black bar filter runs in that pass too, when you turn it on. The Actor downloads the file first, because a streamed MP4 with its index at the end can decode to nothing and still look clean. Downloads run in parallel, and the Actor decodes the videos one by one.

### Other Actors from the same author

| Actor | What it does |
| --- | --- |
| [Script to Subtitle Aligner](https://apify.com/gaocun/script-subtitle-aligner) | Makes SRT/VTT subtitles from a script, timed to the real speech, and reports skipped and misread lines. |

### FAQ

#### Why is my screen recording reported as frozen?

Screen recordings and slideshows can contain identical frames on purpose. For this content, read `FROZEN_FRAMES` as information, not as a defect.

#### Which loudness target do I use?

Use the target of the platform that gets the video. YouTube, Spotify, and TikTok use about -14 LUFS. Apple uses -16 LUFS. European broadcast uses -23 LUFS (EBU R128), and US broadcast uses -24 LUFS (ATSC A/85). If you do not set a target, the Actor still measures the loudness and does not report a defect.

#### Why does a working video show `ok: null`?

The Actor could not download or open the file. Check that the link returns the video file itself, not a web page or a login page. For a Google Drive or Dropbox link, share the file with "Anyone with the link". Signed links can expire before the run starts.

#### Does the Actor keep my videos?

No. The Actor deletes each file after the scan.

#### Can I use the Actor from my own code?

Yes. Use the [Apify API](https://docs.apify.com/api/v2) or the Apify client for JavaScript or Python. The **API** tab of this Actor shows ready-to-use code.

#### Where can I report a problem?

Open an issue in the **Issues** tab of this Actor. Include the run ID, so we can find the run log.

# Actor input Schema

## `videoUrls` (type: `array`):

Direct http(s) links to video files (mp4, mov, webm, mkv, ...). Dropbox and Google Drive share links also work. Other links must return the file itself, not a web page. Maximum file size is 2 GB.

## `requireAudio` (type: `boolean`):

Report NO_AUDIO when a video has no audio track. Turn off for silent videos.

## `expectedResolution` (type: `string`):

Optional. Report RESOLUTION_MISMATCH when a video has a different size. Use WIDTHxHEIGHT (for example 1080x1920) or 360p, 480p, 720p, 1080p, 4k.

## `targetLoudness` (type: `integer`):

Optional. Report LOUDNESS_MISMATCH when the integrated loudness is more than 1 LU from this value, and TRUE_PEAK_HIGH when the true peak is above -1 dBTP. Use -14 for YouTube, Spotify and TikTok, -16 for Apple, -23 for EBU R128 broadcast, -24 for ATSC A/85.

## `expectedFrameRate` (type: `integer`):

Optional. Report FRAME_RATE_MISMATCH when a video has a different frame rate. 24 also accepts 23.976, 30 also accepts 29.97, and 60 also accepts 59.94.

## `rejectBlackBars` (type: `boolean`):

Report BLACK_BARS when black bars (letterbox or pillarbox) are on the edges of every frame. Leave off for content with bars on purpose, for example a cinema crop.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.w3schools.com/html/mov_bbb.mp4",
    "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/360/Big_Buck_Bunny_360_10s_1MB.mp4"
  ],
  "requireAudio": true,
  "rejectBlackBars": false
}
```

# Actor output Schema

## `results` (type: `string`):

One item for each URL. ok is true for a clean video, false for a video with defects, and null for a URL that could not be opened.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "videoUrls": [
        "https://www.w3schools.com/html/mov_bbb.mp4",
        "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/360/Big_Buck_Bunny_360_10s_1MB.mp4"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("gaocun/ai-video-defect-scanner").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "videoUrls": [
        "https://www.w3schools.com/html/mov_bbb.mp4",
        "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/360/Big_Buck_Bunny_360_10s_1MB.mp4",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("gaocun/ai-video-defect-scanner").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "videoUrls": [
    "https://www.w3schools.com/html/mov_bbb.mp4",
    "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/360/Big_Buck_Bunny_360_10s_1MB.mp4"
  ]
}' |
apify call gaocun/ai-video-defect-scanner --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gaocun/ai-video-defect-scanner"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/BqsU8B2xmUBmZ1AZg/builds/cbx36Ymb7MUU0eXMw/openapi.json
