davinci-resolve-mcp 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +85 -0
- package/CHANGELOG.md +802 -0
- package/CLAUDE.md +15 -0
- package/LICENSE +21 -0
- package/README.md +159 -0
- package/SECURITY.md +53 -0
- package/bin/davinci-resolve-mcp.mjs +376 -0
- package/docs/README.md +56 -0
- package/docs/SKILL.md +1145 -0
- package/docs/authoring/fuse-dctl-authoring.md +242 -0
- package/docs/authoring/script-plugin-authoring.md +195 -0
- package/docs/contributing.md +82 -0
- package/docs/guides/color-decision-guide.md +387 -0
- package/docs/guides/editorial-decision-guide.md +136 -0
- package/docs/guides/media-analysis-guide.md +615 -0
- package/docs/guides/multicam-setup-guide.md +138 -0
- package/docs/install.md +198 -0
- package/docs/integrations/workflow-integrations.md +120 -0
- package/docs/kernels/README.md +28 -0
- package/docs/kernels/audio-fairlight-kernel.md +86 -0
- package/docs/kernels/color-grade-kernel.md +103 -0
- package/docs/kernels/extension-authoring-kernel.md +101 -0
- package/docs/kernels/fusion-composition-kernel.md +91 -0
- package/docs/kernels/media-pool-ingest-kernel.md +147 -0
- package/docs/kernels/project-lifecycle-kernel.md +120 -0
- package/docs/kernels/render-deliver-kernel.md +92 -0
- package/docs/kernels/review-annotation-kernel.md +110 -0
- package/docs/kernels/timeline-conform-interchange-kernel.md +99 -0
- package/docs/kernels/timeline-edit-kernel.md +189 -0
- package/docs/notes/codec-plugin-notes.md +136 -0
- package/docs/notes/dctl-notes.md +234 -0
- package/docs/notes/fusion-template-notes.md +136 -0
- package/docs/notes/lut-notes.md +136 -0
- package/docs/notes/openfx-notes.md +120 -0
- package/docs/process/release-process.md +152 -0
- package/docs/reference/api-coverage.md +488 -0
- package/docs/reference/resolve_scripting_api.txt +1012 -0
- package/examples/README.md +53 -0
- package/examples/markers/README.md +81 -0
- package/examples/media/README.md +94 -0
- package/examples/timeline/README.md +98 -0
- package/install.py +1196 -0
- package/package.json +52 -0
- package/scripts/audit_api_parity.py +275 -0
- package/scripts/live_media_analysis_polish_probe.py +65 -0
- package/src/__init__.py +3 -0
- package/src/analysis_dashboard.py +4936 -0
- package/src/control_panel.py +13 -0
- package/src/granular/__init__.py +17 -0
- package/src/granular/common.py +727 -0
- package/src/granular/folder.py +287 -0
- package/src/granular/gallery.py +306 -0
- package/src/granular/graph.py +309 -0
- package/src/granular/media_pool.py +679 -0
- package/src/granular/media_pool_item.py +852 -0
- package/src/granular/media_storage.py +179 -0
- package/src/granular/project.py +1594 -0
- package/src/granular/resolve_control.py +521 -0
- package/src/granular/timeline.py +1074 -0
- package/src/granular/timeline_item.py +2251 -0
- package/src/resolve_mcp_server.py +43 -0
- package/src/server.py +15691 -0
- package/src/utils/__init__.py +3 -0
- package/src/utils/app_control.py +319 -0
- package/src/utils/audio_fairlight_live_probe.py +263 -0
- package/src/utils/cdl.py +20 -0
- package/src/utils/cloud_operations.py +192 -0
- package/src/utils/color_grade_live_probe.py +444 -0
- package/src/utils/dctl_templates.py +368 -0
- package/src/utils/extension_authoring_live_probe.py +292 -0
- package/src/utils/fuse_templates.py +1968 -0
- package/src/utils/fusion_composition_live_probe.py +284 -0
- package/src/utils/layout_presets.py +333 -0
- package/src/utils/mcp_stdio.py +32 -0
- package/src/utils/media_analysis.py +3618 -0
- package/src/utils/media_analysis_jobs.py +796 -0
- package/src/utils/media_pool_ingest_live_probe.py +592 -0
- package/src/utils/multicam.py +393 -0
- package/src/utils/object_inspection.py +287 -0
- package/src/utils/platform.py +157 -0
- package/src/utils/project_lifecycle_live_probe.py +376 -0
- package/src/utils/project_properties.py +601 -0
- package/src/utils/render_deliver_live_probe.py +384 -0
- package/src/utils/resolve_connection.py +77 -0
- package/src/utils/review_annotation_live_probe.py +352 -0
- package/src/utils/script_templates.py +1193 -0
- package/src/utils/sync_detection.py +887 -0
- package/src/utils/timeline_conform_live_probe.py +280 -0
- package/src/utils/timeline_kernel_live_probe.py +1091 -0
- package/src/utils/timeline_kernel_probe.py +185 -0
- package/src/utils/timeline_title_text.py +87 -0
- package/src/utils/update_check.py +610 -0
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
# Media Analysis Guide for DaVinci Resolve MCP
|
|
2
|
+
|
|
3
|
+
This guide teaches AI coding assistants how to use FFprobe, FFmpeg, and Whisper to understand source media files — so the DaVinci Resolve MCP can operate with full context of what the footage actually is.
|
|
4
|
+
|
|
5
|
+
This guide is tool-agnostic. It works with any AI assistant that can run shell commands alongside the MCP server.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The First Rule: Never Touch the Source
|
|
10
|
+
|
|
11
|
+
**This is the foundational, non-negotiable principle.**
|
|
12
|
+
|
|
13
|
+
Your relationship to source media is **READ-ONLY**. Every department in a post-production pipeline depends on an unbroken chain from the camera original files (OCFs) through to final delivery.
|
|
14
|
+
|
|
15
|
+
### NEVER do any of the following unless the user explicitly requests it:
|
|
16
|
+
- Transcode, convert, or re-encode any media file
|
|
17
|
+
- Create proxies, mezzanines, or lower-resolution copies
|
|
18
|
+
- Export media from Resolve and reimport it
|
|
19
|
+
- Apply LUTs, color transforms, or any processing to files on disk
|
|
20
|
+
- Create rendered versions of timeline segments
|
|
21
|
+
- Modify, rename, move, or reorganize source media files
|
|
22
|
+
- Strip, modify, or rewrite metadata in source files
|
|
23
|
+
- Change timecode in source files
|
|
24
|
+
- Create "optimized" or "analysis-friendly" copies
|
|
25
|
+
|
|
26
|
+
### ALWAYS limit yourself to:
|
|
27
|
+
- Reading files with FFprobe (metadata extraction — zero disk writes)
|
|
28
|
+
- Analyzing files with FFmpeg using `-f null -` output (read-through analysis — zero disk writes)
|
|
29
|
+
- Writing analysis results to separate sidecar JSON files only
|
|
30
|
+
- Running Whisper transcription that writes only to an analysis directory
|
|
31
|
+
- Creating sampled frames/contact sheets only for visual analysis workflows, only
|
|
32
|
+
in a designated analysis directory. The `analyze_media` prompt defaults
|
|
33
|
+
visual analysis on when chat-context vision is supported; pass
|
|
34
|
+
`include_visuals=false` to opt out.
|
|
35
|
+
|
|
36
|
+
### Why This Matters
|
|
37
|
+
|
|
38
|
+
- **Assistant Editor:** Every transcode introduces a generation loss. Every conversion makes assumptions about color space, bit depth, and timecode that may be wrong. An unauthorized proxy that doesn't match source timecode breaks the online conform.
|
|
39
|
+
- **Editor:** The edit is discovered from the real footage. Analysis informs creative decisions without creating derivatives that confuse the media pool or timeline.
|
|
40
|
+
- **Colorist:** The grade starts with every bit of dynamic range the camera captured. A transcode bakes in assumptions about color space and gamma. Once latitude is lost, it's gone forever.
|
|
41
|
+
- **Online Editor:** The entire conform workflow traces back to OCFs. Exported-and-reimported media looks like the original but breaks the file path, media hash, and metadata chain.
|
|
42
|
+
- **Producer:** Distributors trace chain of custody back to camera originals. Unauthorized derivatives risk QC failure, E&O issues, and delivery rejection.
|
|
43
|
+
|
|
44
|
+
### The Only Exception
|
|
45
|
+
|
|
46
|
+
If the user explicitly requests a derivative ("make me a proxy," "transcode this to ProRes"), then:
|
|
47
|
+
- Confirm the request before executing
|
|
48
|
+
- Clearly label the output as a derivative
|
|
49
|
+
- Never overwrite or replace the original
|
|
50
|
+
- Document what was created and where
|
|
51
|
+
- Preserve all metadata including timecode
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Setup: First Interaction
|
|
56
|
+
|
|
57
|
+
On first use, determine:
|
|
58
|
+
|
|
59
|
+
### 1. Where should analysis files be saved?
|
|
60
|
+
- **alongside** — Sidecar files next to each media file (e.g., `clip.mov` -> `clip.mov.analysis.json`)
|
|
61
|
+
- **directory** — A central analysis directory (default: `~/resolve-media-analysis/`)
|
|
62
|
+
- **project** — Inside a `.analysis/` folder within the Resolve project's media folder
|
|
63
|
+
|
|
64
|
+
If source media is on read-only storage (camera cards, SAN volumes), use `directory` or `project`.
|
|
65
|
+
|
|
66
|
+
### 2. What tools are available?
|
|
67
|
+
|
|
68
|
+
Check automatically:
|
|
69
|
+
```bash
|
|
70
|
+
# Required
|
|
71
|
+
which ffprobe && ffprobe -version 2>&1 | head -1
|
|
72
|
+
|
|
73
|
+
# Optional — enhanced analysis
|
|
74
|
+
which ffmpeg && ffmpeg -version 2>&1 | head -1
|
|
75
|
+
|
|
76
|
+
# Optional — transcription
|
|
77
|
+
which whisper 2>/dev/null || which whisper-cpp 2>/dev/null || python3 -c "import whisper" 2>/dev/null
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
FFprobe is required. If missing:
|
|
81
|
+
- macOS: `brew install ffmpeg`
|
|
82
|
+
- Linux: `sudo apt install ffmpeg` or `sudo dnf install ffmpeg`
|
|
83
|
+
- Windows: Download from https://ffmpeg.org
|
|
84
|
+
|
|
85
|
+
### 3. Analysis depth preference
|
|
86
|
+
- **quick** — FFprobe metadata only (~1 second per file)
|
|
87
|
+
- **standard** — Metadata, loudness, full-stream scene detection, cut-boundary
|
|
88
|
+
analysis, flash-frame candidates, motion/variance scoring, and analysis
|
|
89
|
+
keyframes (~30-60 seconds per file)
|
|
90
|
+
- **deep** — Standard analysis plus transcription and expanded visual sampling
|
|
91
|
+
when chat-context vision is available (~2-5 minutes per file)
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Analysis Commands
|
|
96
|
+
|
|
97
|
+
Every command below is read-only. None write to the source file.
|
|
98
|
+
|
|
99
|
+
### FFprobe: Technical Metadata (Required)
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
ffprobe -v quiet -print_format json -show_format -show_streams -show_chapters "INPUT_FILE"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Extract and structure:
|
|
106
|
+
- **Video**: codec, profile, level, pixel format, bit depth, resolution, frame rate, scan type (progressive/interlaced), color primaries, transfer characteristics, matrix coefficients, HDR metadata
|
|
107
|
+
- **Audio**: codec, sample rate, channels, channel layout, bit depth
|
|
108
|
+
- **Container**: format, duration, overall bitrate, timecode (if present)
|
|
109
|
+
- **Chapters**: timestamps and titles
|
|
110
|
+
|
|
111
|
+
For frame rate, distinguish between `r_frame_rate` (container) and `avg_frame_rate` (actual). Flag VFR if they differ significantly.
|
|
112
|
+
|
|
113
|
+
### FFmpeg: Content Analysis (Optional)
|
|
114
|
+
|
|
115
|
+
All commands use `-f null -` as output — read-through analysis, zero disk writes.
|
|
116
|
+
|
|
117
|
+
**Loudness (EBU R128):**
|
|
118
|
+
```bash
|
|
119
|
+
ffmpeg -i "INPUT_FILE" -af ebur128=peak=true -f null - 2>&1 | tail -30
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Scene Detection:**
|
|
123
|
+
```bash
|
|
124
|
+
ffmpeg -i "INPUT_FILE" -filter:v "select='gt(scene,0.3)',showinfo" -f null - 2>&1 | grep "showinfo"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Scene detection is a full-stream read. Standard/deep analysis turns the detected
|
|
128
|
+
times into cut-boundary evidence: one frame before and one frame after each
|
|
129
|
+
candidate cut, first/last usable clip frames, and short adjacent scene ranges
|
|
130
|
+
that may be flash frames. Those candidates are advisory until visual review
|
|
131
|
+
checks whether the boundary is a true edit, a flash/title/black insertion, or a
|
|
132
|
+
high-motion moment inside one continuous shot.
|
|
133
|
+
|
|
134
|
+
**Black Frame Detection:**
|
|
135
|
+
```bash
|
|
136
|
+
ffmpeg -i "INPUT_FILE" -vf blackdetect=d=0.5:pix_th=0.10 -f null - 2>&1 | grep "blackdetect"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Silence Detection:**
|
|
140
|
+
```bash
|
|
141
|
+
ffmpeg -i "INPUT_FILE" -af silencedetect=noise=-50dB:d=1 -f null - 2>&1 | grep "silence"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Sync Event Detection
|
|
145
|
+
|
|
146
|
+
Use `media_analysis(action="detect_sync_events")` when the task is to find
|
|
147
|
+
advisory sync points in deliverables, single-camera footage, dual-system sound,
|
|
148
|
+
or multicam source clips.
|
|
149
|
+
|
|
150
|
+
The detector is source-safe:
|
|
151
|
+
|
|
152
|
+
- It uses FFprobe for metadata and FFmpeg to decode source audio to in-memory
|
|
153
|
+
mono samples.
|
|
154
|
+
- It writes no media files, proxies, renders, or derivatives.
|
|
155
|
+
- It returns likely 1 kHz 2-pops, slate-clap transients, frame/timecode
|
|
156
|
+
positions when frame rate/timecode are known, and per-file record-offset
|
|
157
|
+
suggestions.
|
|
158
|
+
- It returns marker suggestions for Media Pool clips, but never writes markers
|
|
159
|
+
during detection.
|
|
160
|
+
- It does not install FFmpeg automatically. If `ffmpeg` or `ffprobe` is missing,
|
|
161
|
+
report the missing optional dependency and suggest installing FFmpeg.
|
|
162
|
+
|
|
163
|
+
Analyze explicit files:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"action": "detect_sync_events",
|
|
168
|
+
"params": {
|
|
169
|
+
"paths": ["/path/to/camera_a.mov", "/path/to/camera_b.mov"],
|
|
170
|
+
"fps": 24,
|
|
171
|
+
"event_types": ["two_pop", "slate_clap"],
|
|
172
|
+
"scan_start_seconds": 30,
|
|
173
|
+
"scan_tail_seconds": 30,
|
|
174
|
+
"prefer_event_type": "slate_clap"
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Analyze selected Media Pool clips:
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"action": "detect_sync_events",
|
|
184
|
+
"params": {
|
|
185
|
+
"target": "selected",
|
|
186
|
+
"prefer_event_type": "slate_clap"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
For multicam prep, use `alignment.suggestions[].suggested_record_offset_frames`
|
|
192
|
+
as per-angle `record_offset` values with
|
|
193
|
+
`media_pool(action="setup_multicam_timeline", sync_mode="record_frame")`, then
|
|
194
|
+
verify sync in Resolve before converting the setup timeline to a native multicam
|
|
195
|
+
clip.
|
|
196
|
+
|
|
197
|
+
To add source-frame Media Pool markers from detected sync events, first show the
|
|
198
|
+
user the marker suggestions. Only after the user approves, call:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"action": "add_sync_event_markers",
|
|
203
|
+
"params": {
|
|
204
|
+
"target": "selected",
|
|
205
|
+
"prefer_event_type": "slate_clap",
|
|
206
|
+
"confirm": true
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
If you already have a detection result, pass it back as `detection` with
|
|
212
|
+
`confirm=true`. Raw file-path detections cannot be marked in Resolve unless
|
|
213
|
+
they are tied to Media Pool clips.
|
|
214
|
+
|
|
215
|
+
### Publishing Analysis Back To Resolve Metadata
|
|
216
|
+
|
|
217
|
+
Use `media_analysis(action="publish_clip_metadata")` when analysis should become
|
|
218
|
+
searchable and usable inside Resolve's own Media Pool metadata views, smart bins,
|
|
219
|
+
and filters.
|
|
220
|
+
|
|
221
|
+
The publish step is a separate Resolve-project mutation. It does not modify
|
|
222
|
+
source media, but it does write to the Resolve project database, so it defaults
|
|
223
|
+
to `dry_run=true` and requires `confirm=true` before writing.
|
|
224
|
+
|
|
225
|
+
Recommended dry-run:
|
|
226
|
+
|
|
227
|
+
```json
|
|
228
|
+
{
|
|
229
|
+
"action": "publish_clip_metadata",
|
|
230
|
+
"params": {
|
|
231
|
+
"target": "selected",
|
|
232
|
+
"fields": ["Description", "Comments", "Keywords", "People"],
|
|
233
|
+
"merge_policy": "append_relevant",
|
|
234
|
+
"vision": {"enabled": true, "provider": "chat_context"},
|
|
235
|
+
"slate_detection": {"enabled": true, "use_vision": true},
|
|
236
|
+
"dry_run": true
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
After reviewing the proposed field changes, confirm only if the target clips and
|
|
242
|
+
merge results are correct:
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"action": "publish_clip_metadata",
|
|
247
|
+
"params": {
|
|
248
|
+
"target": "selected",
|
|
249
|
+
"fields": ["Description", "Comments", "Keywords", "People", "Scene", "Shot", "Take", "Camera #"],
|
|
250
|
+
"merge_policy": "append_relevant",
|
|
251
|
+
"slate_detection": {"enabled": true, "use_vision": true},
|
|
252
|
+
"dry_run": false,
|
|
253
|
+
"confirm": true
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Field policies are conservative by default:
|
|
259
|
+
|
|
260
|
+
- `Description` and `Comments` preserve existing text and update an MCP-owned
|
|
261
|
+
analysis block.
|
|
262
|
+
- `Keywords` and `People` are list-merged with case-insensitive de-duplication.
|
|
263
|
+
- `Scene`, `Shot`, `Take`, `Camera #`, and roll/card fields are fill-empty fields
|
|
264
|
+
unless the caller explicitly requests overwrite behavior.
|
|
265
|
+
- Machine provenance is written to third-party metadata using
|
|
266
|
+
`davinci_resolve_mcp.*` keys so future runs can check report path, signature,
|
|
267
|
+
publish timestamp, publisher version, and changed fields.
|
|
268
|
+
- Source-time observations can optionally be written as Media Pool clip markers
|
|
269
|
+
by calling `publish_clip_metadata` with `write_markers=true`. This is off by
|
|
270
|
+
default; without that flag, best moments, sync events, and warnings remain in
|
|
271
|
+
the analysis JSON and metadata text rather than becoming Resolve markers.
|
|
272
|
+
- If no timed-marker choice or saved default exists, `publish_clip_metadata`
|
|
273
|
+
returns a `timed_marker_prompt` with four choices: `yes`, `no`,
|
|
274
|
+
`default_yes`, and `default_no`. The default choices persist locally for
|
|
275
|
+
future publishes; actual Resolve writes still require `confirm=true`.
|
|
276
|
+
- Conversation-level defaults can also be managed through
|
|
277
|
+
`setup(action="get_defaults")` and `setup(action="set_defaults")`. For
|
|
278
|
+
example, pass
|
|
279
|
+
`{"defaults":{"media_analysis":{"timed_markers_default":"default_no"}}}` to
|
|
280
|
+
make timed markers opt-in without waiting for the next publish prompt.
|
|
281
|
+
The setup tool also stores defaults for slate detection, chat-context vision,
|
|
282
|
+
transcription, session-only vs persisted reports, metadata field lists,
|
|
283
|
+
metadata overwrite policy, timed-marker types/colors/counts, confidence/time
|
|
284
|
+
note reporting, summary style, report format, preferred analysis roots,
|
|
285
|
+
generated-media folders, post-operation page preference, marker custom-data
|
|
286
|
+
style, and dry-run-first behavior. These defaults shape future analysis calls
|
|
287
|
+
but do not remove the `confirm=true` requirement for Resolve project writes.
|
|
288
|
+
|
|
289
|
+
When slate detection is enabled, the helper first looks for likely audio clap
|
|
290
|
+
cues with the source-safe sync detector, then checks temporary frames around the
|
|
291
|
+
cue before publishing slate-specific metadata or markers. Audio-only detections
|
|
292
|
+
remain sync evidence; they do not become slate keywords, slate comments, slate
|
|
293
|
+
fields, or slate markers unless visual review confirms that a slate or clapper
|
|
294
|
+
is actually present. Only high-confidence visual slate reads are proposed for
|
|
295
|
+
structured fields; lower-confidence reads stay out of structured writeback.
|
|
296
|
+
|
|
297
|
+
When visual analysis is requested for metadata publishing, `Description` and
|
|
298
|
+
editorial `Comments` are generated from successful visual analysis rather than
|
|
299
|
+
falling back to filename/duration/motion summaries. If the MCP client cannot
|
|
300
|
+
provide chat-context vision for that request, the publish result reports the
|
|
301
|
+
visual skip and leaves those descriptive fields unchanged.
|
|
302
|
+
|
|
303
|
+
### Clip Marker JSON And Sequence Analysis
|
|
304
|
+
|
|
305
|
+
Executed media analysis writes `clip_analysis_markers.json` beside each
|
|
306
|
+
`analysis.json` report under the project analysis root. This JSON is the durable
|
|
307
|
+
edit-intelligence layer: shot ranges, black/title/QC ranges, best moments, visual
|
|
308
|
+
descriptions, sound notes, transcript excerpts, word-timestamp availability,
|
|
309
|
+
color intent, and timeline occurrences when the clip came from a sequence.
|
|
310
|
+
|
|
311
|
+
Resolve Media Pool clip markers are optional writeback, not the source of truth.
|
|
312
|
+
Only `publish_clip_metadata` with marker writeback enabled and confirmed should
|
|
313
|
+
add markers to the Resolve project. Analysis itself should produce JSON marker
|
|
314
|
+
plans without mutating the project.
|
|
315
|
+
|
|
316
|
+
Use `media_analysis(action="analyze_bin")` for a bin of source clips. Use
|
|
317
|
+
`media_analysis(action="analyze_sequence")` or target `"sequence"`/`"timeline"`
|
|
318
|
+
when the task is to understand an existing edit; the sequence target analyzes
|
|
319
|
+
the distinct Media Pool assets used on the timeline and records each timeline
|
|
320
|
+
occurrence as structured data for later cutdown, adjustment, or recommendation
|
|
321
|
+
work.
|
|
322
|
+
|
|
323
|
+
### Local SQLite Analysis Index
|
|
324
|
+
|
|
325
|
+
For large single-user projects, the derived SQLite index is built automatically
|
|
326
|
+
after persisted analysis reports are written. Durable batch jobs refresh the
|
|
327
|
+
index after each successful slice, so search becomes useful as soon as the first
|
|
328
|
+
clip is analyzed instead of waiting for a long job to finish.
|
|
329
|
+
|
|
330
|
+
Use the explicit build action when you want to repair or fully rebuild the cache
|
|
331
|
+
from existing reports:
|
|
332
|
+
|
|
333
|
+
```json
|
|
334
|
+
{"action": "build_index", "params": {"analysis_root": "/path/to/analysis-root"}}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
The database is stored as `index.sqlite` beside `manifest.json` and
|
|
338
|
+
`project_summary.json` under the project analysis root. The JSON reports remain
|
|
339
|
+
the source of truth; the SQLite index is a rebuildable cache for searching clips,
|
|
340
|
+
markers, transcript segments, visual tags, timeline occurrences, warnings, and
|
|
341
|
+
computed keyframe metrics.
|
|
342
|
+
|
|
343
|
+
Use `media_analysis(action="index_status")` to inspect row counts and size. Use
|
|
344
|
+
`media_analysis(action="query_index", params={"query": "quiet reflective b-roll"})`
|
|
345
|
+
to search indexed clip summaries, marker descriptions, and transcript text.
|
|
346
|
+
|
|
347
|
+
Do not store sampled frames or contact sheets in SQLite. The index stores
|
|
348
|
+
text/metadata only; generated frame files remain disposable artifacts under the
|
|
349
|
+
analysis root and can be removed with `cleanup_artifacts(frames_only=true)`.
|
|
350
|
+
|
|
351
|
+
### Batch Jobs And Local Dashboard
|
|
352
|
+
|
|
353
|
+
For long runs, prefer durable batch jobs over one large analysis call. A job
|
|
354
|
+
stores operational state in `jobs.sqlite` under the same project analysis root
|
|
355
|
+
as the reports and index. Each slice processes a bounded number of clips, exits
|
|
356
|
+
cleanly, and can be resumed by a later agent or dashboard action.
|
|
357
|
+
|
|
358
|
+
Resolve-aware MCP workflow:
|
|
359
|
+
|
|
360
|
+
```json
|
|
361
|
+
{"action": "start_batch_job", "params": {"target": {"type": "bin", "path": "Master/Day 01"}, "depth": "standard"}}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
```json
|
|
365
|
+
{"action": "run_batch_job_slice", "params": {"job_id": "job-...", "max_clips": 1}}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
```json
|
|
369
|
+
{"action": "batch_job_status", "params": {"job_id": "job-..."}}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Use `list_batch_jobs`, `cancel_batch_job`, and `resume_batch_job` for operations
|
|
373
|
+
around the same project analysis root. Jobs refresh the SQLite search index
|
|
374
|
+
after each successful analyzed or reused clip, and completed jobs do a final
|
|
375
|
+
rebuild if needed. Pass `auto_build_index=false` when creating the job to disable
|
|
376
|
+
that behavior.
|
|
377
|
+
|
|
378
|
+
Standalone local dashboard:
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
venv/bin/python -m src.analysis_dashboard --analysis-root ~/Documents/davinci-resolve-mcp-analysis --open
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
The dashboard can create file/folder jobs without Resolve open, run one clip
|
|
385
|
+
slice at a time or auto-run slices, inspect recent events, build the local
|
|
386
|
+
index, and query completed analysis. Chat-context visual analysis still requires
|
|
387
|
+
the MCP request path because the standalone dashboard cannot call the host
|
|
388
|
+
chat/sampling model. It is intentionally single-user and local; it does not
|
|
389
|
+
provide authentication, multi-user locking, media playback, or image storage in
|
|
390
|
+
SQLite.
|
|
391
|
+
|
|
392
|
+
### Mapping Resolve Metadata Fields
|
|
393
|
+
|
|
394
|
+
Use `media_pool(action="metadata_field_inventory")` before expanding metadata
|
|
395
|
+
writeback beyond the default analysis fields. The probe is read-only and reports
|
|
396
|
+
three distinct surfaces for selected or explicit Media Pool clips:
|
|
397
|
+
|
|
398
|
+
- `GetMetadata("")`: project metadata values that have been explicitly written
|
|
399
|
+
or are otherwise exposed through Resolve's metadata API.
|
|
400
|
+
- `GetClipProperty("")`: the larger clip-property map that usually mirrors the
|
|
401
|
+
fields visible in Resolve's Metadata panel.
|
|
402
|
+
- Inferred Metadata-panel groups such as `Shot & Scene`, `Camera`, `Audio`,
|
|
403
|
+
`Production`, and `Reviewed By`.
|
|
404
|
+
|
|
405
|
+
Resolve does not expose a guaranteed public schema for the Metadata panel group
|
|
406
|
+
layout, and field names can differ subtly between the UI and scripting surfaces.
|
|
407
|
+
For example, the UI may show `Keywords` while `GetClipProperty("")` exposes
|
|
408
|
+
`Keyword`; live validation on Resolve Studio 20.3 showed that writeback should
|
|
409
|
+
still call `SetMetadata("Keywords", value)`. Likewise, slate roll/card values
|
|
410
|
+
should write to `Roll Card #` even when older helper code or UI/property maps use
|
|
411
|
+
`Roll/Card`. The probe reports aliases and marks this group map as best-effort.
|
|
412
|
+
|
|
413
|
+
For live validation against a disposable synthetic project, run:
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
venv/bin/python tests/live_metadata_field_inventory_validation.py --output-dir /tmp/resolve-metadata-field-probe
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
That harness compares `metadata_field_inventory`, `MediaPool.ExportMetadata()`,
|
|
420
|
+
and `SetMetadata()` readback without touching user source media. Use a Resolve
|
|
421
|
+
scripting-compatible Python 3.10-3.12 environment for the live run.
|
|
422
|
+
|
|
423
|
+
**Interlace Detection:**
|
|
424
|
+
```bash
|
|
425
|
+
ffmpeg -i "INPUT_FILE" -vf idet -frames:v 500 -f null - 2>&1 | grep "idet"
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**Thumbnail Extraction (explicit user approval required; writes to analysis directory ONLY):**
|
|
429
|
+
```bash
|
|
430
|
+
ffmpeg -i "INPUT_FILE" -vf "select=eq(n\,FRAME_NUM)" -frames:v 1 -q:v 2 "ANALYSIS_DIR/thumbnail.jpg"
|
|
431
|
+
ffmpeg -i "INPUT_FILE" -vf "fps=1/INTERVAL,scale=320:-1,tile=4x4" -frames:v 1 "ANALYSIS_DIR/contact_sheet.jpg"
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Whisper: Transcription (Optional)
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
# OpenAI Whisper CLI
|
|
438
|
+
whisper "INPUT_FILE" --model base --output_format json --output_dir "ANALYSIS_DIR"
|
|
439
|
+
|
|
440
|
+
# Or whisper-cpp
|
|
441
|
+
whisper-cpp -m /path/to/model -f "INPUT_FILE" --output-json
|
|
442
|
+
|
|
443
|
+
# Or Python whisper
|
|
444
|
+
python3 -c "
|
|
445
|
+
import whisper, json, sys
|
|
446
|
+
model = whisper.load_model('base')
|
|
447
|
+
result = model.transcribe(sys.argv[1])
|
|
448
|
+
print(json.dumps(result, indent=2))
|
|
449
|
+
" "INPUT_FILE"
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Analysis Output Format
|
|
455
|
+
|
|
456
|
+
Save as JSON sidecar files:
|
|
457
|
+
|
|
458
|
+
```json
|
|
459
|
+
{
|
|
460
|
+
"analysis_version": "1.0",
|
|
461
|
+
"analyzed_at": "2026-03-09T12:00:00Z",
|
|
462
|
+
"source_file": "/path/to/clip.mov",
|
|
463
|
+
"source_file_size_bytes": 1234567890,
|
|
464
|
+
"source_file_modified": "2026-03-01T10:30:00Z",
|
|
465
|
+
|
|
466
|
+
"video": {
|
|
467
|
+
"codec": "prores",
|
|
468
|
+
"codec_long": "Apple ProRes 422 HQ",
|
|
469
|
+
"profile": "3",
|
|
470
|
+
"pixel_format": "yuv422p10le",
|
|
471
|
+
"bit_depth": 10,
|
|
472
|
+
"width": 3840,
|
|
473
|
+
"height": 2160,
|
|
474
|
+
"display_aspect_ratio": "16:9",
|
|
475
|
+
"frame_rate": "23.976",
|
|
476
|
+
"frame_rate_exact": "24000/1001",
|
|
477
|
+
"is_vfr": false,
|
|
478
|
+
"scan_type": "progressive",
|
|
479
|
+
"color_primaries": "bt709",
|
|
480
|
+
"transfer_characteristics": "bt709",
|
|
481
|
+
"matrix_coefficients": "bt709",
|
|
482
|
+
"hdr": null,
|
|
483
|
+
"duration_seconds": 125.5,
|
|
484
|
+
"frame_count": 3010,
|
|
485
|
+
"bitrate_mbps": 220.5
|
|
486
|
+
},
|
|
487
|
+
|
|
488
|
+
"audio": [
|
|
489
|
+
{
|
|
490
|
+
"stream_index": 1,
|
|
491
|
+
"codec": "pcm_s24le",
|
|
492
|
+
"sample_rate": 48000,
|
|
493
|
+
"channels": 2,
|
|
494
|
+
"channel_layout": "stereo",
|
|
495
|
+
"bit_depth": 24,
|
|
496
|
+
"duration_seconds": 125.5
|
|
497
|
+
}
|
|
498
|
+
],
|
|
499
|
+
|
|
500
|
+
"container": {
|
|
501
|
+
"format": "mov",
|
|
502
|
+
"duration_seconds": 125.5,
|
|
503
|
+
"overall_bitrate_mbps": 225.3,
|
|
504
|
+
"timecode_start": "01:00:00:00",
|
|
505
|
+
"creation_time": "2026-03-01T10:30:00Z"
|
|
506
|
+
},
|
|
507
|
+
|
|
508
|
+
"loudness": {
|
|
509
|
+
"integrated_lufs": -23.1,
|
|
510
|
+
"loudness_range_lu": 12.5,
|
|
511
|
+
"true_peak_dbtp": -1.2
|
|
512
|
+
},
|
|
513
|
+
|
|
514
|
+
"scenes": [
|
|
515
|
+
{"time": 0.0, "score": 0.95},
|
|
516
|
+
{"time": 5.2, "score": 0.45},
|
|
517
|
+
{"time": 12.8, "score": 0.72}
|
|
518
|
+
],
|
|
519
|
+
|
|
520
|
+
"transcription": {
|
|
521
|
+
"language": "en",
|
|
522
|
+
"text": "Full transcription text...",
|
|
523
|
+
"segments": [
|
|
524
|
+
{"start": 1.2, "end": 3.5, "text": "Hello and welcome..."}
|
|
525
|
+
]
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## Connecting Analysis to the MCP
|
|
533
|
+
|
|
534
|
+
### Getting File Paths from Resolve
|
|
535
|
+
|
|
536
|
+
Use MCP tools to get file paths from the current project, then analyze them externally:
|
|
537
|
+
|
|
538
|
+
1. **From media pool clips:** `media_pool_item` -> `get_clip_property(clip_id)` returns `"File Path"`
|
|
539
|
+
2. **From timeline items:** `timeline_item` -> `get_media_pool_item(item_id)` -> then get clip properties
|
|
540
|
+
3. **From media storage:** `media_storage` -> `get_files(path)` lists files in a directory
|
|
541
|
+
|
|
542
|
+
### Workflow: Analyze Before Acting
|
|
543
|
+
|
|
544
|
+
1. **Identify the media** — Use MCP to get clip IDs and file paths
|
|
545
|
+
2. **Check for existing analysis** — Look for sidecar JSON files
|
|
546
|
+
3. **Analyze if needed** — Run FFprobe (+ optional tools) on the files
|
|
547
|
+
4. **Act with context** — Use MCP tools with full knowledge of what the media is
|
|
548
|
+
|
|
549
|
+
Analysis informs Resolve actions. At no point do we create intermediate files that enter the media pipeline.
|
|
550
|
+
|
|
551
|
+
### Examples
|
|
552
|
+
|
|
553
|
+
**"Set up my timeline for this footage"**
|
|
554
|
+
- FFprobe reveals 4K ProRes 422 HQ, 23.976fps, Rec.709
|
|
555
|
+
- Use `project_settings` to set timeline resolution, frame rate, and color science
|
|
556
|
+
- Original files stay untouched
|
|
557
|
+
|
|
558
|
+
**"Create markers at scene changes"**
|
|
559
|
+
- Run FFmpeg scene detection (`-f null -` — no output file)
|
|
560
|
+
- Use `timeline_markers` or `media_pool_item_markers` to add markers
|
|
561
|
+
- Analysis writes nothing to source; markers live in Resolve's database
|
|
562
|
+
|
|
563
|
+
**"What are my audio levels?"**
|
|
564
|
+
- Run EBU R128 loudness analysis (`-f null -`)
|
|
565
|
+
- Report current levels vs target (-24 LUFS broadcast, -14 LUFS streaming)
|
|
566
|
+
- Suggest adjustments in Resolve's Fairlight page
|
|
567
|
+
|
|
568
|
+
**"Help me set up color management"**
|
|
569
|
+
- FFprobe reveals ARRI LogC3, wide gamut, 12-bit
|
|
570
|
+
- Recommend ACES IDT or DaVinci Wide Gamut
|
|
571
|
+
- Camera original retains full latitude
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## What Analysis Enables
|
|
576
|
+
|
|
577
|
+
| Task | Without Analysis | With Analysis |
|
|
578
|
+
|------|-----------------|---------------|
|
|
579
|
+
| Set timeline settings | Guess or ask user | Auto-detect from footage |
|
|
580
|
+
| Color space setup | Default to Rec.709 | Match source (ARRI LogC, S-Log3, etc.) |
|
|
581
|
+
| Audio normalization | Manual measurement | Report LUFS, suggest Fairlight adjustments |
|
|
582
|
+
| Scene-based editing | Manual review | Auto-mark scene changes via MCP markers |
|
|
583
|
+
| Subtitle creation | Use Resolve's built-in | Whisper transcription -> import via MCP |
|
|
584
|
+
| QC checks | Visual inspection | Automated codec/bitrate/level verification |
|
|
585
|
+
| Render settings | Generic defaults | Match source codec/colorspace for delivery |
|
|
586
|
+
| Timecode sync | Manual entry | Extract embedded timecode for reference |
|
|
587
|
+
| VFR detection | Unknown issues | Flag before problems occur in timeline |
|
|
588
|
+
| Mixed-camera projects | Manual identification | Auto-detect cameras, suggest per-clip IDTs |
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## Proactive Warnings
|
|
593
|
+
|
|
594
|
+
When analysis reveals potential issues, always alert the user:
|
|
595
|
+
|
|
596
|
+
- **VFR** — Variable frame rate detected; Resolve may interpret differently than expected
|
|
597
|
+
- **Mismatched sample rates** — 44.1kHz audio in a 48kHz timeline causes drift
|
|
598
|
+
- **HDR metadata** — HDR10/HLG/Dolby Vision present; color management must account for it
|
|
599
|
+
- **Color space flags** — ARRI LogC3 / S-Log3 / V-Log etc. requires appropriate IDT
|
|
600
|
+
- **Timecode discontinuity** — Multiple clips share starting TC; conform conflicts possible
|
|
601
|
+
- **Interlaced content** — Set deinterlacing mode before editing
|
|
602
|
+
- **Missing audio** — No audio streams detected
|
|
603
|
+
- **Extremely high bitrate** — Verify storage can sustain real-time playback
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## Key Principles
|
|
608
|
+
|
|
609
|
+
- **The source is sacred.** Read from source files, write only to analysis sidecars unless a visual analysis workflow needs sampled frames/contact sheets in a separate analysis directory. Confirmed metadata publishing writes to Resolve's project database, not source media. `analyze_media` can opt out with `include_visuals=false`.
|
|
610
|
+
- **Respect file paths.** Use exact paths from Resolve or the filesystem.
|
|
611
|
+
- **Cache analysis.** Skip re-analysis if the sidecar is newer than the source.
|
|
612
|
+
- **Report clearly.** Present analysis to inform the user's next action within Resolve.
|
|
613
|
+
- **Timecode matters.** Always extract and report TC — it's the foundation of conform, sync, and delivery.
|
|
614
|
+
- **Handle errors gracefully.** If a file can't be analyzed, report and move on.
|
|
615
|
+
- **Chain of custody is real.** This tool provides intelligence about the source — never creates alternatives to it.
|