Трансляция с камеры

в 13:45, , рубрики: Песочница, метки: , , ,

Пришла мне однажды идея создать трансляцию с камеры, и я решил ее реализовать. Для создания этого дела нам понадобится 4 файла (5, если считать CSS).
1. Index.php. Где будет сама трансляция.
2. Save.php. Куда будет сохраняться изображение.
3. Now.php. Где будет храниться изображения в base:64.
4. Translate.php. Откуда будет вестись трансляция.

Принцип прост: на странице translate.php пользователь открывает доступ к камере, потом делается снимок каждую секунду, потом этот снимок отправляется на страницу index.php.

Приступим. Index.php. Тут ничего сложного нет.

<!doctype html>
<head>
<meta charset="utf-8">
	<title>Просмотр</title>
	<link rel="stylesheet" href="main.css" />
	<script>
		function g (id) {
				return document.getElementById(id);
			};
			var ajax = {
				init: function (method, url, query, callback) {
					query = typeof query === "string" ? query : ajax._params(query);

					var xhr = new XMLHttpRequest();
					xhr.open(method, url);
					xhr.send(query);
					xhr.onreadystatechange = function (event) {
						if (xhr.readyState === 4)
							callback && callback(JSON.parse(xhr.responseText));
					};
				},
				get: function (url, params, callback) {
					ajax.init("GET", url + "?" + ajax._params(params), null, callback)
				},
				post: function (url, params, callback) {
					ajax.init("POST", url, params, callback);
				},
				_params: function (params) {
					if (typeof params === "string" || params == null)
						return params;
					var data = [], key, d = encodeURIComponent;
					for (key in params)
						data.push(d(key) + "=" + d(params[key]));
					return data.join("&");
				}
			};
			function setLoad () {
				ajax.get("now.php", "", function (data) { //берется изображение
					g("img").src = data.image;
				});
			};
			
			setInterval(setLoad, 50);
	</script>
</head>
<body>
	<div id="title">
		Трансляция с вебкамеры
	</div>
	 
	<div id="viewer">
		<img src="data:base64," alt="" id="img" width="640" height="480" class="img-content" /> //берется изображение и выводится 
	</div>
</body>
</html>

save.php. Предельно прост:

<?
$data = $_REQUEST["data"]; // получаем изображение
$fh = fopen("now.png", "w+"); // создаем и открываем файл с изображением 
$save = fwrite($fh, $data); // записываем данные в него
fclose($fh); // закрываем файл

exit(json_encode(["success" => !!$save, "time" => time()]));
?>

now.php. Тоже ничего сложного:

<?
exit(json_encode(["image" => file_get_contents("./now.png")], JSON_UNESCAPED_UNICODE));
?>

translate.php. Вот тут и начинаются танцы с бубном:

<!doctype html>
<head>
<meta charset="utf-8">
	<title>Трансляция</title>
	<link rel="stylesheet" href="main.css" />
	<script>
		function g (id) {
				return document.getElementById(id);
			};
			var ajax = {
				init: function (method, url, query, callback) {
					query = typeof query === "string" ? query : ajax._params(query);

					var xhr = new XMLHttpRequest();
					xhr.open(method, url);
					xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
					xhr.send(query);
					xhr.onreadystatechange = function (event) {
						if (xhr.readyState === 4)
							callback && callback(JSON.parse(xhr.responseText));
					};
				},
				get: function (url, params, callback) {
					ajax.init("GET", url + "?" + ajax._params(params), null, callback)
				},
				post: function (url, params, callback) {
					ajax.init("POST", url, params, callback);
				},
				_params: function (params) {
					if (typeof params === "string" || params == null)
						return params;
					var data = [], key, d = encodeURIComponent;
					for (key in params)
						data.push(d(key) + "=" + d(params[key]));
					return data.join("&");
				}
			};

			Number.prototype.n2 = function () {
				return this < 10 ? "0" + this : this;
			};

			Date.prototype.getString = function () {
				return [
					this.getDate(),
					".",
					(this.getMonth() + 1).n2(),
					".",
					this.getFullYear(),
					" ",
					this.getHours(),
					":",
					this.getMinutes().n2(),
					":",
					this.getSeconds().n2()
				].join("");
			};

			var Media = {
				media: navigator.getUserMedia || navigator.msGetUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia,
				url: window.URL.createObjectURL || window.URL.msCreateObjectURL || window.URL.mozCreateObjectURL || window.URL.webkitCreateObjectURL,
				video: null,
				canvas: null,
				ctx: null,
				init: function (video, canvas) {
					if (!Media.media || !Media.url)
						return alert("Не поддерживается Вашим браузером!");

					Media.canvas = canvas;
					Media.ctx = canvas.getContext("2d");
					Media.video = video;

					Media.media.call(navigator, {video: true}, Media.onSuccess, Media.onError);
				},
				onSuccess: function (stream) {
					var stream = Media.url(stream);
					Media.video.src = stream;
					Media.video.play();
					setTimeout(function () {
						Media.save(Media.getImage());
					}, 4000);
				},
				getImage: function () {
					Media.canvas.width = Media.canvas.width;
					Media.ctx.drawImage(Media.video, 0, 0, Media.canvas.width, Media.canvas.height);
					Media.ctx.font = "22px Tahoma";
					var date = new Date().getString();

					Media.ctx.fillStyle = "white";
					Media.ctx.fillText(date, 9, Media.canvas.height - 16);

					Media.ctx.fillStyle = "black";
					Media.ctx.fillText(date, 10, Media.canvas.height - 15);

					return Media.canvas.toDataURL("image/jpeg", .9);
				},
				save: function (data) {
					ajax.post("save.php", {
						data: data
					}, function (data) {
						Media.save(Media.getImage());
						if (data.success)
							g("time").innerHTML = "Время: " + (new Date(data.time * 1000).toLocaleString());
					});
				},
				onError: function(error) {
					alert("Видеокамера недоступна");
				}
			};
			window.onload = function (event) {
				Media.init(g("video"), g("canvas"));
			};
	</script>
</head>
<body>
	<div class="wrap">
			<div class="side fl">
				<h2>Веб-камера</h2>
				<div class="img-wrapper"><video id="video"></video></div>
			</div>
			<div class="side fr">
				<h2>Кадр на сайте</h2>
				<div class="img-wrapper"><canvas id="canvas" width="480" height="360"></canvas></div>
				<p id="time"></p>
			</div>
		</div>
</body>

На этом серверная часть готова. Можно теперь добавить чуть-чуть CSS.

			body{
				background-color: beige;
				font-family: ubuntu;
			}
			
/* Шрифт измените на свой, если он у вас есть */

			@font-face {
				font-family: Ubuntu;
				src: url("../Ubuntu.ttf") format("opentype");
			}

			#title{
				text-align: center;
				font-size: 30px;
			}
			
			#viewer{
				text-align: center;
				margin-top: 3%;
			}
			
			#viewer img{
				box-shadow: 0 0 50px rgba(0,0,0,5);
			}

Ну, вроде бы все. Теперь вы можете делать трансляцию с веб-камеры на сайт.

Исходники.

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js