基于LivePlayer的录像回放页面

8 篇文章 1 订阅
7 篇文章 0 订阅

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

html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>录像回放窗口</title>
		<link href="../../layui/css/layui.css" rel="stylesheet" />
		<link href="../css/timeRule.css" rel="stylesheet" />
		<style>
			html,body{
				height: 100%;
				width: 100%;
			}
			.page {
				height: 100%;
				width: 100%;
			} 
			.header {
				height: 15%;
				text-align: center;
			}
			.content {
				height: 70%;
			}
			.footer {
				height: 15%;
			}
		</style>
	</head>
	<body>
		<div class="page" id="videoTape">
			<div class="layui-row header">
				<blockquote class="layui-elem-quote">{{cameraData.address}} {{cameraData.name}}( {{cameraData.main_channel}} )</blockquote>
				<div class="layui-row" style="text-align: center;">
					时间:
					<div class="layui-input-inline">
						<input class="layui-input" id="dateTime" type="text" placeholder="yyyy-MM-dd">
					</div>
				</div>
			</div>
			<div class="layui-row content">
				<div style="width:50%; padding-left: 25%;">
					<live-player id="livePalyer" live muted :video-url="videoUrl">
					</live-player>
				</div>
			</div>
			<div class="footer">
				<div class="time-rule box-div">
				    <div class="time-day box-div" ref="day" :style="{ left: timeDayX + 'px'}">
				        <div class="box-div" :class="['time-minute', minuteActiveClass((n - 1)*minutesPerUnit)]" :style="{width: minutesPerUnit + 'px'}" :title="minuteTitle((n - 1)*minutesPerUnit)"
				            v-for="n in (1440/minutesPerUnit)" :key="n" @click.prevent="clickMinute((n-1)*minutesPerUnit)"></div>
				        <div class="box-div" :class="[ k==1 ? 'time-text-first' : 'time-text']" v-for="k in 24">{{hourText(k - 1)}}</div>
				    </div>
				    <div class="time-cursor box-div" :style="{ left: timeCursorX + 'px'}" ref="cursor">
				        <div class="time-cursor-text box-div">{{timeCursorText}}</div>
				    </div>
				</div>
			</div>
		</div>
		<script type="text/javascript" src="../../js/lib/jquery/jquery.min.js"></script>
		<script type="text/javascript" src="../../layui/layui.js"></script>
		<script type="text/javascript" src="../../js/lib/vue/vue.js"></script>
		<script type="text/javascript" src="../../video/livePlayer/liveplayer-element.min.js"></script>
		<script type="text/javascript" src="../../video/js/lib/moment.min.js"></script>
		<script type="text/javascript" src="../../js/common/common.js"></script>
		<script type="text/javascript" src="../../video/js/common/liveCommon.js"></script>
		<script type="text/javascript" src="../../video/js/videotapeWin.js"></script>
	</body>

</html>

js

/**
 * 录像回放窗口
 * @author chenbin
 * 
 */
var cameraData = url.getUrlParms("record");
cameraData = JSON.parse(cameraData);

var startDate = new Date(); //开始时间
startDate.setHours(0);
startDate.setMinutes(0);
startDate.setSeconds(0);
var endDate = new Date(); //结束时间

var vm = new Vue({
	el: "#videoTape",
	data: {
		cameraData: cameraData,
		timerange: [
			startDate,
			endDate
		],
		videos: [],
		video: null,
		videoUrl: "",
		streamID: "",
		day:Format.dateFormat(new Date(),"YYYY/MM/DD"),
		timeCursorX: 0,
		timeDayX: 0,
		bMoving: false,
		minutesArr:[],
		minutesPerUnit: 5
	},
	watch: {
		videos: function(val) {
			this.triggerTimeChange();
		},
		video: function(newVal, oldVal) {
			if (newVal && newVal != oldVal) {
				this.startPlayback();
			} else {
				this.stopPlayback();
			}
		},
		day:function(newVal, oldVal){
			if(newVal != oldVal){
				var start = new Date(newVal);
				start.setHours(0);
				start.setMinutes(0);
				start.setSeconds(0);
				var end = new Date(newVal);
				end.setHours(23);
				end.setMinutes(59);
				end.setSeconds(59);
				this.timerange = [
				  start,
				  end
				]
				this.getRecords(true);
			}
		},
		minutesArr:function(val){
			var today = new Date();
			var day = new Date(this.day);
			if(day.getDate() != today.getDate()){
				var time = 0;
				if(this.minutesArr.length>0){
					time = Math.min.apply(null, this.minutesArr) + 5;
				}
				this.timeCursorText = time;
			}else{
				var h = today.getHours();
				var m = today.getMinutes();
				this.timeCursorText = h * 60 + m - 10;
			}
			this.triggerTimeChange();
		}
	},
	mounted() { //加载完成后
		let cursor = this.$refs.cursor;
		let day = this.$refs.day;
		let rule = this.$el;
		let _this = this;

		function moveCursor(e) {
			let originPageX = $(cursor).data("originPageX");
			let dx = e.pageX - originPageX;
			_this.timeCursorX = $(cursor).position().left + dx;
			$(cursor).data("originPageX", e.pageX);
		}

		function touchMoveCursor(e) {
			let touch = e.originalEvent.targetTouches[0];
			let originPageX = $(cursor).data("originPageX");
			let dx = touch.pageX - originPageX;
			_this.timeCursorX = $(cursor).position().left + dx;
			$(cursor).data("originPageX", touch.pageX);
		}

		function moveDay(e) {
			let originPageX = $(day).data("originPageX");
			let dx = e.pageX - originPageX;
			_this.timeDayX = $(day).position().left + dx;
			$(day).data("originPageX", e.pageX);
		}

		function touchMoveDay(e) {
			let touch = e.originalEvent.targetTouches[0];
			let originPageX = $(day).data("originPageX");
			let dx = touch.pageX - originPageX;
			_this.timeDayX = $(day).position().left + dx;
			$(day).data("originPageX", touch.pageX);
		}
		$(cursor).on("mousedown", function(e) {
			$(cursor).data("originPageX", e.pageX);
			_this.bMoving = true;
			$(document).on("mousemove", moveCursor).one("mouseup", function(e) {
				$(document).off("mousemove", moveCursor);
				$(cursor).removeData("originPageX");
				_this.triggerTimeChange();
				_this.bMoving = false;
			})
		}).on("touchstart", function(e) {
			let touch = e.originalEvent.targetTouches[0];
			$(cursor).data("originPageX", touch.pageX);
			_this.bMoving = true;
			$(document).on("touchmove", touchMoveCursor).one("touchend", function(e) {
				$(document).off("touchmove", touchMoveCursor);
				$(cursor).removeData("originPageX");
				_this.triggerTimeChange();
				_this.bMoving = false;
			})
		})

		$(day).on("mousedown", function(e) {
			if ($(e.target).hasClass("time-minute")) {
				return false;
			}
			$(day).data("originPageX", e.pageX);
			_this.bMoving = true;
			$(document).on("mousemove", moveDay).one("mouseup", function(e) {
				$(document).off("mousemove", moveDay);
				$(day).removeData("originPageX");
				_this.triggerTimeChange();
				_this.bMoving = false;
			})
		}).on("touchstart", function(e) {
			if ($(e.target).hasClass("time-minute")) {
				return false;
			}
			let touch = e.originalEvent.targetTouches[0];
			$(day).data("originPageX", touch.pageX);
			_this.bMoving = true;
			$(document).on("touchmove", touchMoveDay).one("touchend", function(e) {
				$(document).off("touchmove", touchMoveDay);
				$(day).removeData("originPageX");
				_this.triggerTimeChange();
				_this.bMoving = false;
			})
		})

		let mmt = moment();
		let n = mmt.diff(mmt.clone().startOf('day'), 'minutes');
		n -= 10;
		if (n < 0) n = 0;
		this.clickMinute(n);
		this.getRecords(true);
	},
	methods: {
		hourText(n) {
			let h = moment().hour(n).minute(0).second(0);
			return h.format("HH:mm");
		},
		minuteActiveClass(n) {
			let m = moment().hour(0).minute(n);
			let mtext = m.format("HH:mm");
			return Object.keys(this.activeMinutes).indexOf(mtext) >= 0 ? "active" : "";
		},
		minuteTitle(n) {
			let m = moment().hour(0).minute(n);
			let mtext = m.format("HH:mm");
			return Object.keys(this.activeMinutes).indexOf(mtext) >= 0 ? mtext : "";
		},
		clickMinute(n, bTrigger = true) {
			if (this.bMoving) return;
			this.timeCursorX = n + this.timeDayX;
			if (bTrigger) {
				this.triggerTimeChange();
			}
		},
		triggerTimeChange() {
			this.onTimeChange(this.activeMinutes[this.timeCursorText]);
		},
		onTimeChange(video) {
			this.video = video;
		},
		getRecords(refresh) {
			if (refresh) {
				this.videos = [];
			}
			var p = {
				serial: this.cameraData.main_channel,
				starttime: moment(this.timerange[0]).format("YYYY-MM-DDTHH:mm:ss"),
				endtime: moment(this.timerange[1]).format("YYYY-MM-DDTHH:mm:ss")
			}
			Live.videotape.list(cameraData.nvr_id, p, function(e) {
				var items = e.RecordList || [];
				vm.videos = vm.videos.concat(items.filter(item => {
					if (!item || !item.StartTime || !item.EndTime) {
						return false;
					}
					return true;
				}));
			})
		},
		stopPlayback() {
			if(comm.isEmpty(this.streamID)){
				return;
			}
			Live.videotape.stopPlay(this.cameraData.nvr_id, {
				streamid: this.streamID
			}, function(e) {
				vm.streamID = "";
				vm.videoUrl = "";
			});
		},
		startPlayback() {
			var p = {
				serial: this.video.DeviceID,
				starttime: this.video.StartTime,
				endtime: this.video.EndTime
			}
			if(!comm.isEmpty(this.streamID)){
				Live.videotape.stopPlay(this.cameraData.nvr_id, {
					streamid: this.streamID
				}, function(e) {
					vm.streamID = "";
					vm.videoUrl = "";
					Live.videotape.startPlay(this.cameraData.nvr_id, p, function(e) {
						vm.streamID = e.StreamID;
						vm.videoUrl = e.WS_FLV;
					})
				});
			}else{
				Live.videotape.startPlay(this.cameraData.nvr_id, p, function(e) {
					vm.streamID = e.StreamID;
					vm.videoUrl = e.WS_FLV;
				})
			}
		},
		countTime(str){
			var times = str.split(":");
			var t = parseInt(times[0]) * 60 + parseInt(times[1]);
			return t;
		},
		countPosition(){
			let this_ = this;
			setTimeout(function(){
				if (this_.timeCursorX >= $(this_.$el).innerWidth()) {
					this_.timeCursorX = $(this_.$el).innerWidth() - 1;
				}
				if (this_.timeCursorX < 0) {
					this_.timeCursorX = 0;
				}
				if (this_.timeDayX < $(this_.$el).innerWidth() - $(this_.$refs.day).outerWidth()) {
					this_.timeDayX = $(this_.$el).innerWidth() - $(this_.$refs.day).outerWidth();
				}
				if (this_.timeDayX > 0) {
					this_.timeDayX = 0;
				}
				if (this_.timeCursorX - this_.timeDayX >= 1440) {
					this_.timeDayX = $(this_.$el).innerWidth() - $(this_.$refs.day).outerWidth();
					this_.timeCursorX = $(this_.$el).innerWidth() - 1;
				}
			},100)
		}
	},
	computed: {
		timeCursorText: {
			get:function(){
				this.countPosition();
				var mx = parseInt((this.timeCursorX - this.timeDayX) / this.minutesPerUnit) * this.minutesPerUnit;
				var m = moment().hour(0).minute(mx);
				return m.format("HH:mm");
			},
			set:function(time){
				this.timeCursorX = time;
			}
			
		},
		activeMinutes() {
			var minutes = {};
			var minArr = [];
			var idx = 0;
			for (var video of this.videos) {
				var start = moment(video.StartTime, "YYYY-MM-DDTHH:mm:ss");
				var end = moment(video.EndTime, "YYYY-MM-DDTHH:mm:ss");
				if (!start.isSame(end, "day")) { // 跨天
					if (idx == 0) {
						start = moment(end).startOf("day");
					} else {
						end = moment(start).endOf("day");
					}
				}
				var _start = moment(start).startOf("hour");
				for (var i = 0;; i += 5) {
					var c = moment(_start).add(i, "minute");
					if (c.isBefore(start, "minute")) {
						continue;
					}
					if (c.isAfter(end, "minute")) {
						break;
					}
					var mtext = c.format("HH:mm");
					minArr.push(this.countTime(mtext));
					minutes[mtext] = Object.assign({}, video, {
						StartTime: c.format("YYYY-MM-DDTHH:mm:ss")
					});
				}
				idx++;
			}
			this.minutesArr = minArr;
			return minutes;
		}
	}
})

layui.use('laydate', function() {
	var laydate = layui.laydate;

	var nowDate = Format.dateFormat(new Date(), "YYYY-MM-DD");

	//常规用法
	laydate.render({
		elem: '#dateTime',
		value: nowDate,
		showBottom: false,
		max: nowDate,
		done: function(value, date, endDate) {
			vm.day = value.replace(/-/g,"/");
		}
	});

})

css

/**
 * 录像回放css
 */
.time-rule {
    overflow: hidden;
    position: relative;
    height: 50px;
    margin: 0 auto;
    width: 100%;
    font-size: 12px;
    max-width: 1440px;
    background-color: #CCC;
}

.time-day {
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    width: 1440px;
    cursor: pointer;
    -ms-user-select: none;
    user-select: none;
}

.time-minute {
    float: left;
    height: 8px;
    margin: 0;
    cursor: default;
}

.time-minute.active {
    background-color: #556677;
    cursor: pointer;
}

.time-text {
    float: left;
    width: 60px;
    border-left: 1px solid #999;
    border-top: 1px solid #999;
    -ms-user-select: none;
    user-select: none;
    text-align: center;
    height: 25px;
    line-height: 25px;
}

.time-text-first {
	border-left: 0;
    float: left;
    width: 60px;
    border-top: 1px solid #999;
    -ms-user-select: none;
    user-select: none;
    text-align: center;
    height: 25px;
    line-height: 25px;
   
}

.time-cursor {
    position: absolute;
    left: 0;
    top: 0;
    height: 30px;
    width: 2px;
    background-color: red;
    text-align: center;
}

.time-cursor-text {
    position: absolute;
    padding: 0 5px;
    width: 60px;
    left: -30px;
    top: 30px;
    border: 1px solid red;
    height: 15px;
    line-height: 15px;
    cursor: move;
    background-color: white;
    -ms-user-select: none;
    user-select: none;
}

.box-div{
	box-sizing:border-box;
	-moz-box-sizing:border-box; /* Firefox */
	-webkit-box-sizing:border-box; /* Safari */
}

效果

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值