《视频截取转换为GIF动图》四、@ohos_mp4parser指南

📅 2026/7/21 10:22:00
《视频截取转换为GIF动图》四、@ohos_mp4parser指南
HarmonyOS ohos/mp4parser 使用指南效果一、概述ohos/mp4parser是 HarmonyOS 生态中的 MP4 视频解析库基于 FFmpeg 封装提供了视频帧提取、视频裁剪、视频转 GIF 等能力。它通过简洁的 API 接口让开发者无需了解底层 FFmpeg 细节即可完成复杂的视频处理任务。核心能力能力说明数据源设置设置待处理的视频文件路径帧提取按时间范围提取视频帧为 PixelMapFFmpeg 命令执行自定义 FFmpeg 命令如视频转 GIF停止操作终止正在进行的异步帧提取任务二、安装与配置2.1 安装依赖在项目的oh-package.json5中添加依赖{ dependencies: { ohos/mp4parser: ^2.0.2 } }或通过 DevEco Studio 的File → Project Structure → ohpm面板搜索安装。2.2 导入模块import{MP4Parser,ICallBack,IFrameCallBack}fromohos/mp4parser;三、API 详解3.1 MP4Parser 类方法setDataSource —— 设置视频数据源staticsetDataSource(src:string,callBack:ICallBack):void;参数说明src视频文件路径支持沙箱路径callBack回调接口返回操作结果码使用示例letcallBack:ICallBack{callBackResult:(code:number){if(code0){console.info(数据源设置成功);}else{console.error(数据源设置失败错误码:${code});}}};MP4Parser.setDataSource(/data/storage/el2/base/files/video.mp4,callBack);getFrameAtTimeRang —— 按时间范围提取视频帧staticgetFrameAtTimeRang(startTimeUs:string,endTimeUs:string,option:number,callBack:IFrameCallBack):void;参数说明startTimeUs起始时间微秒字符串类型endTimeUs结束时间微秒字符串类型option帧提取选项MP4Parser.OPTION_PREVIOUS_SYNC提取指定时间之前的最近同步帧MP4Parser.OPTION_NEXT_SYNC提取指定时间之后的最近同步帧MP4Parser.OPTION_CLOSEST_SYNC提取指定时间附近的最近同步帧MP4Parser.OPTION_CLOSEST提取最接近指定时间的帧callBack帧数据回调使用示例letframeCallBack:IFrameCallBack{callBackResult:(data:ArrayBuffer,timeUs:number){// data: 帧图像数据JPEG 格式的 ArrayBuffer// timeUs: 帧的时间戳微秒console.info(获取到帧时间:${timeUs}us);// 将 ArrayBuffer 转换为 PixelMapletimageSourceimage.createImageSource(data);imageSource.createPixelMap().then((pixelMap:image.PixelMap){// 使用 pixelMap 展示帧图像});}};// 提取 0~10 秒的视频帧MP4Parser.getFrameAtTimeRang(0,10000000,MP4Parser.OPTION_CLOSEST,frameCallBack);ffmpegCmd —— 执行 FFmpeg 命令staticffmpegCmd(cmd:string,callBack:ICallBack):void;参数说明cmdFFmpeg 命令字符串callBack命令执行结果回调使用示例// 视频转 GIFletcmdffmpeg -i /path/to/video.mp4 -ss 00:00:05 -t 10 /path/to/output.gif;letcallBack:ICallBack{callBackResult:(code:number){if(code0){console.info(GIF 生成成功);}else{console.error(GIF 生成失败);}}};MP4Parser.ffmpegCmd(cmd,callBack);stopGetFrame —— 停止帧提取staticstopGetFrame():void;在页面销毁或取消操作时调用终止正在进行的帧提取任务。3.2 回调接口ICallBackinterfaceICallBack{callBackResult:(code:number)void;}code 0操作成功code ! 0操作失败IFrameCallBackinterfaceIFrameCallBack{callBackResult:(data:ArrayBuffer,timeUs:number)void;}data帧图像的二进制数据JPEG 格式timeUs帧在视频中的时间戳微秒四、使用场景4.1 场景一视频缩略图列表为视频时间轴生成每秒一帧的缩略图列表import{image}fromkit.ImageKit;import{MP4Parser,ICallBack,IFrameCallBack}fromohos/mp4parser;ObservedclassVideoThumbnail{pixelMap:image.PixelMap|undefinedundefined;timeMs:number0;}// 生成缩略图functiongenerateThumbnails(videoPath:string,startMs:number,endMs:number,onFrameReady:(thumbnail:VideoThumbnail,index:number)void,onComplete:()void):void{// 1. 设置数据源letsetCallback:ICallBack{callBackResult:(code:number){if(code!0)return;// 2. 提取帧letcount0;consttotalFramesMath.ceil((endMs-startMs)/1000);letframeCallback:IFrameCallBack{callBackResult:async(data:ArrayBuffer,timeUs:number){constimageSourceimage.createImageSource(data);constpixelMapawaitimageSource.createPixelMap({sampleSize:1,editable:true,desiredPixelFormat:image.PixelMapFormat.RGBA_8888});constthumbnailnewVideoThumbnail();thumbnail.pixelMappixelMap;thumbnail.timeMstimeUs/1000;onFrameReady(thumbnail,count);count;if(counttotalFrames){onComplete();}imageSource.release();}};conststartUs(startMs*1000).toString();constendUs(endMs*1000).toString();MP4Parser.getFrameAtTimeRang(startUs,endUs,MP4Parser.OPTION_CLOSEST,frameCallback);}};MP4Parser.setDataSource(videoPath,setCallback);}4.2 场景二视频截取并转 GIF将视频的指定时间段转换为 GIF 动图import{fileUri}fromkit.CoreFileKit;import{MP4Parser,ICallBack}fromohos/mp4parser;functioncreateGifFromVideo(videoPath:string,startTimeMs:number,endTimeMs:number,outputPath:string,onSuccess:(gifUri:string)void,onError:(message:string)void):void{// 构建时间字符串conststartSecMath.floor(startTimeMs/1000);constdurationSecMath.floor((endTimeMs-startTimeMs)/1000);conststartTimeStrformatTimeString(startTimeMs);// 构建 FFmpeg 命令constcmdffmpeg -i${videoPath}-ss${startTimeStr}-t${durationSec}${outputPath};letcallback:ICallBack{callBackResult:(code:number){if(code0){constgifUrifileUri.getUriFromPath(outputPath);onSuccess(gifUri);}else{onError(GIF 生成失败错误码: code);}}};MP4Parser.ffmpegCmd(cmd,callback);}// 时间格式化工具functionformatTimeString(timeMs:number):string{consttotalSecMath.floor(timeMs/1000);consthMath.floor(totalSec/3600);constmMath.floor((totalSec%3600)/60);conststotalSec%60;return${pad(h)}:${pad(m)}:${pad(s)};}functionpad(n:number):string{returnn10?0n:n.toString();}4.3 场景三提取单帧截图从视频中提取某一时刻的帧作为截图functioncaptureFrame(videoPath:string,timeMs:number,onFrameReady:(pixelMap:image.PixelMap)void):void{letsetCallback:ICallBack{callBackResult:(code:number){if(code!0)return;letframeCallback:IFrameCallBack{callBackResult:async(data:ArrayBuffer,timeUs:number){constimageSourceimage.createImageSource(data);constpixelMapawaitimageSource.createPixelMap();onFrameReady(pixelMap);imageSource.release();MP4Parser.stopGetFrame();}};consttimeUs(timeMs*1000).toString();MP4Parser.getFrameAtTimeRang(timeUs,timeUs,MP4Parser.OPTION_CLOSEST,frameCallback);}};MP4Parser.setDataSource(videoPath,setCallback);}五、完整示例 —— 视频帧预览与 GIF 生成import{media}fromkit.MediaKit;import{image}fromkit.ImageKit;import{fileUri}fromkit.CoreFileKit;importfsUtilsfromohos.file.fs;import{MP4Parser,ICallBack,IFrameCallBack}fromohos/mp4parser;EntryComponentstruct MP4ParserDemo{Statethumbnails:image.PixelMap[][];StategifPath:string;StateisProcessing:booleanfalse;StatestatusText:string就绪;privatevideoPath:string;build(){Column({space:16}){Text(this.statusText).fontSize(16).fontWeight(FontWeight.Medium);// 帧缩略图列表List(){ForEach(this.thumbnails,(px:image.PixelMap,index:number){ListItem(){Image(px).width(80).height(45).objectFit(ImageFit.Cover).borderRadius(4);Text(${index}s).fontSize(10).fontColor(Color.Gray);}})}.listDirection(Axis.Horizontal).height(80).width(100%);// 操作按钮Row({space:16}){Button(提取帧).onClick(()this.extractFrames());Button(生成 GIF).onClick(()this.createGif());}// GIF 预览if(this.gifPath.length0){Image(this.gifPath).width(80%).height(200).borderRadius(8);}}.padding(16).width(100%).height(100%);}privateextractFrames():void{this.isProcessingtrue;this.statusText正在提取帧...;this.thumbnails[];letsetCallback:ICallBack{callBackResult:(code:number){if(code!0){this.statusText设置数据源失败;this.isProcessingfalse;return;}letframeCallback:IFrameCallBack{callBackResult:async(data:ArrayBuffer,timeUs:number){constimageSourceimage.createImageSource(data);constpixelMapawaitimageSource.createPixelMap({sampleSize:1,desiredPixelFormat:image.PixelMapFormat.RGBA_8888});this.thumbnails.push(pixelMap);imageSource.release();this.statusText已提取${this.thumbnails.length}帧;}};MP4Parser.getFrameAtTimeRang(0,10000000,MP4Parser.OPTION_CLOSEST,frameCallback);}};MP4Parser.setDataSource(this.videoPath,setCallback);}privatecreateGif():void{this.isProcessingtrue;this.statusText正在生成 GIF...;constoutputPathgetContext().cacheDir/output_Date.now().gif;constcmdffmpeg -i${this.videoPath}-ss 00:00:00 -t 5${outputPath};letcallback:ICallBack{callBackResult:(code:number){this.isProcessingfalse;if(code0){this.gifPathfileUri.getUriFromPath(outputPath);this.statusTextGIF 生成成功;}else{this.statusTextGIF 生成失败;}}};MP4Parser.ffmpegCmd(cmd,callback);}}六、注意事项6.1 线程安全setDataSource和getFrameAtTimeRang是异步操作通过回调返回结果帧提取在子线程执行UI 更新需通过状态变量触发页面退出时务必调用stopGetFrame()停止提取6.2 内存管理帧数据ArrayBuffer会占用较大内存及时释放不需要的ImageSource大量缩略图场景建议限制帧数量或使用sampleSize降低分辨率6.3 FFmpeg 命令ffmpegCmd支持的命令有限仅支持基本的视频处理和格式转换命令参数路径必须使用绝对路径生成 GIF 时可添加参数优化-vf fps10,scale320:-16.4 错误处理所有回调的code值含义Code说明0操作成功-1通用错误-2参数错误-3数据源错误-4FFmpeg 执行错误七、常见问题Q1setDataSource回调 code 不为 0检查文件路径是否正确文件是否存在且可读。Q2提取的帧顺序错乱帧提取是异步回调帧返回顺序可能与时间顺序不一致。建议根据timeUs参数排序。Q3GIF 文件过大在 FFmpeg 命令中添加缩放和帧率参数constcmdffmpeg -i${videoPath}-ss 00:00:05 -t 5 -vf fps10,scale320:-1${outputPath};八、总结ohos/mp4parser封装了 FFmpeg 的核心能力为 HarmonyOS 应用提供了便捷的视频处理接口。主要应用场景包括视频帧提取用于时间轴缩略图展示、视频截图视频转 GIF通过 FFmpeg 命令实现视频片段转 GIF 动图视频裁剪提取视频指定时间段在使用时注意合理管理内存、及时释放资源、正确处理异步回调。