跳到主要内容

音视频播放

更新时间: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

字段类型注释
preloadboolean是否开启缓存
liveBufferDynamicboolean直播动态buffer
liveBufferMaxSizeint直播动态buffer最大值
playerViewBgColorint播放器背景颜色
videoCacheSizeint回放缓存大小
mutedboolean是否静音播放
isPlayMultiLensboolean多目设备是否是多个镜头一起播放

软硬解切换

默认硬解,但由于硬件不支持或数据异常等原因硬解失败,需要切成软解

调用前需要先停止播放器

//停止放器
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);
}
}

多目设备播放

注意
  1. 多目设备播放接入需要创建多个播放器
  2. 初始化playerView时,需要不同IoTDeviceInfo实例,并设置lensId
  3. 截图、录制、静音等操作需要同时操作两个播放(根据实际业务情况来定)

示例

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的特殊播放流程

  1. 先唤醒设备
  2. 监听设备上线
  3. 调用播放接口
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();
}