Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
M
mmc-stl-vue2
概览
概览
详情
活动
周期分析
版本库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Administrator
mmc-stl-vue2
Commits
fba2db77
提交
fba2db77
authored
3月 27, 2023
作者:
翁进城
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
优化视频组件代码,支持品牌播放器选择
上级
05893c9a
隐藏空白字符变更
内嵌
并排
正在显示
19 个修改的文件
包含
1209 行增加
和
74 行删除
+1209
-74
index.vue
src/components/MMCPlayer/components/flv/index.vue
+23
-20
index.vue
src/components/MMCPlayer/components/livenvr/index.vue
+1
-1
index.vue
src/components/MMCPlayer/components/srs/index.vue
+99
-0
jquery-1.10.2.min.js
src/components/MMCPlayer/components/srs/jquery-1.10.2.min.js
+0
-0
srs.sdk.js
src/components/MMCPlayer/components/srs/srs.sdk.js
+515
-0
index.vue
src/components/MMCPlayer/components/webrtc/index.vue
+110
-0
jswebrtc.js
src/components/MMCPlayer/components/webrtc/jswebrtc.js
+341
-0
index.vue
src/components/MMCPlayer/index.vue
+73
-32
PIMediaPlayer_api.js
src/components/MMCPlayer/lib/QingLiu/PIMediaPlayer_api.js
+0
-0
audio_render.js
src/components/MMCPlayer/lib/QingLiu/audio_render.js
+0
-0
kbt_api.js
src/components/MMCPlayer/lib/QingLiu/kbt_api.js
+0
-0
libplayer.data
src/components/MMCPlayer/lib/QingLiu/libplayer.data
+0
-0
libplayer.js
src/components/MMCPlayer/lib/QingLiu/libplayer.js
+0
-0
libplayer.wasm
src/components/MMCPlayer/lib/QingLiu/libplayer.wasm
+0
-0
libplayer.wasm.map
src/components/MMCPlayer/lib/QingLiu/libplayer.wasm.map
+0
-0
libplayer.worker.js
src/components/MMCPlayer/lib/QingLiu/libplayer.worker.js
+0
-0
index.html
vue2/public/index.html
+0
-1
demo.js
vue2/src/views/player/demo.js
+25
-10
demo.vue
vue2/src/views/player/demo.vue
+22
-10
没有找到文件。
src/components/MMCPlayer/components/flv/index.vue
浏览文件 @
fba2db77
<
template
>
<div
class=
"flv"
>
<video
controls
autoplay=
"autoplay"
muted=
"muted"
id=
"videoElement
"
>
<video
controls
autoplay=
"autoplay"
muted=
"muted"
ref=
"video
"
>
<source
type=
"video/mp4"
/>
</video>
<!--
<button
@
click=
"play"
>
播放
</button>
-->
...
...
@@ -17,20 +17,20 @@ export default {
return
{
player
:
null
,
flvPlayer
:
null
,
videourl
:
""
};
},
mounted
()
{
this
.
videourl
=
this
.
data
.
vUrl
console
.
log
(
this
.
data
.
vUrl
);
this
.
ngOnInit
();
this
.
init
();
},
beforeDestroy
()
{
this
.
destroy
();
},
methods
:
{
//页面初始化
ngOnI
nit
()
{
i
nit
()
{
if
(
flvjs
.
default
.
isSupported
())
{
// 获取DOM对象
this
.
player
=
document
.
getElementById
(
"videoElement"
)
;
this
.
player
=
this
.
$refs
.
video
;
// 创建flvjs对象
this
.
flvPlayer
=
flvjs
.
default
.
createPlayer
({
type
:
"flv"
,
// 指定视频类型
...
...
@@ -38,21 +38,12 @@ export default {
hasAudio
:
false
,
// 关闭声音
cors
:
true
,
// 开启跨域访问
// url: "http://pzlink999bju.powzamedia.com:8000/live/flv/test/mlinkm/channel1?only-video=1", // 指定流链接
url
:
this
.
getTarget
(
this
.
videourl
)
,
// 指定流链接
url
:
this
.
data
.
vUrl
,
// 指定流链接
});
// 将flvjs对象和DOM对象绑定
this
.
flvPlayer
.
attachMediaElement
(
this
.
player
);
}
this
.
play
()
},
getTarget
(
url
)
{
const
reg
=
/^pzsp:
\/\/(
.*
)
:7788.*
\/
trans
\/(
.*
)\/
mlinkm
\/(
.*
)\?
/
;
url
.
match
(
reg
);
const
hostname
=
RegExp
.
$1
;
const
groupname
=
RegExp
.
$2
;
const
streamname
=
RegExp
.
$3
;
return
`http://
${
hostname
}
:8000/live/flv/
${
groupname
}
a/mlinkm/
${
streamname
}
?only-video=1`
;
this
.
play
();
},
// 播放视频
...
...
@@ -62,7 +53,7 @@ export default {
},
//页面退出销毁和暂停播放
ngOnD
estroy
()
{
d
estroy
()
{
this
.
flvPlayer
.
pause
();
this
.
flvPlayer
.
unload
();
// 卸载DOM对象
...
...
@@ -70,6 +61,18 @@ export default {
// 销毁flvjs对象
this
.
flvPlayer
.
destroy
();
},
fullScreen
()
{
let
video
=
this
.
$refs
.
video
;
if
(
video
.
webkitRequestFullScreen
)
{
video
.
webkitRequestFullScreen
();
}
else
if
(
video
.
requestFullscreen
)
{
video
.
requestFullscreen
();
}
else
if
(
video
.
mozRequestFullScreen
)
setTimeout
(()
=>
{
video
.
play
();
},
200
);
},
},
};
</
script
>
...
...
@@ -78,7 +81,7 @@ export default {
.flv
{
width
:
100%
;
height
:
100%
;
#videoElement
{
video
{
width
:
100%
;
height
:
100%
;
}
...
...
src/components/MMCPlayer/components/livenvr/index.vue
浏览文件 @
fba2db77
...
...
@@ -113,7 +113,7 @@ export default {
const
image
=
canvasToDataURL
(
canvas
);
let
blob
=
dataURLToBlob
(
image
);
return
blob
;
}
}
,
}
};
</
script
>
...
...
src/components/MMCPlayer/components/srs/index.vue
0 → 100644
浏览文件 @
fba2db77
<
template
>
<div
class=
"cpt-player-webrtc"
>
<video
id=
"rtc_media_player"
ref=
"webrtc"
controls
autoplay
></video>
</div>
</
template
>
<
script
>
import
$
from
"./jquery-1.10.2.min"
;
import
{
SrsRtcPublisherAsync
,
SrsRtcPlayerAsync
,
SrsRtcFormatSenders
,
}
from
"./srs.sdk"
;
window
.
$
=
$
;
export
default
{
props
:
{
data
:
{
type
:
Object
,
default
:
()
=>
({}),
},
},
data
()
{
return
{
sdk
:
null
,
};
},
watch
:
{
data
:
{
handler
(
value
)
{
this
.
$nextTick
(()
=>
{
this
.
init
();
});
},
deep
:
true
,
immediate
:
true
,
},
},
beforeDestroy
()
{
this
.
sdk
.
close
();
},
methods
:
{
pause
()
{
if
(
this
.
$refs
[
"webrtc"
])
{
this
.
$refs
[
"webrtc"
].
pause
();
}
},
play
()
{
if
(
this
.
$refs
[
"webrtc"
])
{
this
.
$refs
[
"webrtc"
].
play
();
}
},
init
()
{
let
_this
=
this
;
if
(
this
.
$refs
[
"webrtc"
])
{
if
(
this
.
sdk
)
{
this
.
sdk
.
close
();
}
this
.
sdk
=
new
SrsRtcPlayerAsync
();
this
.
$refs
[
"webrtc"
].
srcObject
=
this
.
sdk
.
stream
;
this
.
sdk
.
play
(
this
.
data
.
vUrl
)
.
then
(
function
(
session
)
{})
.
catch
(
function
(
reason
)
{
console
.
log
(
'srs err'
,
reason
)
_this
.
sdk
.
close
();
});
}
},
fullScreen
()
{
let
video
=
this
.
$refs
[
"webrtc"
];
if
(
video
.
webkitRequestFullScreen
)
{
video
.
webkitRequestFullScreen
();
}
else
if
(
video
.
requestFullscreen
)
{
video
.
requestFullscreen
();
}
else
if
(
video
.
mozRequestFullScreen
)
setTimeout
(()
=>
{
video
.
play
();
},
200
);
},
},
};
</
script
>
<
style
lang=
"scss"
scoped
>
.cpt-player-webrtc
{
height
:
100%
;
width
:
100%
;
background-color
:
#000
;
video
{
width
:
100%
;
height
:
100%
;
object-fit
:
fill
;
}
}
</
style
>
\ No newline at end of file
src/components/MMCPlayer/components/srs/jquery-1.10.2.min.js
0 → 100644
浏览文件 @
fba2db77
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/components/MMCPlayer/components/srs/srs.sdk.js
0 → 100644
浏览文件 @
fba2db77
//
// Copyright (c) 2013-2021 Winlin
//
// SPDX-License-Identifier: MIT
//
'use strict'
;
// Depends on adapter-7.4.0.min.js from https://github.com/webrtc/adapter
// Async-awat-prmise based SRS RTC Publisher.
export
function
SrsRtcPublisherAsync
()
{
var
self
=
{};
// https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
self
.
constraints
=
{
audio
:
true
,
video
:
{
width
:
{
ideal
:
320
,
max
:
576
}
}
};
// @see https://github.com/rtcdn/rtcdn-draft
// @url The WebRTC url to play with, for example:
// webrtc://r.ossrs.net/live/livestream
// or specifies the API port:
// webrtc://r.ossrs.net:11985/live/livestream
// or autostart the publish:
// webrtc://r.ossrs.net/live/livestream?autostart=true
// or change the app from live to myapp:
// webrtc://r.ossrs.net:11985/myapp/livestream
// or change the stream from livestream to mystream:
// webrtc://r.ossrs.net:11985/live/mystream
// or set the api server to myapi.domain.com:
// webrtc://myapi.domain.com/live/livestream
// or set the candidate(eip) of answer:
// webrtc://r.ossrs.net/live/livestream?candidate=39.107.238.185
// or force to access https API:
// webrtc://r.ossrs.net/live/livestream?schema=https
// or use plaintext, without SRTP:
// webrtc://r.ossrs.net/live/livestream?encrypt=false
// or any other information, will pass-by in the query:
// webrtc://r.ossrs.net/live/livestream?vhost=xxx
// webrtc://r.ossrs.net/live/livestream?token=xxx
self
.
publish
=
async
function
(
url
)
{
var
conf
=
self
.
__internal
.
prepareUrl
(
url
);
self
.
pc
.
addTransceiver
(
"audio"
,
{
direction
:
"sendonly"
});
self
.
pc
.
addTransceiver
(
"video"
,
{
direction
:
"sendonly"
});
var
stream
=
await
navigator
.
mediaDevices
.
getUserMedia
(
self
.
constraints
);
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
stream
.
getTracks
().
forEach
(
function
(
track
)
{
self
.
pc
.
addTrack
(
track
);
// Notify about local track when stream is ok.
self
.
ontrack
&&
self
.
ontrack
({
track
:
track
});
});
var
offer
=
await
self
.
pc
.
createOffer
();
await
self
.
pc
.
setLocalDescription
(
offer
);
var
session
=
await
new
Promise
(
function
(
resolve
,
reject
)
{
// @see https://github.com/rtcdn/rtcdn-draft
var
data
=
{
api
:
conf
.
apiUrl
,
tid
:
conf
.
tid
,
streamurl
:
conf
.
streamUrl
,
clientip
:
null
,
sdp
:
offer
.
sdp
};
$
.
ajax
({
type
:
"POST"
,
url
:
conf
.
apiUrl
,
data
:
JSON
.
stringify
(
data
),
contentType
:
'application/json'
,
dataType
:
'json'
}).
done
(
function
(
data
)
{
if
(
data
.
code
)
{
reject
(
data
);
return
;
}
resolve
(
data
);
}).
fail
(
function
(
reason
)
{
reject
(
reason
);
});
});
await
self
.
pc
.
setRemoteDescription
(
new
RTCSessionDescription
({
type
:
'answer'
,
sdp
:
session
.
sdp
})
);
session
.
simulator
=
conf
.
schema
+
'//'
+
conf
.
urlObject
.
server
+
':'
+
conf
.
port
+
'/rtc/v1/nack/'
;
return
session
;
};
// Close the publisher.
self
.
close
=
function
()
{
self
.
pc
&&
self
.
pc
.
close
();
self
.
pc
=
null
;
};
// The callback when got local stream.
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
self
.
ontrack
=
function
(
event
)
{
// Add track to stream of SDK.
self
.
stream
.
addTrack
(
event
.
track
);
};
// Internal APIs.
self
.
__internal
=
{
defaultPath
:
'/rtc/v1/publish/'
,
prepareUrl
:
function
(
webrtcUrl
)
{
var
urlObject
=
self
.
__internal
.
parse
(
webrtcUrl
);
// If user specifies the schema, use it as API schema.
var
schema
=
urlObject
.
user_query
.
schema
;
schema
=
schema
?
schema
+
':'
:
window
.
location
.
protocol
;
var
port
=
urlObject
.
port
||
1985
;
if
(
schema
===
'https:'
)
{
port
=
urlObject
.
port
||
443
;
}
// @see https://github.com/rtcdn/rtcdn-draft
var
api
=
urlObject
.
user_query
.
play
||
self
.
__internal
.
defaultPath
;
if
(
api
.
lastIndexOf
(
'/'
)
!==
api
.
length
-
1
)
{
api
+=
'/'
;
}
apiUrl
=
schema
+
'//'
+
urlObject
.
server
+
':'
+
port
+
api
;
for
(
var
key
in
urlObject
.
user_query
)
{
if
(
key
!==
'api'
&&
key
!==
'play'
)
{
apiUrl
+=
'&'
+
key
+
'='
+
urlObject
.
user_query
[
key
];
}
}
// Replace /rtc/v1/play/&k=v to /rtc/v1/play/?k=v
var
apiUrl
=
apiUrl
.
replace
(
api
+
'&'
,
api
+
'?'
);
var
streamUrl
=
urlObject
.
url
;
return
{
apiUrl
:
apiUrl
,
streamUrl
:
streamUrl
,
schema
:
schema
,
urlObject
:
urlObject
,
port
:
port
,
tid
:
Number
(
parseInt
(
new
Date
().
getTime
()
*
Math
.
random
()
*
100
)).
toString
(
16
).
substr
(
0
,
7
)
};
},
parse
:
function
(
url
)
{
// @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
var
a
=
document
.
createElement
(
"a"
);
a
.
href
=
url
.
replace
(
"rtmp://"
,
"http://"
)
.
replace
(
"webrtc://"
,
"http://"
)
.
replace
(
"rtc://"
,
"http://"
);
var
vhost
=
a
.
hostname
;
var
app
=
a
.
pathname
.
substr
(
1
,
a
.
pathname
.
lastIndexOf
(
"/"
)
-
1
);
var
stream
=
a
.
pathname
.
substr
(
a
.
pathname
.
lastIndexOf
(
"/"
)
+
1
);
// parse the vhost in the params of app, that srs supports.
app
=
app
.
replace
(
"...vhost..."
,
"?vhost="
);
if
(
app
.
indexOf
(
"?"
)
>=
0
)
{
var
params
=
app
.
substr
(
app
.
indexOf
(
"?"
));
app
=
app
.
substr
(
0
,
app
.
indexOf
(
"?"
));
if
(
params
.
indexOf
(
"vhost="
)
>
0
)
{
vhost
=
params
.
substr
(
params
.
indexOf
(
"vhost="
)
+
"vhost="
.
length
);
if
(
vhost
.
indexOf
(
"&"
)
>
0
)
{
vhost
=
vhost
.
substr
(
0
,
vhost
.
indexOf
(
"&"
));
}
}
}
// when vhost equals to server, and server is ip,
// the vhost is __defaultVhost__
if
(
a
.
hostname
===
vhost
)
{
var
re
=
/^
(\d
+
)\.(\d
+
)\.(\d
+
)\.(\d
+
)
$/
;
if
(
re
.
test
(
a
.
hostname
))
{
vhost
=
"__defaultVhost__"
;
}
}
// parse the schema
var
schema
=
"rtmp"
;
if
(
url
.
indexOf
(
"://"
)
>
0
)
{
schema
=
url
.
substr
(
0
,
url
.
indexOf
(
"://"
));
}
var
port
=
a
.
port
;
if
(
!
port
)
{
if
(
schema
===
'http'
)
{
port
=
80
;
}
else
if
(
schema
===
'https'
)
{
port
=
443
;
}
else
if
(
schema
===
'rtmp'
)
{
port
=
1935
;
}
}
var
ret
=
{
url
:
url
,
schema
:
schema
,
server
:
a
.
hostname
,
port
:
port
,
vhost
:
vhost
,
app
:
app
,
stream
:
stream
};
self
.
__internal
.
fill_query
(
a
.
search
,
ret
);
// For webrtc API, we use 443 if page is https, or schema specified it.
if
(
!
ret
.
port
)
{
if
(
schema
===
'webrtc'
||
schema
===
'rtc'
)
{
if
(
ret
.
user_query
.
schema
===
'https'
)
{
ret
.
port
=
443
;
}
else
if
(
window
.
location
.
href
.
indexOf
(
'https://'
)
===
0
)
{
ret
.
port
=
443
;
}
else
{
// For WebRTC, SRS use 1985 as default API port.
ret
.
port
=
1985
;
}
}
}
return
ret
;
},
fill_query
:
function
(
query_string
,
obj
)
{
// pure user query object.
obj
.
user_query
=
{};
if
(
query_string
.
length
===
0
)
{
return
;
}
// split again for angularjs.
if
(
query_string
.
indexOf
(
"?"
)
>=
0
)
{
query_string
=
query_string
.
split
(
"?"
)[
1
];
}
var
queries
=
query_string
.
split
(
"&"
);
for
(
var
i
=
0
;
i
<
queries
.
length
;
i
++
)
{
var
elem
=
queries
[
i
];
var
query
=
elem
.
split
(
"="
);
obj
[
query
[
0
]]
=
query
[
1
];
obj
.
user_query
[
query
[
0
]]
=
query
[
1
];
}
// alias domain for vhost.
if
(
obj
.
domain
)
{
obj
.
vhost
=
obj
.
domain
;
}
}
};
self
.
pc
=
new
RTCPeerConnection
(
null
);
// To keep api consistent between player and publisher.
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
// @see https://webrtc.org/getting-started/media-devices
self
.
stream
=
new
MediaStream
();
return
self
;
}
// Depends on adapter-7.4.0.min.js from https://github.com/webrtc/adapter
// Async-await-promise based SRS RTC Player.
export
function
SrsRtcPlayerAsync
()
{
var
self
=
{};
// @see https://github.com/rtcdn/rtcdn-draft
// @url The WebRTC url to play with, for example:
// webrtc://r.ossrs.net/live/livestream
// or specifies the API port:
// webrtc://r.ossrs.net:11985/live/livestream
// or autostart the play:
// webrtc://r.ossrs.net/live/livestream?autostart=true
// or change the app from live to myapp:
// webrtc://r.ossrs.net:11985/myapp/livestream
// or change the stream from livestream to mystream:
// webrtc://r.ossrs.net:11985/live/mystream
// or set the api server to myapi.domain.com:
// webrtc://myapi.domain.com/live/livestream
// or set the candidate(eip) of answer:
// webrtc://r.ossrs.net/live/livestream?candidate=39.107.238.185
// or force to access https API:
// webrtc://r.ossrs.net/live/livestream?schema=https
// or use plaintext, without SRTP:
// webrtc://r.ossrs.net/live/livestream?encrypt=false
// or any other information, will pass-by in the query:
// webrtc://r.ossrs.net/live/livestream?vhost=xxx
// webrtc://r.ossrs.net/live/livestream?token=xxx
self
.
play
=
async
function
(
url
)
{
var
conf
=
self
.
__internal
.
prepareUrl
(
url
);
self
.
pc
.
addTransceiver
(
"audio"
,
{
direction
:
"recvonly"
});
self
.
pc
.
addTransceiver
(
"video"
,
{
direction
:
"recvonly"
});
var
offer
=
await
self
.
pc
.
createOffer
();
await
self
.
pc
.
setLocalDescription
(
offer
);
var
session
=
await
new
Promise
(
function
(
resolve
,
reject
)
{
// @see https://github.com/rtcdn/rtcdn-draft
var
data
=
{
api
:
conf
.
apiUrl
,
tid
:
conf
.
tid
,
streamurl
:
conf
.
streamUrl
,
clientip
:
null
,
sdp
:
offer
.
sdp
};
$
.
ajax
({
type
:
"POST"
,
url
:
conf
.
apiUrl
,
data
:
JSON
.
stringify
(
data
),
contentType
:
'application/json'
,
dataType
:
'json'
}).
done
(
function
(
data
)
{
if
(
data
.
code
)
{
reject
(
data
);
return
;
}
resolve
(
data
);
}).
fail
(
function
(
reason
){
reject
(
reason
);
});
});
await
self
.
pc
.
setRemoteDescription
(
new
RTCSessionDescription
({
type
:
'answer'
,
sdp
:
session
.
sdp
})
);
session
.
simulator
=
conf
.
schema
+
'//'
+
conf
.
urlObject
.
server
+
':'
+
conf
.
port
+
'/rtc/v1/nack/'
;
return
session
;
};
// Close the player.
self
.
close
=
function
()
{
self
.
pc
&&
self
.
pc
.
close
();
self
.
pc
=
null
;
};
// The callback when got remote track.
// Note that the onaddstream is deprecated, @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/onaddstream
self
.
ontrack
=
function
(
event
)
{
// https://webrtc.org/getting-started/remote-streams
self
.
stream
.
addTrack
(
event
.
track
);
};
// Internal APIs.
self
.
__internal
=
{
defaultPath
:
'/rtc/v1/play/'
,
prepareUrl
:
function
(
webrtcUrl
)
{
var
urlObject
=
self
.
__internal
.
parse
(
webrtcUrl
);
// If user specifies the schema, use it as API schema.
var
schema
=
urlObject
.
user_query
.
schema
;
schema
=
schema
?
schema
+
':'
:
window
.
location
.
protocol
;
var
port
=
urlObject
.
port
||
1985
;
if
(
schema
===
'https:'
)
{
port
=
urlObject
.
port
||
443
;
}
// @see https://github.com/rtcdn/rtcdn-draft
var
api
=
urlObject
.
user_query
.
play
||
self
.
__internal
.
defaultPath
;
if
(
api
.
lastIndexOf
(
'/'
)
!==
api
.
length
-
1
)
{
api
+=
'/'
;
}
apiUrl
=
schema
+
'//'
+
urlObject
.
server
+
':'
+
port
+
api
;
for
(
var
key
in
urlObject
.
user_query
)
{
if
(
key
!==
'api'
&&
key
!==
'play'
)
{
apiUrl
+=
'&'
+
key
+
'='
+
urlObject
.
user_query
[
key
];
}
}
// Replace /rtc/v1/play/&k=v to /rtc/v1/play/?k=v
var
apiUrl
=
apiUrl
.
replace
(
api
+
'&'
,
api
+
'?'
);
var
streamUrl
=
urlObject
.
url
;
return
{
apiUrl
:
apiUrl
,
streamUrl
:
streamUrl
,
schema
:
schema
,
urlObject
:
urlObject
,
port
:
port
,
tid
:
Number
(
parseInt
(
new
Date
().
getTime
()
*
Math
.
random
()
*
100
)).
toString
(
16
).
substr
(
0
,
7
)
};
},
parse
:
function
(
url
)
{
// @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
var
a
=
document
.
createElement
(
"a"
);
a
.
href
=
url
.
replace
(
"rtmp://"
,
"http://"
)
.
replace
(
"webrtc://"
,
"http://"
)
.
replace
(
"rtc://"
,
"http://"
);
var
vhost
=
a
.
hostname
;
var
app
=
a
.
pathname
.
substr
(
1
,
a
.
pathname
.
lastIndexOf
(
"/"
)
-
1
);
var
stream
=
a
.
pathname
.
substr
(
a
.
pathname
.
lastIndexOf
(
"/"
)
+
1
);
// parse the vhost in the params of app, that srs supports.
app
=
app
.
replace
(
"...vhost..."
,
"?vhost="
);
if
(
app
.
indexOf
(
"?"
)
>=
0
)
{
var
params
=
app
.
substr
(
app
.
indexOf
(
"?"
));
app
=
app
.
substr
(
0
,
app
.
indexOf
(
"?"
));
if
(
params
.
indexOf
(
"vhost="
)
>
0
)
{
vhost
=
params
.
substr
(
params
.
indexOf
(
"vhost="
)
+
"vhost="
.
length
);
if
(
vhost
.
indexOf
(
"&"
)
>
0
)
{
vhost
=
vhost
.
substr
(
0
,
vhost
.
indexOf
(
"&"
));
}
}
}
// when vhost equals to server, and server is ip,
// the vhost is __defaultVhost__
if
(
a
.
hostname
===
vhost
)
{
var
re
=
/^
(\d
+
)\.(\d
+
)\.(\d
+
)\.(\d
+
)
$/
;
if
(
re
.
test
(
a
.
hostname
))
{
vhost
=
"__defaultVhost__"
;
}
}
// parse the schema
var
schema
=
"rtmp"
;
if
(
url
.
indexOf
(
"://"
)
>
0
)
{
schema
=
url
.
substr
(
0
,
url
.
indexOf
(
"://"
));
}
var
port
=
a
.
port
;
if
(
!
port
)
{
if
(
schema
===
'http'
)
{
port
=
80
;
}
else
if
(
schema
===
'https'
)
{
port
=
443
;
}
else
if
(
schema
===
'rtmp'
)
{
port
=
1935
;
}
}
var
ret
=
{
url
:
url
,
schema
:
schema
,
server
:
a
.
hostname
,
port
:
port
,
vhost
:
vhost
,
app
:
app
,
stream
:
stream
};
self
.
__internal
.
fill_query
(
a
.
search
,
ret
);
// For webrtc API, we use 443 if page is https, or schema specified it.
if
(
!
ret
.
port
)
{
if
(
schema
===
'webrtc'
||
schema
===
'rtc'
)
{
if
(
ret
.
user_query
.
schema
===
'https'
)
{
ret
.
port
=
443
;
}
else
if
(
window
.
location
.
href
.
indexOf
(
'https://'
)
===
0
)
{
ret
.
port
=
443
;
}
else
{
// For WebRTC, SRS use 1985 as default API port.
ret
.
port
=
1985
;
}
}
}
return
ret
;
},
fill_query
:
function
(
query_string
,
obj
)
{
// pure user query object.
obj
.
user_query
=
{};
if
(
query_string
.
length
===
0
)
{
return
;
}
// split again for angularjs.
if
(
query_string
.
indexOf
(
"?"
)
>=
0
)
{
query_string
=
query_string
.
split
(
"?"
)[
1
];
}
var
queries
=
query_string
.
split
(
"&"
);
for
(
var
i
=
0
;
i
<
queries
.
length
;
i
++
)
{
var
elem
=
queries
[
i
];
var
query
=
elem
.
split
(
"="
);
obj
[
query
[
0
]]
=
query
[
1
];
obj
.
user_query
[
query
[
0
]]
=
query
[
1
];
}
// alias domain for vhost.
if
(
obj
.
domain
)
{
obj
.
vhost
=
obj
.
domain
;
}
}
};
console
.
log
(
"RTCPeerConnection"
);
self
.
pc
=
new
RTCPeerConnection
(
null
);
// Create a stream to add track to the stream, @see https://webrtc.org/getting-started/remote-streams
self
.
stream
=
new
MediaStream
();
// https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/ontrack
self
.
pc
.
ontrack
=
function
(
event
)
{
if
(
self
.
ontrack
)
{
self
.
ontrack
(
event
);
}
};
return
self
;
}
// Format the codec of RTCRtpSender, kind(audio/video) is optional filter.
// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/WebRTC_codecs#getting_the_supported_codecs
export
function
SrsRtcFormatSenders
(
senders
,
kind
)
{
var
codecs
=
[];
senders
.
forEach
(
function
(
sender
)
{
var
params
=
sender
.
getParameters
();
params
&&
params
.
codecs
&&
params
.
codecs
.
forEach
(
function
(
c
)
{
if
(
kind
&&
sender
.
track
.
kind
!==
kind
)
{
return
;
}
if
(
c
.
mimeType
.
indexOf
(
'/red'
)
>
0
||
c
.
mimeType
.
indexOf
(
'/rtx'
)
>
0
||
c
.
mimeType
.
indexOf
(
'/fec'
)
>
0
)
{
return
;
}
var
s
=
''
;
s
+=
c
.
mimeType
.
replace
(
'audio/'
,
''
).
replace
(
'video/'
,
''
);
s
+=
', '
+
c
.
clockRate
+
'HZ'
;
if
(
sender
.
track
.
kind
===
"audio"
)
{
s
+=
', channels: '
+
c
.
channels
;
}
s
+=
', pt: '
+
c
.
payloadType
;
codecs
.
push
(
s
);
});
});
return
codecs
.
join
(
", "
);
}
src/components/MMCPlayer/components/webrtc/index.vue
0 → 100644
浏览文件 @
fba2db77
<!-- 总览页视频 -->
<
template
>
<div
class=
"cpt-player-webrtc"
>
<video
ref=
"webrtc"
:controls=
"controls"
>
<source
/>
</video>
</div>
</
template
>
<
script
>
import
JSWebrtc
from
"./jswebrtc"
;
export
default
{
props
:
{
controls
:
{
type
:
Boolean
,
default
:
()
=>
true
,
},
data
:
{
type
:
Object
,
default
:
()
=>
({}),
},
},
data
()
{
return
{
player
:
null
,
value
:
""
,
times
:
0
,
};
},
watch
:
{
data
:
{
handler
(
value
)
{
if
(
value
)
{
this
.
$nextTick
(()
=>
{
this
.
player
=
new
JSWebrtc
.
Player
(
value
.
vUrl
,
{
video
:
this
.
$refs
[
"webrtc"
],
autoplay
:
true
,
});
});
}
},
deep
:
true
,
immediate
:
true
,
},
},
beforeDestroy
(){
this
.
player
?.
destroy
();
},
methods
:
{
fullScreen
()
{
let
video
=
this
.
$refs
[
"webrtc"
];
if
(
video
.
webkitRequestFullScreen
)
{
video
.
webkitRequestFullScreen
();
}
else
if
(
video
.
requestFullscreen
)
{
video
.
requestFullscreen
();
}
else
if
(
video
.
mozRequestFullScreen
)
setTimeout
(()
=>
{
video
.
play
();
},
200
);
},
exit
()
{
let
video
=
this
.
$refs
[
"webrtc"
];
if
(
document
.
exitFullscreen
)
{
document
.
exitFullscreen
();
}
else
if
(
document
.
mozCancelFullScreen
)
{
document
.
mozCancelFullScreen
();
}
else
if
(
document
.
webkitCancelFullScreen
)
{
document
.
webkitCancelFullScreen
();
}
setTimeout
(()
=>
{
video
.
play
();
},
200
);
},
},
};
</
script
>
<
style
lang=
"scss"
scoped
>
.cpt-player-webrtc
{
height
:
100%
;
width
:
100%
;
background-color
:
#000
;
video
{
width
:
100%
;
height
:
100%
;
object-fit
:
fill
;
position
:
relative
;
.title
{
position
:
absolute
;
font-family
:
MicrosoftYaHei-Bold
;
font-size
:
16px
;
color
:
#69ceff
;
letter-spacing
:
1px
;
text-align
:
center
;
font-weight
:
700
;
height
:
42px
;
line-height
:
42px
;
position
:
relative
;
box-sizing
:
border-box
;
position
:
absolute
;
bottom
:
0
;
}
}
}
</
style
>
\ No newline at end of file
src/components/MMCPlayer/components/webrtc/jswebrtc.js
0 → 100644
浏览文件 @
fba2db77
var
JSWebrtc
=
{
Player
:
null
,
VideoElement
:
null
,
CreateVideoElements
:
function
()
{
var
elements
=
document
.
querySelectorAll
(
".jswebrtc"
);
for
(
var
i
=
0
;
i
<
elements
.
length
;
i
++
)
{
new
JSWebrtc
.
VideoElement
(
elements
[
i
])
}
},
FillQuery
:
function
(
query_string
,
obj
)
{
obj
.
user_query
=
{};
if
(
query_string
.
length
==
0
)
return
;
if
(
query_string
.
indexOf
(
"?"
)
>=
0
)
query_string
=
query_string
.
split
(
"?"
)[
1
];
var
queries
=
query_string
.
split
(
"&"
);
for
(
var
i
=
0
;
i
<
queries
.
length
;
i
++
)
{
var
query
=
queries
[
i
].
split
(
"="
);
obj
[
query
[
0
]]
=
query
[
1
];
obj
.
user_query
[
query
[
0
]]
=
query
[
1
]
}
if
(
obj
.
domain
)
obj
.
vhost
=
obj
.
domain
},
ParseUrl
:
function
(
rtmp_url
)
{
var
a
=
document
.
createElement
(
"a"
);
a
.
href
=
rtmp_url
.
replace
(
"rtmp://"
,
"http://"
).
replace
(
"webrtc://"
,
"http://"
).
replace
(
"rtc://"
,
"http://"
);
var
vhost
=
a
.
hostname
;
var
app
=
a
.
pathname
.
substr
(
1
,
a
.
pathname
.
lastIndexOf
(
"/"
)
-
1
);
var
stream
=
a
.
pathname
.
substr
(
a
.
pathname
.
lastIndexOf
(
"/"
)
+
1
);
app
=
app
.
replace
(
"...vhost..."
,
"?vhost="
);
if
(
app
.
indexOf
(
"?"
)
>=
0
)
{
var
params
=
app
.
substr
(
app
.
indexOf
(
"?"
));
app
=
app
.
substr
(
0
,
app
.
indexOf
(
"?"
));
if
(
params
.
indexOf
(
"vhost="
)
>
0
)
{
vhost
=
params
.
substr
(
params
.
indexOf
(
"vhost="
)
+
"vhost="
.
length
);
if
(
vhost
.
indexOf
(
"&"
)
>
0
)
{
vhost
=
vhost
.
substr
(
0
,
vhost
.
indexOf
(
"&"
))
}
}
}
if
(
a
.
hostname
==
vhost
)
{
var
re
=
/^
(\d
+
)\.(\d
+
)\.(\d
+
)\.(\d
+
)
$/
;
if
(
re
.
test
(
a
.
hostname
))
vhost
=
"__defaultVhost__"
}
var
schema
=
"rtmp"
;
if
(
rtmp_url
.
indexOf
(
"://"
)
>
0
)
schema
=
rtmp_url
.
substr
(
0
,
rtmp_url
.
indexOf
(
"://"
));
var
port
=
a
.
port
;
if
(
!
port
)
{
if
(
schema
===
"http"
)
{
port
=
80
}
else
if
(
schema
===
"https"
)
{
port
=
443
}
else
if
(
schema
===
"rtmp"
)
{
port
=
1935
}
else
if
(
schema
===
"webrtc"
||
schema
===
"rtc"
)
{
port
=
1985
}
}
var
ret
=
{
url
:
rtmp_url
,
schema
:
schema
,
server
:
a
.
hostname
,
port
:
port
,
vhost
:
vhost
,
app
:
app
,
stream
:
stream
};
JSWebrtc
.
FillQuery
(
a
.
search
,
ret
);
return
ret
},
HttpPost
:
function
(
url
,
data
)
{
return
new
Promise
(
function
(
resolve
,
reject
)
{
var
xhr
=
new
XMLHttpRequest
;
xhr
.
onreadystatechange
=
function
()
{
if
(
xhr
.
readyState
===
4
&&
(
xhr
.
status
>=
200
&&
xhr
.
status
<
300
))
{
var
respone
=
JSON
.
parse
(
xhr
.
responseText
);
xhr
.
onreadystatechange
=
new
Function
;
xhr
=
null
;
resolve
(
respone
)
}
};
xhr
.
open
(
"POST"
,
url
,
true
);
xhr
.
timeout
=
5
e3
;
xhr
.
responseType
=
"text"
;
xhr
.
setRequestHeader
(
"Content-Type"
,
"application/json"
);
xhr
.
send
(
data
)
})
}
};
if
(
document
.
readyState
===
"complete"
)
{
JSWebrtc
.
CreateVideoElements
()
}
else
{
document
.
addEventListener
(
"DOMContentLoaded"
,
JSWebrtc
.
CreateVideoElements
)
}
JSWebrtc
.
VideoElement
=
function
()
{
"use strict"
;
var
VideoElement
=
function
(
element
)
{
var
url
=
element
.
dataset
.
url
;
if
(
!
url
)
{
throw
"VideoElement has no `data-url` attribute"
}
var
addStyles
=
function
(
element
,
styles
)
{
for
(
var
name
in
styles
)
{
element
.
style
[
name
]
=
styles
[
name
]
}
};
this
.
container
=
element
;
addStyles
(
this
.
container
,
{
display
:
"inline-block"
,
position
:
"relative"
,
minWidth
:
"80px"
,
minHeight
:
"80px"
});
this
.
video
=
document
.
createElement
(
"video"
);
this
.
video
.
width
=
960
;
this
.
video
.
height
=
540
;
addStyles
(
this
.
video
,
{
display
:
"block"
,
width
:
"100%"
});
this
.
container
.
appendChild
(
this
.
video
);
this
.
playButton
=
document
.
createElement
(
"div"
);
this
.
playButton
.
innerHTML
=
VideoElement
.
PLAY_BUTTON
;
addStyles
(
this
.
playButton
,
{
zIndex
:
2
,
position
:
"absolute"
,
top
:
"0"
,
bottom
:
"0"
,
left
:
"0"
,
right
:
"0"
,
maxWidth
:
"75px"
,
maxHeight
:
"75px"
,
margin
:
"auto"
,
opacity
:
"0.7"
,
cursor
:
"pointer"
});
this
.
container
.
appendChild
(
this
.
playButton
);
var
options
=
{
video
:
this
.
video
};
for
(
var
option
in
element
.
dataset
)
{
try
{
options
[
option
]
=
JSON
.
parse
(
element
.
dataset
[
option
])
}
catch
(
err
)
{
options
[
option
]
=
element
.
dataset
[
option
]
}
}
this
.
player
=
new
JSWebrtc
.
Player
(
url
,
options
);
element
.
playerInstance
=
this
.
player
;
if
(
options
.
poster
&&
!
options
.
autoplay
)
{
options
.
decodeFirstFrame
=
false
;
this
.
poster
=
new
Image
;
this
.
poster
.
src
=
options
.
poster
;
this
.
poster
.
addEventListener
(
"load"
,
this
.
posterLoaded
);
addStyles
(
this
.
poster
,
{
display
:
"block"
,
zIndex
:
1
,
position
:
"absolute"
,
top
:
0
,
left
:
0
,
bottom
:
0
,
right
:
0
});
this
.
container
.
appendChild
(
this
.
poster
)
}
if
(
!
this
.
player
.
options
.
streaming
)
{
this
.
container
.
addEventListener
(
"click"
,
this
.
onClick
.
bind
(
this
))
}
if
(
options
.
autoplay
)
{
this
.
playButton
.
style
.
display
=
"none"
}
if
(
this
.
player
.
audioOut
&&
!
this
.
player
.
audioOut
.
unlocked
)
{
var
unlockAudioElement
=
this
.
container
;
if
(
options
.
autoplay
)
{
this
.
unmuteButton
=
document
.
createElement
(
"div"
);
this
.
unmuteButton
.
innerHTML
=
VideoElement
.
UNMUTE_BUTTON
;
addStyles
(
this
.
unmuteButton
,
{
zIndex
:
2
,
position
:
"absolute"
,
bottom
:
"10px"
,
right
:
"20px"
,
width
:
"75px"
,
height
:
"75px"
,
margin
:
"auto"
,
opacity
:
"0.7"
,
cursor
:
"pointer"
});
this
.
container
.
appendChild
(
this
.
unmuteButton
);
unlockAudioElement
=
this
.
unmuteButton
}
this
.
unlockAudioBound
=
this
.
onUnlockAudio
.
bind
(
this
,
unlockAudioElement
);
unlockAudioElement
.
addEventListener
(
"touchstart"
,
this
.
unlockAudioBound
,
false
);
unlockAudioElement
.
addEventListener
(
"click"
,
this
.
unlockAudioBound
,
true
)
}
};
VideoElement
.
prototype
.
onUnlockAudio
=
function
(
element
,
ev
)
{
if
(
this
.
unmuteButton
)
{
ev
.
preventDefault
();
ev
.
stopPropagation
()
}
this
.
player
.
audioOut
.
unlock
(
function
()
{
if
(
this
.
unmuteButton
)
{
this
.
unmuteButton
.
style
.
display
=
"none"
}
element
.
removeEventListener
(
"touchstart"
,
this
.
unlockAudioBound
);
element
.
removeEventListener
(
"click"
,
this
.
unlockAudioBound
)
}.
bind
(
this
))
};
VideoElement
.
prototype
.
onClick
=
function
(
ev
)
{
if
(
this
.
player
.
isPlaying
)
{
this
.
player
.
pause
();
this
.
playButton
.
style
.
display
=
"block"
}
else
{
this
.
player
.
play
();
this
.
playButton
.
style
.
display
=
"none"
;
if
(
this
.
poster
)
{
this
.
poster
.
style
.
display
=
"none"
}
}
};
VideoElement
.
PLAY_BUTTON
=
'<svg style="max-width: 75px; max-height: 75px;" '
+
'viewBox="0 0 200 200" alt="Play video">'
+
'<circle cx="100" cy="100" r="90" fill="none" '
+
'stroke-width="15" stroke="#fff"/>'
+
'<polygon points="70, 55 70, 145 145, 100" fill="#fff"/>'
+
"</svg>"
;
VideoElement
.
UNMUTE_BUTTON
=
'<svg style="max-width: 75px; max-height: 75px;" viewBox="0 0 75 75">'
+
'<polygon class="audio-speaker" stroke="none" fill="#fff" '
+
'points="39,13 22,28 6,28 6,47 21,47 39,62 39,13"/>'
+
'<g stroke="#fff" stroke-width="5">'
+
'<path d="M 49,50 69,26"/>'
+
'<path d="M 69,50 49,26"/>'
+
"</g>"
+
"</svg>"
;
return
VideoElement
}();
JSWebrtc
.
Player
=
function
()
{
"use strict"
;
var
Player
=
function
(
url
,
options
)
{
this
.
options
=
options
||
{};
if
(
!
url
.
match
(
/^webrtc
?
:
\/\/
/
))
{
throw
"JSWebrtc just work with webrtc"
}
if
(
!
this
.
options
.
video
)
{
throw
"VideoElement is null"
}
this
.
urlParams
=
JSWebrtc
.
ParseUrl
(
url
);
this
.
pc
=
null
;
this
.
autoplay
=
!!
options
.
autoplay
||
false
;
this
.
paused
=
true
;
if
(
this
.
autoplay
)
this
.
options
.
video
.
muted
=
true
;
this
.
startLoading
()
};
Player
.
prototype
.
startLoading
=
function
()
{
var
_self
=
this
;
if
(
_self
.
pc
)
{
_self
.
pc
.
close
()
}
_self
.
pc
=
new
RTCPeerConnection
(
null
);
_self
.
pc
.
ontrack
=
function
(
event
)
{
_self
.
options
.
video
[
"srcObject"
]
=
event
.
streams
[
0
]
};
_self
.
pc
.
addTransceiver
(
"audio"
,
{
direction
:
"recvonly"
});
_self
.
pc
.
addTransceiver
(
"video"
,
{
direction
:
"recvonly"
});
_self
.
pc
.
createOffer
().
then
(
function
(
offer
)
{
return
_self
.
pc
.
setLocalDescription
(
offer
).
then
(
function
()
{
return
offer
})
}).
then
(
function
(
offer
)
{
return
new
Promise
(
function
(
resolve
,
reject
)
{
var
port
=
_self
.
urlParams
.
port
||
1985
;
var
api
=
_self
.
urlParams
.
user_query
.
play
||
"/rtc/v1/play/"
;
if
(
api
.
lastIndexOf
(
"/"
)
!=
api
.
length
-
1
)
{
api
+=
"/"
}
var
url
=
"http://"
+
_self
.
urlParams
.
server
+
":"
+
port
+
api
;
for
(
var
key
in
_self
.
urlParams
.
user_query
)
{
if
(
key
!=
"api"
&&
key
!=
"play"
)
{
url
+=
"&"
+
key
+
"="
+
_self
.
urlParams
.
user_query
[
key
]
}
}
var
data
=
{
api
:
url
,
streamurl
:
_self
.
urlParams
.
url
,
clientip
:
null
,
sdp
:
offer
.
sdp
};
JSWebrtc
.
HttpPost
(
url
,
JSON
.
stringify
(
data
)).
then
(
function
(
res
)
{
resolve
(
res
.
sdp
)
},
function
(
rej
)
{
reject
(
rej
)
})
})
}).
then
(
function
(
answer
)
{
return
_self
.
pc
.
setRemoteDescription
(
new
RTCSessionDescription
({
type
:
"answer"
,
sdp
:
answer
}))
}).
catch
(
function
(
reason
)
{
throw
reason
});
if
(
this
.
autoplay
)
{
this
.
play
()
}
};
Player
.
prototype
.
play
=
function
(
ev
)
{
if
(
this
.
animationId
)
{
return
}
this
.
animationId
=
requestAnimationFrame
(
this
.
update
.
bind
(
this
));
this
.
paused
=
false
};
Player
.
prototype
.
pause
=
function
(
ev
)
{
if
(
this
.
paused
)
{
return
}
cancelAnimationFrame
(
this
.
animationId
);
this
.
animationId
=
null
;
this
.
isPlaying
=
false
;
this
.
paused
=
true
;
this
.
options
.
video
.
pause
();
if
(
this
.
options
.
onPause
)
{
this
.
options
.
onPause
(
this
)
}
};
Player
.
prototype
.
stop
=
function
(
ev
)
{
this
.
pause
()
};
Player
.
prototype
.
destroy
=
function
()
{
this
.
pause
();
this
.
pc
&&
this
.
pc
.
close
()
&&
this
.
pc
.
destroy
();
this
.
audioOut
&&
this
.
audioOut
.
destroy
()
};
Player
.
prototype
.
update
=
function
()
{
this
.
animationId
=
requestAnimationFrame
(
this
.
update
.
bind
(
this
));
if
(
this
.
options
.
video
.
readyState
<
4
)
{
return
}
if
(
!
this
.
isPlaying
)
{
this
.
isPlaying
=
true
;
this
.
options
.
video
.
play
();
if
(
this
.
options
.
onPlay
)
{
this
.
options
.
onPlay
(
this
)
}
}
};
return
Player
}();
export
default
JSWebrtc
;
\ No newline at end of file
src/components/MMCPlayer/index.vue
浏览文件 @
fba2db77
...
...
@@ -17,8 +17,15 @@
</div>
<div
v-show=
"!fullScreen"
class=
"close"
@
click=
"onClose(data)"
>
关闭
</div>
</div>
<el-tooltip
content=
"模式切换"
placement=
"bottom"
v-if=
"playerCom !== 'QingLiuPlayer' && fpvUrl.vUrl"
>
<div
class=
"fpv-switch iconfont icon-moshiqiehuan modelStyle pointer"
@
click=
"onChangeFPV"
></div>
<el-tooltip
content=
"模式切换"
placement=
"bottom"
v-if=
"playerCom !== 'QingLiuPlayer' && fpvUrl.vUrl"
>
<div
class=
"fpv-switch iconfont icon-moshiqiehuan modelStyle pointer"
@
click=
"onChangeFPV"
></div>
</el-tooltip>
<components
:is=
"playerCom"
...
...
@@ -98,10 +105,15 @@
<div
v-else
class=
"left ml24"
style=
"margin-left: 124px; color: #fff;"
></div>
<div
class=
"ctrl-items"
>
<div
class=
"ctrl-items-selects"
>
<el-select
class=
"video_type mr24"
v-model=
"streamSelect"
@
change=
"fpvSmallWindow = true;"
placeholder=
"切换源"
>
<el-select
class=
"video_type mr24"
v-model=
"streamSelect"
@
change=
"fpvSmallWindow = true;"
placeholder=
"切换源"
>
<el-option
v-for=
"
item in
streamOptions"
:key=
"i
tem.value
"
v-for=
"
(item, i) in _
streamOptions"
:key=
"i"
:label=
"item.label"
:value=
"item.value"
></el-option>
...
...
@@ -129,18 +141,24 @@
<
script
>
// import API from "@/api";
import
LiveNVRPlayer
from
"./components/livenvr
/index.vue
"
;
import
LiveNVRPlayer
from
"./components/livenvr"
;
// import QingLiuPlayer from "./flv/index.vue";
import
QingLiuPlayer
from
"./components/qingliu/index.vue"
;
import
QingLiuPlayer
from
"./components/qingliu"
;
import
FLVPlayer
from
"./components/flv"
;
import
SRSPlayer
from
"./components/srs"
;
import
WebRtcPlayer
from
'./components/webrtc'
;
import
{
to_moveMount
}
from
"../../lib/to_moveMount"
;
import
Obstacle
from
'./components/obstacle'
;
import
Obstacle
from
"./components/obstacle"
;
export
default
{
name
:
"MMCPlayer"
,
components
:
{
QingLiuPlayer
,
LiveNVRPlayer
,
Obstacle
FLVPlayer
,
SRSPlayer
,
WebRtcPlayer
,
Obstacle
,
},
props
:
{
//网络类型
...
...
@@ -148,7 +166,7 @@ export default {
type
:
String
,
default
:
()
=>
"公网"
,
},
//流可选项, {value: "播放地址", label: '流名称', fpvUrl: ''}
//流可选项, {value: "播放地址", label: '流名称', fpvUrl: ''
, brand: 'srs|fly|liveNVR|QingLiu|webrtc'
}
streamOptions
:
{
type
:
Array
,
default
:
()
=>
[],
...
...
@@ -164,13 +182,13 @@ export default {
},
obstacleData
:
{
type
:
Object
,
default
(){
default
()
{
return
null
;
/* {
distances: [], //array<int>(36个值每10度一个与障碍物的距离厘米);
obsDistance: 0, //int(避障警告距离米)}
} */
}
}
}
,
}
,
},
data
()
{
return
{
...
...
@@ -214,12 +232,43 @@ export default {
* 播放器组件名
*/
playerCom
()
{
if
(
this
.
streamSelect
?.
includes
(
"pzsp://"
))
{
return
"QingLiuPlayer"
;
if
(
this
.
stream
?.
brand
)
{
switch
(
this
.
stream
.
brand
.
toLowerCase
())
{
case
"flv"
:
return
"FLVPlayer"
;
case
"srs"
:
return
"SRSPlayer"
;
case
"livenvr"
:
return
"LiveNVRPlayer"
;
case
"qingliu"
:
return
"QingLiuPlayer"
;
case
"webrtc"
:
return
"WebRtcPlayer"
;
default
:
throw
"不支持的播放器品牌!"
;
}
}
else
{
return
"LiveNVRPlayer"
;
if
(
this
.
vUrl
.
vUrl
?.
includes
(
"pzsp://"
))
{
return
"QingLiuPlayer"
;
}
else
{
return
"LiveNVRPlayer"
;
}
}
},
_streamOptions
(){
return
this
.
streamOptions
.
map
((
item
,
i
)
=>
{
item
.
value
=
i
;
return
item
;
})
},
/**
* 选择流选项
*/
stream
()
{
let
find
=
this
.
streamOptions
.
find
((
item
)
=>
{
return
item
.
value
===
this
.
streamSelect
;
...
...
@@ -237,7 +286,7 @@ export default {
*/
vUrl
()
{
return
{
vUrl
:
this
.
stream
?.
value
||
""
,
vUrl
:
this
.
stream
?.
url
||
""
,
};
},
fpvUrl
()
{
...
...
@@ -248,31 +297,23 @@ export default {
},
watch
:
{
streamOptions
:
{
handler
:
function
()
{
console
.
log
(
'streamOptions'
);
handler
:
function
()
{
console
.
log
(
"streamOptions"
);
//当流选项变化时,如果未选择流类型,则自动选择第一个流类型
if
(
this
.
streamOptions
.
length
>
0
)
{
this
.
streamSelect
=
this
.
streamOptions
[
0
].
value
;
if
(
this
.
_
streamOptions
.
length
>
0
)
{
this
.
streamSelect
=
this
.
_
streamOptions
[
0
].
value
;
}
},
deep
:
true
,
immediate
:
true
immediate
:
true
,
},
},
mounted
()
{
this
.
wrapCenter
();
},
methods
:
{
test
(){
alert
(
'TEST'
);
},
firstCopySuccess
(
e
)
{
console
.
log
(
"copy arguments e:"
,
e
);
alert
(
"复制成功!"
);
},
firstCopyError
(
e
)
{
console
.
log
(
"copy arguments e:"
,
e
);
alert
(
"复制失败!"
);
test
()
{
alert
(
"TEST"
);
},
/**
* 切换展示清流调试信息
...
...
src/components/MMCPlayer/lib/
js
/PIMediaPlayer_api.js
→
src/components/MMCPlayer/lib/
QingLiu
/PIMediaPlayer_api.js
浏览文件 @
fba2db77
File moved
src/components/MMCPlayer/lib/
js
/audio_render.js
→
src/components/MMCPlayer/lib/
QingLiu
/audio_render.js
浏览文件 @
fba2db77
File moved
src/components/MMCPlayer/lib/
js
/kbt_api.js
→
src/components/MMCPlayer/lib/
QingLiu
/kbt_api.js
浏览文件 @
fba2db77
File moved
src/components/MMCPlayer/lib/
js
/libplayer.data
→
src/components/MMCPlayer/lib/
QingLiu
/libplayer.data
浏览文件 @
fba2db77
File moved
src/components/MMCPlayer/lib/
js
/libplayer.js
→
src/components/MMCPlayer/lib/
QingLiu
/libplayer.js
浏览文件 @
fba2db77
File moved
src/components/MMCPlayer/lib/
js
/libplayer.wasm
→
src/components/MMCPlayer/lib/
QingLiu
/libplayer.wasm
浏览文件 @
fba2db77
File moved
src/components/MMCPlayer/lib/
js
/libplayer.wasm.map
→
src/components/MMCPlayer/lib/
QingLiu
/libplayer.wasm.map
浏览文件 @
fba2db77
File moved
src/components/MMCPlayer/lib/
js
/libplayer.worker.js
→
src/components/MMCPlayer/lib/
QingLiu
/libplayer.worker.js
浏览文件 @
fba2db77
File moved
vue2/public/index.html
浏览文件 @
fba2db77
...
...
@@ -10,7 +10,6 @@
<script
src=
"./js/icontfont.js"
></script>
<script
type=
"text/javascript"
src=
"./js/nipplejs.min.js"
></script>
<script
src=
"js/PIMediaPlayer_api.js"
></script>
<script
src=
"./js/liveplayer-lib.min.js"
></script>
<script
src=
"./s3m.js"
></script>
<script
type=
"text/javascript"
src=
"js/kbt_api.js"
></script>
<script
src=
"liveplayer/liveplayer-lib.min.js"
></script>
...
...
vue2/src/views/player/demo.js
浏览文件 @
fba2db77
...
...
@@ -3,7 +3,10 @@ export default `
1.清流需要网站响应头中添加
"Cross-Origin-Opener-Policy": "same-origin",
"Cross-Origin-Embedder-Policy": "require-corp",
2.需要将mmc-stl-vue2/components/MMCPlayer/lib/js和mmc-stl-vue2/components/MMCPlayer/lib/liveplayer复制到项目的public文件中
2.需要将mmc-stl-vue2/components/MMCPlayer/lib/js和mmc-stl-vue2/components/MMCPlayer/lib/liveplayer复制到项目的public文件中, index.html添加以下代码
<script src="js/PIMediaPlayer_api.js"></script>
<script src="js/kbt_api.js"></script>
<script src="liveplayer/liveplayer-lib.min.js"></script>
<template>
<div>
...
...
@@ -22,24 +25,36 @@ export default {
return {
streamOptions: [
{
label: "播放源1",
value:
label: "flv",
brand: "flv", //支持以下品牌播放器"srs|fly|liveNVR|QingLiu|webrtc", 为空则根据url判断使用liveNVR或QingLiu
url:
"https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",
fpvUrl:
"http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8",
},
{
label: "播放源2",
value:
label: "liveNVR",
brand: 'liveNVR',
url:
"http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8",
fpvUrl:
fpvUrl:
//只有liveNVR支持fpvUrl
"https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",
},
{
label: "播放源3",
value:
label: "srs",
brand: 'srs',
url:
"webrtc://live.mmcuav.cn/hls/shouguang01",
},
{
label: "QingLiu",
url:
"pzsp://pzlink999bju.powzamedia.com:7788/live/ld/trans/test/mlinkm/channel1?ndselect=2&linkmode=8&fstusrd=1&us=1&wsinfo=pzlink999bju.powzamedia.com-13000&only-video=1&rct=500",
},
{
label: "WebRtc",
brand: 'webrtc',
url:
"webrtc://live.mmcuav.cn/hls/shouguang01",
},
],
obstacleData: null,
/* {
...
...
vue2/src/views/player/demo.vue
浏览文件 @
fba2db77
...
...
@@ -15,24 +15,36 @@ export default {
return
{
streamOptions
:
[
{
label
:
"播放源1"
,
value
:
label
:
"flv"
,
brand
:
"flv"
,
//支持以下品牌播放器"srs|fly|liveNVR|QingLiu|webrtc", 为空则根据url判断使用liveNVR或QingLiu
url
:
"https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv"
,
fpvUrl
:
"http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8"
,
},
{
label
:
"播放源2"
,
value
:
"http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8"
,
fpvUrl
:
label
:
"liveNVR"
,
brand
:
'liveNVR'
,
url
:
"https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv"
,
fpvUrl
:
//只有liveNVR支持fpvUrl
"webrtc://live.mmcuav.cn/hls/shouguang01"
,
},
{
label
:
"播放源3"
,
value
:
label
:
"srs"
,
brand
:
'srs'
,
url
:
"webrtc://live.mmcuav.cn/hls/shouguang01"
,
},
{
label
:
"QingLiu"
,
url
:
"pzsp://pzlink999bju.powzamedia.com:7788/live/ld/trans/test/mlinkm/channel1?ndselect=2&linkmode=8&fstusrd=1&us=1&wsinfo=pzlink999bju.powzamedia.com-13000&only-video=1&rct=500"
,
},
{
label
:
"WebRtc"
,
brand
:
'webrtc'
,
url
:
"webrtc://live.mmcuav.cn/hls/shouguang01"
,
},
],
obstacleData
:
null
,
/* {
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论