feat(export): save clip/range as media (#48)#216
Open
appergb wants to merge 1 commit into
Open
Conversation
- export_range command: single clip or marked range local render - reuses run_export_with_control + composite_frame (same RenderPlan) - output to project media/ + import_media (appears in panel, undoable) - audio-only clip → wav via encode::mix - UI: ClipContextMenu 'Save as Media' wired
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Wires up the Save as Media right-click action (#48 tail, HANDOFF §3.5): render a single clip or a marked timeline range to a file on disk and import it back into the media library, so the result appears in the panel and is undoable.
Changes
Backend (
src-tauri/src/export.rs)export_rangecommand: renders a single clip (clip_id) or a marked range (in_frame..out_frame) of the whole-timeline composite.run_export_with_controlwith an optionalframe_rangeparameter (full-timeline export passesNone→ unchanged behavior); the frame loop, progress reporting, and audio mixdown are all sliced to the requested range.composite_frame/MediaResolverpixel path as the preview and full-timeline export → a saved clip drags back onto the timeline pixel-identical.media_type = audio) and explicitAudioWavformat skip the GPU: mix down viaopentake_media::encode::mix→ hand-written 44-byte WAV header (no ffmpeg child for raw PCM).<cache_root>/saves/save_<id>_<in>_<out>.{mp4,wav}, thenimport_onebrings it into the manifest (same path ascapture_frame_to_media).export://progressevent; cancel via the existingcancel_exportflag.IPC registration (
src-tauri/src/lib.rs)export::export_rangeadded togenerate_handler!.Frontend
web/src/lib/types.ts:ExportFormat = "video" | "audioWav"(mirror of Rust enum, camelCase wire tag pinned by test).web/src/lib/api.ts:saveClipAsMedia(clipId, inFrame, outFrame, format?, trackIndex?)IPC wrapper; returns null outside Tauri.web/src/components/timeline/ClipContextMenu.tsx: "Save as Media" menu item (was a disabled placeholder) now wired — resolves clip span + track index, picksaudioWavfor audio clips, subscribes to progress, toasts success/failure.web/src/i18n/dict.ts:media.saveAsMediaSaved/media.saveAsMediaFailedtoast copy (zh + en).Acceptance
.wav(auto-downgradeVideo→AudioWav)clip_id=null) → whole-timeline composite for that spanimport_onemanifest mutation)Local verification (all green)
New unit tests:
export_format_defaults_to_video,export_format_parses_audio_wav_tag(IPC camelCase pin),slice_pcm_*(3),write_wav_s16le_writes_valid_riff_header.Closes #48.