### Install Dependencies and Start Dev Server Source: https://github.com/webav-tech/webav/blob/main/doc-site/README.md Use these commands to install project dependencies and start the local development server for the WebAV documentation site. ```bash pnpm install ``` ```bash pnpm start ``` ```bash pnpm run build ``` -------------------------------- ### Install and Build Project Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/contribution.md Steps to clone the project, install dependencies, and build the project from the root directory. ```bash pnpm install && pnpm build ``` -------------------------------- ### Install @webav/av-cliper with npm Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/quick-start.en-US.md Use this command to install the @webav/av-cliper package if you are using npm. ```bash $ npm install @webav/av-cliper ``` -------------------------------- ### Run Documentation Site Development Server Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/contribution.md Navigate to the doc-site directory and start the development server for the project documentation. ```bash cd doc-site pnpm dev ``` -------------------------------- ### Install @webav/av-cliper with pnpm Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/quick-start.en-US.md Use this command to install the @webav/av-cliper package if you are using pnpm. ```bash $ pnpm add @webav/av-cliper ``` -------------------------------- ### Run Package Development Server Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/contribution.md Navigate to a specific package directory and start the development server. ```bash cd av-cliper pnpm dev ``` -------------------------------- ### Install WebAV Packages Source: https://context7.com/webav-tech/webav/llms.txt Install the core WebAV package and optional modules for canvas and recording functionalities. Ensure all @webav/* package versions are kept in sync. ```bash npm install @webav/av-cliper # Optional packages npm install @webav/av-canvas npm install @webav/av-recorder ``` -------------------------------- ### Generate Video with GIF and Voiceover Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/2_2-video-add-audio.md This example shows how to create a video from an animated GIF and add a voiceover. Ensure your audio file is compatible. ```typescript import { WebAV, AudioClip } from 'webav'; async function gifWithVoiceover(gifSrc: string, audioSrc: string, outputSrc: string) { const webav = new WebAV(); const audio = new AudioClip(audioSrc); await webav.video.addAudio(gifSrc, audio).write(outputSrc); } ``` -------------------------------- ### Split Video Track Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/6_3-split-track.en-US.md This example demonstrates how to split a video file into its independent audio and video components. This is useful for applying separate edits or playback to each track. ```typescript import React, { useState } from "react"; import { Button, message, Spin } from "antd"; import Webav, { WebavPlayer } from "@webav/av-player"; const App: React.FC = () => { const [loading, setLoading] = useState(false); const [videoUrl, setVideoUrl] = useState(undefined); const handleSplitTrack = async () => { setLoading(true); try { const webav = new Webav(); const url = await webav.splitTrack( "./video/test.mp4", "./output/test.mp4", "./output/test.mp3" ); setVideoUrl(url); message.success("Split track successfully!"); } catch (error) { message.error("Split track failed!"); console.error(error); } finally { setLoading(false); } }; return (
{videoUrl && (

Video

)}
); }; export default App; ``` -------------------------------- ### Video Compositing and Concatenation Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/2_5-video-compsite-and-concat.en-US.md This example demonstrates removing green screen backgrounds, compositing videos with a background image, and then concatenating the resulting videos using fastConcatMP4. Ensure you have the necessary video assets and a background image. ```typescript import { WebAV, VideoCompositor, FastConcatMP4 } from '@webav/avtools'; async function demo() { const compositor = new VideoCompositor(); const fastConcat = new FastConcatMP4(); // 1. Remove green screen background and composite with a background image const assets = [ './green.mp4', './green2.mp4', './green3.mp4', ]; const background = './background.jpg'; const outputs = await Promise.all( assets.map(async (asset) => { const ret = await compositor.composite( asset, background, { type: 'chroma' } // Remove green screen ); return ret; }) ); // 2. Concatenate the three video files end to end const finalVideo = await fastConcat.concat(outputs); // 3. Save the final video const blob = new Blob([finalVideo.buffer], { type: 'video/mp4', }); const url = URL.createObjectURL(blob); console.log('Final video URL:', url); } demo(); ``` -------------------------------- ### Play MP4 Video with WebCodecs Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/1_4-play-video.en-US.md This example shows how to play an MP4 video by decoding its frames and audio using WebCodecs. It requires setting up a decoder, a canvas for video rendering, and the Web Audio API for audio playback. ```typescript import React, { useEffect, useRef } from "react"; const App = () => { const videoRef = useRef(null); useEffect(() => { const init = async () => { if (!videoRef.current) return; const res = await fetch("./big_buck_bunny.mp4"); const buffer = await res.arrayBuffer(); const chunk = buffer.slice(0, 1024 * 1024); const track = { // The video track from the MP4 file. // The audio track from the MP4 file. }; const decoder = new VideoDecoder({ output: (frame) => { // Called for each decoded video frame. // You can draw the frame to a canvas here. console.log(frame); }, error: (error) => { console.error(error); }, }); const demuxer = { // The demuxer is responsible for parsing the MP4 file and extracting // the video and audio tracks. // You can use a library like @ffmpeg/ffmpeg or write your own demuxer. }; const audioDecoder = new AudioDecoder({ output: (audioData) => { // Called for each decoded audio frame. // You can play the audio data here using the Web Audio API. console.log(audioData); }, error: (error) => { console.error(error); }, }); await decoder.configure({ codec: "avc1.42E01E", // Example codec string for H.264 codedWidth: 1920, codedHeight: 1080, // More configuration options might be needed depending on the video. }); await audioDecoder.configure({ codec: "opus", // Example codec string for Opus audio sampleRate: 48000, numberOfChannels: 2, // More configuration options might be needed depending on the audio. }); // Feed the video and audio data to the decoders. // This would typically involve reading chunks from the buffer and // sending them to the demuxer, which then provides data to the decoders. // For simplicity, we'll just simulate feeding some data. const videoChunk = new EncodedVideoChunk({ type: "key", timestamp: 0, duration: 1000000 / 30, // Assuming 30 FPS data: chunk, }); decoder.decode(videoChunk); const audioChunk = new EncodedAudioChunk({ type: "key", timestamp: 0, duration: 1000000 / 48000, // Assuming 48kHz sample rate data: chunk, }); audioDecoder.decode(audioChunk); }; init(); }, []); return ; }; export default App; ``` -------------------------------- ### Implement CountdownClip using IClip Interface Source: https://context7.com/webav-tech/webav/llms.txt This example demonstrates creating a custom clip that renders a countdown timer. It utilizes OffscreenCanvas for rendering and returns bitmaps for video frames. Ensure the necessary imports are available. ```typescript import { IClip, OffscreenSprite, Combinator } from '@webav/av-cliper'; // Custom clip that renders a countdown timer class CountdownClip implements IClip { readonly ready: Promise<{ width: number; height: number; duration: number }>; readonly meta = { width: 400, height: 400, duration: 10_000_000 }; // 10 s constructor() { this.ready = Promise.resolve(this.meta); } async tick(time: number) { const seconds = Math.max(0, 10 - Math.floor(time / 1e6)); const cvs = new OffscreenCanvas(400, 400); const ctx = cvs.getContext('2d')!; ctx.fillStyle = '#222'; ctx.fillRect(0, 0, 400, 400); ctx.fillStyle = 'white'; ctx.font = 'bold 180px sans-serif'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(String(seconds), 200, 200); const bitmap = await createImageBitmap(cvs); return { video: bitmap, audio: [] as Float32Array[], state: time >= this.meta.duration ? ('done' as const) : ('success' as const), }; } async clone() { return new CountdownClip() as this; } destroy() {} } // Use it in a composition const countdownSpr = new OffscreenSprite(new CountdownClip()); countdownSpr.rect.x = 440; countdownSpr.rect.y = 160; countdownSpr.time = { offset: 0, duration: 10_000_000 }; countdownSpr.zIndex = 5; const bgSpr = new OffscreenSprite( new MP4Clip((await fetch('./video/background.mp4')).body!), ); const com = new Combinator({ width: 1280, height: 720 }); await com.addSprite(bgSpr, { main: true }); await com.addSprite(countdownSpr); const outStream = com.output(); ``` -------------------------------- ### Record Camera Stream to Local File Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/4_1-recorder-usermedia.en-US.md Records the camera's video stream and writes it to a local file in real-time. Ensure a local file is created before starting the recording. ```typescript const recorder = new MediaRecorder(stream, { mimeType: 'video/mp4; codecs="avc1.42E01E,mp4a.40.2"' }); // Create a file to write the stream data to const fileHandle = await getFileHandle('output.mp4'); const writable = await fileHandle.createWritable(); recorder.ondataavailable = async (event) => { if (event.data.size > 0) { await writable.write(event.data); } }; recorder.onstop = async () => { await writable.close(); }; recorder.start(); // To stop recording, call recorder.stop(); ``` -------------------------------- ### Complete Camera Recording with OPFS Duration Fix Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/4_1-recorder-usermedia.en-US.md A full example demonstrating camera recording where video data is temporarily stored in OPFS. The duration field is corrected at the end of the recording, and the local file is created only after the 'Stop' action is triggered. ```typescript const recorder = new MediaRecorder(stream, { mimeType: 'video/mp4; codecs="avc1.42E01E,mp4a.40.2"' }); recorder.ondataavailable = async (event) => { if (event.data.size > 0) { // Data is written to OPFS here by fixFMP4Duration } }; recorder.onstop = async () => { // The file is created and written here after duration is fixed const fileHandle = await getFileHandle('output.mp4'); const writable = await fileHandle.createWritable(); const blob = await fixFMP4Duration(recorder.getStream()); // Assuming getStream() is available or similar await writable.write(blob); await writable.close(); }; recorder.start(); // To stop recording, call recorder.stop(); ``` -------------------------------- ### Record MediaStream to MP4 File Stream with AVRecorder Source: https://github.com/webav-tech/webav/blob/main/README.md Records a MediaStream from the camera and microphone using AVRecorder and starts the recording process, outputting a ReadableStream. ```javascript import { AVRecorder } from '@webav/av-recorder'; const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true, }); const recorder = new AVRecorder(mediaStream); recorder.start(); // => ReadableStream ``` -------------------------------- ### Chroma Key Video Processing Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/3_2-chromakey-video.en-US.md This TypeScript code snippet demonstrates the setup and rendering of a video with a green screen background removed. It requires a video element and a WebGL context to apply the chroma key effect. ```typescript import React, { useEffect, useRef } from "react"; import { WebAV, VideoDecoder } from "@webav/avtools"; const App = () => { const ref = useRef(null); useEffect(() => { const main = async () => { const webav = new WebAV(); await webav.init(); const decoder = new VideoDecoder(); await decoder.init(); const demuxer = webav.demuxer; const url = "./video.mp4"; const resp = await fetch(url); const buffer = await resp.arrayBuffer(); const { streams } = await demuxer.probe(buffer); const videoTrack = streams.find((e) => e.type === "video"); if (!videoTrack) { return; } const { codec, frame_rate } = videoTrack; const { format } = await decoder.configure(codec); const reader = demuxer.createReader(buffer, format); const canvas = document.createElement("canvas"); canvas.width = 1280; canvas.height = 720; ref.current?.appendChild(canvas); const ctx = canvas.getContext("2d") as CanvasRenderingContext2D; const img = new Image(); img.src = "./bg.jpg"; img.onload = () => { ctx.drawImage(img, 0, 0, canvas.width, canvas.height); }; const frameRender = async () => { const { chunk, frame } = await reader.read(); if (frame) { const { width, height } = frame; const texture = webav.makeTexture(frame); const pipeline = webav.pipeline(); const bg = webav.makeTexture(img); pipeline.add(bg).add(texture).chromakey(0x00ff00); const out = pipeline.run(); webav.draw(out, ctx, 0, 0, width, height); frame.close(); } if (chunk) { await decoder.decode(chunk); } requestAnimationFrame(frameRender); }; decoder.ondata = (frame) => { frameRender(); }; await decoder.decode(null); }; main(); }, []); return
; }; export default App; ``` -------------------------------- ### Enter Beta Prerelease Mode Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/contribution.md Command to enter prerelease mode for publishing beta versions. ```bash pnpm changeset pre enter beta ``` -------------------------------- ### Capture MediaStream from AVCanvas Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/4_2-recorder-avcanvas.en-US.md Use AVCanvas.captureStream() to composite all assets and get a MediaStream. This stream can be used for WebRTC. ```typescript const stream = await avCanvas.captureStream(); ``` -------------------------------- ### Overlaying an Image onto Video Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/2_1-concat-video.en-US.md Creates an ImgClip instance to overlay a normal image onto a video. Ensure the image URL is correctly fetched. ```javascript import { ImgClip } from "@webav/webav"; // ... inside an async function const imgClip = new ImgClip((await fetch('')).body); ``` -------------------------------- ### Create and Configure VisibleSprite Source: https://context7.com/webav-tech/webav/llms.txt Instantiate a VisibleSprite with an MP4Clip and configure its properties like position, size, opacity, z-index, flip, time, and interaction. ```typescript import { VisibleSprite, MP4Clip } from '@webav/av-cliper'; const spr = new VisibleSprite( new MP4Clip((await fetch('./video/clip.mp4')).body!), ); await spr.ready; // wait for clip metadata spr.rect.x = 100; // horizontal offset in pixels spr.rect.y = 50; // vertical offset in pixels spr.rect.w = 640; // width spr.rect.h = 360; // height spr.opacity = 0.8; // 80% opaque spr.zIndex = 5; // layer order spr.flip = 'horizontal'; // mirror horizontally spr.time = { offset: 2_000_000, duration: 8_000_000 }; // start at 2 s, last 8 s spr.time.playbackRate = 2; // 2× speed // Disable interaction (e.g., background layer) spr.interactable = 'disabled'; ``` -------------------------------- ### Version and Publish Beta Release Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/contribution.md Commands to update versions based on generated changesets and publish to the npm registry with the 'next' tag. ```bash pnpm changeset version pnpm publish:all:next ``` -------------------------------- ### Run Unit Tests Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/contribution.md Execute unit tests for a specific package. ```bash pnpm test ``` -------------------------------- ### Exit Prerelease Mode Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/contribution.md Command to exit prerelease mode after beta versions have been handled. ```bash pnpm changeset pre exit ``` -------------------------------- ### Decode GIF Frames with ImageDecoder and ImgClip Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/1_3-decode-image.en-US.md This snippet demonstrates decoding GIF frames using both the browser's ImageDecoder API and the ImgClip utility. Use ImgClip.tick(time) to get a frame at a specific time. GIFs loop by default if their duration is Infinity. ```tsx import React, { useEffect, useRef } from "react"; import { ImgClip } from "@tldraw/webav"; const App = () => { const ref = useRef(null); useEffect(() => { const init = async () => { const img = await ImgClip.fromPath( "https://webav.tldraw.com/webav-tech/webav/assets/demo.gif", { loop: true } ); if (ref.current) { ref.current.src = await img.tick(0); } let time = 0; setInterval(async () => { if (ref.current) { ref.current.src = await img.tick(time); } time += 100; }, 100); }; init(); }, []); return ; }; export default App; ``` -------------------------------- ### Record Camera and Microphone to MP4 Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/packages.en-US.md Demonstrates recording media from the camera and microphone into an MP4 file stream using av-recorder. This requires user permission to access media devices and initializes the AVRecorder with the media stream. ```javascript import { AVRecorder } from '@webav/av-recorder'; const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true, }); const recorder = new AVRecorder(recodeMS); recorder.start(); // => ReadableStream ``` -------------------------------- ### Initialize OTExplorer Source: https://github.com/webav-tech/webav/blob/main/packages/av-canvas/demo/video-editor.html Initializes the OTExplorer component. Ensure this is called before other OTExplorer functionalities. ```javascript OTExplorer.init(); ``` -------------------------------- ### Use Images as Video Material with ImgClip Source: https://context7.com/webav-tech/webav/llms.txt Create video clips from static images (PNG, JPG) or animated formats (GIF, WebP, AVIF). Text can also be rendered into an image for use as a clip. ```typescript import { ImgClip, renderTxt2ImgBitmap } from '@webav/av-cliper'; // Static image from URL const logoClip = new ImgClip((await fetch('./logo.png')).body!); await logoClip.ready; // Animated GIF const gifClip = new ImgClip({ type: 'image/gif', stream: (await fetch('./animation.gif')).body!, }); await gifClip.ready; // Text rendered as an image (for watermarks / captions) const textClip = new ImgClip( await renderTxt2ImgBitmap( 'Hello WebAV', 'font-size: 48px; color: white; font-weight: bold; text-shadow: 2px 2px 6px black;', ), ); ``` -------------------------------- ### Initialize and Use AVCanvas for Editing Source: https://context7.com/webav-tech/webav/llms.txt Initializes an AVCanvas for interactive editing, adding sprites, and controlling playback. Use this for creating dynamic video compositions. ```typescript import { AVCanvas } from '@webav/av-canvas'; import { VisibleSprite, MP4Clip, ImgClip, MediaStreamClip, renderTxt2ImgBitmap, } from '@webav/av-cliper'; // Initialize canvas attached to a DOM element const avCvs = new AVCanvas(document.querySelector('#editor')!, { bgColor: '#1a1a1a', width: 1920, height: 1080, }); // Add an MP4 video sprite const videoSpr = new VisibleSprite( new MP4Clip((await fetch('./video/clip.mp4')).body!), ); videoSpr.time = { offset: 0, duration: 30_000_000 }; await avCvs.addSprite(videoSpr); // Add a text overlay const textSpr = new VisibleSprite( new ImgClip( await renderTxt2ImgBitmap('Title Text', 'font-size: 72px; color: #fff;'), ), ); textSpr.time = { offset: 0, duration: 5_000_000 }; await avCvs.addSprite(textSpr); // Subscribe to events avCvs.on('timeupdate', (t) => console.log(`Playhead: ${(t / 1e6).toFixed(2)}s`)); avCvs.on('activeSpriteChange', (spr) => console.log('Selected:', spr)); // Play back the timeline avCvs.play({ start: 0 }); // Seek to preview a specific frame await avCvs.previewFrame(5_000_000); // preview at 5 s // Capture a screenshot (base64 PNG) const screenshot = avCvs.captureImage(); // Remove a sprite avCvs.removeSprite(textSpr); // Export to MP4 via Combinator const com = await avCvs.createCombinator({ bitrate: 8_000_000 }); const outStream = com.output(); // Tear down when done avCvs.destroy(); ``` -------------------------------- ### Generate Changeset for Contributions Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/contribution.md Command to initiate the creation of a changeset file after making code commits. This is used for version management. ```bash pnpm changeset add ``` -------------------------------- ### Wrap Live MediaStreams with MediaStreamClip Source: https://context7.com/webav-tech/webav/llms.txt Integrate live media streams from cameras, microphones, or screen shares into the WebAV pipeline. Note: Not compatible with Combinator due to real-time constraints. ```typescript import { MediaStreamClip, VisibleSprite } from '@webav/av-cliper'; import { AVCanvas } from '@webav/av-canvas'; const avCvs = new AVCanvas(document.querySelector('#canvas-container')!, { bgColor: '#000', width: 1920, height: 1080, }); // Add camera feed const cameraStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true, }); const cameraSpr = new VisibleSprite(new MediaStreamClip(cameraStream)); await avCvs.addSprite(cameraSpr); // Add screen share on top const screenStream = await navigator.mediaDevices.getDisplayMedia({ video: true }); const screenSpr = new VisibleSprite(new MediaStreamClip(screenStream)); screenSpr.zIndex = 1; await avCvs.addSprite(screenSpr); ``` -------------------------------- ### Add Moving Watermark to Video with av-cliper Source: https://github.com/webav-tech/webav/blob/main/README.md Demonstrates adding a moving, semi-transparent text watermark to a video using `av-cliper`. Requires importing necessary classes and fetching video/image resources. The watermark can be animated with position, opacity, and duration. ```javascript import { ImgClip, MP4Clip, OffscreenSprite, renderTxt2ImgBitmap, Combinator, } from '@webav/av-cliper'; const spr1 = new OffscreenSprite( new MP4Clip((await fetch('./video/bunny.mp4')).body), ); const spr2 = new OffscreenSprite( new ImgClip( await renderTxt2ImgBitmap( 'Watermark', `font-size:40px; color: white; text-shadow: 2px 2px 6px red;`, ), ), ); spr2.time = { offset: 0, duration: 5e6 }; spr2.setAnimation( { '0%': { x: 0, y: 0 }, '25%': { x: 1200, y: 680 }, '50%': { x: 1200, y: 0 }, '75%': { x: 0, y: 680 }, '100%': { x: 0, y: 0 }, }, { duration: 4e6, iterCount: 1 }, ); spr2.zIndex = 10; spr2.opacity = 0.5; const com = new Combinator({ width: 1280, height: 720, }); await com.addSprite(spr1); await com.addSprite(spr2); com.output(); // => ReadableStream ``` -------------------------------- ### Add Video and Text to Canvas with AVCanvas Source: https://github.com/webav-tech/webav/blob/main/README.md Initializes an AVCanvas, adds a video clip and a text-based image clip to it. Use `createCombinator().output()` to export edited materials or `captureStream()` for live streaming. ```javascript import { ImgClip, MP4Clip, VisibleSprite, renderTxt2ImgBitmap, } from '@webav/av-cliper'; import { AVCanvas } from '@webav/av-canvas'; const avCvs = new AVCanvas(document.querySelector('#app'), { width: 1280, height: 720, }); const spr1 = new VisibleSprite( new MP4Clip((await fetch('./video/bunny.mp4')).body), ); const spr2 = new VisibleSprite( new ImgClip( await renderTxt2ImgBitmap( 'Watermark', `font-size:40px; color: white; text-shadow: 2px 2px 6px red;`, ), ), ); await avCvs.add(spr1); await avCvs.add(spr2); // Export user-edited materials into a video // (await avCvs.createCombinator()).output() // Capture stream from the canvas (MediaStream) for live streaming or video recording // avCvs.captureStream() ``` -------------------------------- ### AudioClip Source: https://context7.com/webav-tech/webav/llms.txt Wraps an MP3/WAV/OGG audio stream and decodes it to PCM. Supports looping and volume control. ```APIDOC ## `AudioClip` — Load and loop an audio file Wraps an MP3/WAV/OGG audio stream and decodes it to PCM. Supports looping and volume control. ```ts import { AudioClip } from '@webav/av-cliper'; // Load a background music file with looping const bgm = new AudioClip( (await fetch('./audio/background.mp3')).body!, { loop: true, volume: 0.3 }, ); await bgm.ready; // Split at 10 s const [intro, rest] = await bgm.split(10_000_000); // Concatenate two clips const combined = await AudioClip.concatAudioClip([intro, rest]); ``` ``` -------------------------------- ### Check Browser Compatibility with Combinator.isSupported Source: https://context7.com/webav-tech/webav/llms.txt Verify if the current browser environment supports WebCodecs for video synthesis. This check is crucial before initializing video processing operations. Requires Chrome 102+. ```typescript import { Combinator } from '@webav/av-cliper'; const supported = await Combinator.isSupported({ videoCodec: 'avc1.42E032', // H.264 baseline profile width: 1920, height: 1080, bitrate: 7e6, }); if (!supported) { console.error('WebCodecs not supported in this browser. Requires Chrome 102+'); } ``` -------------------------------- ### Load and Manipulate Audio with AudioClip Source: https://context7.com/webav-tech/webav/llms.txt Load audio files (MP3/WAV/OGG) for playback, looping, and volume control. Supports splitting and concatenating audio clips. ```typescript import { AudioClip } from '@webav/av-cliper'; // Load a background music file with looping const bgm = new AudioClip( (await fetch('./audio/background.mp3')).body!, { loop: true, volume: 0.3 }, ); await bgm.ready; // Split at 10 s const [intro, rest] = await bgm.split(10_000_000); // Concatenate two clips const combined = await AudioClip.concatAudioClip([intro, rest]); ``` -------------------------------- ### Add Moving Translucent Watermark to Video Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/guide/packages.en-US.md Demonstrates how to add a moving, translucent text watermark to a video using av-cliper. Requires MP4Clip and ImgClip for video and text respectively, with OffscreenSprite for positioning and animation. The Combinator merges these elements into a final video stream. ```javascript import { ImgClip, MP4Clip, OffscreenSprite, renderTxt2ImgBitmap, Combinator, } from '@webav/av-cliper'; const spr1 = new OffscreenSprite( new MP4Clip((await fetch('./video/bunny.mp4')).body), ); const spr2 = new OffscreenSprite( new ImgClip( await renderTxt2ImgBitmap( '水印', `font-size:40px; color: white; text-shadow: 2px 2px 6px red;`, ), ), ); spr2.time = { offset: 0, duration: 5e6 }; spr2.setAnimation( { '0%': { x: 0, y: 0 }, '25%': { x: 1200, y: 680 }, '50%': { x: 1200, y: 0 }, '75%': { x: 0, y: 680 }, '100%': { x: 0, y: 0 }, }, { duration: 4e6, iterCount: 1 }, ); spr2.zIndex = 10; spr2.opacity = 0.5; const com = new Combinator({ width: 1280, height: 720, }); await com.addSprite(spr1); await com.addSprite(spr2); com.output(); // => ReadableStream ``` -------------------------------- ### Decode Video Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/1_1-decode-video.en-US.md This snippet shows the basic usage of the video decoder. Ensure network connectivity for loading test video resources. ```tsx import React from 'react'; import { VideoDecoder } from '@webav/webav-react'; export default function App() { return ( ); } ``` -------------------------------- ### Generate Video from GIF with Audio Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/2_2-video-add-audio.en-US.md This snippet shows how to dub audio onto a GIF to create a video file. Note that AudioClip internally uses AudioContext and will not work in WebWorkers. ```typescript import { create } from '@video-craft/webav'; const webav = create(); async function main() { const gif = await webav.gif.fromFile('./input.gif'); const audio = await webav.audio.fromFile('./input.mp3'); const output = await webav.video.fromGif(gif, audio); await output.save('./output.mp4'); } main(); ``` -------------------------------- ### Combinator.isSupported Source: https://context7.com/webav-tech/webav/llms.txt Checks if the current browser environment supports WebCodecs-based video synthesis with a specified configuration. This is crucial for ensuring compatibility before attempting video processing. ```APIDOC ## Combinator.isSupported ### Description Checks whether the current browser environment supports WebCodecs-based video synthesis with the specified configuration. ### Method `static async isSupported(config: { videoCodec: string; width: number; height: number; bitrate: number }): Promise` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```ts import { Combinator } from '@webav/av-cliper'; const supported = await Combinator.isSupported({ videoCodec: 'avc1.42E032', // H.264 baseline profile width: 1920, height: 1080, bitrate: 7e6, }); if (!supported) { console.error('WebCodecs not supported in this browser. Requires Chrome 102+'); } ``` ### Response #### Success Response (boolean) - `true` if supported, `false` otherwise. #### Response Example `true` ``` -------------------------------- ### Video Editor Implementation Source: https://github.com/webav-tech/webav/blob/main/doc-site/docs/demo/6_4-video-editor.en-US.md This code implements a video editor with features like adding/removing assets, splitting, controlling spatial and temporal properties, and live preview playback. It operates in a pure browser environment. ```typescript import React, { useEffect, useRef, useState } from "react"; import { Canvas, Asset, Scene, Clip, Time } from "@webav/av-canvas"; import "./styles.css"; const App = () => { const canvasRef = useRef(null); const [canvas, setCanvas] = useState(null); const [scene, setScene] = useState(null); const [clips, setClips] = useState([]); useEffect(() => { if (canvasRef.current) { const cv = new Canvas(canvasRef.current); setCanvas(cv); const sc = new Scene(); setScene(sc); cv.scene = sc; } }, []); const addVideoClip = async (url: string) => { if (!canvas || !scene) return; const asset = await Asset.fromURL(url); const clip = new Clip(asset); clip.name = `Video Clip ${clips.length + 1}`; clip.duration = Time.fromMs(asset.duration * 1000); clip.offset = Time.fromMs(clips.length * 1000); clip.x = 100 + clips.length * 50; clip.y = 100 + clips.length * 50; clip.width = 320; clip.height = 180; scene.addClip(clip); setClips([...clips, clip]); }; const addImageClip = async (url: string) => { if (!canvas || !scene) return; const asset = await Asset.fromURL(url); const clip = new Clip(asset); clip.name = `Image Clip ${clips.length + 1}`; clip.duration = Time.fromMs(5000); clip.offset = Time.fromMs(clips.length * 1000); clip.x = 100 + clips.length * 50; clip.y = 100 + clips.length * 50; clip.width = 200; clip.height = 200; scene.addClip(clip); setClips([...clips, clip]); }; const addTextClip = (text: string) => { if (!canvas || !scene) return; const clip = Clip.fromText(text); clip.name = `Text Clip ${clips.length + 1}`; clip.duration = Time.fromMs(5000); clip.offset = Time.fromMs(clips.length * 1000); clip.x = 100 + clips.length * 50; clip.y = 100 + clips.length * 50; clip.width = 300; clip.height = 50; scene.addClip(clip); setClips([...clips, clip]); }; const removeClip = (clipToRemove: Clip) => { if (!scene) return; scene.removeClip(clipToRemove); setClips(clips.filter((clip) => clip !== clipToRemove)); }; const splitClip = (clipToSplit: Clip) => { if (!scene) return; const splitTime = clipToSplit.duration.toMs() / 2; const newClip = clipToSplit.split(Time.fromMs(splitTime)); if (newClip) { newClip.name = `${clipToSplit.name} (split)`; newClip.offset = Time.add(clipToSplit.offset, Time.fromMs(splitTime)); scene.addClip(newClip); setClips([...clips, newClip]); } }; const moveClip = (clipToMove: Clip, dx: number, dy: number) => { clipToMove.x += dx; clipToMove.y += dy; canvas?.render(); }; const rotateClip = (clipToRotate: Clip, angle: number) => { clipToRotate.rotation = angle; canvas?.render(); }; const scaleClip = (clipToScale: Clip, scale: number) => { clipToScale.scale = scale; canvas?.render(); }; const changeOffset = (clipToChange: Clip, offsetMs: number) => { clipToChange.offset = Time.fromMs(offsetMs); canvas?.render(); }; const changeDuration = (clipToChange: Clip, durationMs: number) => { clipToChange.duration = Time.fromMs(durationMs); canvas?.render(); }; const play = () => { canvas?.play(); }; const pause = () => { canvas?.pause(); }; const seek = (timeMs: number) => { canvas?.seek(Time.fromMs(timeMs)); }; return (
seek(Number(e.target.value))} placeholder="Seek (ms)" />

Clips

    {clips.map((clip) => (
  • {clip.name} changeOffset(clip, Number(e.target.value))} placeholder="Offset (ms)" /> changeDuration(clip, Number(e.target.value))} placeholder="Duration (ms)" />
  • ))}
); }; export default App; ``` -------------------------------- ### MediaStreamClip Source: https://context7.com/webav-tech/webav/llms.txt Wrap a live MediaStream (camera, microphone, screen-share, or `