Media — Video record, playback, screen-capture, formats (privacy + widgets)
Contrato cross-surface para captura, playback e screen-capture de vídeo em apps Koder. Toggles de privacidade (`media.video.camera`, `media.video.screen`, `media.video.mic`) em Settings; defaults seguros (tudo OFF até prompt do SO); codecs canônicos (H.264/HEVC/AV1/VP9 in via kodec; H.264 + AAC out); widgets `KoderVideoPlayer` + `KoderVideoRecorder` + `KoderScreenCapture` em `engines/sdk/koder_kit`. Recording indicator obrigatório quando capture ativo. Upload size cap 500 MB. `<APP>-VIDEO-*` error map.
Media — Video Spec — v0.1
Normative cross-surface spec para video I/O em apps Koder. Implementação obrigatória via widgets
KoderVideo*emengines/sdk/koder_kit(Flutter) ekoder_web_kit(JS) — nunca rolarvideo_playerupstream ou<video>raw local. Codec layer viaengines/kodec(canônica) ou Koda port (shadow-active).
Scope
Aplica-se a *odo app Koder que grave, reproduza, ou faça screencapture de vídeo* call recording, tutorial inapp, attachment de vídeo em chat, demo em landing, screen-share em ferramenta de dev, upload de vídeo de produto.
Surfaces cobertas: Flutter mobile (Android + iOS), Flutter desktop (Linux + macOS + Windows), Flutter web ou templ+HTMX, TV (playback; gravação fora de escopo em TV). CLI/TUI exigem path arg + delegam ao desktop player externo.
1 — MUST: expose "Vídeo" toggle group in Settings
Sub-seção "Vídeo" do agrupamento "Mídia" em Settings; *eve*conter, na ordem:
- *âmera*(
media.video.camera) — gate à camera - *icrofone para vídeo*(
media.video.mic) — gate ao mic durante gravação - *ompartilhar tela*(
media.video.screen) — gate ao screen-capture - *esolução máxima*(
media.video.max_height) — dropdown 480 / 720 / 1080 / 2160 - *ualidade*(
media.video.bitrate_mbps) — slider 1-20 Mbps
Compartilha media.image.camera quando ambos coexistem (camera permission é granted ao app, não ao sub-uso); cada toggle controla *so* não permissão de SO.
2 — MUST: defaults seguros em fresh install
| Chave | Default | Notas |
|---|---|---|
media.video.camera |
*FF* | Privacy |
media.video.mic |
*FF* | Vídeo silencioso até user ativar |
media.video.screen |
*FF* | Screen |
media.video.max_height |
1080 | Cap em 4K só se Settings.advanced ativo (raras as redes) |
media.video.bitrate_mbps |
5 | 5 Mbps casa com 1080p30 H.264 sem visible blocking |
Quando qualquer toggle for OFF em runtime, o app *eve*parar qualquer capture ativo + liberar handles + dismiss screen-share dialog.
3 — MUST: privacidade + recording indicator
- *UNCA*auto-upload de gravação (user confirma antes do POST)
- *UNCA*screen
capture em background sem uservisible indicator - *UNCA*keep camera open em background além de 5 s pós-leave
- *ecording indicator*obrigatório: dot vermelho + timer + título
da janela alterado para
● Recording — <app>; em mobile, system status bar fica vermelho (iOS) / mostra ícone (Android) - *XIF/metadata*strip equivalente para vídeo (camera serial, GPS
de container MP4);
media.video.strip_metadata = truedefault
4 — MUST: widget surface no koder_kit
| Widget | Função |
|---|---|
KoderVideoPlayer |
Playback de KoderVideoRef ou URL; controls config (playpauseseekfullscreencaptions/speed) |
KoderVideoRecorder |
Gravação com preview + start/stop + flip-camera; gates media.video.camera |
KoderScreenCapture |
Screen share dialog + capture pipeline; gates media.video.screen; *orça*recording indicator |
KoderVideoPicker |
Sheet "Gravar vídeo" / "Escolher da galeria"; retorna KoderVideoRef |
KoderVideoThumbnail |
Frame thumbnail (default 1s mark) + lazy-load |
KoderVideoRef: {uri, mime, durationMs, width, height, sizeBytes,
hasAudio, codec, koderUserId?, workspaceId?}.
5 — MUST: format support
*ecode (via engines/kodec):*H.264, HEVC (HEIC pipeline), AV1, VP9 — container MP4, WebM, MOV.
*ncode (default):*H.264 + AAC + MP4 container. HEVC e AV1 são opt-in quando suportado pela surface (iOS encoder, browser MediaRecorder com codec hint).
*pload size cap:*500 MB pós-compress. Exceder → erro <APP>-VIDEO-SIZE-001 com sugestão de bitrate menor ou trim.
*ompression knob:*media.video.bitrate_mbps (§2) controla output; duração + resolução + bitrate determinam tamanho. App *eve*estimar size pré-encode e avisar se ultrapassar cap.
6 — MUST: error surface
| Cenário | ID | Texto pt-BR |
|---|---|---|
| Permissão de câmera negada | <APP>-VIDEO-CAM-001 |
"Permita o acesso à câmera para gravar vídeo." |
| Permissão de mic negada | <APP>-VIDEO-MIC-001 |
"Permita o acesso ao microfone para vídeo com áudio." |
| Permissão de screen-capture negada | <APP>-VIDEO-SCR-001 |
"Permita o compartilhamento de tela para continuar." |
| Codec não suportado pelo decoder local | <APP>-VIDEO-CDC-001 |
"Este vídeo usa codec não suportado ($codec)." |
| Tamanho excede 500 MB | <APP>-VIDEO-SIZE-001 |
"Vídeo muito grande. Reduza qualidade ou corte trechos." |
| Upload falhou | <APP>-VIDEO-NET-001 |
"Falha ao enviar o vídeo. Tente novamente." |
| Encode falhou (kodec/hardware) | <APP>-VIDEO-ENC-001 |
"Falha ao processar o vídeo. Tente novamente ou reduza qualidade." |
7 — Observability
- Counters:
media.video.recorded,media.video.uploaded,media.video.upload_error,media.video.screen_captured - Latency histograms:
media.video.encode_ms,media.video.upload_ms,media.video.first_frame_ms(playback) - *ão*emitir métricas que vazem conteúdo (transcript, frames,
file path) — apenas counters + latência + dimensões anonimizadas (resolução, codec, duration)
8 — Adoption checklist (per app)
- [ ] Importa
KoderMediaSettingsTile(sub-seção Vídeo visível) - [ ] Usa
KoderVideoPlayerKoderVideoRecorderKoderScreenCapture(nuncavideo_playerupstream raw) - [ ] Defaults da §2 respeitados em fresh install
- [ ] Recording indicator obrigatório (§3)
- [ ] Codec layer via
engines/kodec(ou Koda port quando flipped) - [ ] Error map da §6 implementado
- [ ] Upload path respeita
multi-tenancy/contract.kmd
Non-normative — referências
- Sibling specs:
specs/media/image.kmd(camera shared),specs/media/audio.kmd(mic + recording indicator paralelo),specs/media/document.kmd - Codec engine:
engines/kodec/(canônica, Rust); Koda port emengines/lang/koda/lib/{mp4,mp3,wav}.kd(shadow-active per Flipping Point em CLAUDE.md) - Implementation surface:
engines/sdk/koder_kit/lib/src/media/ - Voice precedent (mic + privacy contract):
specs/voice/wake-word.kmd