Skip to content

事件 ​

编辑器在原生层运行,通过事件把结果通知给 JS。事件名称和数据在 iOS 与 Android 上完全一致,类型定义见 VideoTrimEventMap。

事件数据触发时机
onShow无编辑器已显示。
onLoadLoadEvent:{ duration }媒体加载完成。
onStartTrimming无用户已确认保存,开始处理。
onStatisticsStatisticsEvent处理过程中 FFmpeg 的进度。
onLogLogEvent:{ level, message, sessionId }处理过程中 FFmpeg 输出的日志行。
onFinishTrimmingFinishTrimmingEvent:{ outputPath, startTime, endTime, duration }输出文件已就绪。
onCancelTrimming无用户中止了正在进行的裁剪。
onCancel无用户未保存就离开了编辑器。
onErrorVideoTrimErrorEvent:{ message, errorCode }加载、处理或保存失败。参阅错误处理。
onHide无编辑器已关闭(无论什么原因)。

所有时间均以毫秒为单位。

新架构 ​

默认导出就是原生模块。每个事件对应一个方法,传入监听函数,返回订阅对象:

tsx
import { useEffect } from 'react';
import VideoTrim from 'react-native-video-trim';

export function useVideoTrimEvents() {
  useEffect(() => {
    const subs = [
      VideoTrim.onLoad(({ duration }) => console.log('loaded', duration)),
      VideoTrim.onStartTrimming(() => console.log('started')),
      VideoTrim.onFinishTrimming(({ outputPath }) => console.log('done', outputPath)),
      VideoTrim.onCancel(() => console.log('cancelled')),
      VideoTrim.onError(({ message, errorCode }) => console.warn(errorCode, message)),
      VideoTrim.onHide(() => console.log('hidden')),
    ];
    return () => subs.forEach((s) => s.remove());
  }, []);
}

只需订阅一次(例如在顶层组件中),并在组件卸载时移除订阅。

从旧版本迁移?

(NativeVideoTrim as Spec).onLoad(...) 这种写法仍然可用。默认导出现在自带类型,不再需要类型断言。

旧架构 ​

在旧架构下,所有事件都通过同一个名为 "VideoTrim" 的原生事件发送。事件体的 name 字段是事件名,其余字段是该事件的数据。VideoTrimEvent 把它定义为联合类型,可以用 switch 收窄类型:

tsx
import { useEffect } from 'react';
import { NativeEventEmitter, NativeModules } from 'react-native';
import type { VideoTrimEvent } from 'react-native-video-trim';

export function useVideoTrimEvents() {
  useEffect(() => {
    const emitter = new NativeEventEmitter(NativeModules.VideoTrim);
    const sub = emitter.addListener('VideoTrim', (event: VideoTrimEvent) => {
      switch (event.name) {
        case 'onFinishTrimming':
          console.log('done', event.outputPath, event.duration);
          break;
        case 'onError':
          console.warn(event.errorCode, event.message);
          break;
      }
    });
    return () => sub.remove();
  }, []);
}

其他少量差异请参阅旧架构。

进度 ​

FFmpeg 编码期间会反复触发 onStatistics。time 是输出已处理到的位置,单位为毫秒;speed 是 FFmpeg 相对于实时速度的处理倍率。onStartTrimming 不包含所选范围,因此最简单的进度界面是显示已处理的时长。如果需要显示百分比,可以把 onLoad 中的 duration 作为输出时长的上限:

ts
let mediaDuration = 0;

VideoTrim.onLoad(({ duration }) => {
  mediaDuration = duration;
});

VideoTrim.onStatistics(({ time, speed }) => {
  const seconds = (time / 1000).toFixed(1);
  const atMost = mediaDuration > 0 ? Math.min(1, time / mediaDuration) : 0;
  console.log(`${seconds}s processed at ${speed.toFixed(1)}x (≥ ${Math.round(atMost * 100)}%)`);
});

只有 FFmpeg 实际编码时才会收到统计信息。普通的流复制裁剪通常非常快,可能只收到很少几次,甚至一次也收不到。

典型事件序列 ​

text
Save (closeWhenFinish: true):  onShow → onLoad → onStartTrimming → onStatistics / onLog … → onFinishTrimming → onHide
Leave without saving:          onShow → onLoad → onCancel → onHide
Stop a running trim:           … → onStartTrimming → onCancelTrimming

基于 MIT 许可证发布。