跳到主要内容

存储卡

更新时间:2026-07-31 19:58:04

提供存储卡录制不同方式的播放能力

package com.polaris.iot.appsdk.libplayback

object SDCardService {
/**
* 按时间段获取SD卡录制文件
*
* @param params 请求参数 [SDCardRecordQueryReq]
* @param listener 回调 [OnResultListener]<[RecordQueryRsp]>
*/
@JvmStatic
fun recordTimeQuery(params: SDCardRecordQueryReq, listener: OnResultListener<RecordQueryRsp>)

/**
* 按文件获取SD卡录制文件
*
* @param params 请求参数 [SDCardRecordQueryReq]
* @param listener 回调 [OnResultListener]<[RecordFileQueryRsp]>
*/
@JvmStatic
fun recordFileQuery(params: SDCardRecordQueryReq, listener: OnResultListener<RecordFileQueryRsp>)

/**
* 按时间段获取事件文件
*
* @param params 请求参数 [SDCardEventQueryReq]
* @param listener 回调 [OnResultListener]<[EventQueryRsp]>
*/
@JvmStatic
fun eventTimeQuery(params: SDCardEventQueryReq, listener: OnResultListener<EventQueryRsp>)

/**
* 按月查询录制统计
*
* @param monthQueryReq
* @param listener
*/
@JvmStatic
fun monthRecordQuery(monthQueryReq: SDCardRecordMonthQueryReq, listener: OnResultListener<MonthQueryRsp>)
}

按时间录制列表

时间跨度不能超过7天,开始时间不能大于结束时间

分页逻辑是查询beginTime至endTime时间段内按时间降序数据 前pageSize条数据。下 一页数据将上次返回的nextEndTime 作为下次请求的endTime

返回列表倒序排列


/**
* SD卡查询条件
*
* @property productKey
* @property deviceName
* @property beginTime 查询开始时间。
* @property endTime 查询结束时间。
* @property pageSize
* @constructor Create empty S d card record query req
*/
data class SDCardRecordQueryReq(
var productKey: String,

var deviceName: String,

var beginTime: Long,

var endTime: Long,

var pageSize: Int
) {
constructor(productKey: String, deviceName: String, beginTime: Long, endTime: Long) : this(productKey, deviceName, beginTime, endTime, 100)

/**
* 录像类型:0 计划录像,1 报警录像,2 主动录像 99:所有类型
*/
var recordType: Int = 99

/**
* 是否压缩数据 0不压缩(默认) 1压缩 版本要求:v1.4.1
* 需要区分设备是否有压缩能力
*/
var compressAck: Int = 0
}

示例

String iotId = ""
long endTime = System.currentTimeMillis();
long beginTime = endTime - 6 * 3600 * 1000;

final RecordQueryReq recordQueryReq = new SDCardRecordQueryReq(mPlayDeviceInfo.getProductKey(), mPlayDeviceInfo.getDeviceName(), beginTime, endTime);

//mPanelDevice 见物模型初始化
//初始化成功后调用判断设备是否具有压缩能力 默认不压缩
int compressAck = mPanelDevice.supportAbility(ThingAbilityEnum.COMPRESS_DATA) ? 1 : 0;
recordQueryReq.setCompressAck(mCompressAck);

SDCardService.recordTimeQuery(recordQueryReq, new OnResultListener<RecordQueryRsp>() {
@Override
public void onError(@NonNull IoTSDKError error) {

}

@Override
public void onResult(RecordQueryRsp result) {
final List<TimelineRecordInfo> RecordInfoList = result.getRecordFileList();
}
});

按时间录制列表播放

IoTPlayerParam param = new IoTPlayerParam();
//从录制数据接口返回
boolean isSDCardPlayback = true;
IoTPlayerSeekParam seekParam = new IoTPlayerSeekParam(beginTime,endTime,isSDCardPlayback )
mPlayerCtrl.prepare(param,seekParam);
mPlayerCtrl.start();

//回看seek
IoTPlayerSeekParam seekParam = new IoTPlayerSeekParam(beginTime,endTime,isSDCardPlayback)
mPlayerCtrl.seekTo(seekParam);

按文件录制列表

时间跨度不能超过7天,开始时间不能大于结束时间

分页逻辑是查询beginTime至endTime时间段内按时间降序数据 前pageSize条数据。下 一页数据将上次返回的nextEndTime 作为下次请求的endTime

返回列表倒序排列

String iotId = ""
long endTime = System.currentTimeMillis();
long beginTime = endTime - 6 * 3600 * 1000;

SDCardRecordQueryReq recordQueryReq = new SDCardRecordQueryReq(mDeviceInfo.getProductKey(), mDeviceInfo.getDeviceName(), beginTime, endTime);

//mPanelDevice 见物模型初始化
//初始化成功后调用判断设备是否具有压缩能力 默认不压缩
int compressAck = mPanelDevice.supportAbility(ThingAbilityEnum.COMPRESS_DATA) ? 1 : 0;
recordQueryReq.setCompressAck(mCompressAck);

SDCardService.recordFileQuery(recordQueryReq, new OnResultListener<RecordFileQueryRsp>() {
@Override
public void onError(@NonNull IoTSDKError error) {

}

@Override
public void onResult(RecordFileQueryRsp result) {
List<SDCardRecordFileInfo> recordInfoList = result.getRecordFileList();
}
});

按文件录制播放

IoTPlayerParam param = new IoTPlayerParam();
//录制文件名
String filename = ""
//播放绝对时间
long beginTime;
//录制文件结束时间(绝对时间)
long endTme;
//播放绝对时间相对于文件起始时间(绝对时间)的偏移时间
int seekPos;
IoTPlayerSeekParam seekParam = new IoTPlayerSeekParam(beginTime,endTime,filename, seekPos)
mPlayerCtrl.prepare(param,seekParam);
mPlayerCtrl.start();

//回看seek
IoTPlayerSeekParam seekParam = new IoTPlayerSeekParam(beginTime,endTime,filename, seekPos)
mPlayerCtrl.seekTo(seekParam);

录制事件列表

时间跨度不能超过7天,开始时间不能大于结束时间

分页逻辑是查询beginTime至endTime时间段内按时间降序数据 前pageSize条数据。下 一页数据将上次返回的nextEndTime 作为下次请求的endTime

返回列表倒序排列

事件播放同按时间录制列表播放


data class SDCardEventQueryReq(
var productKey: String,

var deviceName: String,

/**
* 查询开始时间。单位秒。
*/
var beginTime: Long,

/**
* 查询结束时间。单位秒。
*/
var endTime: Long,


var pageSize: Int
) {
constructor(productKey: String, deviceName: String, beginTime: Long, endTime: Long) : this(productKey, deviceName, beginTime, endTime, 100)

/**
* 报警类型 不传默认全部
*/
var eventType: Int? = null


/**
* 是否压缩数据 0不压缩(默认) 1压缩 版本要求:v1.4.1
* 需要区分设备是否有压缩能力
*/
var compressAck: Int = 0
}

示例

String iotId = ""
long endTime = System.currentTimeMillis();
long beginTime = endTime - 6 * 3600 * 1000;


final SDCardEventQueryReq queryReq = new SDCardEventQueryReq(mDeviceInfo.getProductKey(), mDeviceInfo.getDeviceName(), beginTime, endTime);


//mPanelDevice 见物模型初始化
//初始化成功后调用判断设备是否具有压缩能力 默认不压缩
int compressAck = mPanelDevice.supportAbility(ThingAbilityEnum.COMPRESS_DATA) ? 1 : 0;
queryReq.setCompressAck(mCompressAck);

SDCardService.eventTimeQuery(queryReq, new OnResultListener<EventQueryRsp>() {
@Override
public void onError(@NonNull IoTSDKError error) {

}

@Override
public void onResult(EventQueryRsp result) {
final List<TimelineEventInfo> eventInfoList = result.getEventList();
}
});

按月统计录制

按月查询每天是否有录制,使用场景:在日历上加小红点

示例

private void startRecordMonthQuery() throws ParseException {
Date queryDate = getQueryBeginTime();
Calendar calendar = Calendar.getInstance();
calendar.setTime(queryDate);
SDCardRecordMonthQueryReq params = new SDCardRecordMonthQueryReq(
mDeviceInfo.getProductKey(),
mDeviceInfo.getDeviceName(),
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH) + 1
);
SDCardService.monthRecordQuery(params, new OnResultListener<>() {
@Override
public void onError(@NonNull IoTSDKError error) {
hideLoading();
showToast("月录制查询失败," + error.getMessage());
}

@Override
public void onResult(MonthQueryRsp result) {
runOnUiThread(() -> {
hideLoading();
List<CommonListItem> list = new ArrayList<>();
for (MonthQueryItem item : Objects.requireNonNull(result.getDayCntList())) {
list.add(new CommonListItem(item.getDateStr(), String.valueOf(item.getCount())));
}
mCommonListAdapter.setDataList(list);
showToast("月录制查询成功");
});
}
});
}

获取存储卡图片

通过图片ID获取SD卡存储的图片

注意
  1. 请严格控制请求频率, 大量获取图片会影响设备性能,导致请求失败
  2. 请不要重复发起相同图片的获取请求,并且缓存获已取到的图片
  3. 不再使用请及时销毁实例
package com.polaris.iot.appsdk.libplayer.datachannel
/**
* 获取设备SD卡图片
*
* @property context 上下文件
* @property deviceInfo 设备信息[IoTDeviceInfo]
* @constructor Create empty Io t media pusher
*/
class SDCardPictureGetter(
context: Context,
deviceInfo: IoTDeviceInfo,
) {
/**
* 获取SD卡事件缩略图
*
* @param picId 图片ID 比如从SD卡事件列表返回的TimelineEventInfo对象中获取picId
* @param listener [OnResultListener]<[Bitmap]>
*/
fun getPicture(picId: String, listener: OnResultListener<Bitmap>)
/**
* 获取SD卡事件缩略图
*
* @param picId 图片ID
* @param listener [OnResultListener]<[Bitmap]>
* @param timeoutMS 超时,毫秒
*/
fun getPicture(picId: String, listener: OnResultListener<Bitmap>, timeoutMS: Long)
/**
* 销毁对象
*
*/
fun destroy()

/**
* 是否支持SD卡图片下载
*
* @return
*/
fun isSupport(): Boolean
}

示例

private var mSDCardThumbnailGetter: SDCardPictureGetter? = null

private fun createSDCardPictureGetter() {
if (mSDCardThumbnailGetter == null) {
mSDCardThumbnailGetter = SDCardPictureGetter(mContext, IoTDeviceInfo.copyFrom(mDeviceInfo))
IoTLogger.d(TAG, "createSDCardPictureGetter ${JsonUtils.toJsonString(this.mDeviceInfo)}")
if (mSDCardThumbnailGetter?.isSupport() != true) {
destroy()
}
}
}

fun destroy() {
mSDCardThumbnailGetter?.let {
mSDCardThumbnailGetter?.destroy()
mSDCardThumbnailGetter = null
}
}
/**
* @param picId 图片ID 比如从SD卡事件列表返回的TimelineEventInfo对象中获取picId
*/
fun getPic(picId:String){
val fileKey = mDeviceInfo.iotId + picId
val ivEventPic = (ImageView)findViewById(R.id.ivEventPic)
ivEventPic.tag = fileKey
val listener = object : OnResultListener<Bitmap> {
override fun onResult(result: Bitmap) {
if (ivEventPic.tag != fileKey) return
IoTLogger.d(TAG, " sdcard event picId=${picId} getPicture success. ")
Glide.with(mContext).load(result)
.placeholder(R.drawable.device_default)
.error(R.drawable.device_default).into(ivEventPic)
}

override fun onError(error: IoTSDKError) {
if (ivEventPic.tag != fileKey) return
IoTLogger.e(TAG, "sdcard event picId=${picId} getPicture error. ", error)
}

}
mSDCardThumbnailGetter?.getPicture(picId, listener)
}

存储卡录制视频下载

使用场景:下载设备端存储卡录制录制视频

请先申请文件写入权限

package com.polaris.iot.appsdk.libplayer

/**
* 回看视频下载
*
* @param deviceInfo 设备信息
* @param fileOption 文件选项
* @param downloaderListener 下载状态监听
* @param isSdCard 是否是SdCard回看
* @param context 上下文 isSdCard=true时必传
*/
class IoTPlaybackDownloader(
deviceInfo: DeviceInfo,
fileOption: IoTPlaybackDownloadFileOption,
downloaderListener: IoTPlaybackDownloadListener,
isSdCard: Boolean = false,
context: Context? = null,
){

/**
* 开始下载 最大5分钟
*
* @param beginTime
* @param endTime
*/
fun start(beginTime: Long, endTime: Long)

/**
* 双目设备开始下载 最大5分钟
*
* @param beginTime 开始时间
* @param endTime 结束时间
* @param lensId 设备镜头id
*/
fun start(beginTime: Long, endTime: Long, lensId: Int?)


/**
* 停止下载
*
* @param beginTime
* @param endTime
*/
fun stop()
}

下载文件选项

package com.polaris.iot.appsdk.libplayer.model

/**
* 卡录制下载文件配置选项
*
* @property saveDirection 下载文件保存目录
* @property fileBasename 下载文件名称前缀
* @property maxFileDuration 下载文件总时长(单位:秒)
* @constructor Create empty Io t stream download file option
*/
data class IoTPlaybackDownloadFileOption(
val saveDirection: String,
var fileBasename: String?,
var maxFileDuration: Float?
) {
constructor(saveDirection: String) : this(saveDirection, null, null)
}

下载回调

存储卡下载增加了新错误码,详见:【云视频下载 -> 下载回调

下载错误码

详见:【云视频下载 -> 下载错误码

下载示例

注意

调用start方法后,请在收到onProgress回调且completed=true时,或收到onError回调时调用stop方法

import com.polaris.iot.appsdk.libplayer.IoTPlaybackDownloader;
private IoTPlaybackDownloader mPlaybackDownloader = null;
private String directoryPath = "录制文件保存目录"
private IoTDeviceInfo mPlayDeviceInfo = IoTDeviceInfo.copyFrom(deviceInfo)
private void startDownload() {
if (mPlaybackDownloader == null) {
IoTPlaybackDownloadFileOption fileOption = new IoTPlaybackDownloadFileOption(directoryPath);
IoTPlaybackDownloadListener downloadListener = new IoTPlaybackDownloadListener() {
@Override
public void onProgress(long progress, boolean completed) {
IoTLogger.d(TAG, "onProgress progress=" + progress + ", completed=" + completed);
if(completed) stopDownload()
}

@Override
public void onFilePath(@Nullable String filePath) {
hideLoading();
IoTLogger.i(TAG, "onFilePath filePath=" + filePath);
showToast(getString(R.string.download_success) + ":" + filePath);
}

@Override
public void onError(int code) {
hideLoading();
stopDownload();
IoTLogger.e(TAG, "onError code=" + code);
switch (code) {
case IoTPlaybackDownloadCodeEnum.SDCARD_DOWNLOAD_BUSYING:
showToast(R.string.sdcard_download_limit);
break;
case IoTPlaybackDownloadCodeEnum.POLARIS_MUXER_EINIT:
showToast(R.string.error_muxer_init);
break;
case IoTPlaybackDownloadCodeEnum.POLARIS_MUXER_EUNINIT:
showToast(R.string.error_muxer_uninit);
break;
case IoTPlaybackDownloadCodeEnum.POLARIS_MUXER_EINVAL:
showToast(R.string.error_muxer_params);
break;
case IoTPlaybackDownloadCodeEnum.POLARIS_MUXER_EFILTER:
showToast(R.string.error_muxer_filter);
break;
case IoTPlaybackDownloadCodeEnum.POLARIS_MUXER_EOUTPUTFILE:
showToast(R.string.error_output_file);
break;
}

}
};
Context applicationContext = getApplicationContext()
boolean isSDCard = mSeekParam.isPlaySDCard()
mPlaybackDownloader = new IoTPlaybackDownloader(mPlayDeviceInfo, fileOption, downloadListener, isSDCard, applicationContext);
}
IoTLogger.d(TAG, "start download startTime=" + mSeekParam.getBeginTime() + ", endTime=" + mSeekParam.getEndTime());
mPlaybackDownloader.start(mSeekParam.getBeginTime(), mSeekParam.getEndTime());

//多目设备下载指定镜头录像需要传lensId
// int lensId = 0
//mPlaybackDownloader.start(mSeekParam.getBeginTime(), mSeekParam.getEndTime(), lensId);
}

private void stopDownload() {
if (mPlaybackDownloader != null) mPlaybackDownloader.stop();
}