# How to Spot Deepfakes in Video and Phone Calls: Detection Tools and Protection

> AI Release · @ai_release1 · https://ai-release.org/guides/kak-raspoznat-dipfeyk-v-video-i-zvonke-proverka-instrum_en.html

## TL;DR
- Time to complete: about 45 minutes for one video file, plus the length of any live call.
- Difficulty: Intermediate — you need a shell and basic comfort with command-line output.
- You will need: `ffmpeg`/`ffprobe` (a build that includes the `blurdetect`, `tile` and `showspectrumpic` filters — confirm with the check in Step 1), `exiftool`, `mediainfo`, a shell (bash/zsh/WSL on Windows), about 1 GB of free disk space per 10 minutes of video for extracted frames.

## Requirements and setup
![Illustration: Requirements and setup](https://ai-release.org/guides/img/kak-raspoznat-dipfeyk-v-video-i-zvonke-proverka-instrum-en-1.jpg?v=1793003877)

**What to do:** install the toolchain, create a working directory, and confirm your `ffmpeg` build has the filters used later.

**Why:** almost every useful check — frame extraction, scene cutting, audio spectra — is a filter inside `ffmpeg`. If a filter is missing, later commands fail with a confusing error instead of a result, so verify first.

Install:

```bash
# Debian / Ubuntu
sudo apt update && sudo apt install -y ffmpeg libimage-exiftool-perl mediainfo

# macOS (Homebrew)
brew install ffmpeg exiftool mediainfo

# Windows (PowerShell) — confirm exact package IDs with: winget search exiftool
winget install Gyan.FFmpeg
winget install --id OliverBetz.ExifTool
```

Create the workspace and a fixed folder layout (all later commands assume it):

```bash
mkdir -p ~/dfcheck/{frames,scenes,audio,evidence}
cd ~/dfcheck
```

**How to check:** run the three verification commands and compare with the expected output below.

```bash
ffmpeg -version | head -n 1
exiftool -ver
ffmpeg -filters | grep -E "blurdetect|showspectrumpic|tile"
```

Expected: a version banner starting with `ffmpeg version`, a bare version number from `exiftool`, and three lines containing `blurdetect`, `showspectrumpic` and `tile`. If `blurdetect` is absent from that list, either upgrade `ffmpeg` through your package manager or skip the blur measurement in Step 2 — the guide still works without it. Exact filter availability per build is not guaranteed; check the documentation for your distribution's package.

**Example:** on a clean Ubuntu container after `apt install ffmpeg`, `ffmpeg -version | head -n 1` prints something like `ffmpeg version 6.1.1-3ubuntu5 Copyright (c) 2000-2023 the FFmpeg developers` — the number after `version` is what matters, not the copyright tail.

**Example (mobile):** if the clip arrived on your phone and you have no laptop at hand, you can run the same `ffmpeg` commands inside a Linux environment on Android — see [How to Run Linux on Android Without Root: Termux, PRoot, and AI Tools](https://ai-release.org/guides/kak-zapustit-linux-na-android-bez-root-termux-proot-i-i.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide) for the shell setup, then reuse every command below unchanged.

Finally, record a hash before you touch the file — it proves the file you analysed is the file you received:

```bash
sha256sum ~/dfcheck/evidence/incoming.mp4 | tee ~/dfcheck/evidence/hash.txt
```

## Step 1. Read the container and metadata before looking at a single frame
**What to do:** dump the file's stream structure and all embedded tags into a report.

**Why:** most forwarded "deepfake" files are simply re-encoded or screen-recorded, and the container tells you that in seconds. A single video stream with no audio, an unusual encoder string, or tags that contradict the claimed source are all cheaper signals than pixel inspection.

```bash
ffprobe -v error -show_format -show_streams -of json \
  ~/dfcheck/evidence/incoming.mp4 > ~/dfcheck/evidence/probe.json

exiftool -a -G1 -s ~/dfcheck/evidence/incoming.mp4 \
  > ~/dfcheck/evidence/exif.txt

mediainfo ~/dfcheck/evidence/incoming.mp4
```

Then pull the short summary you actually read:

```bash
ffprobe -v error -select_streams v:0 \
  -show_entries stream=codec_name,width,height,r_frame_rate,nb_frames,duration \
  -of default=noprint_wrappers=1 ~/dfcheck/evidence/incoming.mp4
```

**Why this works:** `ffprobe` reads the container index, not the picture, so it answers "how many streams, what codec, how many frames" without decoding — a one-second answer to questions a viewer cannot answer at all.

Things worth flagging in `probe.json` and `exif.txt`:

| Field | What to note |
|---|---|
| Number of streams | A "video call recording" with no audio stream is suspicious; a screen recording is not a deepfake, just a re-capture |
| `format_tags` / `encoder` | Names the writing software (e.g. `Lavf…` means an ffmpeg-based pipeline); a mismatch with the claimed device is a hint, not proof |
| `creation_time` vs `file:FileModifyDate` | Large gaps usually mean re-encoding or re-download |
| `nb_frames` vs `duration × r_frame_rate` | A mismatch means truncation or frame drops |

**Example:** if `ffprobe` reports `codec_name=hevc`, `width=720`, `height=1280` and `nb_frames=1820` with `duration=60.6`, the maths `1820 / 60.6 ≈ 30` matches `r_frame_rate=30/1` — the file is internally consistent and the frames you extract in Step 2 will be evenly spaced.

**How to check:** `probe.json` exists and is non-empty, and `exif.txt` contains at least the `File` and `System` groups.

```bash
wc -c ~/dfcheck/evidence/probe.json && grep -c "\[System\]" ~/dfcheck/evidence/exif.txt
```

Expected: a byte count in the thousands and a non-zero count for `[System]`. If both commands return `0`, the file did not open — go to Troubleshooting.

## Step 2. Extract frames and audio, then inspect the signals that synthesis breaks
![Illustration: Step 2. Extract frames and audio, then inspect the signals that synthesis breaks](https://ai-release.org/guides/img/kak-raspoznat-dipfeyk-v-video-i-zvonke-proverka-instrum-en-2.jpg?v=1793003886)

**What to do:** cut the video into reviewable images and separate the audio channel, then run the four checks below.

**Why:** deepfake artefacts are local and brief — a jaw edge that flickers for six frames, a tooth that melts during a smile. You cannot see them at 1× playback. Extracting stills at a fixed rate, plus a contact sheet, makes the artefacts visible and comparable.

Extract frames at 2 per second:

```bash
ffmpeg -v error -i ~/dfcheck/evidence/incoming.mp4 \
  -vf "fps=2,scale=640:-1" ~/dfcheck/frames/frame_%04d.png
```

Cut scenes where the picture changes sharply (cuts, cuts to a different face):

```bash
ffmpeg -v error -i ~/dfcheck/evidence/incoming.mp4 \
  -vf "select='gt(scene,0.3)',showinfo" -vsync vfr ~/dfcheck/scenes/scene_%03d.png
```

Build one contact sheet you can scan in a single glance:

```bash
ffmpeg -v error -i ~/dfcheck/evidence/incoming.mp4 \
  -vf "fps=1,scale=320:-1,tile=4x3" -vsync vfr ~/dfcheck/frames/sheet_%02d.png
```

Extract audio, then draw its spectrum:

```bash
ffmpeg -v error -i ~/dfcheck/evidence/incoming.mp4 -vn -ac 1 -ar 16000 \
  ~/dfcheck/audio/track.wav

ffmpeg -v error -i ~/dfcheck/audio/track.wav \
  -lavfi "showspectrumpic=s=1024x512:legend=1" ~/dfcheck/audio/spectrum.png
```

Optional blur measurement, if `blurdetect` is in your build:

```bash
ffmpeg -i ~/dfcheck/evidence/incoming.mp4 \
  -vf "blurdetect=block_width=32:block_height=32,metadata=print:key=lavfi.blur" \
  -f null - 2>&1 | head -n 20
```

**Why this works:** `fps=2` gives you a deterministic, reproducible sample (the same file always yields the same frame numbers), `tile` packs 12 of them into one image so a flicker becomes visible as a row-to-row difference, and a spectrogram turns "the voice sounds flat" into a picture you can point at.

Read the following signals in the extracted material:

| Signal | Where to look | What is worth a second check |
|---|---|---|
| Hairline and jaw edge | Full-size frames, zoomed | A soft halo or a boundary that shifts between two consecutive frames |
| Teeth and tongue | Any laughing or speaking frame | Teeth merging into one shape, no gap between them |
| Ears and earrings | Profile or angled frames | Asymmetry that changes frame to frame, jewellery that disappears |
| Blinking | Contact sheet rows | No blink across many seconds, or a blink that looks like a wipe |
| Lip-sync | Spectrum next to the frame sheet | Audio events and mouth closures that drift apart over the clip |
| Spectrum shape | `spectrum.png` | A perfectly straight horizontal cut-off instead of natural roll-off |

**Example:** extracting a 60-second clip at `fps=2` produces files `frame_0001.png` to `frame_0120.png`; the first contact sheet `sheet_01.png` holds frames 1–12, i.e. the first 12 seconds. Compare `sheet_01.png` and `sheet_02.png` side by side — a lighting or edge change exactly at the boundary is where a face swap was stitched in.

**How to check:** all three output sets exist and the frame count matches your rate.

```bash
ls ~/dfcheck/frames | wc -l
ls ~/dfcheck/audio
```

Expected: roughly `2 × duration_in_seconds` PNG files in `frames/`, plus `track.wav` and `spectrum.png` in `audio/`. If `audio/` is empty, the source has no audio stream — confirm with `ffprobe -v error -select_streams a -show_entries stream=index -of csv=p=0 ~/dfcheck/evidence/incoming.mp4`.

If you also produce synthetic video yourself and need to label it honestly, the production pipeline in [How to Create Videos with AI and Remotion: Automation Guide](https://ai-release.org/guides/kak-sozdavat-video-s-pomoschyu-ii-i-remotion-gayd-po-av.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide) shows where to attach a provenance note at render time instead of after the fact.

## Step 3. Verify live on the call and confirm through a second channel
![Illustration: Step 3. Verify live on the call and confirm through a second channel](https://ai-release.org/guides/img/kak-raspoznat-dipfeyk-v-video-i-zvonke-proverka-instrum-en-3.jpg?v=1793003890)

**What to do:** run a fixed protocol on any call where money, credentials or urgency is involved, then close the loop on an independent channel.

**Why:** metadata and frames decide whether a *recording* is suspicious. On a live call you cannot run `ffprobe`, so you rely on prompts that real-time face synthesis handles badly and on one rule that beats every detector: never trust the channel that contacted you.

Run these prompts in this order and note the reaction:

- [ ] Ask the person to turn their head fully to one side and back — a profile view is the hardest angle for a face swap.
- [ ] Ask them to bring a hand close to the face for two seconds — occlusion forces the model to invent pixels.
- [ ] Ask a question whose answer only the real person knows and that is not in any email signature or public profile.
- [ ] Listen for a fixed delay between lips and sound, and for a voice that never varies in pace.
- [ ] Say you will call back, hang up, and dial the number published on the organisation's own website — not the number from the incoming message.

**Example:** a "bank security officer" calls from a spoofed number and asks you to confirm a code. You end the call, dial the number printed on the back of your card, and ask the bank to confirm whether any case exists under your name. That single step resolves the situation without any software.

**How to check:** you have a positive confirmation from the second channel — the person answering the official number confirms the request, or your colleague confirms on the internal chat that they called. Anything short of that is a `not verified` result, and the correct action is to stop the transaction.

## Troubleshooting

**Problem. `ffprobe` refuses to open the file at all.**
- Ошибка: `moov atom not found`
- Причина: the MP4 index sits at the end of the file and the download/forward was truncated, so the index is missing.
- Решение: re-download the original, then re-save a copy with the index moved to the front: `ffmpeg -err_detect ignore_err -i incoming.mp4 -c copy -movflags +faststart fixed.mp4` and re-run `ffprobe` on `fixed.mp4`. If the same error appears, the source really is incomplete — request it again.

**Problem. Frame extraction stops immediately with a filter error.**
- Ошибка: `No such filter: 'blurdetect'`
- Причина: your `ffmpeg` build was compiled without that filter (common on minimal distro packages and older static builds).
- Решение: confirm what you have with `ffmpeg -filters | grep blurdetect`. If the line is absent, upgrade `ffmpeg` from the vendor's repository, or drop the blur step and continue with the frame sheet and spectrogram — those two carry most of the signal. Which filters ship in which build is version-dependent; check the documentation for your package.

**Problem. Audio extraction produces nothing.**
- Ошибка: `Output file #0 does not contain any stream`
- Причина: you passed `-vn` (no video) against a file that has only a video stream — typical for screen recordings and for clips whose audio was stripped by a messenger.
- Решение: list the streams first with `ffprobe -v error -show_entries stream=index,codec_type -of csv=p=0 incoming.mp4`. If only `video` appears, obtain the original with sound; there is no audio to analyse in this copy.

## Summary and next steps
Hash the file, read the container with `ffprobe` and `exiftool`, then extract frames, a contact sheet and an audio spectrum before judging the picture. On a live call, skip the software entirely: use the head-turn, occlusion and knowledge prompts, then call back on the officially published number.

## FAQ
**Can a deepfake be detected from a single screenshot?**
Sometimes — melted teeth, an asymmetric ear or a soft jaw boundary may be visible — but a single frame gives you no flicker comparison, so absence of artefacts proves nothing. Always extract a sequence at a fixed rate before concluding.

**Does clean metadata prove a video is genuine?**
No. `ffprobe` and `exiftool` describe the container, and any container can be rewritten or stripped. Treat metadata as a filter for obviously re-encoded or truncated files, not as a certificate of authenticity.

**What should I do if I already sent money after such a call?**
Contact your bank immediately and request a recall, report the number and the account to the police, and preserve the evidence: the original file, `hash.txt`, `probe.json` and the call log. Do not delete the chat — timestamps and account details are what the investigation uses.

**Are commercial deepfake detector services reliable enough to decide alone?**
Accuracy varies by service, language and compression, and published claims are not a substitute for your own test set — check the vendor's documentation and validate on clips you know the answer for. Use a detector as one more signal next to the metadata checks and the call-back rule, never as the deciding vote.
