# Why a 15-second MP4 can exceed an AI video reference limit

> Source: <https://dev.to/best-sites/why-a-15-second-mp4-can-exceed-an-ai-video-reference-limit-3gh2>
> Published: 2026-11-10 02:16:38+00:00

A player showing “0:15” does not prove that an MP4 fits a 15-second reference limit. The video stream, audio stream, and container can report different durations. An output `duration: 15` setting also does not necessarily trim an uploaded reference.

*AI disclosure: This article was drafted with AI assistance. The commands and synthetic example were checked locally with FFmpeg 7.1.1; no paid model calls were used.*

Run this in an empty directory with FFmpeg installed. It deliberately creates 15 seconds of video and slightly longer audio. `-n` prevents overwriting existing files.

```
ffmpeg -hide_banner -loglevel error -n \
  -f lavfi -i 'testsrc2=size=320x180:rate=24:duration=15' \
  -f lavfi -i 'sine=frequency=440:sample_rate=44100:duration=15.07' \
  -map 0:v:0 -map 1:a:0 \
  -c:v libx264 -preset ultrafast -pix_fmt yuv420p \
  -c:a aac demo.mp4
```

There is no `-shortest`: the mismatch is intentional. Inspect the actual file rather than the rounded player display:

```
ffprobe -v error \
  -show_entries 'format=duration,start_time:stream=index,codec_type,codec_name,duration,start_time,nb_frames' \
  -of json demo.mp4
```

In the local test, the video stream was **15.000000 seconds / 360 frames**, while the audio stream and container were **15.070000 seconds**. Exact values can vary with the encoder and version. A validator checking the longer timeline sees a reference longer than 15 seconds. This synthetic test does not establish how any particular AI service validates files.

For a deeper diagnostic, inspect packet presentation timestamps and durations. This script reports the largest `PTS + duration` for each stream:

``` python
import json
import subprocess
from decimal import Decimal

data = json.loads(subprocess.check_output([
    "ffprobe", "-v", "error", "-show_packets",
    "-show_entries", "packet=stream_index,pts_time,duration_time",
    "-of", "json", "demo.mp4"
], text=True))

ends = {}
missing = 0
for packet in data["packets"]:
    if "pts_time" not in packet or "duration_time" not in packet:
        missing += 1
        continue
    stream = packet["stream_index"]
    end = Decimal(packet["pts_time"]) + Decimal(packet["duration_time"])
    ends[stream] = max(ends.get(stream, end), end)

print({stream: str(end) for stream, end in ends.items()})
print("Packets needing further inspection:", missing)
```

The test produced endpoints of **15.000000** for video and **15.070000** for audio. Use the maximum presentation endpoint, rather than assuming the final packet in file order has the latest presentation time.

This is a diagnostic, not a universal duration validator. Nonzero start times, edit lists, codec delay, variable frame rate, and missing packet timestamps need further inspection. An absolute endpoint is not automatically a duration; account for the relevant timeline start and the service’s validation rules.

For this particular file, the video already fits. If a silent reference is accepted, removing audio avoids re-encoding the video:

```
ffmpeg -hide_banner -loglevel error -n -i demo.mp4 \
  -map 0:v:0 -an -c:v copy -movflags +faststart video-only.mp4
```

Re-run the probes on `video-only.mp4`. In the local test, its container duration, video duration, and maximum video packet endpoint were all **15.000000 seconds**.

This command removes audio; it does not generally trim an overlong video. If audio is required, trim and re-encode the necessary tracks, then inspect the output again. Stream-copy cuts can be constrained by keyframes, and a separate soundtrack is useful only if the API explicitly supports one.

Validate the media you actually upload, as well as the JSON request.

References: [FFprobe documentation](https://ffmpeg.org/ffprobe.html) and [FFmpeg documentation](https://ffmpeg.org/ffmpeg.html).
