一、基本概念
- HarmonyOS 视频模块支持视频业务的开发和生态开放,开发者可以通过已开放的接口很容易地实现视频媒体的播放、操作和新功能开发。
- 视频媒体的常见操作有视频编解码、视频合成、视频提取、视频播放以及视频录制等。
- 编码:编码是信息从一种形式或格式转换为另一种形式的过程。用预先规定的方法将文字、数字或其他对象编成数码,或将信息、数据转换成规定的电脉冲信号。在本模块中,编码是指编码器将原始的视频信息压缩为另一种格式的过程。
- 解码:解码是一种用特定方法,把数码还原成它所代表的内容或将电脉冲信号、光信号、无线电波等转换成它所代表的信息、数据等的过程。在本模块中,解码是指解码器将接收到的数据还原为视频信息的过程,与编码过程相对应。
- 帧率:帧率是以帧为单位的位图图像连续出现在显示器上的频率(速率),以赫兹(Hz)为单位。
二、媒体编解码能力查询
① 应用场景
- 媒体编解码能力查询主要指查询设备所支持的编解码器的 MIME(Multipurpose Internet Mail Extensions,媒体类型)列表,并判断设备是否支持指定 MIME 对应的编码器/解码器。
② 媒体编解码能力 API
- 媒体编解码能力查询类 CodecDescriptionList 的主要接口:
接口名 | 功能描述 |
---|
getSupportedMimes() | 获取某设备所支持的编解码器的MIME列表 |
isDecodeSupportedByMime(String mime) | 判断某设备是否支持指定MIME对应的解码器 |
isEncodeSupportedByMime(String mime) | 判断某设备是否支持指定MIME对应的编码器 |
isDecoderSupportedByFormat(Format format) | 判断某设备是否支持指定媒体格式对应的解码器 |
isEncoderSupportedByFormat(Format format) | 判断某设备是否支持指定媒体格式对应的编码器 |
③ 媒体编解码能力查询
- 调用 CodecDescriptionList 类的静态 getSupportedMimes() 方法,获取某设备所支持的编解码器的 MIME 列表。代码示例如下:
List<String> mimes = CodecDescriptionList.getSupportedMimes();
- 调用 CodecDescriptionList 类的静态 isDecodeSupportedByMime 方法,判断某设备是否支持指定 MIME 对应的解码器,支持返回 true,否则返回 false。代码示例如下:
boolean result = CodecDescriptionList.isDecodeSupportedByMime(Format.VIDEO_VP9);
- 调用 CodecDescriptionList 类的静态 isEncodeSupportedByMime 方法,判断某设备是否支持指定 MIME 对应的编码器,支持返回 true,否则返回 false。代码示例如下:
boolean result = CodecDescriptionList.isEncodeSupportedByMime(Format.AUDIO_FLAC);
- 调用 CodecDescriptionList 类的静态 isDecoderSupportedByFormat/isEncoderSupportedByFormat 方法,判断某设备是否支持指定 Format 的编解码器,支持返回 true,否则返回 false。代码示例如下:
Format format = new Format();
format.putStringValue(Format.MIME, Format.VIDEO_AVC);
format.putIntValue(Format.WIDTH, 2560);
format.putIntValue(Format.HEIGHT, 1440);
format.putIntValue(Format.FRAME_RATE, 30);
format.putIntValue(Format.FRAME_INTERVAL, 1);
boolean result = CodecDescriptionList.isDecoderSupportedByFormat(format);
result = CodecDescriptionList.isEncoderSupportedByFormat(format);
三、视频编解码
① 视频编解码 API
接口名 | 功能描述 |
---|
createDecoder() | 创建解码器Codec实例 |
createEncoder() | 创建编码器Codec实例 |
registerCodecListener(ICodecListener listener) | 注册侦听器用来异步接收编码或解码后的数据 |
setSource(Source source, TrackInfo trackInfo) | 根据解码器的源轨道信息设置数据源,对于编码器trackInfo无效 |
setSourceFormat(Format format) | 编码器的管道模式下,设置编码器编码格式 |
setCodecFormat(Format format) | 普通模式设置编/解码器参数 |
setVideoSurface(Surface surface) | 设置解码器的Surface |
getAvailableBuffer(long timeout) | 普通模式获取可用ByteBuffer。 |
writeBuffer(ByteBuffer buffer, BufferInfo info) | 推送源数据给Codec |
getBufferFormat(ByteBuffer buffer) | 获取输出Buffer数据格式 |
start() | 启动编/解码 |
stop() | 停止编/解码 |
release() | 释放所有资源 |
② 普通模式
- 在普通模式下进行编解码,应用必须持续地传输数据到 Codec 实例。
- 编码的具体步骤如下:
-
- 创建编码 Codec 实例,可调用 createEncoder() 创建。
final Codec encoder = Codec.createEncoder();
-
- 构造数据源格式,并设置给 Codec 实例,调用 setCodecFormat(),代码示例如下:
Format fmt = new Format();
fmt.putStringValue(Format.MIME, Format.VIDEO_AVC);
fmt.putIntValue(Format.WIDTH, 1920);
fmt.putIntValue(Format.HEIGHT, 1080);
fmt.putIntValue(Format.BIT_RATE, 392000);
fmt.putIntValue(Format.FRAME_RATE, 30);
fmt.putIntValue(Format.FRAME_INTERVAL, 30);
codec.setCodecFormat(fmt);
-
- 如果需要编码过程中,检测是否读取到 Buffer 数据以及是否发生异常,可以构造 ICodecListener,ICodecListener 需要实现两个方法,实现读到 Buffer 数据时、编码发生异常时做相应的操作。上面的例子中读到 Buffer 时,获取 buffer 的 format 格式,异常时抛出运行时异常,代码示例如下:
Codec.ICodecListener listener = new Codec.ICodecListener() {
@Override
public void onReadBuffer(ByteBuffer byteBuffer, BufferInfo bufferInfo, int trackId) {
Format fmt = codec.getBufferFormat(byteBuffer);
}
@Override
public void onError(int errorCode, int act, int trackId) {
HiLog.error(TAG, "CodeListener onError errorCode: %{public}d, act: %{public}d", errorCode, act);
}
};
-
-
- 调用 getAvailableBuffer() 取到一个可用的 ByteBuffer,把数据填入 ByteBuffer 里,然后再调用 writeBuffer() 把 ByteBuffer 写入编码器实例。
-
-
- 编码任务结束后,调用 release() 释放资源。
- 解码的具体步骤如下:
-
- 创建解码 Codec 实例,可调用 createDecoder() 创建。
-
- 构造数据源格式,并设置给 Codec 实例,调用 setCodecFormat(),代码示例如下:
Format fmt = new Format();
fmt.putStringValue(Format.MIME, Format.VIDEO_AVC);
fmt.putIntValue(Format.WIDTH, 1920);
fmt.putIntValue(Format.HEIGHT, 1080);
fmt.putIntValue(Format.BIT_RATE, 392000);
fmt.putIntValue(Format.FRAME_RATE, 30);
fmt.putIntValue(Format.FRAME_INTERVAL, -1);
codec.setCodecFormat(fmt);
-
- (可选)如果需要解码过程中,检测是否读取到 Buffer 数据以及是否发生异常,可以构造 ICodecListener,ICodecListener 需要实现两个方法,实现读到 Buffer 数据时、解码发生异常时做相应的操作。举例中读到 buffer 时,获取 buffer 的 format 格式,异常时抛出运行时异常,代码示例如下:
Codec.ICodecListener listener = new Codec.ICodecListener() {
@Override
public void onReadBuffer(ByteBuffer byteBuffer, BufferInfo bufferInfo, int trackId) {
Format fmt = codec.getBufferFormat(byteBuffer);
}
@Override
public void onError(int errorCode, int act, int trackId) {
throw new RuntimeException();
}
};
-
-
- 调用 getAvailableBuffer 取到一个可用的 ByteBuffer,把数据填入 ByteBuffer 里,然后再调用 writeBuffer 把 ByteBuffer 写入解码器实例。
-
-
- 解码任务结束后,调用 release() 释放资源。
③ 管道模式
- 管道模式下应用只需要调用 Source 类的 setSource() 方法,数据会自动解析并传输给 Codec 实例。
- 管道模式编码支持视频流编码和音频流编码。
- 编码的具体步骤如下:
-
- 调用 createEncoder() 创建编码 Codec 实例。
-
- 调用 setSource() 设置数据源,支持设定文件路径或者文件 File Descriptor。
-
- 构造数据源格式或者从 Extractor 中读取数据源格式,并设置给 Codec 实例,调用 setSourceFormat(),构造数据源格式代码示例如下:
Format fmt = new Format();
fmt.putStringValue(Format.MIME, Format.VIDEO_AVC);
fmt.putIntValue(Format.WIDTH, 1920);
fmt.putIntValue(Format.HEIGHT, 1080);
fmt.putIntValue(Format.BIT_RATE, 392000);
fmt.putIntValue(Format.FRAME_RATE, 30);
fmt.putIntValue(Format.FRAME_INTERVAL, -1);
codec.setSourceFormat(fmt);
-
- (可选)如果需要编码过程中,检测是否读取到 Buffer 数据以及是否发生异常,可以构造 ICodecListener,ICodecListener 需要实现两个方法,实现读到 Buffer 数据时、编码发生异常时做相应的操作。举例中读到 buffer 时,获取 buffer 的 format 格式,异常时抛出运行时异常,代码示例如下:
Codec.ICodecListener listener = new Codec.ICodecListener() {
@Override
public void onReadBuffer(ByteBuffer byteBuffer, BufferInfo bufferInfo, int trackId) {
Format fmt = codec.getBufferFormat(byteBuffer);
}
@Override
public void onError(int errorCode, int act, int trackId) {
throw new RuntimeException();
}
};
-
-
-
- 编码任务结束后,调用 release() 释放资源。
- 解码的具体步骤如下:
-
- 调用 createDecoder() 创建解码 Codec 实例。
-
- 调用 setSource() 设置数据源,支持设定文件路径或者文件 File Descriptor。
-
- (可选)如果需要解码过程中,检测是否读取到 Buffer 数据以及是否发生异常,可以构造 ICodecListener,ICodecListener 需要实现两个方法,实现读到 Buffer 数据时、解码发生异常时做相应的操作。举例中读到 buffer 时,获取 buffer 的 format 格式,异常时抛出运行时异常,代码示例如下:
Codec.ICodecListener listener = new Codec.ICodecListener() {
@Override
public void onReadBuffer(ByteBuffer byteBuffer, BufferInfo bufferInfo, int trackId) {
Format fmt = codec.getBufferFormat(byteBuffer);
}
@Override
public void onError(int errorCode, int act, int trackId) {
throw new RuntimeException();
}
};
-
-
-
- 解码任务结束后,调用 release() 释放资源。
四、视频播放
① 视频播放 API
- 视频播放包括播放控制、播放设置和播放查询,如播放的开始/停止、播放速度设置和是否循环播放等。
- 视频播放类 Player 的主要接口:
接口名 | 功能描述 |
---|
Player(Context context) | 创建Player实例 |
setSource(Source source) | 设置媒体源 |
prepare() | 准备播放 |
play() | 开始播放 |
pause() | 暂停播放 |
stop() | 停止播放 |
rewindTo(long microseconds) | 拖拽播放 |
setVolume(float volume) | 调节播放音量 |
setVideoSurface(Surface surface) | 设置视频播放的窗口 |
enableSingleLooping(boolean looping) | 设置为单曲循环 |
isSingleLooping() | 检查是否单曲循环播放 |
isNowPlaying() | 检查是否播放 |
getCurrentTime() | 获取当前播放位置 |
getDuration() | 获取媒体文件总时长 |
getVideoWidth() | 获取视频宽度 |
getVideoHeight() | 获取视频高度 |
setPlaybackSpeed(float speed) | 设置播放速度 |
getPlaybackSpeed() | 获取播放速度 |
setAudiostreamType(int type) | 设置音频类型 |
getAudioStreamType() | 获取音频类型 |
setNextPlayer(Player next) | 设置当前播放结束后的下一个播放器 |
reset() | 重置播放器 |
release() | 释放播放资源 |
setPlayerCallback(IPlayerCallback callback) | 注册回调,接收播放器的事件通知或异常通知 |
② 视频播放流程
- 创建 Player 实例,可调用 Player(Context context),创建本地播放器,用于在本设备播放。
- 构造数据源对象,并调用 Player 实例的 setSource(Source source) 方法,设置媒体源,代码示例如下:
Player player = new Player(context);
File file = new File("/sdcard/test_audio.mp4"); // 根据实际情况设置文件路径
FileInputStream in = new FileInputStream(file);
FileDescriptor fd = in.getFD(); // 从输入流获取FD对象
Source source = new Source(fd);
player.setSource(source);
- 调用 prepare(),准备播放。
- (可选)构造 IPlayerCallback,IPlayerCallback 需要实现 onPlayBackComplete 和 onError(int errorType, int errorCode) 两个方法,实现播放完成和播放异常时做相应的操作。代码示例如下:
@Override
public void onPlayBackComplete() {
HiLog.info(TAG, "PlayerCallback onPlayBackComplete");
if (player != null) {
player.stop();
player = null;
}
}
@Override
public void onError(int errorType, int errorCode) {
HiLog.error(TAG, "PlayerCallback onError errorType: %{public}d, errorCode: %{public}d", errorType, errorCode);
}
- 调用 play() 方法,开始播放。
- (可选)调用 pause() 方法和 play() 方法,可以实现暂停和恢复播放。
- (可选)调用 rewindTo(long microseconds) 方法实现播放中的拖拽功能。
- (可选)调用 getDuration() 方法和 getCurrentTime() 方法,可以实现获取总播放时长以及当前播放位置功能。
- 调用 stop() 方法停止播放。
- 播放结束后,调用 release() 释放资源。
五、视频录制
① 视频录制 API
- 视频录制的主要工作是选择视频/音频来源后,录制并生成视频/音频文件。
- 视频录制类 Recorder 的主要接口:
接口名 | 功能描述 |
---|
Recorder() | 创建Recorder实例 |
setSource(Source source) | 设置音视频源 |
setAudioProperty(AudioProperty property) | 设置音频属性 |
setVideoProperty(VideoProperty property) | 设置视频属性 |
setStorageProperty(StorageProperty property) | 设置音视频存储属性 |
prepare() | 准备录制资源 |
start() | 开始录制 |
stop() | 停止录制 |
pause() | 暂停录制 |
resume() | 恢复录制 |
reset() | 重置录制 |
setRecorderLocation(float latitude, float longitude) | 设置视频的经纬度 |
setOutputFormat(int outputFormat) | 设置输出文件格式 |
getVideoSurface() | 获取视频窗口 |
setRecorderProfile(RecorderProfile profile) | 设置媒体录制配置信息 |
registerRecorderListener(IRecorderListener listener) | 注册媒体录制回调 |
release() | 释放媒体录制资源 |
② 视频录制流程
- 调用 Recorder() 方法,创建 Recorder 实例。
- 构造数据源对象,并调用 Recorder 实例的 setSource(Source source) 方法,设置媒体源,代码示例如下:
Recorder recorder = new Recorder();
Source source = new Source();
source.setRecorderAudioSource(Recorder.AudioSource.DEFAULT);
recorder.setSource(source);
- 调用 setOutputFormat(int outputFormat) 方法,设置录制文件存储格式。
- (可选)构造音频属性 AudioProperty 对象(不设置音频则是只录视频),并调用 Recorder 实例的 setAudioProperty(AudioProperty property) 方法,设置录制的音频属性,代码示例如下:
final int AUDIO_NUM_CHANNELS_STEREO = 2;
final int AUDIO_SAMPLE_RATE_HZ = 8000;
AudioProperty audioProperty = new AudioProperty.Builder()
.setRecorderNumChannels(AUDIO_NUM_CHANNELS_STEREO)
.setRecorderSamplingRate(AUDIO_SAMPLE_RATE_HZ)
.setRecorderAudioEncoder(Recorder.AudioEncoder.DEFAULT)
.build();
recorder.setAudioProperty(audioProperty);
- 构造存储属性 StorageProperty 对象,并调用 Recorder 实例的 setStorageProperty(StorageProperty property) 方法,设置录制的存储属性,代码示例如下:
String path = "/sdcard/audiotestRecord.mp4";
StorageProperty storageProperty = new StorageProperty.Builder()
.setRecorderPath(path)
.setRecorderMaxDurationMs(1000000)
.setRecorderMaxFileSizeBytes(1000000)
.build();
recorder.setStorageProperty(storageProperty);
- (可选)构造视频属性 VideoProperty 对象,并调用 Recorder 实例的 setVideoProperty(VideoProperty property) 方法,设置录制的视频属性,代码示例如下:
VideoProperty videoProperty = new VideoProperty.Builder()
.setRecorderVideoEncoder(Recorder.VideoEncoder.DEFAULT)
.setRecorderWidth(1080)
.setRecorderDegrees(0)
.setRecorderHeight(800)
.setRecorderBitRate(10000000)
.setRecorderRate(30)
.build();
recorder.setVideoProperty(videoProperty);
- 调用 prepare(),准备录制。
- (可选)构造录制回调,首先构造对象 IRecorderListener,IRecorderListener 需要实现 onError(int what, int extra),实现录制过程收到错误信息时做相应的操作。下面的代码例子中录制异常时,打印了相关的日志信息,代码示例如下:
class RecorderErrorAndInfoListener implements IRecorderListener {
@Override
public void onError(int what, int extra) {
}
@Override
public void onMessage(int what, int extra) {
}
}
IRecorderListener listener = new RecorderErrorAndInfoListener() {
@Override
public void onError(int what, int extra) {
HiLog.error(TAG, "EncodeWriteFileListener onError what:%{public}d, extra:%{public}d", what, extra);
}
}
- 调用 start() 方法,开始录制。
- (可选)调用 pause() 方法和 resume() 方法,可以实现暂停和恢复录制。
- 调用 stop() 方法停止录制。
- 录制结束后,调用 release() 释放资源。
六、视频提取
① 视频提取 API
- 视频提取主要工作是将多媒体文件中的音视频数据进行分离,提取出音频、视频数据源。
- 视频提取类 Extractor 的主要接口:
接口名 | 功能描述 |
---|
Extractor() | 创建Extractor实例 |
setSource(Source source) | 设置媒体播放源 |
getStreamFormat(int id) | 获取对应索引的轨道数据的格式 |
getTotalStreams() | 获取媒体文件中总轨道数 |
selectStream(int id) | 根据轨道号选择媒体文件中对应的轨道 |
unselectStream(int id) | 取消轨道选择 |
rewindTo(long microseconds, int mode) | 根据时间和mode跳转到指定帧 |
next() | 跳转到下一帧 |
readBuffer(ByteBuffer buf, int offset) | 读取解复用后的数据 |
getStreamId() | 获取当前轨道号 |
getFrameTimestamp() | 获取当前媒体数据帧的时间戳 |
getFrameSize() | 获取当前媒体数据帧的数据大小 |
getFrameType() | 获取当前媒体数据帧的flags |
release() | 释放资源 |
② 视频提取流程
- 调用 Extractor() 方法创建 Extractor 实例。
- 构造数据源对象,并调用 Extractor 实例的 setSource(Source source) 方法,设置媒体源,代码示例如下:
Extractor extractor = new Extractor();
File file = new File("/sdcard/test_audio.mp4"); // 根据实际情况设置文件路径
FileInputStream in = new FileInputStream(file);
FileDescriptor fd = in.getFD();
Source source = new Source(fd);
extractor.setSource(source);
- 调用 getTotalStreams() 方法获取媒体的轨道数量。
- 调用 selectStream(int id) 方法选择特定轨道的数据,进行提取。
- (可选)调用 unselectStream(int id) 方法取消选择轨道。
- (可选)调用 rewindTo(long microseconds, int mode) 方法实现提取过程中的跳转指定位置。
- 调用 readBuffer(ByteBuffer buf, int offset) 方法,可以实现获取提取出来的 Buffer 数据功能。
- 调用 next() 方法,实现提取下一帧的功能。
- (可选)调用 getMediaStreamId() 方法,可以实现获取当前选择的轨道编号的功能。
- (可选)调用 getFrameTimestamp() 方法,可以实现获取当前轨道内媒体数据帧时间戳的功能。
- (可选)调用 getFrameSize() 方法,可以实现获取当前轨道的媒体数据帧大小的功能。
- (可选)调用 getFrameType() 方法,可以实现获取当前轨道的媒体数据帧 flags 的功能。
- 提取结束后,调用 release() 释放资源。
七、媒体描述信息
① 媒体描述信息 API
- 媒体描述信息主要工作是支持多媒体的相关描述信息的存取。
- 媒体描述信息类 AVDescription 的主要接口:
接口名 | 功能描述 |
---|
getMediaId() | 获取媒体标识 |
getTitle() | 获取媒体标题 |
getSubTitle() | 获取媒体副标题 |
getDescription() | 获取媒体描述信息 |
getIcon() | 获取媒体图标 |
getIconUri() | 获取媒体图标的Uri |
getExtras() | 获取媒体添加的额外信息,例如应用和系统使用的内部信息 |
getMediaUri() | 获取媒体内容的Uri |
marshalling(Parcel parcel) | 将一个AVDescription对象写入到Parcel对象 |
unmarshalling(Parcel parcel) | 将一个Parcel对象写入到AVDescription对象 |
- 媒体描述信息内部静态类 AVDescription.Builder 的主要接口:
接口名 | 功能描述 |
---|
setMediaId(String mediaId) | 设置媒体标识 |
setTitle(CharSequence title) | 设置媒体标题 |
setSubTitle(CharSequence subTitle) | 设置媒体副标题 |
setDescription(String description) | 设置媒体描述信息 |
setIcon(PixelMap icon) | 设置媒体图标 |
setIconUri(Uri iconUri) | 设置媒体图标的Uri |
setExtras(PacMap extras) | 设置媒体的额外信息,例如应用和系统使用的内部信息 |
setIMediaUri(Uri mediaUri) | 设置媒体的Uri |
build() | 构造方法 |
② 媒体描述信息流程
- 调用 AVDescription.Builder 类的 build 方法创建 AVDescription 实例。代码示例如下:
AVDescription avDescription = new AVDescription.Builder().setExtras(null)
.setMediaId("1")
.setDescription("Description")
.setIconUri(iconUri)
.setIMediaUri(mediaUri)
.setExtras(pacMap)
.setIcon(pixelMap)
.setTitle("title")
.setSubTitle("subTitle")
.build();
- (可选)根据已有的 AVDescription 对象,可以获取媒体的描述信息,如获取媒体 Uri,代码示例如下:
Uri uri = avDescription.getMediaUri();
- (可选)根据已有的 AVDescription 对象,可以将媒体的描述信息写入 Parcel 对象,代码示例如下:
Parcel parcel = Parcel.create();
boolean result = avDescription.marshalling(parcel);
- (可选)根据已有的 Parcel 对象,可以读取到 AVDescription 对象,实现媒体描述信息的写入,代码示例如下:
boolean result = avDescription.unmarshalling(parcel);
八、媒体元数据
① 媒体元数据 API
- 媒体元数据主要用于媒体数据的存放和读取,包含诸如媒体资源的描述、创建日期、作者、封面图片等等。
- 媒体元数据存放类 AVMetadata.Builder 的主要接口:
接口名 | 功能描述 |
---|
Builder() | 媒体元数据构造器的构造函数 |
Builder(AVMetadata source) | 媒体元数据构造器的带参构造函数 |
setText(String key, CharSequence value) | 用于存储媒体标题等信息 |
setString(String key, String value) | 用于存储媒体作者、艺术家、描述等 |
setLong(String key, long value) | 用于存储媒体ID、媒体时长等信息 |
setPixelMap(String key, PixelMap value) | 用于存储媒体元数据相关的图片资源 |
build() | 媒体元数据生成函数 |
接口名 | 功能描述 |
---|
hasKey(String key) | 媒体元数据中是否包含某一个key的数据 |
getText(String key) | 获取text类型的key的数据,比如获取媒体标题等信息 |
getString(String key) | 获取String类型key的数据,比如获取媒体作者、艺术家、描述等 |
getLong(String key) | 获取Long类型key数据,比如获取媒体ID、媒体时长等信息 |
getKeysSet() | 获取媒体元数据的集合 |
getPixelMap(String key) | 获取PixelMap类型key数据,获取媒体元数据相关的图片资源 |
marshalling(Parcel in) | 将一个AVMetadata对象写入到Parcel对象 |
getAVDescription() | 获取媒体的简要描述信息 |
① 媒体元数据使用流程
- 调用 AVMetadata.Builder 类的 build 方法创建 AVMetadata 实例。代码示例如下:
AVMetadata avMetadata = new AVMetadata.Builder().setString(AVMetadata.AVTextKey.META_ID, "illuminate.mp3")
.setString(AVMetadata.AVTextKey.TITLE, "title")
.setString(AVMetadata.AVTextKey.ARTIST, "artist")
.setString(AVMetadata.AVTextKey.ALBUM, "album")
.setString(AVMetadata.AVTextKey.TITLE, "display_subtitle")
.setPixelMap(AVMetadata.AVPixelMapKey.ICON, pixelmap)
.build();
- (可选)根据已有的 AVMetadata 对象,可以获取媒体元数据信息,如获取媒体标题等,代码示例如下:
String title = avMetadata.getString(AVMetadata.AVTextKey.TITLE);
- 我们需要结合 AVSession 使用,将已有的媒体元数据 AVMetadata 对象下发给应用,具体参考 AVSession 使用,示例如下:
mediaSession.setAVMetadata(avMetadata);
- 应用获取媒体元数据一般结合 AVControllerCallback 相关类使用,通过 onAVMetadataChanged 回调获取媒体元数据。
Image musicCover;
Text musicTitle;
public class Callback extends AVControllerCallback {
@Override
public void onAVMetadataChanged(AVMetadata metadata) {
// 歌曲信息回调
AVDescription description = metadata.getAVDescription();
// 获取标题
String title = description.getTitle().toString();
CharSequence sequence = metadata.getText(AVMetadata.AVTextKey.TITLE);
if (sequence != null) {
title = sequence.toString();
}
// 设置媒体title
musicTitle.setText(title);
// 获取曲目专封面
PixelMap iconPixelMap = description.getIcon();
// 设置歌曲封面图
musicCover.setPixelMap(iconPixelMap);
}
}