html5视频播放器和服务端

服务端可以用nginx,示例配置:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       8089;
        server_name  localhost;

        location / {
            root   d:/video;
            index  index.html index.htm;
        }

    }
}


也可以写个支持处理请求头Range的文件下载http请求的servlet
	private static final int BUFFER_LENGTH = 1024 * 16;
	private static final long EXPIRE_TIME = 1000 * 60 * 60 * 24;
	private static final Pattern RANGE_PATTERN = Pattern.compile("bytes=(?<start>\\d*)-(?<end>\\d*)");
	private static final File baseDir = new File("D:/video");

	@RequestMapping(value = "resource")
	public void resource(HttpSession session, String fileName,
			HttpServletRequest request, HttpServletResponse response) throws IOException {
		String realPath = baseDir.getPath() + File.separator + fileName;
		File file = new File(realPath);
		if (!file.exists() || !file.isFile()) {
			response.sendError(404);
			return;
		}

		// 未修改判断
		String IfModifiedSince = request.getHeader("If-Modified-Since"); // Tue, 06 Jun 2017 06:04:45 GMT
		SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd, MMM yyyy hh:mm:ss z", Locale.ENGLISH);
		if (IfModifiedSince != null) {
			try {
				Date date = sdf.parse(IfModifiedSince);
				if (date.getTime() >= file.lastModify()) {
					response.sendError(304);
					return;
				}
			} catch(Exception e) {
				System.out.println("解析If-Modified-Since失败");
			}
		}

		long lastModified = file.lastModified; // sdf.format(new Date(f.getLastModify()));
		String fileName = file.getName();

		Path ffff = Paths.get(realPath);

		// 处理文件读取的范围
		int length = (int) Files.size(ffff);
		int start = 0;
		int end = length - 1;

		String range = request.getHeader("Range");
		range = range == null ? "" : range;
		Matcher matcher = RANGE_PATTERN.matcher(range);

		int status = 206;;
		if (matcher.matches()) {
			String startGroup = matcher.group("start");
			start = startGroup.isEmpty() ? start : Integer.valueOf(startGroup);
			start = start < 0 ? 0 : start;

			String endGroup = matcher.group("end");
			end = endGroup.isEmpty() ? end : Integer.valueOf(endGroup);
			end = end > length - 1 ? length - 1 : end;
		} else {
			status = 200;
		}

		int contentLength = end - start + 1;

		//
		response.reset();
		response.setBufferSize(BUFFER_LENGTH);

		// 信息
		response.setHeader("Content-Disposition", String.format("inline;filename=\"%s\"", fileName));
		response.setContentType(Files.probeContentType(Paths.get(fileName)));
		// response.setContentType("application/octet-stream");

		// 缓存
		response.setDateHeader("Last-Modified", lastModified);
		response.setDateHeader("Expires", System.currentTimeMillis() + EXPIRE_TIME);

		// 内容范围和长度
		response.setHeader("Accept-Ranges", "bytes");
		response.setHeader("Content-Range", String.format("bytes %s-%s/%s", start, end, length));
		response.setHeader("Content-Length", String.format("%s", contentLength));
		response.setStatus(status);

		// 写出
		int bytesRead;
		int bytesLeft = contentLength;
		ByteBuffer buffer = ByteBuffer.allocate(BUFFER_LENGTH);
		try (SeekableByteChannel input = Files.newByteChannel(ffff, StandardOpenOption.READ);
				OutputStream output = response.getOutputStream()) {
			input.position(start);
			while ((bytesRead = input.read(buffer)) != -1 && bytesLeft > 0) {
				buffer.clear();
				output.write(buffer.array(), 0,
						bytesLeft < bytesRead ? bytesLeft : bytesRead);
				bytesLeft -= bytesRead;
			}
		}
	}





<!DOCTYPE HTML>
<html>
<body>
<h4>播放视频</h4>
视频源URL<input id="url" style="min-width:400px;" value="http://localhost:8089/videc/test.mp4">
<button οnclick="loadvideo();">载入视频</button>
<br>
<span style="font-size:10px; color: #aaa;">视频源可以用nginx配置访问静态资源的方式搭建</span>
<br>
<video id="video_ele" src=""
	controls="controls"
	style="min-width: 400px; min-height: 300px;"
	></video>

<script>
function vdonkeydown(event) {
	var keynum;
    var keychar;
    keynum = window.event ? event.keyCode : event.which;
    //keychar = String.fromCharCode(keynum);
    //console.log(keynum+':'+keychar);
    
    var e = document.getElementById("video_ele");
    if (keynum == 32) { // space
    	if (e.paused)
    		e.play();
    	else
    		e.pause();
    } else if (keynum == 37) { // left
    	var all = e.duration;
    	var v = e.currentTime;
    	v = v - 5;
    	if (v < 0)
    		v = 0;
    	e.currentTime = v;
    } else if (keynum == 39) { // right
    	var all = e.duration;
    	var v = e.currentTime;
    	v = v + 5;
    	if (v > all)
    		v = all - 1;
    	e.currentTime = v;
    } else if (keynum == 38) { // up
    	var v = e.volume;
    	v += 0.1;
    	if (v > 1)
    		v = 1;
    	e.volume = v;
    } else if (keynum == 40) { // down
    	var v = e.volume;
    	v -= 0.1;
    	if (v < 0)
    		v = 0;
    	e.volume = v;
    } else {
    	return true;
    }
    return false;
}

//单击双击判断
var dbclk = false;
function doclick(event) {
	// pauseswitch();
	//console.log(event.detail);
	if (event.detail == 1) {
		dbclk = false;
		setTimeout(function() {
			if (!dbclk) {
				pauseswitch(); // 暂停切换
			}
		}, 300);
	} else if (event.detail == 2) {
		dbclk = true;
		fullscreenswitch(); // 全屏切换
	}
	return false;
}

function pauseswitch() {
	var e = document.getElementById("video_ele");
	if (e.paused)
		e.play();
	else
		e.pause();
}

function fullscreenswitch() {
	var e = document.getElementById("video_ele");
	// 这种全屏判断方法,也还行,如果f12时肯定不行
	// console.log(e.scrollHeight + ' - ' + window.screen.height);
	// console.log(document.body.scrollHeight + ' - ' + window.screen.height);
	var bfullscreen = (document.body.scrollHeight == window.screen.height && document.body.scrollWidth == window.screen.width)
	if (!bfullscreen) {
		var e = document.getElementById("video_ele");
		console.log("inter full screen");
		if (e.requestFullscreen) { // w3c
			e.requestFullscreen();
		} else if (e.mozRequestFullScreen) { // FireFox
			e.mozRequestFullScreen();
		} else if (e.webkitRequestFullScreen) { // chrome
			e.webkitRequestFullScreen();  
		} else if (e.msRequestFullscreen) { // IE11
			e.msRequestFullscreen();
		}
		bfullscreen = true;
	} else {
		console.log("exist full screen");
		if (document.exitFullscreen) {
			document.exitFullscreen();
		} else if (document.mozCancelFullScreen) {
			document.mozCancelFullScreen();
		} else if (document.webkitCancelFullScreen) {
			document.webkitCancelFullScreen();
		} else if (document.msExitFullscreen) {
			document.msExitFullscreen();
		}
		bfullscreen = false;
	}
}
function loadvideo() {
	var e = document.getElementById("video_ele");
	if (!e.paused)
		e.pause();
	e.src = document.getElementById("url").value;
	return false;
}
(function(){
	var e = document.getElementById("video_ele");
	e.volume = 0.2;
	e.onclick = doclick;
	document.onkeydown = vdonkeydown;
})();


</script>
</body>
</html>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值