Security News
Weekly Downloads Now Available in npm Package Search Results
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
TAVMedia 是一个跨平台的音视频编辑框架,支持在移动端、桌面端、浏览器端和服务器端使用。
TAVMedia 目前支持 Chrome 75+, Safari 12+.
在 Web 工程中使用 TAVMedia,您可以直接使用 NPM 将 TAVMedia 安装到您的项目中
npm install tav-media
import { initializeWasm, TAVWasmOptions } from 'tav-media';
const env: TAVWasmOptions = {
/**
* 可选,指定 wasm 文件在服务端的路径。如果不指定,则使用 `./tav-media-wasm.wasm`
*/
locateFile: wasmFileName => `/node_modules/tav-media/bin/wasm/${wasmFileName}`,
/**
* 可选,后续资源的 path 为相对路径时,会自动添加此前缀
*/
baseUrl: '/',
};
initializeWasm(env).then(async () => {
// 调用业务初始化代码
});
在 TAVMedia SDK 中提供了鉴权的对应的 API ,可以参考使用:
/**
* 验证授权信息
*/
async function authorize() {
const authResult = await TAVLicense.Auth(
// License url 或者 license 内容的 ArrayBuffer
'assets/tav_media.license',
// AppId
'your_appid_here',
// License secret
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
);
if (authResult !== OAuthErrorCode.OK) {
// 根据验证结果进行进一步处理
console.warn('授权失败,使用 TAVMedia 水印试用版');
}
}
initializeWasm(env).then(async () => {
// 加载 TAVMedia wasm 后验证 license
await authorize();
});
TAVMedia Web 版封装了 TAVMediaView
类, 封装了 TAVSurface
, TAVVideoReader
, TAVAudioReader
的创建和调用过程,
提供了适合 Web 播放使用的 API。视频图像渲染到指定的 canvas,音频会直接通过浏览器输出,暂时不支持读取每帧的音频合成数据。
// 创建一个 MovieClip 对象
const ghost = await MovieAsset.MakeFromPath('assets/ghost.mp4');
const movie = await MovieClip.MakeFromAsset(ghost);
movie.duration = ghost.duration;
// 创建一个 TAVMediaView,将图像渲染到 id 为 stage 的 canvas
const view = TAVMediaView.MakeFromHtmlCanvas('#stage');
// 播放视频
await view.setMedia(movie);
view.play();
通过将多个媒体添加到 Composition 的方式,可以在场景中同时播放多个视频和特效。例如下面的视频转场的例子。
// 创建主时间轴
const root = new Composition();
root.width = 1280;
root.height = 720;
root.duration = 3_000_000;
// 添加第一个视频
const ghost = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie1 = await MovieClip.MakeFromAsset(ghost);
movie1.duration = ghost.duration;
movie1.startTime = 0;
// 添加第二个视频
const dog = await MovieAsset.MakeFromPath('video-640x360-2.mp4');
const movie2 = await MovieClip.MakeFromAsset(dog);
movie2.duration = dog.duration;
movie2.startTime = 800_000;
// 添加转场
const zcAsset = await PAGAsset.MakeFromPath('zc.pag');
const zc = await PAGEffect.MakeFromAsset(zcAsset);
zc.startTime = 800_000;
zc.duration = zcAsset.duration;
// 将两个视频作为转场效果的输入,在转场播放过程中,将根据设计师
// 指定的方式展示两个视频切换的效果。
zc.addInput(movie1);
zc.addInput(movie2);
// 添加到主时间轴
root.addClip(movie1);
root.addClip(movie2);
root.addClip(zc);
// 播放
await view.setMedia(root);
view.play();
const asset = await MovieAsset.MakeFromPath('video-640x360.mp4');
const clip = await MovieClip.MakeFromAsset(asset);
clip.duration = 3_000_000;
const matrix = new Matrix();
matrix.postTranslate(-asset.width / 2, -asset.height / 2);
matrix.postScale(2, 2);
matrix.postTranslate(asset.width / 2, asset.height / 2);
const cropRect = Rect.MakeXYWH(asset.width / 4, asset.height / 4, asset.width / 2, asset.height / 2);
clip.matrix = matrix;
clip.cropRect = cropRect;
opacity是不透明度,通过设置opacity可以控制Movie的透明度。取值范围是0.0-1.0。0是完全透明,1是完全不透明。
const clip = await MovieClip.MakeFromAsset(asset);
clip.opacity = 0.5;
const ghost = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie1 = await MovieClip.MakeFromAsset(ghost);
movie1.startTime = 1_000_000;
movie1.duration = 4_000_000;
// 创建一个分辨率为 720 * 1280 的Composition
// contentStartTime 为 1_000_000,表示从视频的第1秒开始播放
// contentDuration 为 10_000_000,表示播放 10 秒
const composition = await Composition.Make(720, 1280, 2_000_000, 10_000_000);
composition.duration = 10_000_000;
composition.addClip(movie1);
const ghost = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie1 = await MovieClip.MakeFromAsset(ghost, 1_000_000, 4_000_000);
movie1.startTime = 0;
movie1.duration = 4_000_000;
// 通过 Movie 直接变速
const totalDuration = 10_000_000;
const asset = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie = await MovieClip.MakeFromAsset(asset, 0, totalDuration);
movie.startTime = 0;
movie.duration = totalDuration / 2;
// 通过 Composition 进行变速
const asset1 = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie1 = await MovieClip.MakeFromAsset(asset1, 0, totalDuration);
movie1.startTime = 0;
movie1.duration = totalDuration;
const composition = await Composition.Make(640, 360, 0, totalDuration);
composition.addClip(movie1);
composition.startTime = 0;
composition.duration = totalDuration / 2;
// 通过 Movie 定格
const totalDuration = 10_000_000;
const asset = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie = await MovieClip.MakeFromAsset(asset, 1_000_000, 0);
movie.startTime = 0;
movie.duration = totalDuration;
// 通过 Composition 定格
const asset1 = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie1 = await MovieClip.MakeFromAsset(asset1, 0, totalDuration);
movie1.startTime = 0;
movie1.duration = totalDuration;
const composition = await Composition.Make(640, 360, 1_000_000, 0);
composition.addClip(movie1);
composition.startTime = 0;
composition.duration = totalDuration;
const totalDuration = 10_000_000;
const path = 'hoaprox.mp3';
const asset = await AudioAsset.MakeFromPath(path);
const audio = await AudioClip.MakeFromAsset(asset, 0, totalDuration);
audio.duration = totalDuration;
const effect = await AudioVolumeEffect.MakeFIFOEffect(audio, 1.0, 3_000_000, 3_000_000);
effect.startTime = 0;
effect.duration = totalDuration;
const asset1 = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie1 = await MovieClip.MakeFromAsset(asset1);
movie1.startTime = 0;
movie1.duration = asset1.duration;
const transformEffect = TransformEffect.MakeTransformEffect();
const keyframes: NoBlankArray<Keyframe> = [
TAVKeyframe.MakeLinear(0, 1_000_000, 0, 90),
];
transformEffect.transform2D = {
rotation: TAVProperty.MakeAnimatableProperty(keyframes),
}
transformEffect.addInput(movie1);
const asset1 = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie1 = await MovieClip.MakeFromAsset(asset1);
movie1.startTime = 0;
movie1.duration = asset1.duration;
const colorTuningEffect = ColorTuningEffect.MakeColorTuningEffect();
const keyframes: NoBlankArray<Keyframe> = [
TAVKeyframe.MakeLinear(0, 1_000_000, -50, 50),
];
// 设置饱和度
colorTuningEffect.colorTuning = {
saturation: TAVProperty.MakeAnimatableProperty(keyframes),
}
colorTuningEffect.addInput(movie1);
const asset1 = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie1 = await MovieClip.MakeFromAsset(asset1);
movie1.startTime = 0;
movie1.duration = asset1.duration;
const lutEffect = await LUTEffect.MakeFromPath('lut.png');
lutEffect.startTime = 0;
lutEffect.duration = 1_000_000;
lutEffect.strength = 0.5;
lutEffect.addInput(movie1);
const asset1 = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie1 = await MovieClip.MakeFromAsset(asset1);
movie1.startTime = 0;
movie1.duration = asset1.duration;
const chromaMattingEffect = ChromaMattingEffect.Make();
chromaMattingEffect.chromaMattingConfig = {
intensity: 0.2,
shadow: 0.5,
selectedColor: {
red: 0,
green: 255,
blue: 0,
alpha: 255,
},
}
chromaMattingEffect.startTime = 0;
chromaMattingEffect.duration = 1_000_000;
chromaMattingEffect.addInput(movie1);
const asset1 = await MovieAsset.MakeFromPath('video-640x360.mp4');
const movie1 = await MovieClip.MakeFromAsset(asset1);
movie1.startTime = 0;
movie1.duration = asset1.duration;
const pagAsset = await PAGAsset.MakeFromPath('fw.pag');
const pagEffect = await PAGEffect.MakeFromAsset(pagAsset);
// numImgs 表示该 PAG File 最大支持的替换图层数量
const numImgs = pagEffect.numImages;
// 添加 movie1 作为 effect 的输入,
// scaleMode 可以设置如何缩放 movie1 以适应 PAG 图层的大小
// editableIndex 表示 PAG File 中的第几个可替换图层
pagEffect.addInput(movie1, ScaleMode.LetterBox, 0);
pagEffect.startTime = 0;
// 这边可以根据需求设置成任意时长,例子中设置成文件时长
pagEffect.duration = pagAsset.duration;
const movieDuration = 3_000_000;
const asset1 = await MovieAsset.MakeFromPath('1.mp4');
const movie1 = await MovieClip.MakeFromAsset(asset1);
movie1.duration = movieDuration;
const asset2 = await MovieAsset.MakeFromPath('2.mp4');
const movie2 = await MovieClip.MakeFromAsset(asset2);
movie2.duration = movieDuration;
const pagAsset = await PAGAsset.MakeFromPath('zc.pag');
const pagEffect = await PAGEffect.MakeFromAsset(pagAsset);
const numImgs = pagEffect.numImages;
// 分别设置 movie1 和 movie2 替换 PAG file 中的第一个替换图层和第二个替换图层
// 替换哪两个替换图层需要根据 PAG 文件来决定,通常情况下 input0 对应 editableIndex0,input1 对应 editableIndex1
// 也可以通过 `addInput` 的 `editableIndex` 参数来指定
pagEffect.addInput(movie1);
pagEffect.addInput(movie2);
// 这边可以根据需求设置成任意时长,例子中设置成文件时长
pagEffect.duration = pagAsset.duration;
// 设置转场和 movie2 的开始时间为 movie1 的时长减去 PAG File 的时长,
// 这样 PAG Effect 能够将效果作用到 movie1 和 movie2 之间
movie2.startTime = movie1.duration - pagEffect.duration;
pagEffect.startTime = movie2.startTime;
FAQs
Cross platform media editing framework
The npm package tav-media receives a total of 1 weekly downloads. As such, tav-media popularity was classified as not popular.
We found that tav-media demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
Security News
A Stanford study reveals 9.5% of engineers contribute almost nothing, costing tech $90B annually, with remote work fueling the rise of "ghost engineers."
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.