基于LivePlayer的录像回放页面

在视频播放中,少不了录像回放功能。其回放功能进行接口调用暂且不谈,主要记录下包含回放条的录像回放页面。

html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>录像回放窗口</title>
  6. <link href="../../layui/css/layui.css" rel="stylesheet" />
  7. <link href="../css/timeRule.css" rel="stylesheet" />
  8. <style>
  9. html,body{
  10. height: 100%;
  11. width: 100%;
  12. }
  13. .page {
  14. height: 100%;
  15. width: 100%;
  16. }
  17. .header {
  18. height: 15%;
  19. text-align: center;
  20. }
  21. .content {
  22. height: 70%;
  23. }
  24. .footer {
  25. height: 15%;
  26. }
  27. </style>
  28. </head>
  29. <body>
  30. <div class="page" id="videoTape">
  31. <div class="layui-row header">
  32. <blockquote class="layui-elem-quote">{
  33. {cameraData.address}} {
  34. {cameraData.name}}( {
  35. {cameraData.main_channel}} )</blockquote>
  36. <div class="layui-row" style="text-align: center;">
  37. 时间:
  38. <div class="layui-input-inline">
  39. <input class="layui-input" id="dateTime" type="text" placeholder="yyyy-MM-dd">
  40. </div>
  41. </div>
  42. </div>
  43. <div class="layui-row content">
  44. <div style="width:50%; padding-left: 25%;">
  45. <live-player id="livePalyer" live muted :video-url="videoUrl">
  46. </live-player>
  47. </div>
  48. </div>
  49. <div class="footer">
  50. <div class="time-rule box-div">
  51. <div class="time-day box-div" ref="day" :style="{ left: timeDayX + 'px'}">
  52. <div class="box-div" :class="['time-minute', minuteActiveClass((n - 1)*minutesPerUnit)]" :style="{width: minutesPerUnit + 'px'}" :title="minuteTitle((n - 1)*minutesPerUnit)"
  53. v-for="n in (1440/minutesPerUnit)" :key="n" @click.prevent="clickMinute((n-1)*minutesPerUnit)"></div>
  54. <div class="box-div" :class="[ k==1 ? 'time-text-first' : 'time-text']" v-for="k in 24">{
  55. {hourText(k - 1)}}</div>
  56. </div>
  57. <div class="time-cursor box-div" :style="{ left: timeCursorX + 'px'}" ref="cursor">
  58. <div class="time-cursor-text box-div">{
  59. {timeCursorText}}</div>
  60. </div>
  61. </div>
  62. </div>
  63. </div>
  64. <script type="text/javascript" src="../../js/lib/jquery/jquery.min.js"></script>
  65. <script type="text/javascript" src="../../layui/layui.js"></script>
  66. <script type="text/javascript" src="../../js/lib/vue/vue.js"></script>
  67. <script type="text/javascript" src="../../video/livePlayer/liveplayer-element.min.js"></script>
  68. <script type="text/javascript" src="../../video/js/lib/moment.min.js"></script>
  69. <script type="text/javascript" src="../../js/common/common.js"></script>
  70. <script type="text/javascript" src="../../video/js/common/liveCommon.js"></script>
  71. <script type="text/javascript" src="../../video/js/videotapeWin.js"></script>
  72. </body>
  73. </html>

js

  1. /**
  2. * 录像回放窗口
  3. * @author chenbin
  4. *
  5. */
  6. var cameraData = url.getUrlParms("record");
  7. cameraData = JSON.parse(cameraData);
  8. var startDate = new Date(); //开始时间
  9. startDate.setHours(0);
  10. startDate.setMinutes(0);
  11. startDate.setSeconds(0);
  12. var endDate = new Date(); //结束时间
  13. var vm = new Vue({
  14. el: "#videoTape",
  15. data: {
  16. cameraData: cameraData,
  17. timerange: [
  18. startDate,
  19. endDate
  20. ],
  21. videos: [],
  22. video: null,
  23. videoUrl: "",
  24. streamID: "",
  25. day:Format.dateFormat(new Date(),"YYYY/MM/DD"),
  26. timeCursorX: 0,
  27. timeDayX: 0,
  28. bMoving: false,
  29. minutesArr:[],
  30. minutesPerUnit: 5
  31. },
  32. watch: {
  33. videos: function(val) {
  34. this.triggerTimeChange();
  35. },
  36. video: function(newVal, oldVal) {
  37. if (newVal && newVal != oldVal) {
  38. this.startPlayback();
  39. } else {
  40. this.stopPlayback();
  41. }
  42. },
  43. day:function(newVal, oldVal){
  44. if(newVal != oldVal){
  45. var start = new Date(newVal);
  46. start.setHours(0);
  47. start.setMinutes(0);
  48. start.setSeconds(0);
  49. var end = new Date(newVal);
  50. end.setHours(23);
  51. end.setMinutes(59);
  52. end.setSeconds(59);
  53. this.timerange = [
  54. start,
  55. end
  56. ]
  57. this.getRecords(true);
  58. }
  59. },
  60. minutesArr:function(val){
  61. var today = new Date();
  62. var day = new Date(this.day);
  63. if(day.getDate() != today.getDate()){
  64. var time = 0;
  65. if(this.minutesArr.length>0){
  66. time = Math.min.apply(null, this.minutesArr) + 5;
  67. }
  68. this.timeCursorText = time;
  69. }else{
  70. var h = today.getHours();
  71. var m = today.getMinutes();
  72. this.timeCursorText = h * 60 + m - 10;
  73. }
  74. this.triggerTimeChange();
  75. }
  76. },
  77. mounted() { //加载完成后
  78. let cursor = this.$refs.cursor;
  79. let day = this.$refs.day;
  80. let rule = this.$el;
  81. let _this = this;
  82. function moveCursor(e) {
  83. let originPageX = $(cursor).data("originPageX");
  84. let dx = e.pageX - originPageX;
  85. _this.timeCursorX = $(cursor).position().left + dx;
  86. $(cursor).data("originPageX", e.pageX);
  87. }
  88. function touchMoveCursor(e) {
  89. let touch = e.originalEvent.targetTouches[0];
  90. let originPageX = $(cursor).data("originPageX");
  91. let dx = touch.pageX - originPageX;
  92. _this.timeCursorX = $(cursor).position().left + dx;
  93. $(cursor).data("originPageX", touch.pageX);
  94. }
  95. function moveDay(e) {
  96. let originPageX = $(day).data("originPageX");
  97. let dx = e.pageX - originPageX;
  98. _this.timeDayX = $(day).position().left + dx;
  99. $(day).data("originPageX", e.pageX);
  100. }
  101. function touchMoveDay(e) {
  102. let touch = e.originalEvent.targetTouches[0];
  103. let originPageX = $(day).data("originPageX");
  104. let dx = touch.pageX - originPageX;
  105. _this.timeDayX = $(day).position().left + dx;
  106. $(day).data("originPageX", touch.pageX);
  107. }
  108. $(cursor).on("mousedown", function(e) {
  109. $(cursor).data("originPageX", e.pageX);
  110. _this.bMoving = true;
  111. $(document).on("mousemove", moveCursor).one("mouseup", function(e) {
  112. $(document).off("mousemove", moveCursor);
  113. $(cursor).removeData("originPageX");
  114. _this.triggerTimeChange();
  115. _this.bMoving = false;
  116. })
  117. }).on("touchstart", function(e) {
  118. let touch = e.originalEvent.targetTouches[0];
  119. $(cursor).data("originPageX", touch.pageX);
  120. _this.bMoving = true;
  121. $(document).on("touchmove", touchMoveCursor).one("touchend", function(e) {
  122. $(document).off("touchmove", touchMoveCursor);
  123. $(cursor).removeData("originPageX");
  124. _this.triggerTimeChange();
  125. _this.bMoving = false;
  126. })
  127. })
  128. $(day).on("mousedown", function(e) {
  129. if ($(e.target).hasClass("time-minute")) {
  130. return false;
  131. }
  132. $(day).data("originPageX", e.pageX);
  133. _this.bMoving = true;
  134. $(document).on("mousemove", moveDay).one("mouseup", function(e) {
  135. $(document).off("mousemove", moveDay);
  136. $(day).removeData("originPageX");
  137. _this.triggerTimeChange();
  138. _this.bMoving = false;
  139. })
  140. }).on("touchstart", function(e) {
  141. if ($(e.target).hasClass("time-minute")) {
  142. return false;
  143. }
  144. let touch = e.originalEvent.targetTouches[0];
  145. $(day).data("originPageX", touch.pageX);
  146. _this.bMoving = true;
  147. $(document).on("touchmove", touchMoveDay).one("touchend", function(e) {
  148. $(document).off("touchmove", touchMoveDay);
  149. $(day).removeData("originPageX");
  150. _this.triggerTimeChange();
  151. _this.bMoving = false;
  152. })
  153. })
  154. let mmt = moment();
  155. let n = mmt.diff(mmt.clone().startOf('day'), 'minutes');
  156. n -= 10;
  157. if (n < 0) n = 0;
  158. this.clickMinute(n);
  159. this.getRecords(true);
  160. },
  161. methods: {
  162. hourText(n) {
  163. let h = moment().hour(n).minute(0).second(0);
  164. return h.format("HH:mm");
  165. },
  166. minuteActiveClass(n) {
  167. let m = moment().hour(0).minute(n);
  168. let mtext = m.format("HH:mm");
  169. return Object.keys(this.activeMinutes).indexOf(mtext) >= 0 ? "active" : "";
  170. },
  171. minuteTitle(n) {
  172. let m = moment().hour(0).minute(n);
  173. let mtext = m.format("HH:mm");
  174. return Object.keys(this.activeMinutes).indexOf(mtext) >= 0 ? mtext : "";
  175. },
  176. clickMinute(n, bTrigger = true) {
  177. if (this.bMoving) return;
  178. this.timeCursorX = n + this.timeDayX;
  179. if (bTrigger) {
  180. this.triggerTimeChange();
  181. }
  182. },
  183. triggerTimeChange() {
  184. this.onTimeChange(this.activeMinutes[this.timeCursorText]);
  185. },
  186. onTimeChange(video) {
  187. this.video = video;
  188. },
  189. getRecords(refresh) {
  190. if (refresh) {
  191. this.videos = [];
  192. }
  193. var p = {
  194. serial: this.cameraData.main_channel,
  195. starttime: moment(this.timerange[0]).format("YYYY-MM-DDTHH:mm:ss"),
  196. endtime: moment(this.timerange[1]).format("YYYY-MM-DDTHH:mm:ss")
  197. }
  198. Live.videotape.list(cameraData.nvr_id, p, function(e) {
  199. var items = e.RecordList || [];
  200. vm.videos = vm.videos.concat(items.filter(item => {
  201. if (!item || !item.StartTime || !item.EndTime) {
  202. return false;
  203. }
  204. return true;
  205. }));
  206. })
  207. },
  208. stopPlayback() {
  209. if(comm.isEmpty(this.streamID)){
  210. return;
  211. }
  212. Live.videotape.stopPlay(this.cameraData.nvr_id, {
  213. streamid: this.streamID
  214. }, function(e) {
  215. vm.streamID = "";
  216. vm.videoUrl = "";
  217. });
  218. },
  219. startPlayback() {
  220. var p = {
  221. serial: this.video.DeviceID,
  222. starttime: this.video.StartTime,
  223. endtime: this.video.EndTime
  224. }
  225. if(!comm.isEmpty(this.streamID)){
  226. Live.videotape.stopPlay(this.cameraData.nvr_id, {
  227. streamid: this.streamID
  228. }, function(e) {
  229. vm.streamID = "";
  230. vm.videoUrl = "";
  231. Live.videotape.startPlay(this.cameraData.nvr_id, p, function(e) {
  232. vm.streamID = e.StreamID;
  233. vm.videoUrl = e.WS_FLV;
  234. })
  235. });
  236. }else{
  237. Live.videotape.startPlay(this.cameraData.nvr_id, p, function(e) {
  238. vm.streamID = e.StreamID;
  239. vm.videoUrl = e.WS_FLV;
  240. })
  241. }
  242. },
  243. countTime(str){
  244. var times = str.split(":");
  245. var t = parseInt(times[0]) * 60 + parseInt(times[1]);
  246. return t;
  247. },
  248. countPosition(){
  249. let this_ = this;
  250. setTimeout(function(){
  251. if (this_.timeCursorX >= $(this_.$el).innerWidth()) {
  252. this_.timeCursorX = $(this_.$el).innerWidth() - 1;
  253. }
  254. if (this_.timeCursorX < 0) {
  255. this_.timeCursorX = 0;
  256. }
  257. if (this_.timeDayX < $(this_.$el).innerWidth() - $(this_.$refs.day).outerWidth()) {
  258. this_.timeDayX = $(this_.$el).innerWidth() - $(this_.$refs.day).outerWidth();
  259. }
  260. if (this_.timeDayX > 0) {
  261. this_.timeDayX = 0;
  262. }
  263. if (this_.timeCursorX - this_.timeDayX >= 1440) {
  264. this_.timeDayX = $(this_.$el).innerWidth() - $(this_.$refs.day).outerWidth();
  265. this_.timeCursorX = $(this_.$el).innerWidth() - 1;
  266. }
  267. },100)
  268. }
  269. },
  270. computed: {
  271. timeCursorText: {
  272. get:function(){
  273. this.countPosition();
  274. var mx = parseInt((this.timeCursorX - this.timeDayX) / this.minutesPerUnit) * this.minutesPerUnit;
  275. var m = moment().hour(0).minute(mx);
  276. return m.format("HH:mm");
  277. },
  278. set:function(time){
  279. this.timeCursorX = time;
  280. }
  281. },
  282. activeMinutes() {
  283. var minutes = {};
  284. var minArr = [];
  285. var idx = 0;
  286. for (var video of this.videos) {
  287. var start = moment(video.StartTime, "YYYY-MM-DDTHH:mm:ss");
  288. var end = moment(video.EndTime, "YYYY-MM-DDTHH:mm:ss");
  289. if (!start.isSame(end, "day")) { // 跨天
  290. if (idx == 0) {
  291. start = moment(end).startOf("day");
  292. } else {
  293. end = moment(start).endOf("day");
  294. }
  295. }
  296. var _start = moment(start).startOf("hour");
  297. for (var i = 0;; i += 5) {
  298. var c = moment(_start).add(i, "minute");
  299. if (c.isBefore(start, "minute")) {
  300. continue;
  301. }
  302. if (c.isAfter(end, "minute")) {
  303. break;
  304. }
  305. var mtext = c.format("HH:mm");
  306. minArr.push(this.countTime(mtext));
  307. minutes[mtext] = Object.assign({}, video, {
  308. StartTime: c.format("YYYY-MM-DDTHH:mm:ss")
  309. });
  310. }
  311. idx++;
  312. }
  313. this.minutesArr = minArr;
  314. return minutes;
  315. }
  316. }
  317. })
  318. layui.use('laydate', function() {
  319. var laydate = layui.laydate;
  320. var nowDate = Format.dateFormat(new Date(), "YYYY-MM-DD");
  321. //常规用法
  322. laydate.render({
  323. elem: '#dateTime',
  324. value: nowDate,
  325. showBottom: false,
  326. max: nowDate,
  327. done: function(value, date, endDate) {
  328. vm.day = value.replace(/-/g,"/");
  329. }
  330. });
  331. })

css

  1. /**
  2. * 录像回放css
  3. */
  4. .time-rule {
  5. overflow: hidden;
  6. position: relative;
  7. height: 50px;
  8. margin: 0 auto;
  9. width: 100%;
  10. font-size: 12px;
  11. max-width: 1440px;
  12. background-color: #CCC;
  13. }
  14. .time-day {
  15. position: absolute;
  16. left: 0;
  17. top: 0;
  18. height: 100%;
  19. width: 1440px;
  20. cursor: pointer;
  21. -ms-user-select: none;
  22. user-select: none;
  23. }
  24. .time-minute {
  25. float: left;
  26. height: 8px;
  27. margin: 0;
  28. cursor: default;
  29. }
  30. .time-minute.active {
  31. background-color: #556677;
  32. cursor: pointer;
  33. }
  34. .time-text {
  35. float: left;
  36. width: 60px;
  37. border-left: 1px solid #999;
  38. border-top: 1px solid #999;
  39. -ms-user-select: none;
  40. user-select: none;
  41. text-align: center;
  42. height: 25px;
  43. line-height: 25px;
  44. }
  45. .time-text-first {
  46. border-left: 0;
  47. float: left;
  48. width: 60px;
  49. border-top: 1px solid #999;
  50. -ms-user-select: none;
  51. user-select: none;
  52. text-align: center;
  53. height: 25px;
  54. line-height: 25px;
  55. }
  56. .time-cursor {
  57. position: absolute;
  58. left: 0;
  59. top: 0;
  60. height: 30px;
  61. width: 2px;
  62. background-color: red;
  63. text-align: center;
  64. }
  65. .time-cursor-text {
  66. position: absolute;
  67. padding: 0 5px;
  68. width: 60px;
  69. left: -30px;
  70. top: 30px;
  71. border: 1px solid red;
  72. height: 15px;
  73. line-height: 15px;
  74. cursor: move;
  75. background-color: white;
  76. -ms-user-select: none;
  77. user-select: none;
  78. }
  79. .box-div{
  80. box-sizing:border-box;
  81. -moz-box-sizing:border-box; /* Firefox */
  82. -webkit-box-sizing:border-box; /* Safari */
  83. }

效果

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW95YW5saTgwNzc_size_16_color_FFFFFF_t_70

发表评论

表情:
评论列表 (有 0 条评论,91人围观)

还没有评论,来说两句吧...

相关阅读