跳到主要内容

音视频播放

更新时间:2025-07-02 14:54:22

提供设备的直播、点播、截图、录制等相关功能

播放器的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);
}

onPlayStateChanged回调

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.PLAYING播放出图(视频出首个画面)
IoTPlayerStateEnum.PAUSED暂停播放
IoTPlayerStateEnum.COMPLETED播放完成
code注释
IoTPlayerErrorCodes.ERROR_CODE_CON_FAILED=100000直播建立连接失败
IoTPlayerErrorCodes.ERROR_CODE_P2P_CON_FAILED=1000001P2P建立连接失败
IoTPlayerErrorCodes.ERROR_CODE_P2P_LIMIT=1000004P2P播放通道已达设备最大支持数量
IoTPlayerErrorCodes.ERROR_CODE_SDCARD_LIMIT=1000009SDCard播放通道已达设备最大支持数量
IoTPlayerErrorCodes.ERROR_CODE_LIVE_FAILED=1000011直播连接服务失败(播放设备超时)
IoTPlayerErrorCodes.ERROR_CODE_SDCARD_SDP_TIMEOUT=1000013播放SDCard连接服务失败
IoTPlayerErrorCodes.ERROR_CODE_SDP_TIMEOUT=1000014直播连接服务失败(app信令超时)
IoTPlayerErrorCodes.ERROR_CODE_SDCARD_PLAYBACK_END=1000015SDCard播放已经没有数据
IoTPlayerErrorCodes.ERROR_CODE_PLAYBACK_URL_FAILED=1000016获取云回看地址失败

onPlayMessage 回调

code注释
IoTPlayerMsgEnum.MSG_VIDEO_CODEC_UNSUPPORTED不支持硬解(默认),需要转软解

初始化示例

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多目设备是否是多个镜头一起播放

停止播放

注意

停止Player,播放器停止后,必须重新调用prepare

请在退出播放界面,停止播放

//停止放器
mPlayerCtrl.stop();
mPlayerCtrl = null

软硬解切换

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

调用前需要先停止播放器

//停止放器
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;
}
  • 开始录制/停止录制

recordStart需要在播放成功后调用

    /**
* 开始边播边录
* @param filePath 录制文件存储目录
* @return
*/
boolean recordStart(String filePath);

/**
* 结束边播边录
* @return
*/
boolean recordStop();
  • 设置录制回调

请在每次recordStart前设置回调,recordStop时会主动清除设置的listener

/**
* 设置边播边录回调
* @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);
}
});

画面旋转

版本要求:1.4.2

设置播放画面旋转角度,需要在播放成功后调用

/**
* 设置播放画面旋转角度
* @param rotation 角度,仅支持:0、90、180、270
* @return
*/
fun setVideoRotation(rotation: Int)

示例

mPlayerCtrl.setVideoRotation(180);

静音

调用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);

获取播放时间戳

获取当前播放绝对时间戳,可能为0

long timestamp = mPlayerCtrl.getCurrentAbsoluteTime();

直播码率

获取直播时码率 单位: bps

long bitrate = mPlayerCtrl.getBitrate();

直播帧率

获取直播时帧率 单位: fps

long fps = mPlayerCtrl.getPlayFPS();

直播预连接

使用场景:设备列表展示界面,当设备处于列表可见区域时调用,用于优化直播首屏效果

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);
}
}

播放示例

提供播放器使用示例

注意

退到后台,请调用stop,回到前台重新prepare 再 start

基础示例

以在Fragment为例,在Activity中接入播放器同理,注意在各生命周期对播放接口的使用

退出播放界面时,请停止播放

package com.polaris.iot.appsdk.xsdemoapp.ui.testplay;

import static androidx.navigation.Navigation.findNavController;

import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.polaris.iot.appsdk.libcommon.log.IoTLogger;
import com.polaris.iot.appsdk.libplayer.IoTPlayerCtrl;
import com.polaris.iot.appsdk.libplayer.IoTPlayerInterface;
import com.polaris.iot.appsdk.libplayer.IoTPlayerParam;
import com.polaris.iot.appsdk.libplayer.enums.IoTPlayerMsgEnum;
import com.polaris.iot.appsdk.libplayer.enums.IoTPlayerStateEnum;
import com.polaris.iot.appsdk.libplayer.enums.IoTStreamTypeEnum;
import com.polaris.iot.appsdk.libplayer.enums.VideoDecodeModeEnum;
import com.polaris.iot.appsdk.libplayer.hook.IIoTPlayerListener;
import com.polaris.iot.appsdk.libplayer.model.IoTDeviceInfo;
import com.polaris.iot.appsdk.libplayer.model.IoTPlayerViewInitParam;
import com.polaris.iot.appsdk.libuserdevicemgr.model.DeviceInfo;
import com.polaris.iot.appsdk.xsdemoapp.R;
import com.polaris.iot.appsdk.xsdemoapp.databinding.FragmentTestPlayBinding;

public class PlayerTestFragment extends Fragment implements IIoTPlayerListener {
private static final String TAG = "PlayerTestFragment";

public static PlayerTestFragment newInstance(DeviceInfo deviceInfo) {

Bundle args = new Bundle();
args.putSerializable("deviceInfo", deviceInfo);
PlayerTestFragment fragment = new PlayerTestFragment();
fragment.setArguments(args);
return fragment;
}

private FragmentTestPlayBinding binding;

private DeviceInfo mDeviceInfo;

private IoTDeviceInfo iotDevice;
private IoTPlayerCtrl playerCtrl;

private DisplayMetrics mDisplayMetrics;

public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
IoTLogger.d(TAG, "onCreateView");

binding = FragmentTestPlayBinding.inflate(inflater, container, false);
Bundle bundle = getArguments();
if (bundle == null) {
Intent intent = requireActivity().getIntent();
if (intent != null) bundle = intent.getExtras();
}
if (bundle != null) {
mDeviceInfo = (DeviceInfo) bundle.getSerializable("deviceInfo");
}
mDisplayMetrics = new DisplayMetrics();
requireActivity().getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);

initView();

return binding.getRoot();
}


@Override
public void onDestroyView() {
super.onDestroyView();
IoTLogger.d(TAG, "onDestroyView");
iotDevice = null;
playerCtrl = null;
}


@Override
public void onStart() {
super.onStart();
IoTLogger.d(TAG, "onStart initPlayer");
initPlayer();

}


private void initView() {

binding.llTitleBarWrapper.tvTitleBarTitle.setText("播放Fragment");
binding.llTitleBarWrapper.ibTitleBarLeft.setOnClickListener(v -> {
requireActivity().onBackPressed();
});

ImageButton ibTitleBarRight = binding.llTitleBarWrapper.ibTitleBarRight;
ibTitleBarRight.setVisibility(View.VISIBLE);
ibTitleBarRight.setOnClickListener(v -> {
findNavController(v).navigate(R.id.test_setting_frag, null);
});

binding.btnToLandscape.setOnClickListener(v -> {
showLandscape(true);
});
binding.btnToPortal.setOnClickListener(v -> {
showLandscape(false);
});
}


@Override
public void onResume() {
super.onResume();
IoTLogger.d(TAG, "onResume");
if (playerCtrl != null) playerCtrl.resume();

}

@Override
public void onPause() {
super.onPause();
IoTLogger.d(TAG, "onPause");
if (playerCtrl != null) playerCtrl.pause();
}

@Override
public void onStop() {
super.onStop();
IoTLogger.d(TAG, "onStop");
if (playerCtrl != null) playerCtrl.stop();
}


private void initPlayer() {
if (mDeviceInfo == null) throw new IllegalStateException("need device info");

if (playerCtrl == null) {

// val deviceInfo = DeviceInfo("","","")
iotDevice = IoTDeviceInfo.copyFrom(mDeviceInfo);
IoTLogger.d(TAG, "init iotDevice=" + (iotDevice));
IoTPlayerViewInitParam param = new IoTPlayerViewInitParam(VideoDecodeModeEnum.HARDWARE, iotDevice);

param.setStreamType(IoTStreamTypeEnum.MAIN);
//IoTPlayerCtrl 的初始化
binding.iotPlayerView.init(param);
playerCtrl = binding.iotPlayerView.getPlayerCtrl();
playerCtrl.setOnPlayerListener(this);
IoTLogger.d(TAG, "init ");
}
playerCtrl.prepare(new IoTPlayerParam());
playerCtrl.start();
}


@Override
public void onPlayStateChanged(@NonNull IoTPlayerStateEnum playState, @Nullable Integer code) {
IoTLogger.d(TAG, "onPlayMessage code=" + code + " playState=" + playState);
}

@Override
public void onPlayMessage(@NonNull IoTPlayerMsgEnum code, int extra) {
IoTLogger.d(TAG, "onPlayMessage code=" + code + " extra=" + extra);

}

@Override
public void onPlayerVideoSize(@Nullable IoTPlayerInterface player, int width, int height) {
IoTLogger.d(TAG, "onPlayMessage width=" + width + " height=" + height);
//根据播放视频的宽高比例,调整播放窗口,避免画面变形
FrameLayout playerViewWrapper = binding.playerViewWrapper;
ViewGroup.LayoutParams layoutParams = playerViewWrapper.getLayoutParams();
layoutParams.width = mDisplayMetrics.widthPixels;
layoutParams.height = Math.min(mDisplayMetrics.widthPixels * height / width, mDisplayMetrics.widthPixels * 9 / 16);
playerViewWrapper.setLayoutParams(layoutParams);

}

public void showLandscape(boolean isLandscape) {
requireActivity().setRequestedOrientation(
isLandscape ? ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
: ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
);
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
boolean isLandscape = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
ViewGroup.LayoutParams layoutParams = binding.playerViewWrapper.getLayoutParams();
if (isLandscape) {
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;

binding.llTitleBarWrapper.llTitleBarWrapper.setVisibility(View.GONE);
binding.btnToPortal.setVisibility(View.VISIBLE);
} else {
layoutParams.width = mDisplayMetrics.widthPixels;
int videoWidth = playerCtrl.getVideoWidth();
int videoHeight = playerCtrl.getVideoHeight();
IoTLogger.d(TAG, "onConfigurationChanged videoWidth=" + videoWidth + ",videoHeight=" + videoHeight);
if (videoWidth > 0 && videoHeight > 0) {
layoutParams.height = (mDisplayMetrics.widthPixels) * videoHeight / videoWidth;
} else {
layoutParams.height = (mDisplayMetrics.widthPixels) * 9 / 16;
}
binding.llTitleBarWrapper.llTitleBarWrapper.setVisibility(View.VISIBLE);
binding.btnToPortal.setVisibility(View.GONE);
}
binding.flexboxLayout.setVisibility(isLandscape ? View.GONE : View.VISIBLE);
binding.playerViewWrapper.setLayoutParams(layoutParams);

super.onConfigurationChanged(newConfig);
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mainConstraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">


<FrameLayout
android:id="@+id/playerViewWrapper"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="h,16:9"
app:layout_constraintTop_toBottomOf="@id/llTitleBarWrapper">

<com.polaris.iot.appsdk.libplayer.IoTPlayerView
android:id="@+id/iotPlayerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<Button
android:id="@+id/btnToPortal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="竖屏" />
</FrameLayout>

<com.google.android.flexbox.FlexboxLayout
android:id="@+id/flexboxLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:paddingHorizontal="16dp"
app:alignItems="stretch"
app:flexWrap="wrap"
app:justifyContent="space_evenly"
app:layout_constraintTop_toBottomOf="@id/playerViewWrapper">

<Button
android:id="@+id/btnToLandscape"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="横屏" />
</com.google.android.flexbox.FlexboxLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

多目设备播放

请先查阅 【播放示例-基础示例】

注意
  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); //kotlin param.isPlayMultiLens = 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); //kotlin param2.isPlayMultiLens = 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();
}