HarmonyOS鸿蒙NEXT视频截取gif图代码案例

HarmonyOS鸿蒙NEXT视频截取gif图代码案例 HarmonyOS Next应用开发案例(持续更新中……)

本案例完整代码,请访问:代码仓库

本案例已上架HarmonyOS NEXT开源组件市场,如需获取或移植该案例,可安装此插件。开发者可使用插件获取鸿蒙组件,添加到业务代码中直接编译运行。

介绍

本示例介绍了如何截取视频的一段内容制作gif图片。该场景多出现在长视频类应用。使用FFmpeg命令对视频进行截取gif图。

效果图预览

GIF 示例

使用说明:

  • 点击“本地视频截取gif”或“在线视频截取gif”的视频,进入视频播放页面。
  • 在视频播放页面中点击“gif”按钮,进入视频截取gif图页面。
  • 可以拖动底部时间轴的选中框来选取需要截取的gif的片段,然后点击“下一步”按钮,进入gif图生成页面。
  • 在gif图生成页面稍等片刻会生成gif图片,可以将gif图保存至相册。

实现步骤

  1. 打开视频播放页面,根据视频是本地视频还是线上视频选择设置avPlayer的url。如果是线上视频,使用边缓存边播放的方式,需要记录缓存文件的本地路径。
if (this.url.startsWith(getContext().filesDir)) {
  this.srcFilePath = this.url;
  let file = await fs.open(this.url);
  this.avPlayer.url = `fd://${file.fd}`;
} else {
  let that = this;

  class MyCacheListener implements CacheListener {
    onCacheAvailable(cacheFilePath: string, url: string, percentsAvailable: number): void {
      AppStorage.setOrCreate('currentCachePercent', percentsAvailable);
      if (!that.srcFilePath) {
        // 记录缓存文件的本地路径
        that.srcFilePath = cacheFilePath;
      }
    }
  }

  GlobalProxyServer?.getInstance()?.getServer()?.registerCacheListener(new MyCacheListener(), this.url);

  let proxyUrl: string | undefined =
    await GlobalProxyServer?.getInstance()?.getServer()?.getProxyUrl(this.url);
  if (proxyUrl.startsWith(getContext().cacheDir)) {
    this.srcFilePath = proxyUrl;
    const file = fs.openSync(this.srcFilePath, fs.OpenMode.READ_ONLY);
    proxyUrl = `fd://${file.fd}`;
  }
  this.avPlayer.url = proxyUrl;
}
  1. 根据视频播放页面上"gif"按钮的时间点,按一定规则确定截取的时间范围,进入选取生成gif时间片段页面,通过MP4Parser获取每秒的视频帧图片,展示在时间轴上。
MP4Parser.getFrameAtTimeRang(startTimeUs, endTimeUs, MP4Parser.OPTION_CLOSEST, frameCallBack);
  1. 时间轴选择框框取范围处理,具体处理可以查看RangeSeekBarView.ets文件,
let touchXNew: number = this.clearUndefined(event?.offsetX);
let deltaX: number = touchXNew - this.touchXOld;
if (this.touchType == TouchType.TouchLeftThumb) {
  this.leftThumbUpdate(deltaX);
  this.onRangeValueChanged();
} else if (this.touchType == TouchType.TouchRightThumb) {
  this.rightThumbUpdate(deltaX);
  this.onRangeValueChanged();
} else if (this.touchType == TouchType.TouchMiddleThumb) {
  if ((deltaX < 0 && this.leftThumbRect[0] > 0)
        || (deltaX > 0 && this.rightThumbRect[2] < this.componentMaxWidth)) {
    this.leftThumbUpdate(deltaX);
    this.rightThumbUpdate(deltaX);
    this.onRangeValueChanged();
  }
}

this.touchXOld = this.clearUndefined(event?.offsetX);  
  1. 点击"下一步"按钮,会出现gif生成页面,根据起始时间和截取长度通过MP4Parser的ffmpegCmd方法生成gif图片。
MP4Parser.ffmpegCmd("ffmpeg -i " + srcFilePath + " -ss " + startTime + " -t " + duration + " " + dst, callBack);

高性能知识点

不涉及

工程结构 & 模块类型

videocreategif                                     // har
|--components
|   |--CustomLoadingDialog.ets                    // 自定义等待弹窗
|   |--GifCreateView.ets                          // gif生成页面
|   |--RangeSeekBarView.ets                       // 时间轴选中框
|   |--SelectGifTimeFrameView.ets                 // 选取生成gif时间片段页面
|   |--VideoThumbListView.ets                     // 时间轴小图展示
|--model
|   |--BannerInfo.ets                             // banner信息
|   |--GlobalProxyServer.ets                      // 边缓存边播放服务器管理
|   |--VideoInfo.ets                              // 视频信息
|--util
|   |--Logger.ets                                 // 日志打印工具  
|   |--TimeTools.ets                              // 时长数据转换工具
|--view
|   |--VideoCreateGif.ets                         // 视频项展示页面
|   |--VideoPlayPage.ets                          // 视频播放页面

模块依赖

依赖动态路由模块来实现页面的动态加载。

依赖mp4parser来使用FFmpeg命令。

依赖OhosVideoCache来实现边缓存边播放。

参考资料


更多关于HarmonyOS鸿蒙NEXT视频截取gif图代码案例的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

你好,你发的git代码有问题,SelectGifTimeFrameView.ets的381行有问题,而且显示的gif截取长度最多20帧

更多关于HarmonyOS鸿蒙NEXT视频截取gif图代码案例的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS NEXT中,视频截取GIF图的功能可以通过ImageMedia模块实现。以下是一个简单的代码示例,展示如何从视频中截取GIF图:

import image from '@ohos.multimedia.image';
import media from '@ohos.multimedia.media';

// 初始化视频源
let videoSource = media.createVideoSource('path/to/video.mp4');

// 获取视频帧
let frame = videoSource.getFrameAtTime(1000, media.TimeUnit.MICROSECONDS);

// 将帧转换为图像
let imageSource = image.createImageSource(frame);

// 配置GIF编码参数
let gifEncoder = image.createGifEncoder();
gifEncoder.setSize(frame.width, frame.height);
gifEncoder.setRepeat(0); // 0表示无限循环

// 编码并保存GIF
let outputStream = image.createOutputStream('path/to/output.gif');
gifEncoder.encode(imageSource, outputStream);

这段代码首先从视频中提取指定时间的帧,然后使用Image模块将帧编码为GIF并保存。

在HarmonyOS鸿蒙NEXT中,可以使用ImageMedia模块来实现视频截取GIF图的功能。以下是一个简单的代码示例:

import ohos.media.image.ImagePacker;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;
import ohos.media.mediaplayer.MediaPlayer;
import ohos.media.mediaplayer.MediaPlayer.PlayerState;
import ohos.media.mediaplayer.MediaPlayer.PlayerCallback;

public class VideoToGif {
    private MediaPlayer mediaPlayer;
    private ImagePacker imagePacker;

    public void convertVideoToGif(String videoPath, String gifPath) {
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setSource(videoPath);
        mediaPlayer.prepare();
        mediaPlayer.setLooping(false);

        imagePacker = ImagePacker.create();
        imagePacker.setOutputFile(gifPath);

        mediaPlayer.setPlayerCallback(new PlayerCallback() {
            @Override
            public void onFrameAvailable(MediaPlayer player, PixelMap pixelMap) {
                if (pixelMap != null) {
                    imagePacker.addImage(pixelMap);
                }
            }

            @Override
            public void onPlaybackComplete(MediaPlayer player) {
                imagePacker.finish();
                mediaPlayer.release();
            }
        });

        mediaPlayer.start();
    }
}

该代码通过MediaPlayer播放视频,并在每一帧可用时将其添加到ImagePacker中,最终生成GIF文件。

回到顶部