O que resolve-cut faz?
Você monta, renderiza e verifica vídeos no DaVinci Resolve Studio por meio de scripts salvos com parâmetros. Você não reescreve a montagem em cada sessão: você chama os scripts, lê o que eles retornam e verifica o resultado com números e quadros. O gosto permanece humano: a pessoa decide o que fica, você executa e mede.
$SKILL abaixo é a pasta desta habilidade (onde este arquivo está). Scripts em scripts/resolve/ são executados dentro do Resolve
através de run.py; scripts em scripts/media/ são Python puro com ffmpeg. Cada script tem --help.
Antes de começar
- Resposta do Resolve:
python3 "$SKILL/scripts/resolve/run.py" - '{}' <<< 'result = resolve.GetVersionString()'. Código de saída 2 significa que o Resolve está fechado, é a edição gratuita, ou em Preferências > Sistema > Geral > Scripts externos usando não está definido como Local. ffmpeg -version,python3 -c "import numpy, PIL"eELEVENLABS_API_KEY(ambiente ou./.env).- Se o projeto mantém um arquivo de notas (
VIDEO_NOTES.mdou similar), leia-o: o que a pessoa aprovou e rejeitou antes. Não peça a mesma correção duas vezes. - Pasta de trabalho: tudo o que você escreve (transcrições, dossiê, quadros, renderizações) vai para uma pasta de trabalho, nunca para a pasta de filmagem bruta.
O fluxo
1. Transcrever. Transcrições em nível de palavra, um JSON por clipe:
python3 "$SKILL/scripts/media/transcribe.py" <pasta de clipes> --out work/transcripts [--language por].
A transcrição é a base de tudo: escolher takes, cortar nos limites dos quadros e verificar a mixagem final.
2. Dossiê. Todo o material em um arquivo de texto compacto, leia uma vez:
python3 "$SKILL/scripts/media/dossier.py" <pasta de clipes> --transcripts work/transcripts --out work/dossier.md [--sheets].
Ele lista cada frase com seu tempo e sinaliza «repeats C0076 20.2» quando uma frase começa como uma anterior:
outra tentativa da mesma fala. Com um roteiro, mantenha o último take completo de cada parágrafo; descarte
hesitações, falsos começos e tentativas repetidas. Abra um clipe apenas para decidir algo:
python3 "$SKILL/scripts/media/inspect_range.py" <clipe> <t0> <t1> --words work/transcripts/<clipe>.json (quadros,
forma de onda e palavras em uma imagem).
3. Lista de cortes. Escreva work/plan.json com os takes escolhidos em ordem
({"Lesson 01 v1": [["01a", "C0081", 1.9, 12.6], ["01b", "C0083", 5.4, 23.8], ...]}: take, clipe, de, até em segundos
do clipe), então:
python3 "$SKILL/scripts/media/cut_list.py" work/plan.json work/transcripts <pasta de clipes> work/cuts.json.
Os cortes pousam no limite de quadro mais silencioso próximo às palavras, pausas acima de 1 s são encurtadas, e os segmentos
alternam zoom 1 / 1.2 para que cortes entre takes não saltem. Para um falso começo sem lacuna ("co- contar"), force o quadro com
{"in_frame": N} ou {"out_frame": N}. Notas para o editor: add_markers.py.
4. Montar no Resolve. Uma operação pesada por chamada, e leia cada result antes da próxima:
R="$SKILL/scripts/resolve/run.py"
python3 "$R" "$SKILL/scripts/resolve/project.py" '{"name": "Lesson 01", "width": 1920, "height": 1080, "fps": "25"}'
python3 "$R" "$SKILL/scripts/resolve/assemble.py" '{"phase": "import", "bin": "Raw", "media": "/abs/clips", "files": ["C0081.MP4"]}'
python3 "$R" "$SKILL/scripts/resolve/assemble.py" '{"phase": "timeline", "bin": "Raw", "cuts": "/abs/work/cuts.json", "timeline": "Lesson 01 v1", "zoom": {"center": [0.45, 0.37]}, "voice_isolation": 50}'
zoom.center é onde o rosto está (fração do quadro), então o close-in o mantém no lugar. Verifique se
frames == expected e failures está vazio.
5. Olhar antes de renderizar. frames.py exporta quadros diretamente da linha do tempo em menos de um segundo
({"timeline": "Lesson 01 v1", "frames": [100, 500], "folder": "/abs/work/frames", "max": 960}). Olhe um quadro
simples e um com close-in.
6. Renderizar.
python3 "$R" "$SKILL/scripts/resolve/render.py" '{"phase": "start", "timeline": "Lesson 01 v1", "folder": "/abs/out", "name": "lesson-01", "preset": "reel", "width": 1920, "height": 1080, "mark": [0, <frames - 1>]}',
depois verifique {"phase": "status", "job": "<id>"} a cada 10 s até que JobStatus seja Complete. Aguarde a renderização terminar
antes de responder: uma execução headless que termina sua vez em "renderização iniciada" deixa ninguém para verificá-la.
7. Verificar. python3 "$SKILL/scripts/media/qc.py" out/lesson-01.mp4 --expected <frames> --transcribe
(adicione --ref contra a última versão aprovada, --frames para uma planilha, --simulate para Instagram). Leia a
transcrição da mixagem final em cada corte: palavras repetidas ("decide, decide"), palavras cortadas e palavras no lugar errado
são os defeitos que uma lista de cortes cria. Confirme um corte suspeito na forma de onda (inspect_range.py) antes de movê-lo, corrija
a lista de cortes, monte uma nova versão (v2) e renderize novamente. No máximo 3 rodadas, cada defeito nomeado com seu tempo
exato. Nunca considere concluído porque "parece certo": cite os números.
8. Entregar. loudness.py quando a mixagem estiver fora do alvo (ganho linear e um limitador, nunca loudnorm), depois
deliver.py export.mp4 clean.mp4 [--no-editlist] [--copy <pasta>]: sem trilha de timecode, sem metadados, moov primeiro,
cópia comparada byte a byte.
9. Revisar, após a aprovação da pessoa. Escreva no arquivo de notas o que eles aprovaram e rejeitaram, em suas palavras, uma linha cada; toda nova armadilha com sua data; e toda rotina que você fez manualmente mais de uma vez se torna um script com parâmetros ao lado destes.
Executando scripts dentro do Resolve
run.pyconecta-se ao Resolve aberto e executa um script comresolve,project,P(o JSON) e__file__definidos, depois imprimeresultcomo JSON. Custa muito menos tokens do que escrever o mesmo script através de um MCP.- Com um servidor MCP em vez disso (oficial
run_script_unsafe):P = {...}; __file__ = "<caminho absoluto do script>"; exec(open(__file__, encoding="utf-8").read()). O sandbox lê arquivos como ASCII semencoding, e os nomes persistem entre chamadas: os scripts prefixam suas variáveis. - Salve antes e depois de escrever (
GetProjectManager().SaveProject()); não há desfazer. Faça cada nova versão em uma cópia da linha do tempo (DuplicateTimeline, que copia também composições Fusion). - Consulte a API em vez de adivinhar: o MCP oficial tem
search_scripting_api,get_scripting_docseget_whats_new(uma vez por sessão), ou o README da Blackmagic na pastaDeveloper/Scriptingdo Resolve (Ajuda > Documentação > Desenvolvedor). - Nova operação que se repetirá? Escreva-a uma vez como um script com um dicionário
Pe umresult, ao lado destes.
Destinos de entrega
| Destino | Imagem | Som |
|---|---|---|
| Reels, Stories, Shorts, TikTok | 1440x2560 na taxa de quadros de gravação, H.264 High a cerca de 20 Mbps real, tags Rec.709 (1-1-1), faststart | -14 LUFS, pico verdadeiro abaixo de -1.5 dBTP |
| Aulas e cursos | como gravado (1920x1080 ou 3840x2160) | -16 LUFS, pico verdadeiro até -1 dBTP |
| YouTube | o master 4K (uploads em 1080p perdem qualidade), MP4 sem listas de edição | a mixagem do master |
| 1920x1080 e 1080x1920 a 16 Mbps, com SRT | a mixagem do master |
Armadilhas verificadas
Medido no macOS com Resolve Studio 21.1.1 e 21.1.2, outubro e novembro de 2026.
Máquina
- Um ffmpeg por vez, com
nice -n 15e-threads 2: 96 processos ffmpeg paralelos congelaram o Mac e forçaram uma reinicialização. - No zsh,
$varnão divide em palavras (ffmpeg $argsquebra): construa listas de argumentos em Python. - Escreva saídas na pasta de trabalho: um auxiliar que salvava imagens ao lado do clipe escreveu na unidade de filmagem bruta.
Configuração e API do Resolve
- O Resolve 21.1 moveu o scripting Python para o Studio:
run.pye ambos os servidores MCP precisam do DaVinci Resolve Studio. - Scripts externos devem estar definidos como Local (Preferências > Sistema > Geral) ou
scriptapp("Resolve")retorna None. StartRenderingé a última chamada de um script: tudo o mais retorna None até que a renderização termine.- A taxa de quadros do projeto trava quando a primeira linha do tempo é criada: defina-a antes (
project.py). - Resolução:
SetSettinguma chave por vez,useCustomSettingsprimeiro. - O tempo limite do MCP (10 s por padrão, no máximo 60 s) retorna um erro, mas o script continua executando dentro do Resolve: verifique o estado antes de executá-lo novamente.
- Não há cortar, mover ou deslizar: exclua o item e anexe-o novamente com
startFrame,endFrame(exclusivo) erecordFrame. startFrameconta a partir do primeiro quadro do arquivo, mesmo com timecode de câmera.GetSourceStartFrameàs vezes lê um quadro antes (866 lê 865) enquanto o posicionamento está correto: leia o ponto de entrada comGetLeftOffset.AddMarkermantém um marcador por quadro.ReplaceClipapaga os metadados do clipe.SetTrackEnableretorna True e não muda nada em algumas linhas do tempo: desative os clipes comSetClipEnablede confirme em um quadro exportado.SetClipEnabledem uma linha do tempo que não é a atual retorna False:SetCurrentTimelineprimeiro, depois confirme comGetClipEnabled.DeleteClips(items, True)ondula todas as faixas: primeiro exclua, sem ondular, o que cruza o corte (stems, legendas).- Isolamento de Voz funciona por script:
TimelineItem.SetVoiceIsolationState({"isEnabled": True, "amount": 100})reduziu a reverberação da sala em 3 a 4 dB;Timeline.SetVoiceIsolationState(track, {...})define um controle para uma faixa inteira. - A API não pode definir parâmetros do ResolveFX (Refinamento Facial, Remoção de Imperfeições): uma pessoa os define, ou você dirige a interface através de acessibilidade.
- Com a tela bloqueada ou o Resolve minimizado, a janela desaparece da acessibilidade, mas a API continua funcionando: verifique com quadros exportados.
- Super Scale é uma propriedade do media pool:
SetClipProperty("Super Scale", 2); um arquivo de substituição precisa defini-la novamente. - LUTs para
Graph.SetLUTvão na pasta de LUTs do sistema do Resolve, em uma subpasta, passados por caminho relativo apósRefreshLUTList(). - Mudar de página enquanto o Resolve reproduz trava-o;
item.GetFusionCompByIndex(1).Execute(lua)edita uma composição sem abrir a página Fusion.
Importação e mídia
- Um ProRes por chamada de importação: vários ProRes 4444 (e uma vez dois novos ProRes 422) em uma chamada travaram o Resolve 21.1 (
UiMpController,std::out_of_range). MP4s de câmera, 22 em uma chamada, funcionaram bem. - Após essa trava, um processo
ResolvePythonórfão faz o MCPlaunch_resolverelatar o Resolve como em execução: mate-o e abra o Resolve novamente. ImportMediacom uma lista de caminhos: a forma com dicionários retornou None para MP4 no 21.1.- O Resolve armazena em cache a decodificação por caminho: um arquivo que você renderiza novamente recebe um novo nome.
- PCM 24-bit little-endian em MOV é lido como ruído branco: use
pcm_s24be. - iPhone HEVC travou o decodificador macOS: edite a partir de ProRes.
- iPhone HDR (HLG, Dolby Vision): nosso tone mapping parecia desbotado e foi rejeitado duas vezes. Peça uma exportação SDR no início.
- Um
.movde 1 quadro importa como um still de 150 quadros: dê a ele pelo menos 3 quadros e corte na linha do tempo. - Alfa direto: o Resolve lê alfa não pré-multiplicado, então uma sobreposição feita com ffmpeg
overlayem uma tela transparente fica escura; posicione-a compad=W:H:x:y:[email protected].
Renderização
- Com
SelectAllFrames,StartRenderingàs vezes retorna False: definaMarkIn/MarkOut(render.pymark), que também corta as caudas de som que alongam uma linha do tempo. - Um trabalho H.264 criado logo após um trabalho somente de áudio saiu sem vídeo: carregue uma predefinição antes de
SetRenderSettings, e verifique o fluxo de vídeo com ffprobe. VideoQualitydo H.264 é um teto, não uma média: 20000 deu 14.7 Mbps e 27300 deu 20.7 Mbps em 1440x2560.- "Forçar redimensionamento para máxima qualidade" não é uma chave de
SetRenderSettings, mas viaja dentro de uma predefinição de renderização (ForceHighestQualitySizing). ExportRenderPreset(name, path)tratapathcomo uma pasta;ImportRenderPresetnomeia a predefinição após o arquivo.- As predefinições armazenam uma taxa de quadros: defina
FrameRatea partir da linha do tempo, ou uma linha do tempo de 29.97 renderiza convertida (render.py faz isso). ExportFrame(21.1.2) deu 4 quadros em 1440x2560 em 0.75 s, dentro de 41 a 46 dB da renderização: verifique quadros sem renderizar.
Som e transcrições
- Um corte entre dois takes pode unir uma palavra repetida ("decide, decide"): transcreva a mixagem final e procure por duplicatas. Corrija sem alterar o comprimento: termine a primeira parte antes da palavra, comece a segunda mais cedo na pausa do take bom.
- A transcrição não ouve sussurros e respirações: os pontos de corte vêm do som da própria câmera (
cut_list.py). - Scribe uma vez colocou uma palavra 3 s antes, depois de uma palma e um sussurro: confirme na forma de onda antes de mover um corte.
- Efeitos sonoros MP3 chegam cerca de 60 ms atrasados (o atraso do codificador não é compensado): use WAV para qualquer coisa que precise acertar um quadro.
- loudnorm em uma passagem é dinâmico e altera a mixagem aprovada; em duas passagens, silenciosamente volta ao dinâmico: use
loudness.py.
Filmagem e plataformas
- 25 fps no Instagram: servido a 25 (ffprobe dos arquivos servidos, novembro de 2026). A gagueira vem dos iPhones ProMotion, que não têm modo de 25 ou 50 Hz. Mantenha filmagem de 25 fps a 25 (converter para 30 repete um quadro em cada cinco); filme novo material a 29.97 com obturador de 1/50.
- Cintilação sob luzes de 50 Hz depende do obturador, não da taxa de quadros: 1/50 e 1/100 não cintilam; 1/60 a 30 fps cintila.
- O Instagram recodifica no telefone e novamente no servidor: a entrega básica é cerca de 720x1280 a 1.4 Mbps, com som normalizado para cerca de -14 LUFS, então um master acima de -14 não ganha nada.
qc.py --simulatemostra o que sobrevive. - CRF no ffmpeg esgota fundos escuros: um reel ficou a 6.8 Mbps. Verifique a taxa de bits real antes de entregar.
- Uma execução
claude -pheadless termina sua vez quando a renderização começa, a menos que o prompt diga para esperar.
Scripts
| Script | O que faz |
|---|---|
scripts/media/transcribe.py | Scribe JSON em nível de palavra por clipe (chave via stdin, nunca na lista de processos) |
scripts/media/dossier.py | cada clipe como texto compacto: frases com tempos, pausas, tentativas repetidas, folhas de quadro opcionais |
scripts/media/inspect_range.py | uma imagem de um intervalo: quadros, forma de onda, palavras com tempos |
scripts/media/cut_list.py | take |