HarmonyOS之深入解析视频的功能和使用
一、基本概念
- 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
- 视频编解码类 Codec 的主要接口:
接口名 | 功能描述 |
---|---|
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() {@Overridepublic void onReadBuffer(ByteBuffer byteBuffer, BufferInfo bufferInfo, int trackId) {Format fmt = codec.getBufferFormat(byteBuffer);}@Overridepublic void onError(int errorCode, int act, int trackId) {HiLog.error(TAG, "CodeListener onError errorCode: %{public}d, act: %{public}d", errorCode, act);}};
- 调用 start() 方法开始编码。
- 调用 getAvailableBuffer() 取到一个可用的 ByteBuffer,把数据填入 ByteBuffer 里,然后再调用 writeBuffer() 把 ByteBuffer 写入编码器实例。
- 调用 stop() 方法停止编码。
- 编码任务结束后,调用 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() {@Overridepublic void onReadBuffer(ByteBuffer byteBuffer, BufferInfo bufferInfo, int trackId) {Format fmt = codec.getBufferFormat(byteBuffer);}@Overridepublic void onError(int errorCode, int act, int trackId) {throw new RuntimeException();}};
- 调用 start() 方法开始解码。
- 调用 getAvailableBuffer 取到一个可用的 ByteBuffer,把数据填入 ByteBuffer 里,然后再调用 writeBuffer 把 ByteBuffer 写入解码器实例。
- 调用 stop() 方法停止解码。
- 解码任务结束后,调用 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() {@Overridepublic void onReadBuffer(ByteBuffer byteBuffer, BufferInfo bufferInfo, int trackId) {Format fmt = codec.getBufferFormat(byteBuffer);}@Overridepublic void onError(int errorCode, int act, int trackId) {throw new RuntimeException();}};
- 调用 start() 方法开始编码。
- 调用 stop() 方法停止编码。
- 编码任务结束后,调用 release() 释放资源。
- 解码的具体步骤如下:
- 调用 createDecoder() 创建解码 Codec 实例。
- 调用 setSource() 设置数据源,支持设定文件路径或者文件 File Descriptor。
- (可选)如果需要解码过程中,检测是否读取到 Buffer 数据以及是否发生异常,可以构造 ICodecListener,ICodecListener 需要实现两个方法,实现读到 Buffer 数据时、解码发生异常时做相应的操作。举例中读到 buffer 时,获取 buffer 的 format 格式,异常时抛出运行时异常,代码示例如下:
Codec.ICodecListener listener = new Codec.ICodecListener() {@Overridepublic void onReadBuffer(ByteBuffer byteBuffer, BufferInfo bufferInfo, int trackId) {Format fmt = codec.getBufferFormat(byteBuffer);}@Overridepublic void onError(int errorCode, int act, int trackId) {throw new RuntimeException();}};
- 调用 start() 方法开始解码。
- 调用 stop() 方法停止解码。
- 解码任务结束后,调用 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) 两个方法,实现播放完成和播放异常时做相应的操作。代码示例如下:
@Overridepublic void onPlayBackComplete() {HiLog.info(TAG, "PlayerCallback onPlayBackComplete");if (player != null) {player.stop();player = null;}}@Overridepublic 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 {@Overridepublic void onError(int what, int extra) {}@Overridepublic void onMessage(int what, int extra) {}}IRecorderListener listener = new RecorderErrorAndInfoListener() {@Overridepublic 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() | 媒体元数据生成函数 |
- 媒体元数据类 AVMetadata 的主要接口:
接口名 | 功能描述 |
---|---|
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 {@Overridepublic 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();}// 设置媒体titlemusicTitle.setText(title);// 获取曲目专封面PixelMap iconPixelMap = description.getIcon();// 设置歌曲封面图musicCover.setPixelMap(iconPixelMap);}}
HarmonyOS之深入解析视频的功能和使用相关推荐
- HarmonyOS之深入解析Ability的功能和使用
一.Ability 概述 Ability 是应用所具备能力的抽象,也是应用程序的重要组成部分.一个应用可以具备多种能力(即可以包含多个 Ability),HarmonyOS 支持应用以 Ability ...
- HarmonyOS之深入解析相机的功能和使用
一.简介 ① 概念 HarmonyOS 相机模块支持相机业务的开发,开发者可以通过已开放的接口实现相机硬件的访问.操作和新功能开发,最常见的操作如:预览.拍照.连拍和录像等. 相机静态能力:用于描述相 ...
- HarmonyOS之深入解析WLAN的功能和使用
一.WLAN 简介 无线局域网(Wireless Local Area Networks,WLAN),是通过无线电.红外光信号或者其他技术发送和接收数据的局域网,用户可以通过 WLAN 实现结点之间无 ...
- HarmonyOS之深入解析NFC的功能和使用
一.简介 NFC(Near Field Communication,近距离无线通信技术) 是一种非接触式识别和互联技术,让移动设备.消费类电子产品.PC 和智能设备之间可以进行近距离无线通信. Har ...
- IOS视频编辑功能详解上篇-添加水印
前言 用代码在简单视频编辑中,主要就是加美颜.水印(贴图).视频截取.视频拼接.音视频的处理,在美颜中,使用GPUImage即可实现多种滤镜.磨皮美颜的功能,并且可以脸部识别实时美颜等功能,这个有很多 ...
- 完爆Facebook/GraphQL,APIJSON全方位对比解析(一)-基础功能
相关阅读: 完爆Facebook/GraphQL,APIJSON全方位对比解析(二)-权限控制 完爆Facebook/GraphQL,APIJSON全方位对比解析(三)-表关联查询 自APIJSON发 ...
- python视频下载-Python实现视频下载功能
最近一两年短视频业务风生水起,各个视频网站都有各自特色的短视频内容.如果有这样一个程序,可以把各大视频网站的热门用户最新发布的视频都下载下来,不仅方便自己观看,还可以将没有版权的视频发布在个人社交网站 ...
- python编程实例视屏-使用Python实现视频下载功能实例代码
最近一两年短视频业务风生水起,各个视频网站都有各自特色的短视频内容.如果有一个程序可以把各大视频网站的热门用户最新发布的视频下载下来,不仅方便了观看,还可以将没有版权的视频发布在个人社交网站上,增加自 ...
- 基于OpenGL的Android系统视频转换功能实现
第1章OpenGL ES 3D图形编程首先OpenGL.OpenGL的英文全称是OpenGL Graphics Library,中午名称是开发式图形库.OpenGL为程序开发人员定义了一个 ...
最新文章
- 多线程共享全局变量以及锁机制
- GATB的使用小例子test.cpp
- 智慧停车介绍、产业链市场全透析
- 5 java中的集合类_java基础(5)-集合类1
- linux shell程序设计实验报告,linux的shell脚本实验报告
- 部署用于生产的Exceptionlees(一个强大易用的日志收集服务)
- 网易云音乐评论催泪刷屏?我用Python抓取了1008328条热评告诉你为什么!
- 如何做到“对扩展开放、修改关闭”?
- 剑指offer-二叉树
- VS2010 中 error 2732: 链接规范与的早期规范冲突 的解决
- 文件I/O(不带缓冲)之read函数
- NBA历史上50大巨星2
- 黑马程序员Java零基础视频教程(2022最新Java)B站视频学习笔记-Day2-Java基础概念
- wordpress主题转html,WordPress主题的 HTML静态页面模板制作教程
- Gtk-ERROR **: GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not suppor
- uni.navigateBack直接返回到首页
- 多个三元表达式的写法
- javaScript:实现倒计时定时器setInterval的开始计时、暂停计时、停止计时效果
- 潭州学院java大型企业内部技术_【JAVA教程】分享5款课提高Java开发性能的调试工具-潭州JAVA...
- 微软 Win11 22H2 (KB5017321) 更新失败并显示下载错误 0x800F0806,修复方法来了