[Fix]解决视频流功能问题

This commit is contained in:
chenfufeng
2021-11-24 10:30:29 +08:00
parent 5113a0a893
commit 4480001fba
9 changed files with 147 additions and 73 deletions

View File

@@ -36,7 +36,7 @@ class CameraListAdapter : Adapter<CameraListAdapter.CameraListHolder> {
data?.let { data?.let {
val cameraEntity = it[position] val cameraEntity = it[position]
holder.cameraInfo.text = with(cameraEntity) { holder.cameraInfo.text = with(cameraEntity) {
if (!isCarLive()) "${roadName}${crossingName}${getHeadingStr()}" else "${street}${township}" if (!isCarLive()) "${crossingName}${headingDesc}${getHeadingStr()}" else "${street}${township}"
} }
holder.bottomLine.visibility = holder.bottomLine.visibility =
if (it.size - 1 == position) View.INVISIBLE else View.VISIBLE if (it.size - 1 == position) View.INVISIBLE else View.VISIBLE

View File

@@ -23,8 +23,12 @@ import com.mogo.eagle.core.widget.media.video.SimpleVideoPlayer
import com.mogo.utils.logger.Logger import com.mogo.utils.logger.Logger
import com.shuyu.gsyvideoplayer.GSYVideoManager import com.shuyu.gsyvideoplayer.GSYVideoManager
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import com.shuyu.gsyvideoplayer.model.VideoOptionModel
import com.shuyu.gsyvideoplayer.player.IjkPlayerManager
import com.shuyu.gsyvideoplayer.player.PlayerFactory
import com.shuyu.gsyvideoplayer.utils.GSYVideoType import com.shuyu.gsyvideoplayer.utils.GSYVideoType
import kotlinx.android.synthetic.main.view_camera_list.view.* import kotlinx.android.synthetic.main.view_camera_list.view.*
import tv.danmaku.ijk.media.player.IjkMediaPlayer
import java.lang.Exception import java.lang.Exception
/** /**
@@ -88,16 +92,14 @@ class CameraListView : FrameLayout {
if (cameraEntity is CameraEntity) { if (cameraEntity is CameraEntity) {
when { when {
!cameraEntity.isCarLive() -> { !cameraEntity.isCarLive() -> {
// 开启摄像头推流 if (!cameraEntity.flvUrl.isNullOrEmpty()) {
cameraEntity.ip?.let { ip -> Logger.d(TAG, "播放地址为:${cameraEntity.flvUrl!!}ip为${cameraEntity.ip}")
// 华哥那边现在只支持一个ip"183.242.46.150",现在不用这一套 gsyVideoPlay(cameraEntity.flvUrl!!)
// CallerMonitorManager.openCameraStream(ip) } else if (!cameraEntity.ip.isNullOrEmpty()) {
// 测试一直打开的顺义摄像头,不需要调接口让摄像头开启推流,现在走这一套流程 Logger.d(TAG, "打开推流的摄像头ip为${cameraEntity.ip}")
if (!cameraEntity.flvUrl.isNullOrEmpty()) { CallerMonitorManager.openCameraStream(cameraEntity.ip!!)
gsyVideoPlay(cameraEntity.flvUrl!!) } else {
} else { Logger.e(TAG, "摄像头视频播放地址和ip均为空")
Logger.e(TAG, "视频播放地址为空!")
}
} }
} }
else -> { else -> {
@@ -132,7 +134,12 @@ class CameraListView : FrameLayout {
isPlaySuccess = false isPlaySuccess = false
isFirstPage = true isFirstPage = true
} }
val list: MutableList<VideoOptionModel> = ArrayList()
list.add(VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "reconnect", 3))
GSYVideoManager.instance().optionModelList = list
GSYVideoType.setShowType(GSYVideoType.SCREEN_MATCH_FULL) GSYVideoType.setShowType(GSYVideoType.SCREEN_MATCH_FULL)
PlayerFactory.setPlayManager(IjkPlayerManager::class.java)
IjkPlayerManager.setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG)
svpPlayer.setPlayListener(object : SimpleVideoPlayer.PlayListener { svpPlayer.setPlayListener(object : SimpleVideoPlayer.PlayListener {
override fun onPlayEvent(event: Int) { override fun onPlayEvent(event: Int) {
Logger.d(TAG, "onPlayEvent: event is:$event") Logger.d(TAG, "onPlayEvent: event is:$event")
@@ -284,6 +291,8 @@ class CameraListView : FrameLayout {
gsyVideoOptionBuilder.setUrl(flvUrl) gsyVideoOptionBuilder.setUrl(flvUrl)
.setCacheWithPlay(false) .setCacheWithPlay(false)
.setAutoFullWithSize(false) .setAutoFullWithSize(false)
.setIsTouchWigetFull(false)
.setIsTouchWiget(false)
.setPlayTag(TAG).build(svpPlayer) .setPlayTag(TAG).build(svpPlayer)
svpPlayer.startButton.performClick() svpPlayer.startButton.performClick()
} }

View File

@@ -1,5 +1,6 @@
package com.mogo.eagle.core.function.monitoring package com.mogo.eagle.core.function.monitoring
import android.content.Context
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.os.Message import android.os.Message
@@ -14,17 +15,20 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
class CronTaskManager { class CronTaskManager(private var context: Context?) {
private val TAG = "CronTaskManager" private val TAG = "CronTaskManager"
private val CRON_TASK_TYPE = 1011 private val CRON_TASK_TYPE = 1011
private val netWork by lazy { private val netWork by lazy {
MogoApisHandler.getInstance().apis.networkApi MogoApisHandler.getInstance().apis.networkApi
} }
// 请求路侧摄像头 // 请求路侧摄像头
private var disposable: Disposable? = null private var disposable: Disposable? = null
// 请求车侧摄像头 // 请求车侧摄像头
private var carDisposable: Disposable? = null private var carDisposable: Disposable? = null
// 开启路侧摄像头推流 // 开启路侧摄像头推流
private var streamDisposable: Disposable? = null private var streamDisposable: Disposable? = null
private var cameraList: List<CameraEntity>? = null private var cameraList: List<CameraEntity>? = null
@@ -36,7 +40,7 @@ class CronTaskManager {
when (msg.what) { when (msg.what) {
CRON_TASK_TYPE -> { CRON_TASK_TYPE -> {
removeMessages(CRON_TASK_TYPE) removeMessages(CRON_TASK_TYPE)
// 路测和车侧摄像头列表分开调用 // 路测和车侧摄像头列表分开调用
// requestCameraList() // requestCameraList()
requestDeviceList() requestDeviceList()
requestCarCameraList() requestCarCameraList()
@@ -57,8 +61,10 @@ class CronTaskManager {
crossing.cameras.filter { camera -> crossing.cameras.filter { camera ->
!camera.flvUrl.isNullOrEmpty() !camera.flvUrl.isNullOrEmpty()
}.map { }.map {
CameraEntity(it.flvUrl, "", it.roadName, CameraEntity(
it.crossingName, it.getHeadingStr(), it.ip) it.flvUrl, "", it.roadName,
it.crossingName, it.getHeadingStr(), it.ip
)
} }
} ?: ArrayList() } ?: ArrayList()
} }
@@ -76,9 +82,8 @@ class CronTaskManager {
* 请求路口一定范围内的设备信息(包含:摄像头、灯) * 请求路口一定范围内的设备信息(包含:摄像头、灯)
*/ */
private fun requestDeviceList() { private fun requestDeviceList() {
CallerMapLocationListenerManager.getCurrentLocation()?.let { location -> MogoApisHandler.getInstance().apis.mapServiceApi.getSingletonLocationClient(context).lastKnowLocation?.let { location ->
// 办公室测试顺义摄像头(116.74071467, 40.20051636) disposable = netWork.create(CameraListServices::class.java, HostConst.CITY_HOST)
disposable = netWork.create(CameraListServices::class.java, HostConst.MEC_ETL_HOST)
.getDeviceList(location.longitude, location.latitude, 500) .getDeviceList(location.longitude, location.latitude, 500)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.map { cameraListInfo -> .map { cameraListInfo ->
@@ -86,8 +91,10 @@ class CronTaskManager {
crossing.cameras.filter { camera -> crossing.cameras.filter { camera ->
!camera.ip.isNullOrEmpty() !camera.ip.isNullOrEmpty()
}.map { }.map {
CameraEntity(it.flvUrl, "", it.roadName, CameraEntity(
it.crossingName, it.getHeadingStr(), it.ip) it.flvUrl, "", it.roadName,
it.crossingName, it.getHeadingStr(), it.ip
)
} }
} ?: ArrayList() } ?: ArrayList()
} }
@@ -97,7 +104,10 @@ class CronTaskManager {
Logger.d(TAG, "requestDeviceList返回结果为$it") Logger.d(TAG, "requestDeviceList返回结果为$it")
}, { }, {
it.printStackTrace() it.printStackTrace()
Logger.e(TAG, "requestDeviceList:message is:${it.message}, cause is:${it.cause}") Logger.e(
TAG,
"requestDeviceList:message is:${it.message}, cause is:${it.cause}"
)
}) })
} ?: run { } ?: run {
Logger.e(TAG, "CurrentLocation is null!") Logger.e(TAG, "CurrentLocation is null!")
@@ -105,25 +115,30 @@ class CronTaskManager {
} }
private fun requestCarCameraList() { private fun requestCarCameraList() {
CallerMapLocationListenerManager.getCurrentLocation()?.let { location -> MogoApisHandler.getInstance().apis.mapServiceApi.getSingletonLocationClient(context).lastKnowLocation?.let { location ->
carDisposable = netWork.create(CameraListServices::class.java, HostConst.LAUNCHER_SNAPSHOT_HOST) carDisposable =
.getCarCameraList(ReqLiveCarBean(location.longitude, location.latitude)) netWork.create(CameraListServices::class.java, HostConst.CITY_HOST)
.subscribeOn(Schedulers.io()) .getCarCameraList(ReqLiveCarBean(location.longitude, location.latitude))
.map { liveCarCameraInfo -> .subscribeOn(Schedulers.io())
liveCarCameraInfo.result?.liveCamera?.filter { liveCarCamera -> .map { liveCarCameraInfo ->
!liveCarCamera.videoSn.isNullOrEmpty() liveCarCameraInfo.result?.liveCamera?.filter { liveCarCamera ->
}?.map { cameraInfo -> !liveCarCamera.videoSn.isNullOrEmpty()
CameraEntity(sn = cameraInfo.videoSn, street = cameraInfo.street, township = cameraInfo.township) }?.map { cameraInfo ->
} ?: ArrayList() CameraEntity(
} sn = cameraInfo.videoSn,
.observeOn(AndroidSchedulers.mainThread()) street = cameraInfo.street,
.subscribe({ township = cameraInfo.township
carCameraList = it )
Logger.d(TAG, "requestCarCameraList返回结果为:$it") } ?: ArrayList()
}, { }
Logger.e(TAG, "message is:${it.message}, cause is:${it.cause}") .observeOn(AndroidSchedulers.mainThread())
it.printStackTrace() .subscribe({
}) carCameraList = it
Logger.d(TAG, "requestCarCameraList返回结果为$it")
}, {
Logger.e(TAG, "message is:${it.message}, cause is:${it.cause}")
it.printStackTrace()
})
} ?: run { } ?: run {
Logger.e(TAG, "CurrentLocation is null!") Logger.e(TAG, "CurrentLocation is null!")
} }
@@ -132,21 +147,46 @@ class CronTaskManager {
/** /**
* 开启从摄像头拉流 * 开启从摄像头拉流
*/ */
@Deprecated("已废弃", ReplaceWith("requestDeviceList()"), DeprecationLevel.WARNING)
fun requestOpenCamera(cameraIp: String) { fun requestOpenCamera(cameraIp: String) {
streamDisposable?.let { streamDisposable?.let {
if (!it.isDisposed) it.dispose() if (!it.isDisposed) it.dispose()
} }
streamDisposable = netWork.create(CameraListServices::class.java, HostConst.OPEN_CAMERA_STREAM_HOST) streamDisposable =
.openCameraStream(cameraIp) netWork.create(CameraListServices::class.java, HostConst.OPEN_CAMERA_STREAM_HOST)
.openCameraStream(cameraIp)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
Logger.d(TAG, "openCameraStream返回结果为$it")
it.result?.let { streamResult ->
if (!streamResult.flvUrl.isNullOrEmpty()) CallerHmiManager.startRoadCameraLive(
streamResult.flvUrl!!
)
}
}, {
Logger.e(TAG, "openCameraStream&message is:${it.message}, cause is:${it.cause}")
CallerHmiManager.showNoSignalView()
it.printStackTrace()
})
}
/**
* 打开单个视频推流
*/
fun reqOpenCameraStream(cameraIp: String) {
streamDisposable?.let {
if (!it.isDisposed) it.dispose()
}
streamDisposable = netWork.create(CameraListServices::class.java, HostConst.CITY_HOST)
.reqOpenCameraStream(cameraIp)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ .subscribe({
Logger.d(TAG, "openCameraStream返回结果为$it") Logger.d(TAG, "reqOpenCameraStream返回结果为$it")
it.result?.let { streamResult -> if (!it.flvUrl.isNullOrEmpty()) CallerHmiManager.startRoadCameraLive(it.flvUrl!!)
if (!streamResult.flvUrl.isNullOrEmpty()) CallerHmiManager.startRoadCameraLive(streamResult.flvUrl!!)
}
}, { }, {
Logger.e(TAG, "openCameraStream&message is:${it.message}, cause is:${it.cause}") Logger.e(TAG, "reqOpenCameraStream&message is:${it.message}, cause is:${it.cause}")
CallerHmiManager.showNoSignalView() CallerHmiManager.showNoSignalView()
it.printStackTrace() it.printStackTrace()
}) })
@@ -159,27 +199,6 @@ class CronTaskManager {
fun getCameraList() = ArrayList<CameraEntity>().apply { fun getCameraList() = ArrayList<CameraEntity>().apply {
cameraList?.let { addAll(it) } cameraList?.let { addAll(it) }
carCameraList?.let { addAll(it) } carCameraList?.let { addAll(it) }
// // 不需要走华哥打开推流的接口,顺义直接就可以播放的摄像头直播地址
// add(
// CameraEntity("https://video.zhidaohulian.com/live/origin_13_44.flv?txSecret=dc913522389abfc2ab1f2b72f9f4ef41&txTime=6AABBEB2",
// "", "顺义测试道路",
// "路口1", "朝向1", "183.242.46.150")
// )
// add(
// CameraEntity("https://video.zhidaohulian.com/live/origin_13_45.flv?txSecret=7fee9c4ae986169d0e9bd0e1c1b7fab8&txTime=6AABBEB2",
// "", "顺义测试道路",
// "路口2", "朝向2", "183.242.46.150")
// )
// add(
// CameraEntity("https://video.zhidaohulian.com/live/origin_13_46.flv?txSecret=d5ddbd2236743bcf177563bb6680a462&txTime=6AABBEB2",
// "", "顺义测试道路",
// "路口3", "朝向3", "183.242.46.150")
// )
// add(
// CameraEntity("https://video.zhidaohulian.com/live/origin_13_48.flv?txSecret=397b1296eb548c737871fca242ff7ec5&txTime=6AABBEB2",
// "", "顺义测试道路",
// "路口4", "朝向4", "183.242.46.150")
// )
} }
fun clear() { fun clear() {
@@ -189,6 +208,7 @@ class CronTaskManager {
} }
fun onDestroy() { fun onDestroy() {
context = null
disposable?.dispose() disposable?.dispose()
carDisposable?.dispose() carDisposable?.dispose()
streamDisposable?.let { streamDisposable?.let {

View File

@@ -31,7 +31,7 @@ public class MoGoMonitoringProvider implements IMoGoMonitoringProvider {
@Override @Override
public void init(Context context) { public void init(Context context) {
Logger.d(TAG, "初始化……"); Logger.d(TAG, "初始化……");
mCronTaskManager = new CronTaskManager(); mCronTaskManager = new CronTaskManager(context);
mCronTaskManager.startCronTask(); mCronTaskManager.startCronTask();
} }
@@ -42,7 +42,9 @@ public class MoGoMonitoringProvider implements IMoGoMonitoringProvider {
@Override @Override
public void openCameraStream(String cameraIp) { public void openCameraStream(String cameraIp) {
mCronTaskManager.requestOpenCamera(cameraIp); // 现在不用华哥接口,改用卫明的打开视频推流接口
// mCronTaskManager.requestOpenCamera(cameraIp);
mCronTaskManager.reqOpenCameraStream(cameraIp);
} }
@Override @Override

View File

@@ -14,6 +14,9 @@ interface CameraListServices {
@GET("/openStream/{cameraIp}") @GET("/openStream/{cameraIp}")
fun openCameraStream(@Path("cameraIp") cameraIp: String): Single<CameraStreamEntity> fun openCameraStream(@Path("cameraIp") cameraIp: String): Single<CameraStreamEntity>
@GET("/camera-stream/stream/camera/openStream")
fun reqOpenCameraStream(@Query("ip") cameraIp: String): Single<OpenCameraStreamEntity>
@GET("/mec-etl-server/crossing/geo/device") @GET("/mec-etl-server/crossing/geo/device")
fun getDeviceList( fun getDeviceList(
@Query("lon") lon: Double, @Query("lat") lat: Double, @Query("lon") lon: Double, @Query("lat") lat: Double,

View File

@@ -3,9 +3,11 @@ package com.mogo.eagle.core.function.v2x.redlightwarning
import com.mogo.eagle.core.data.trafficlight.* import com.mogo.eagle.core.data.trafficlight.*
import com.mogo.eagle.core.data.trafficlight.TrafficLightStatusHelper.getCurrentRoadTrafficLight import com.mogo.eagle.core.data.trafficlight.TrafficLightStatusHelper.getCurrentRoadTrafficLight
import com.mogo.eagle.core.function.api.trafficlight.IMoGoTrafficLightListener import com.mogo.eagle.core.function.api.trafficlight.IMoGoTrafficLightListener
import com.mogo.eagle.core.function.api.vip.IMoGoVipSetListener
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
import com.mogo.eagle.core.function.call.map.CallerMapLocationListenerManager import com.mogo.eagle.core.function.call.map.CallerMapLocationListenerManager
import com.mogo.eagle.core.function.call.trafficlight.CallTrafficLightListenerManager import com.mogo.eagle.core.function.call.trafficlight.CallTrafficLightListenerManager
import com.mogo.eagle.core.function.call.vip.CallVipSetListenerManager
import com.mogo.eagle.core.utilcode.util.SPUtils import com.mogo.eagle.core.utilcode.util.SPUtils
import com.mogo.eagle.core.utilcode.util.ThreadUtils import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.module.common.enums.EventTypeEnum import com.mogo.module.common.enums.EventTypeEnum
@@ -15,7 +17,9 @@ import kotlin.math.ceil
import kotlin.math.floor import kotlin.math.floor
class RedLightWarningManager : IMoGoTrafficLightListener { class RedLightWarningManager : IMoGoTrafficLightListener, IMoGoVipSetListener {
private var vip: Boolean = false
companion object { companion object {
@@ -32,14 +36,19 @@ class RedLightWarningManager : IMoGoTrafficLightListener {
} }
} }
override fun onVipSet(status: Boolean) {
vip = status
}
fun listenTrafficLight() { fun listenTrafficLight() {
CallTrafficLightListenerManager.registerTrafficLightListener(TAG, this) CallTrafficLightListenerManager.registerTrafficLightListener(TAG, this)
CallVipSetListenerManager.registerVipSetListener(TAG, this)
} }
private fun handleRedLightWarning(trafficLightStatus: TrafficLightStatus, yellowLightTime: Int = 0) { private fun handleRedLightWarning(trafficLightStatus: TrafficLightStatus, yellowLightTime: Int = 0) {
// 如果是Vip则不处理 // 如果是Vip则不处理
if (SPUtils.getInstance().getLong("vip") > 0) { if (vip) {
Logger.w(TAG, "Vip用户不处理闯红灯预警逻辑") Logger.w(TAG, "Vip用户不处理闯红灯、绿灯通行预警逻辑!")
return return
} }
// 路口100m闯红灯预警 // 路口100m闯红灯预警
@@ -147,5 +156,6 @@ class RedLightWarningManager : IMoGoTrafficLightListener {
fun onDestroy() { fun onDestroy() {
CallTrafficLightListenerManager.unRegisterTrafficLightListener(TAG) CallTrafficLightListenerManager.unRegisterTrafficLightListener(TAG)
CallVipSetListenerManager.unRegisterVipSetListener(TAG)
} }
} }

View File

@@ -0,0 +1,11 @@
package com.mogo.eagle.core.data.camera
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName
import com.mogo.eagle.core.data.BaseData
@Keep
data class OpenCameraStreamEntity (
@SerializedName("data")
var flvUrl: String?
): BaseData()

View File

@@ -190,6 +190,9 @@ object CallerHmiManager : CallerBase() {
waringProviderApi.vipIdentification(visible) waringProviderApi.vipIdentification(visible)
} }
/**
* 开启道路视频直播
*/
fun startRoadCameraLive(flvUrl: String) { fun startRoadCameraLive(flvUrl: String) {
waringProviderApi.startRoadCameraLive(flvUrl) waringProviderApi.startRoadCameraLive(flvUrl)
} }

View File

@@ -5,6 +5,7 @@ import android.util.AttributeSet
import android.view.Surface import android.view.Surface
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import androidx.core.view.postDelayed
import com.mogo.eagle.core.widget.R import com.mogo.eagle.core.widget.R
import com.shuyu.gsyvideoplayer.GSYVideoManager import com.shuyu.gsyvideoplayer.GSYVideoManager
import com.shuyu.gsyvideoplayer.utils.GSYVideoType import com.shuyu.gsyvideoplayer.utils.GSYVideoType
@@ -27,6 +28,7 @@ class SimpleVideoPlayer : StandardGSYVideoPlayer {
private var playListener: PlayListener? = null private var playListener: PlayListener? = null
private lateinit var start: ImageView private lateinit var start: ImageView
private var updateTimer = 0L
interface PlayListener { interface PlayListener {
fun onPlayEvent(event: Int) fun onPlayEvent(event: Int)
@@ -136,11 +138,25 @@ class SimpleVideoPlayer : StandardGSYVideoPlayer {
isPostBufferUpdate = false isPostBufferUpdate = false
} }
private var runnable = object :Runnable {
override fun run() {
updateTimer++
postDelayed(this, 1000)
if (updateTimer >= 3) {
removeCallbacks(this)
playListener?.onPlayEvent(PLAY_EVT_PLAY_ERROR)
}
}
}
override fun onSurfaceUpdated(surface: Surface) { override fun onSurfaceUpdated(surface: Surface) {
super.onSurfaceUpdated(surface) super.onSurfaceUpdated(surface)
if (mThumbImageViewLayout != null && mThumbImageViewLayout.visibility == View.VISIBLE) { if (mThumbImageViewLayout != null && mThumbImageViewLayout.visibility == View.VISIBLE) {
mThumbImageViewLayout.visibility = View.INVISIBLE mThumbImageViewLayout.visibility = View.INVISIBLE
} }
updateTimer = 0
removeCallbacks(runnable)
postDelayed(runnable, 1000)
} }
override fun onPrepared() { override fun onPrepared() {