1# 使用AVMetadataExtractor提取音视频元数据信息(ArkTS) 2 3使用[AVMetadataExtractor](media-kit-intro.md#avmetadataextractor)可以实现从原始媒体资源中获取元数据,本开发指导将以获取一个音频资源的元数据作为示例,向开发者讲解AVMetadataExtractor元数据相关功能。视频资源的元数据获取流程与音频类似,由于视频没有专辑封面,所以无法获取视频资源的专辑封面。 4 5获取音频资源的元数据的全流程包含:创建AVMetadataExtractor,设置资源,获取元数据,获取专辑封面,销毁资源。 6 7## 开发步骤及注意事项 8 9详细的API说明请参考[AVMetadataExtractor API参考](../../reference/apis-media-kit/js-apis-media.md#avmetadataextractor11)。 10 111. 使用createAVMetadataExtractor()创建实例。 12 132. 设置资源:用户可以根据需要选择设置属性fdSrc(表示文件描述符), 或者设置属性dataSrc(表示dataSource描述符)。 14 > **说明:** 15 > 16 > 开发者需根据实际情况,确认资源有效性并设置(只能设置其中一种): 17 > 18 > - 如果设置fdSrc,可以使用ResourceManager.getRawFd打开HAP资源文件描述符,使用方法可参考[ResourceManager API参考](../../reference/apis-localization-kit/js-apis-resource-manager.md#getrawfd9)。也可以通过应用沙箱路径访问对应资源(必须确保资源可用),参考[获取应用文件路径](../../application-models/application-context-stage.md#获取应用文件路径)。应用沙箱的介绍及如何向应用沙箱推送文件,请参考[文件管理](../../file-management/app-sandbox-directory.md)。 19 > 20 > - 如果设置dataSrc,必须正确设置dataSrc中的callback属性,确保callback被调用时能正确读取到对应资源,使用应用沙箱路径访问对应资源,参考[获取应用文件路径](../../application-models/application-context-stage.md#获取应用文件路径)。应用沙箱的介绍及如何向应用沙箱推送文件,请参考[文件管理](../../file-management/app-sandbox-directory.md)。 21 > 22 > - 不同AVMetadataExtractor或者[AVImageGenerator](../../reference/apis-media-kit/js-apis-media.md#avimagegenerator12)实例,如果需要操作同一资源,需要多次打开文件描述符,不要共用同一文件描述符。 23 243. 获取元数据:调用fetchMetadata(),可以获取到一个AVMetadata对象,通过访问该对象的各个属性,可以获取到元数据。 25 264. (可选)获取专辑封面:调用fetchAlbumCover(),可以获取到专辑封面。 27 285. 释放资源:调用release()销毁实例,释放资源。 29 30## 完整示例 31 32参考以下示例,设置文件描述符,获取一个音频的元数据和专辑封面。 33 34```ts 35import { media } from '@kit.MediaKit'; 36import { image } from '@kit.ImageKit'; 37import { common } from '@kit.AbilityKit'; 38import { fileIo as fs, ReadOptions } from '@kit.CoreFileKit'; 39 40const TAG = 'MetadataDemo'; 41 42@Entry 43@Component 44struct Index { 45 @State message: string = 'Hello World'; 46 // pixelMap对象声明,用于图片显示。 47 @State pixelMap: image.PixelMap | undefined = undefined; 48 rootPath: string = getContext(this).getApplicationContext().filesDir; 49 testFilename: string = '/cover.mp3'; 50 51 build() { 52 Row() { 53 Column() { 54 Text(this.message).fontSize(50).fontWeight(FontWeight.Bold) 55 Button() { 56 Text('TestButton') 57 .fontSize(30) 58 .fontWeight(FontWeight.Bold) 59 } 60 .type(ButtonType.Capsule) 61 .margin({ 62 top: 20 63 }) 64 .backgroundColor('#0D9FFB') 65 .width('60%') 66 .height('5%') 67 .onClick(() => { 68 // 设置fdSrc, 获取音频元数据和专辑封面(异步接口以Callback形式调用)。 69 this.testFetchMetadataFromFdSrcByCallback(); 70 // 设置fdSrc, 获取音频元数据和专辑封面(异步接口以Promise形式调用)。 71 this.testFetchMetadataFromFdSrcByPromise(); 72 // 通过fdSrc获取沙箱路径下音频元数据和专辑封面(文件必须在沙箱路径里存在)。 73 this.testFetchMetadataFromFdSrc(); 74 // 设置dataSrc, 获取沙箱路径下音频元数据和专辑封面(文件必须在沙箱路径里存在)。 75 this.testFetchMetadataFromDataSrc(); 76 }) 77 78 Image(this.pixelMap).width(300).height(300) 79 .margin({ 80 top: 20 81 }) 82 } 83 .width('100%') 84 } 85 .height('100%') 86 } 87 88 // 在以下demo中,使用资源管理接口获取打包在HAP内的媒体资源文件,通过设置fdSrc属性,获取音频元数据并打印。 89 // 获取音频专辑封面并通过Image控件显示在屏幕上。该demo以Callback形式进行异步接口调用。 90 async testFetchMetadataFromFdSrcByCallback() { 91 if (canIUse("SystemCapability.Multimedia.Media.AVMetadataExtractor")) { 92 // 创建AVMetadataExtractor对象。 93 let avMetadataExtractor: media.AVMetadataExtractor = await media.createAVMetadataExtractor(); 94 95 // 设置fdSrc。 96 avMetadataExtractor.fdSrc = await getContext(this).resourceManager.getRawFd('cover.mp3'); 97 98 // 获取元数据(callback模式)。 99 avMetadataExtractor.fetchMetadata((error, metadata) => { 100 if (error) { 101 console.error(TAG, `fetchMetadata callback failed, err = ${JSON.stringify(error)}`); 102 return; 103 } 104 console.info(TAG, `fetchMetadata callback success, genre: ${metadata.genre}`); 105 }) 106 107 //获取专辑封面(callback模式)。 108 avMetadataExtractor.fetchAlbumCover((err, pixelMap) => { 109 if (err) { 110 console.error(TAG, `fetchAlbumCover callback failed, err = ${JSON.stringify(err)}`); 111 return; 112 } 113 this.pixelMap = pixelMap; 114 115 // 释放资源(callback模式)。 116 avMetadataExtractor.release((error) => { 117 if (error) { 118 console.error(TAG, `release failed, err = ${JSON.stringify(error)}`); 119 return; 120 } 121 console.info(TAG, `release success.`); 122 }) 123 }) 124 } 125 } 126 127 // 在以下demo中,使用资源管理接口获取打包在HAP内的媒体资源文件,通过设置fdSrc属性,获取音频元数据并打印。 128 // 获取音频专辑封面并通过Image控件显示在屏幕上。该demo以Promise形式进行异步接口调用。 129 async testFetchMetadataFromFdSrcByPromise() { 130 if (canIUse("SystemCapability.Multimedia.Media.AVMetadataExtractor")) { 131 // 创建AVMetadataExtractor对象。 132 let avMetadataExtractor: media.AVMetadataExtractor = await media.createAVMetadataExtractor(); 133 // 设置fdSrc。 134 avMetadataExtractor.fdSrc = await getContext(this).resourceManager.getRawFd('cover.mp3'); 135 136 // 获取元数据(promise模式)。 137 let metadata = await avMetadataExtractor.fetchMetadata(); 138 console.info(TAG, `get meta data, hasAudio: ${metadata.hasAudio}`); 139 140 // 获取专辑封面(promise模式)。 141 this.pixelMap = await avMetadataExtractor.fetchAlbumCover(); 142 143 // 释放资源(promise模式)。 144 avMetadataExtractor.release(); 145 console.info(TAG, `release success.`); 146 } 147 } 148 149 // 在以下demo中,使用fs文件系统打开沙箱地址获取媒体文件地址,设置fdSrc属性,获取音频元数据并打印。 150 // 获取音频专辑封面并通过Image控件显示在屏幕上。 151 async testFetchMetadataFromFdSrc() { 152 if (canIUse("SystemCapability.Multimedia.Media.AVMetadataExtractor")) { 153 // 创建AVMetadataExtractor对象。 154 let avMetadataExtractor = await media.createAVMetadataExtractor(); 155 156 // 设置fdSrc。 157 avMetadataExtractor.fdSrc = fs.openSync(this.rootPath + this.testFilename); 158 159 // 获取元数据(promise模式)。 160 let metadata = await avMetadataExtractor.fetchMetadata(); 161 console.info(TAG, `get meta data, mimeType: ${metadata.mimeType}`); 162 163 // 获取专辑封面(promise模式)。 164 this.pixelMap = await avMetadataExtractor.fetchAlbumCover(); 165 166 // 释放资源(promise模式)。 167 avMetadataExtractor.release(); 168 console.info(TAG, `release data source success.`); 169 } 170 } 171 172 // 在以下demo中,使用fs文件系统打开沙箱地址获取媒体文件地址,设置dataSrc属性,获取音频元数据并打印。 173 // 获取音频专辑封面并通过Image控件显示在屏幕上。 174 async testFetchMetadataFromDataSrc() { 175 let context = getContext(this) as common.UIAbilityContext; 176 // 通过UIAbilityContext获取沙箱地址filesDir(以Stage模型为例)。 177 let fd: number = fs.openSync(this.rootPath + this.testFilename).fd; 178 let fileSize: number = fs.statSync(this.rootPath + this.testFilename).size; 179 // 设置dataSrc描述符,通过callback从文件中获取资源,写入buffer中。 180 let dataSrc: media.AVDataSrcDescriptor = { 181 fileSize: fileSize, 182 callback: (buffer, len, pos) => { 183 if (buffer == undefined || len == undefined || pos == undefined) { 184 console.error(TAG, `dataSrc callback param invalid`); 185 return -1; 186 } 187 let options: ReadOptions = { 188 offset: pos, 189 length: len 190 }; 191 let num = fs.readSync(fd, buffer, options); 192 console.info(TAG, 'readAt end, num: ' + num); 193 if (num > 0 && fileSize >= pos) { 194 return num; 195 } 196 return -1; 197 } 198 }; 199 if (canIUse("SystemCapability.Multimedia.Media.AVMetadataExtractor")) { 200 // 创建AVMetadataExtractor对象。 201 let avMetadataExtractor = await media.createAVMetadataExtractor(); 202 // 设置dataSrc。 203 avMetadataExtractor.dataSrc = dataSrc; 204 205 // 获取元数据(promise模式)。 206 let metadata = await avMetadataExtractor.fetchMetadata(); 207 console.info(TAG, `get meta data, mimeType: ${metadata.mimeType}`); 208 209 // 获取专辑封面(promise模式)。 210 this.pixelMap = await avMetadataExtractor.fetchAlbumCover(); 211 212 // 释放资源(promise模式)。 213 avMetadataExtractor.release(); 214 console.info(TAG, `release data source success.`); 215 } 216 } 217} 218```