获取网络视频首帧图
方法一:需下载到本地(不推荐)
import { GetFirstFrameAnimation } from './GetFirstFrameAnimation';
import { media } from '@kit.MediaKit';
import { image } from '@kit.ImageKit';
import fs from '@ohos.file.fs';
import { common } from '@kit.AbilityKit';
import request from '@ohos.request';
import { rcp } from '@kit.RemoteCommunicationKit';
import { DownloadManager } from '@hadss/super_fast_file_trans';
import { DownloadConfig, DownloadListener, DownloadTask, DownloadProgressInfo } from '@hadss/super_fast_file_trans';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@State coverImage: image.PixelMap | null = null;
// pixelMap对象声明,用于图片显示
@State pixelMap: image.PixelMap | string | undefined = undefined;
private downloadTask: DownloadTask | undefined;
private ctx: Context | undefined;
// 获取视频第一帧
async testFetchFrameByTime(filePath: string) {
// 创建AVImageGenerator对象
let avImageGenerator: media.AVImageGenerator = await media.createAVImageGenerator()
let file = fs.openSync(filePath, fs.OpenMode.READ_ONLY);
let avFileDescriptor: media.AVFileDescriptor = { fd: file.fd };
avImageGenerator.fdSrc = avFileDescriptor;
// 初始化入参
let timeUs = 0
let queryOption = media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC
let param: media.PixelMapParams = {
width: 300,
height: 400,
}
// 获取缩略图(promise模式)
this.pixelMap = await avImageGenerator.fetchFrameByTime(timeUs, queryOption, param)
// 释放资源(promise模式)
avImageGenerator.release()
console.info(`release success.`)
fs.closeSync(file);
}
async aboutToAppear() {
const videoUrl = 'http://192.168.1.254/DCIM/MOVIE/20260518165941_000001.MP4';
const downloadManager = DownloadManager.getInstance(); // 获取DownloadManager单例对象
this.ctx = getContext();
await downloadManager.init(this.ctx); // 初始化数据库
// 自定义下载回调
let customDownloadListener: DownloadListener = {
onSuccess: () => {
console.log("onSuccess: download success");
this.testFetchFrameByTime(this.ctx!.filesDir + '/aaa.mp4');
},
onFail: (err: BusinessError) => {
console.error(`onFail: download fail, err.message:${err.message}, err.code:${err.code}`);
},
// ...
onProgressUpdate: (downloadProgress: DownloadProgressInfo) => {
console.log(`onProgressUpdate:, download: transferred size:${downloadProgress.transferredSize}, total size:${downloadProgress.totalSize}`);
//如果下载超过1m则停止下载
// if (downloadProgress.transferredSize > 1024 * 1024) {
// this.downloadTask?.pause();
// this.downloadTask?.cancel();
// // this.testFetchFrameByTime(this.ctx!.filesDir + '/aaa.mp4');
// }
},
};
// 自定义下载配置
let downloadConfig: DownloadConfig = {
url: `${videoUrl}`, // 远端下载地址(必选)
fileName: `aaa.mp4`, // 下载后的本地文件名(必选)
concurrency: 2, // 启用的并发线程数(可选)AppUtil.getApplicationContext().filesDir
fileDir: this.ctx.filesDir, // 下载后的文件保存路径(可选)
// ...
};
// 创建下载任务
this.downloadTask = downloadManager.createDownloadTask(downloadConfig, customDownloadListener);
}
build() {
Column() {
Text('开始下载')
.fontSize($r('app.float.page_text_font_size'))
.fontWeight(FontWeight.Bold)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
.onClick(() => {
this.downloadTask?.start();
})
// Text(this.message)
// .id('HelloWorld')
// .fontSize($r('app.float.page_text_font_size'))
// .fontWeight(FontWeight.Bold)
// .alignRules({
// center: { anchor: '__container__', align: VerticalAlign.Center },
// middle: { anchor: '__container__', align: HorizontalAlign.Center }
// })
// .onClick(() => {
// this.message = 'Welcome';
// })
// GetFirstFrameAnimation()
Column() {
if (this.pixelMap) {
Image(this.pixelMap)
.width(200)
.height(200)
.objectFit(ImageFit.Contain)
}
}
}
.height('100%')
.width('100%')
}
}
async function downloadAndExtractFrame(ctx: common.UIAbilityContext, url: string) {
// const session = rcp.createSession();
// let req = new rcp.Request("url", "POST");
// session.fetch(req).then((response) => {
// console.info(`Succeeded in getting the response ${response}`);
// }).catch((err: BusinessError) => {
// console.error(`err: error code is ${err.code}, error data is ${err.data}`);
// });
let headers: rcp.RequestHeaders = {
"accept": "application/json"
};
let content = "data to send";
let configuration: rcp.Configuration = {
transfer: {
timeout: { connectMs: 60000, transferMs: 60000 }
}
};
let cookies: rcp.RequestCookies = { 'name1': 'value1', 'name2': 'value2' };
let transferRange: rcp.TransferRange = { from: 0, to: 100 };
let req = new rcp.Request(url, "POST", headers, content, cookies, transferRange, configuration);
}
方法二:直接获取(推荐)
import { media } from '@kit.MediaKit';
import { image } from '@kit.ImageKit';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@State pixelMap: image.PixelMap | string | undefined = undefined;
private videoUrl: string = '';
@State videoWidth: number = 0;
@State videoHeight: number = 0;
aboutToAppear() {
this.videoUrl = 'http://192.168.1.254/DCIM/MOVIE/20260520175143_000003.MP4';
}
build() {
Column() {
Text('开始下载')
.fontSize($r('app.float.page_text_font_size'))
.fontWeight(FontWeight.Bold)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
.onClick(() => {
getVideoKeyFramesWithInfo(this.videoUrl).then((res) => {
if (res) {
this.pixelMap = res.pixelMap;
this.videoWidth = res.width;
this.videoHeight = res.height;
}
});
})
Column() {
if (this.pixelMap) {
Image(this.pixelMap)
.width(this.videoWidth)
.height(this.videoHeight)
.objectFit(ImageFit.Contain)
}
}
}
.height('100%')
.width('100%')
}
}
const TAG = "[KeyframeUtils]";
export interface VideoInfo {
pixelMap: image.PixelMap;
width: number;
height: number;
}
// 获取网络视频关键帧,宽高单位px
export async function getVideoKeyFramesWithInfo(url: string): Promise<VideoInfo | null> {
try {
let avMetadataExtractor: media.AVMetadataExtractor = await media.createAVMetadataExtractor();
let headers: Record<string, string> = {
"User-Agent": "User-Agent-Value"
};
avMetadataExtractor.setUrlSource(url, headers);
//获取视频宽高
const metadata = await avMetadataExtractor.fetchMetadata();
const width = Number(metadata.videoWidth) || 0;
const height = Number(metadata.videoHeight) || 0;
console.info(TAG, `Video frame size: ${width}x${height}`);
let timeUs: number = 0; //关键帧位置
let queryOption: media.AVImageQueryOptions = media.AVImageQueryOptions.AV_IMAGE_QUERY_PREVIOUS_SYNC;
//图片宽高
let param: media.PixelMapParams = {
width: width,
height: height
}
const pixelMap = await avMetadataExtractor.fetchFrameByTime(timeUs, queryOption, param);
avMetadataExtractor.release();
return pixelMap ? { pixelMap, width, height } : null;
} catch (error) {
console.error(TAG, `getVideoKeyFramesWithInfo error: ${JSON.stringify(error)}`);
return null;
}
}
浙公网安备 33010602011771号