# uni.compressVideo(options)

压缩视频

# compressVideo 兼容性

Web 微信小程序 Android iOS HarmonyOS HarmonyOS(Vapor)
x 4.41 4.18 4.25 4.61 5.0

# 参数

名称 类型 必填 默认值 兼容性 描述
options CompressVideoOptions -
名称 类型 必备 默认值 兼容性 描述
src string.VideoURIString -
视频文件路径,可以是临时文件路径也可以是永久文件路径
quality string -
压缩质量
bitrate number -
码率,单位 kbps
fps number -
帧率
resolution number -
相对于原视频的分辨率比例,取值范围(0, 1]
success (callback: CompressVideoSuccess) => void -
接口调用成功的回调函数
fail (callback: CompressVideoFail) => void -
接口调用失败的回调函数
complete (callback: any) => void -
接口调用结束的回调函数(调用成功、失败都会执行)

# CompressVideoSuccess 的属性值

名称 类型 必备 默认值 兼容性 描述
tempFilePath string -
压缩后的临时文件地址
size number -
压缩后的大小,单位 kB
byteSize number -
视频文件的字节大小

# CompressVideoFail 的属性值

名称 类型 必备 默认值 兼容性 描述
errCode number -
错误码
合法值 兼容性 描述
1101001
用户取消
1101002
urls至少包含一张图片地址
1101003
文件不存在
1101004
图片加载失败
1101005
未获取权限
1101006
图片或视频保存失败
1101007
图片裁剪失败
1101008
拍照或录像失败
1101009
图片压缩失败
1101010
其他错误
errSubject string -
统一错误主题(模块)名称
data any -
错误信息中包含的数据
cause Error -
源错误信息,可以包含多个错误,详见SourceError
errMsg string -

# 参见

# 示例

示例为hello uni-app x alpha分支,与最新HBuilderX Alpha版同步。与最新正式版同步的master分支示例另见

该 API 不支持 Web,请运行 hello uni-app x 到 App 平台体验

扫码体验(手机浏览器跳转到App直达页)
<template>
  <!-- #ifdef APP -->
  <scroll-view style="flex:1">
  <!-- #endif -->
    <page-head :title="title"></page-head>
    <view>
      <view class="uni-padding-wrap">
        <video class="video" :src="beforeCompressPath" :controls="true" :poster="beforeCoverImagePath"></video>
        <view class="uni-title">
          <text class="uni-subtitle-text">压缩前视频信息</text>
        </view>
        <text>{{beforeCompressVideoInfo}}</text>
        <video class="video" :src="afterCompressPath" :controls="true" :poster="afterCoverImagePath"></video>
        <view class="uni-title">
          <text class="uni-subtitle-text">压缩后视频信息</text>
        </view>
        <text>{{afterCompressVideoInfo}}</text>
        <view class="uni-btn-v">
          <button type="primary" @click="chooseVideo">从相册中选取待压缩的视频</button>
        </view>
        <view class="uni-btn-v">
          <button type="primary" @click="compressVideo">压缩视频</button>
        </view>
        <enum-data title="压缩质量" :items="qualityItemTypes" @change="onQualityChange"></enum-data>
        <view class="uni-common-mt">
          <text class="uni-title uni-title-text">相对于原视频的分辨率比例,取值范围(0, 1]</text>
          <slider :min="0.1" :max="1" :step="0.1" :show-value="true" @change="onResolutionChange"></slider>
        </view>
      </view>
    </view>
  <!-- #ifdef APP -->
  </scroll-view>
  <!-- #endif -->
</template>

<script setup lang="uts">
  import { ItemType } from '@/components/enum-data/enum-data-types';
  type VideoInfoForTest = {
    width: number;
    height: number;
    isSizeReduce: boolean;
  }

  type TestStateType = {
    videoInfoForTest: VideoInfoForTest | null,
    videoSrcForTestWidth: number,
    videoSrcForTestHeight: number
  }

  const title = ref("compressVideo")
  const beforeCompressVideoInfo = ref("")
  const afterCompressVideoInfo = ref("")
  const beforeCompressPath = ref("")
  const afterCompressPath = ref("")
  const beforeCoverImagePath = ref("")
  const afterCoverImagePath = ref("")
  const qualityItemTypes = ref([{ "value": 0, "name": "low(低)" }, { "value": 1, "name": "medium(中)" }, { "value": 2, "name": "high(高)" }] as ItemType[])
  const qualityItems = ref(["low", "medium", "high"])
  const quality = ref(null as string | null)
  const bitrate = ref(null as number | null)
  const fps = ref(null as number | null)
  const resolution = ref(null as number | null)
  const videoSrcForTest = ref('/static/test-video/10second-demo.mp4')
  // 自动化测试
  const testState = reactive({
    videoInfoForTest: null as VideoInfoForTest | null,
    videoSrcForTestWidth: 0,
    videoSrcForTestHeight: 0
  } as TestStateType)

  const compressVideo = () => {
    if (beforeCompressPath.value == "") {
      uni.showToast({
        title: "请先选择视频",
        icon: "error"
      });
      return;
    }
    uni.showLoading({
      title: "视频压缩中"
    });
    uni.compressVideo({
      src: beforeCompressPath.value,
      quality: quality.value,
      resolution: resolution.value,
      success: (res) => {
        console.log("compressVideo success", JSON.stringify(res));
        afterCompressPath.value = res.tempFilePath;
        uni.showToast({
          title: "压缩成功",
          icon: null
        });
        uni.getVideoInfo({
          src: res.tempFilePath,
          success: (_res) => {
            afterCompressVideoInfo.value = `视频画面方向: ${_res.orientation}\n视频格式: ${_res.type}\n视频长度: ${_res.duration}s\n视频大小: ${_res.size}KB\n视频宽度: ${_res.width}\n视频高度: ${_res.height}\n视频帧率: ${_res.fps}fps\n视频码率: ${_res.bitrate}kbps`;
            // #ifdef APP-ANDROID || APP-IOS
            afterCompressVideoInfo.value = afterCompressVideoInfo.value + `\n视频字节大小: ${_res.byteSize}B\n视频首帧图片路径: ${_res.thumbTempFilePath}`
            if(_res.thumbTempFilePath != null) {
            afterCoverImagePath.value = _res.thumbTempFilePath!
            }
            // #endif
          }
        });
      },
      fail: (err) => {
        uni.showModal({
          title: "压缩视频失败",
          content: JSON.stringify(err),
          showCancel: false
        });
      },
      complete: (_) => {
        uni.hideLoading();
      }
    });
  }

  const chooseVideo = () => {
    uni.chooseVideo({
      sourceType: ["album"],
      compressed: false,
      success: (res) => {
        beforeCompressPath.value = res.tempFilePath;
        uni.getVideoInfo({
          src: res.tempFilePath,
          success: (_res) => {
            beforeCompressVideoInfo.value = `视频画面方向: ${_res.orientation}\n视频格式: ${_res.type}\n视频长度: ${_res.duration}s\n视频大小: ${_res.size}KB\n视频宽度: ${_res.width}\n视频高度: ${_res.height}\n视频帧率: ${_res.fps}fps\n视频码率: ${_res.bitrate}kbps`;
            // #ifdef APP-ANDROID || APP-IOS
            beforeCompressVideoInfo.value = beforeCompressVideoInfo.value + `\n视频字节大小: ${_res.byteSize}B\n视频首帧图片路径: ${_res.thumbTempFilePath}`
            if(_res.thumbTempFilePath != null) {
            beforeCoverImagePath.value = _res.thumbTempFilePath!
            }
            // #endif
          }
        });
      }
    });
  }

  const onQualityChange = (value: number) => {
    quality.value = qualityItems.value[value];
  }

  const onResolutionChange = (event: UniSliderChangeEvent) => {
    resolution.value = event.detail.value;
  }

  const testCompressVideo = () => {
    let beforeCompressSize: number, afterComoressSize: number;
    uni.compressVideo({
      src: videoSrcForTest.value,
      quality: 'medium',
      success: (res) => {
        uni.getVideoInfo({
          src: videoSrcForTest.value,
          success: (_res) => {
            beforeCompressSize = Math.trunc(_res.size);
            testState.videoSrcForTestWidth = _res.width
            testState.videoSrcForTestHeight = _res.height
            uni.getVideoInfo({
              src: res.tempFilePath,
              success: (__res) => {
                afterComoressSize = Math.trunc(__res.size);
                testState.videoInfoForTest = {
                  "width": __res.width,
                  "height": __res.height,
                  "isSizeReduce": afterComoressSize < beforeCompressSize
                } as VideoInfoForTest;
              },
              fail(err) {
                console.log('>>>>>> 压缩失败', err.errMsg)
              }
            });
          }
        });
      },
      fail: (_) => {
        testState.videoInfoForTest = null;
      }
    });
  }

  defineExpose({
    testState,
    testCompressVideo
  })
</script>

<style>
  .video {
    align-self: center;
  }

  .image-container {
    flex-direction: row;
  }
</style>

# 通用类型

# GeneralCallbackResult

名称 类型 必备 默认值 兼容性 描述
errMsg string -
错误信息

# Tips

  • 从HBuilderX4.61版起,CompressVideoSuccess中的size精度统一调整为小数点后3位数