信息发布系统中需要支持海康视频监控预览功能,下面将列出功能实现相关流程
文末附带demo
准备工作(省略步骤,module文件和so文件见demo)
1.引用module
//组件依赖
implementation project(path: ':hatom-video-player')
2.创建jnilib,复制粘贴so库文件
3.build.gradle文件
defaultConfig {
...
ndk{
abiFilters 'arm64-v8a','armeabi-v7a'
}
...
}
正式开始:
1.manifest文件,申请权限,开启硬件加速(SurfaceView需要)
<uses-permission android:name="android.permission.INTERNET" />
<!-- 存储 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:name=".MyApp"
android:allowBackup="true"
android:hardwareAccelerated="true"
...
</application>
2.自定义Application,初始化sdk
public class BaseApp extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
HatomPlayerSDK.init(this, "", isAppDebug());
}
public static Context getContext() {
return context;
}
public static boolean isAppDebug() {
if ("".equals(context.getPackageName())) return false;
try {
PackageManager pm = context.getPackageManager();
ApplicationInfo ai = pm.getApplicationInfo(context.getPackageName(), 0);
return ai != null && (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return false;
}
}
}
3.MainActivity中调用
//监控视频短链接地址
public static final String playUrl = "rtsp://61.53.68.15:554/openUrl/NCfAEgM";
//创建HatomPlayer实例
HatomPlayer hatomPlayer = new DefaultHatomPlayer();
//onCreate中增加回调
binding.texture.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
//设置播放画面显示surface,支持TextureView和SurfaceView
hatomPlayer.setSurfaceTexture(binding.texture.getSurfaceTexture());
//播放前设置播放配置(可选)
PlayConfig playConfig = new PlayConfig();
//使用硬解码
playConfig.hardDecode = false;
//开启智能信息
playConfig.privateData = false;
hatomPlayer.setPlayConfig(playConfig);
//设置播放参数
//realPlayUrl为预览短链接,需要通过调用openApi获取
hatomPlayer.setDataSource(playUrl, null);
//设置播放回调
hatomPlayer.setPlayStatusCallback((status, s) -> {
switch (status) {
case SUCCESS:
Log.i("swyLog", "播放成功");
break;
case FAILED:
case EXCEPTION:
case FINISH:
hatomPlayer.stop();
Log.i("swyLog", "error is : " + MessageFormat.format("播放失败,错误码为:{0}", convertToHexString(s)));
break;
default:
break;
}
});
hatomPlayer.start();
}
@Override
public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
}
});
//格式化错误码方法
public static String convertToHexString(String errorCode) {
if (errorCode.startsWith("0x")) {
return errorCode;
}
if (TextUtils.isEmpty(errorCode)) {
return "";
}
int parseInt = Integer.parseInt(errorCode);
StringBuilder hexCode = new StringBuilder(Integer.toHexString(parseInt));
if (hexCode.length() < 8) {
int count = 8 - hexCode.length();
for (int i = 0; i < count; i++) {
hexCode.insert(0, "0");
}
}
return MessageFormat.format("{0}{1}", "0x", hexCode.toString());
}
重要说明:
binding.texture.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
//设置播放画面显示surface,支持TextureView和SurfaceView
hatomPlayer.setSurfaceTexture(binding.texture.getSurfaceTexture());
这里使用的TextureView.getSurfaceTexture,如果不增加SurfaceTextureListener监听,则会无法正常显示监控预览,另外,根据自己在设备上实际测试发现,从设置该回调,到进入onSurfaceTextureAvailable回调,中间会有一段比较长的时间(秒级)
实际业务场景遇到的问题分享:
信息发布系统的业务场景里,因为要单独定义一个组件PreviewWidget,然后父布局动态的addView加载该组件,因为MainActivity中需要执行业务,然后组件中只给外部返回一个hatomPlayer对象,但是把后续代码拿出来之后,就发现总是白屏,显示不出来,打断点发现,texture.getSurfaceTexture总是拿到空,想了很多办法都无法解决。最终发现的问题所在,就是上面说的进入回调会有一个秒级的延时,所以,最终的解决方法就是PreviewWidget中的onSurfaceTextureAvailable响应之后,给MainActivity发event事件通知,然后MainActivity再去执行后续逻辑,至此问题就解决了,代码如下,可以参考一下便于理解本段表述的意思
PreviewWidget
texture_view.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
hatomPlayer.setSurfaceTexture(texture_view.getSurfaceTexture());
LiveDataBus.getInstance()
.with(EventBus.PREVIEW_AVAILABLE, PreviewAvailableEvent.class)
.postValue(new PreviewAvailableEvent());
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
});
MainActivity
LiveDataBus.getInstance()
.with(EventBus.PREVIEW_AVAILABLE, PreviewAvailableEvent.class)
.observe(this, event -> {
showTextures();
});
public void showTextures() {
if (TextUtils.isEmpty(previewUrl)) {
Log.i("swyLog", "监控预览地址为空");
return;
}
//播放前设置播放配置(可选)
PlayConfig playConfig = new PlayConfig();
//使用硬解码
playConfig.hardDecode = true;
//开启智能信息
playConfig.privateData = true;
hatomPlayer.setPlayConfig(playConfig);
//设置播放参数
//预览短链接,需要通过调用openApi获取
// String url = "rtsp://61.53.68.15:554/openUrl/e9KXHVu";
hatomPlayer.setDataSource(previewUrl, null);
//设置播放回调
hatomPlayer.setPlayStatusCallback((status, s) -> {
switch (status) {
case SUCCESS:
runOnUiThread(() -> {
previewWidget.setError("");
Log.i("swyLog", "播放成功");
});
break;
case FAILED:
case EXCEPTION:
case FINISH:
runOnUiThread(() -> {
hatomPlayer.stop();
previewWidget.setError(MessageFormat.format("播放失败,错误码为:{0}", convertToHexString(s)));
Log.i("swyLog", "error is : " + MessageFormat.format("播放失败,错误码为:{0}", convertToHexString(s)));
});
break;
default:
break;
}
});
hatomPlayer.start();
}
至此完结