音视频播放
更新时间:2025-04-25 10:37:52
提供设备的直播、点播、截图、录制等相关功能
播放器的View是 IoTPlayerView ,类似于 MediaPlayer,View 和 Controller分离。
<com.polaris.iot.appsdk.libplayer.IoTPlayerView
android:id="@+id/iotPlayerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
播放器View初始化
/**
* 初始化,设置解码模式及设备信息
* @param mode视频确码模式,硬解或软解
* @param playDeviceInfo 设备信息信息
*/
class IoTPlayerViewInitParam(VideoDecodeModeEnum mode, IoTDeviceInfo playDeviceInfo)
public void init(IoTPlayerViewInitParam param)
示例
private DeviceInfo mDeviceInfo; //设备列表获取到的设备信息对象
private IoTDeviceInfo mPlayDeviceInfo = IoTDeviceInfo.copyFrom(mDeviceInfo)
mPlayerView = (IoTPlayerView) findViewById(R.id.iotPlayerView);
//Player初始化
IoTPlayerViewInitParam param = new IoTPlayerViewInitParam(VideoDecodeModeEnum.HARDWARE, mPlayDeviceInfo );
mPlayerView.init(param);
获取IoTPlayerCtrl
IoTPlayerCtrl类负责控制播放器,用于直播、回放、截图等功能
/**
* 获取IoTPlayerCtrl
*/
public IoTPlayerCtrl getPlayerCtrl();
/**
* 播放状态回调
*/
void setOnPlayerListener(IIoTPlayerListener listener)
IIoTPlayerListener
interface IIoTPlayerListener{
/**
* 当播放器的播放状态发生变化,在此方法中回调不同的播放状态
*
* @param playState 播放状态:
*/
void onPlayStateChanged(IoTPlayerStateEnumplayState playState, int code);
/**
* Player播放过程中交互消息回调
* @param code 消息code
* @param extra 消息额外的值回调
*/
void onPlayMessage(int code, int extra);
/**
* 当视频开始播放时回调视频真实尺寸,需要对{@link IoTPlayerView IoTPlayerView}重新调整大小
*
* @param player
* @param width
* @param height
*/
void onPlayerVideoSize(IoTPlayerInterface player, int width, int height);
}
播放状态
playState | 注释 |
---|---|
IoTPlayerStateEnum.STOPPED | 播放停止/未开始 |
IoTPlayerStateEnum.STOPPING | 播放结束中 |
IoTPlayerStateEnum.ERROR | 播放错误 |
IoTPlayerStateEnum.PREPARING | 播放准备中 |
IoTPlayerStateEnum.PREPARING_TO_START | 播放准备中,已经调用Start |
IoTPlayerStateEnum.PREPARED | 播放准备完成 |
IoTPlayerStateEnum.PREPARED_TO_START | 播放准备就绪,已经调用Start |
IoTPlayerStateEnum.BUFFERING_START | 缓冲开始 |
IoTPlayerStateEnum.BUFFERING_END | 缓冲完成 |
IoTPlayerStateEnum.PAUSED | 暂停播放 |
IoTPlayerStateEnum.COMPLETED | 播放完成 |
onPlayMessage 回调
playState | 注释 |
---|---|
IoTPlayerMsgEnum.MSG_VIDEO_CODEC_UNSUPPORTED | 不支持硬解,需要转软解 |
IoTPlayerMsgEnum.MSG_REACHED_EDGE | 放大后移动视频到达边界,1:上,2:右,4:下,8:左 |
初始化示例
import com.polaris.iot.appsdk.libplayer.model.IoTDeviceInfo;
import com.polaris.iot.appsdk.libplayer.enums.VideoDecodeModeEnum;
import com.polaris.iot.appsdk.libuserdevicemgr.model.DeviceInfo;
private DeviceInfo mDeviceInfo; //设备列表获取到的设备信息对象
private IoTDeviceInfo mPlayDeviceInfo = IoTDeviceInfo.copyFrom(mDeviceInfo)
mPlayerView = (IoTPlayerView) findViewById(R.id.iotPlayerView);
//Player初始化
IoTPlayerViewInitParam param = new IoTPlayerViewInitParam(VideoDecodeModeEnum.HARDWARE, mPlayDeviceInfo );
mPlayerView.init(param);
//IoTPlayerCtrl 的初始化
mPlayerCtrl = mPlayerView.getPlayerCtrl();
mPlayerCtrl.setOnPlayerListener(this);
播放相关
通过IoTPlayerView获取到IoTPlayerCtrl后,使用IoTPlayerCtrl来进行播放操作
/**
* 初始化直播
* @param param 播放参数
*/
void prepare(IoTPlayerParam param);
/**
* 初始化回看
* @param param 播放参数
* @param seekParam 回看参数
*/
void prepare(IoTPlayerParam param, IoTPlayerSeekParam seekParam);
/**
* 开始播放
*/
void start();
/**
* seek 到不同位置,如果seek到直播 param = null
* @param param IoTPlayerSeekParam
*/
void seekTo(IoTPlayerSeekParam param);
/**
* 恢复播放
*/
void resume();
/**
* 暂停播放
*/
void pause();
/**
* 停止Player,播放器停止后,必须重新调用prepare
*/
void stop();
直播
IoTPlayerParam param = new IoTPlayerParam();
mPlayerCtrl.prepare(param);
mPlayerCtrl.start()
回放
IoTPlayerParam param = new IoTPlayerParam();
//从数据接口返回
IoTPlayerSeekParam seekParam = new IoTPlayerSeekParam(beginTime,endTime)
mPlayerCtrl.prepare(param,seekParam);
mPlayerCtrl.start();
直播和回放切换
直播和回放互相切换可以无需重新初始化播放器,调用Seek方法即可
//直播
mPlayerCtrl.seekTo(null);
//回看
IoTPlayerSeekParam seekParam = new IoTPlayerSeekParam(beginTime,endTime)
mPlayerCtrl.seekTo(seekParam);
IoTPlayerParam
字段 | 类型 | 注释 |
---|---|---|
preload | boolean | 是否开启缓存 |
liveBufferDynamic | boolean | 直播动态buffer |
liveBufferMaxSize | int | 直播动态buffer最大值 |
playerViewBgColor | int | 播放器背景颜色 |
videoCacheSize | int | 回放缓存大小 |
muted | boolean | 是否静音播放 |
isPlayMultiLens | boolean | 多目设备是否是多个镜头一起播放 |
软硬解切换
默认硬解,但由于硬件不支持或数据异常等原因硬解失败,需要切成软解
调用前需要先停止播放器
//停止放器
mPlayerCtrl.stop();
//切换软硬解切换
mPlayerCtrl.switchVideoDecodeMode();
//当前解码模式
mPlayerCtrl.getVideoDecodeMode();
边播边录
- 申请文件写入权限
private int accessStorageWritePermission() {
String permission = Build.VERSION.SDK_INT > 32 ? Manifest.permission.READ_MEDIA_VIDEO : Manifest.permission.WRITE_EXTERNAL_STORAGE;
int permissionCheck = ContextCompat.checkSelfPermission(this, permission);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{permission}, REQUEST_PERMISSTION);
}
return permissionCheck;
}
- 开始录制/停止录制
/**
* 开始边播边录
* @param filePath 录制文件存储目录
* @return
*/
boolean recordStart(String filePath);
/**
* 结束边播边录
* @return
*/
boolean recordStop();
- 设置录制回调
/**
* 设置边播边录回调
* @param listener
* @throws IllegalArgumentException
* @throws IllegalStateException
* @throws IOException
*/
public void setOnPOLARISReorderListener(POLARISMediaPlayer.OnPOLARISReorderListener listener) throws IllegalArgumentException, IllegalStateException, IOException;
public interface OnPOLARISReorderListener {
/*
* @param POLARISMediaPlayer: 播放器对象
* @param type:返回类型,POLARISMediaPlayer.POLARIS_MP4_MUX_PROGRESS,POLARISMediaPlayer.POLARIS_MP4_MUX_FILEPATH,POLARISMediaPlayer.POLARIS_MP4_MUX_ERROR
* @param progress:录制时长,单位ms
* @param sFilePath:保存录像文件路径, type == POLARISMediaPlayer.POLARIS_MP4_MUX_FILEPATH 时返回
*/
void onPOLARISReorderCallback(POLARISMediaPlayer POLARISMediaPlayer, int type, int progress, String sFilePath);
}
示例
//开始录制
private boolean startRecord() {
if (accessStorageWritePermission() != PackageManager.PERMISSION_GRANTED) return false;
if (mPlayerCtrl != null) {
try {
mPlayerCtrl.setOnPOLARISReorderListener(new POLARISMediaPlayer.OnPOLARISReorderListener() {
@Overridepublic void onPOLARISReorderCallback(POLARISMediaPlayer POLARISMediaPlayer, int type, int progress, String sFilePath) {
if (type == POLARISMediaPlayer.POLARIS_MP4_MUX_PROGRESS) {
IoTLogger.d(TAG, "onPOLARISReorderCallback progress : " + progress);
} else if (type == POLARISMediaPlayer.POLARIS_MP4_MUX_FILEPATH) {
IoTLogger.d(TAG, "onPOLARISReorderCallback progress : " + progress + " ,FilePath : " + sFilePath);
Toast.makeText(LivePreviewActivity.this, "record success, FilePath = " + sFilePath, Toast.LENGTH_LONG).show();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
mPlayerCtrl.recordStart(DirectoryMgrUtils.getVideoRecorderDir());
isRecording = true;
}
return true;
}
//停止录制
private void stopRecord() {
if (mPlayerCtrl != null) {
mPlayerCtrl.recordStop();
}
isRecording = false;
}
截图
调用IoTPlayerCtrl.screenshot()实现,该方法通过回调返回bitmap对象
/**
* 截图
* @return
*/
Bitmap screenshot(listener: IScreenshotListener);
示例
mPlayerCtrl.screenshot(bitmap -> {
if (bitmap != null) {
showScreenShotDialog(bitmap);
}
});
静音
调用IoTPlayerCtrl.setVolume(float volume)实现
/**
* 截图
* @param volume 0:静音 1:取消静音
* @return
*/
setVolume(float volume);
示例
mPlayerCtrl.setVolume(0);
设置回看速率
调用IoTPlayerCtrl.setPlaybackRate(float rate)实现
存储卡回看播放在非 1 倍速播放时没有声音、不能边播边录及截图
/**
* 设置回放速率
*
* @param rate
* @return 设置是否成功
*/
fun setPlaybackRate(rate: Float): Boolean
示例
private final float[] mPlaybackSpeedSupport = {0.5f, 1.0f 2.0f, 4.0f};
int playbackSpeed= mPlaybackSpeedSupport[2]
mPlayerCtrl.setPlaybackRate(playbackSpeed);
获取回看速率
调用IoTPlayerCtrl.getPlaybackRate()实现
/**
* 设置回放速率
*
* @param rate
* @return 设置是否成功
*/
fun getPlaybackRate(): Float
示例
mPlayerCtrl.getPlaybackRate();
播放主子码流
- 初始化指定码流
默认主码流 IoTStreamTypeEnum.MAIN
mPlayerView = (IoTPlayerView) findViewById(R.id.iotPlayerView);
//Player初始化
IoTPlayerViewInitParam param = new IoTPlayerViewInitParam(VideoDecodeModeEnum.HARDWARE, mPlayDeviceInfo );
//指定子码流
params.setStreamType(IoTStreamTypeEnum.SUB);
mPlayerView.init(param);
- 中间切换
调用前需要先停止播放器
//停止播放器
mPlayerCtrl.stop();
//切换软硬解切换
mPlayerCtrl.switchStreamType(IoTStreamTypeEnum.SUB);
直播预连接
使用场景:设备列表展示界面,当设备处于列表可见区域时调用,用于优化直播首屏效果
package com.polaris.iot.appsdk.libplayer
/**
* 设备直播预连接管理
*/
object IoTPlayPreConnectMgr{
/**
* 通知设备设备与服务预连接
*
* @param deviceInfo
*/
@JvmStatic
fun notifyDevicePreConnect(deviceInfo: DeviceInfo)
/**
* 播放预先建立播放通道
*
* @param context
* @param deviceInfo
*/
@JvmStatic
fun preConnect(context: Context, deviceInfo: DeviceInfo)
}
示例:
rvDeviceList.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
doVisibleDeviceExtraAction();
}
super.onScrollStateChanged(recyclerView, newState);
}
});
private void doVisibleDeviceExtraAction() {
LinearLayoutManager layoutManager = (LinearLayoutManager) binding.rvDeviceList.getLayoutManager();
if (layoutManager == null) return;
int first = layoutManager.findFirstVisibleItemPosition();
int last = layoutManager.findLastVisibleItemPosition();
IoTLogger.d(TAG, "player preload first=" + first + ",last=" + last);
for (int i = first; i <= last; i++) {
IoTLogger.d(TAG, "player preload i=" + i);
DeviceInfo deviceInfo = mDeviceListAdapter.getItem(i);
//播放预建立通道 可选
IoTPlayPreConnectMgr.preConnect(requireContext(), deviceInfo);
//通知设备与服务建立直播预连接 可选
IoTPlayPreConnectMgr.notifyDevicePreConnect(deviceInfo);
}
}
多目设备播放
注意
- 多目设备播放接入需要创建多个播放器
- 初始化playerView时,需要不同IoTDeviceInfo实例,并设置lensId
- 截图、录制、静音等操作需要同时操作两个播放(根据实际业务情况来定)
示例
import com.polaris.iot.appsdk.libplayer.model.IoTDeviceInfo;
import com.polaris.iot.appsdk.libplayer.enums.VideoDecodeModeEnum;
import com.polaris.iot.appsdk.libuserdevicemgr.model.DeviceInfo;
//列表接口获取
private DeviceInfo mDeviceInfo;
IoTDeviceInfo mPlayDeviceInfo = IoTDeviceInfo.copyFrom(mDeviceInfo);
//多目设备 非多目设备,不需要设置lensId参数
if(mDeviceInfo.lensCount>1)mPlayDeviceInfo.lensId = 0
//Player初始化
mPlayerView = (IoTPlayerView) findViewById(R.id.iotPlayerView);
IoTPlayerViewInitParam param = new IoTPlayerViewInitParam(VideoDecodeModeEnum.HARDWARE, mPlayDeviceInfo );
//如果同时播放多个镜头设置,单个不用设置该参数
param.setPlayMultiLens(true);
mPlayerView.init(param);
//IoTPlayerCtrl 的初始化
mPlayerCtrl = mPlayerView.getPlayerCtrl();
IIoTPlayerListener playerListener1 = new IIoTPlayerListener()
mPlayerCtrl.setOnPlayerListener(playerListener1);
//初始化第二个播放器
if(mDeviceInfo.lensCount>1){
IoTDeviceInfo mPlayDeviceInfo2 = IoTDeviceInfo.copyFrom(mDeviceInfo);
mPlayDeviceInfo2.lensId = 1
//Player初始化
mPlayerView2 = (IoTPlayerView) findViewById(R.id.iotPlayerView2);
IoTPlayerViewInitParam param2 = new IoTPlayerViewInitParam(VideoDecodeModeEnum.HARDWARE, mPlayDeviceInfo2 );
//如果同时播放多个镜头设置,单个不用设置该参数
param2.setPlayMultiLens(true);
mPlayerView2.init(param2);
//IoTPlayerCtrl 的初始化
mPlayerCtrl2 = mPlayerView.getPlayerCtrl();
IIoTPlayerListener playerListener2 = new IIoTPlayerListener()
mPlayerCtrl2.setOnPlayerListener(playerListener2);
}
低功耗设备播放
低功耗设备由于实现方案的不同,播放的方式有所区别,以下是设备DeviceSDK中定义的几种方式
/**
* XS_IOT_WORK_MODE_LOWPOWER_PROXY = 1, //低功耗设备,代理模式,注意只有支持低功耗保活连接的设备才需要设置此模式,设置了此模式之后必须和wifi 芯片上的 lowPwrSDK配合才能工作
* XS_IOT_WORK_MODE_LONG_TIME_POWER = 2 , //长上电设备,正常链接模式(iotsdk和streamsdk运行在一个进程中)
* XS_IOT_WORK_MODE_LOWPOWER_SEPARATE = 3, //低功耗设备,iotsdk和streamsdk分离模式,iotsdk运行在wifi或4g芯片上维持信令长连接,streamsdk运行在主控芯片上
* XS_IOT_WORK_MODE_LOWPOWER_KEEPLIVE = 4, //低功耗设备,iotsdk和streamsdk运行在主控芯片上,wifi或4g芯片上仅维持简单心跳保活,支持远程唤醒
*/
注意
工作模式为1,3的低功耗设备低功耗设备与常长电设备(工作模式为2)播放流程一致,以下示例仅为工作模式4的特殊播放流程
- 先唤醒设备
- 监听设备上线
- 调用播放接口
package com.polaris.iot.appsdk.libuserdevicemgr
/**
* 低功耗设备唤醒
*
* @property mIotId 设备唯一ID
* @property mWaitTimeout 超时时长 默认30秒
* @constructor Create empty Device wake up mgr
*/
class DeviceWakeUpMgr(
private val mIotId: String,
private var mWaitTimeout: Long
){
constructor(iotId: String)
/**
* 唤醒设备
*
*/
fun wakeup()
/**
* 结束唤醒
*
*/
fun stop()
/**
* 设备状态监听
*
* @param listener
*/
fun setOnStatusListener(listener: OnResultListener<DeviceStatus>)
}
示例
import com.polaris.iot.appsdk.libuserdevicemgr.DeviceWakeUpMgr;
import com.polaris.iot.appsdk.libplayer.model.IoTDeviceInfo;
import com.polaris.iot.appsdk.libplayer.enums.VideoDecodeModeEnum;
import com.polaris.iot.appsdk.libuserdevicemgr.model.DeviceInfo;
//列表接口获取
private DeviceInfo mDeviceInfo;
private DeviceWakeUpMgr mDeviceWakeupMgr;
@Override
public void onStart() {
super.onStart();
IoTDeviceInfo mPlayDeviceInfo = IoTDeviceInfo.copyFrom(mDeviceInfo);
//Player初始化
mPlayerView = (IoTPlayerView) findViewById(R.id.iotPlayerView);
IoTPlayerViewInitParam param = new IoTPlayerViewInitParam(VideoDecodeModeEnum.HARDWARE, mPlayDeviceInfo );
mPlayerView.init(param);
//IoTPlayerCtrl 的初始化
mPlayerCtrl = mPlayerView.getPlayerCtrl();
IIoTPlayerListener playerListener1 = new IIoTPlayerListener()
mPlayerCtrl.setOnPlayerListener(playerListener1);
}
@Override
public void onResume() {
super.onResume();
//直播唤醒
if ("4".equals(mDeviceInfo.getDeviceWorkMode()) && mPlayDeviceInfo.isOnline()) {
if (mDeviceWakeupMgr == null) {
mDeviceWakeupMgr = new DeviceWakeUpMgr(mDeviceInfo.getIotId());
//监听设备状态,设备上线后开始直播
//也可以在【物模型功能->订阅设备事件】中订阅设备上下线状态
mDeviceWakeupMgr.setOnStatusListener(new OnResultListener<DeviceStatus>() {
@Override
public void onResult(DeviceStatus result) {
//更新设备状态
mDeviceInfo.setStatus(result.getStatus());
mPlayDeviceInfo = IoTDeviceInfo.copyFrom(mDeviceInfo);
IoTPlayerParam param = new IoTPlayerParam();
mPlayerCtrl.prepare(param);
mPlayerCtrl.start();
}
@Override
public void onError(@NonNull IoTSDKError error) {
}
});
}
//开始唤醒设备
mDeviceWakeupMgr.wakeup();
showPlayerLoading();
return;
}
}
@Override
public void onPause() {
//结束唤醒设备
if (mDeviceWakeupMgr != null) mDeviceWakeupMgr.stop();
}