Друзья! Близятся те времена, когда почти все, для чего нужен был флеш в браузере, можно будет делать и без него. Не знаю как у вас, а у меня это вызывает кучу положительных эмоций. Одним из шагов на пути вытеснения flash становится реализация в браузерах getUserMedia (Stream) javascript API. На данный момент Stream API для видеопотока реализовано в последних десктопных версиях Chrome и Opera. Firefox на подходе. Аудиопоток «coming soon». Даже не знаю, ждать ли чего-то от IE .. по идее, он скорее умрет (..а он умрет), чем начнет догонять всех остальных.
Подробнее о поддержке в браузерах можно посмотреть тут — /caniuse.com/stream
Давайте взглянем на пример, а потом посмотрим, как это работает:
Давайте разберемся, как это работает.
Для начала нам понадобятся такие элементы, как:
video
, в котором мы будем воспроизводить поточное видео с камеры пользователяcanvas
, в который мы будем помещать кадры для сохранения- кнопка для захвата изображения
- подсказка для юзера, который не понял, что вообще от него хотят.
Далее нам нужно спросить у пользователя разрешения использовать его видеопоток.
JS
navigator.getUserMedia(
{video:true}, // тип запрашиваемого стрима (может быть audio)
function(stream) {/*callback в случае удачи*/},
function(){/*callback в случае отказа*/})
Как видно, в случае удачи в callback вернется объект stream, на основе которого можно получить url видеопотока. Сделать это можно с помощью window.URL.createObjectURL(stream)
, которая может быть вам знакома, если вы когда-либо использовали js file API.
JS
var url = window.URL.createObjectURL(stream);
Далее:
- передаем этот url объекту video
- при нажатии на кнопку захватываем текущий кадр video в canvas
- забираем data:url получившегося изображения из canvas
- и все, готово! Можно делать с ним все, что угодно: отправить на сервер, отфильтровать, передать другу через сокет и тп. Подробнее про base64 и data:url формат можно почитать тут.
Давайте рассмотрим код примера в начале статьи для наглядности
Конечно, лучше и красивее создать все элементы (canvas, video, ..) динамически, но для наглядности и понимания давайте изначально расположим их статически на странице:
HTML
<div id="allow">▲ ▲ ▲ Разрешите использовать камеру ▲ ▲ ▲ <br/> ( Сверху текущей страницы )</div>
<div class="item">
<span> video </span>
<video id="video" width="320" height="240" autoplay="autoplay" ></video>
</div>
<div class="item">
<span> canvas </span>
<canvas id="canvas" width="320" height="240" ></canvas>
</div>
<input id="button" type="button" value="Жми!" />
JS
<script>
window.onload = function () {
var canvas = document.getElementById('canvas');
var video = document.getElementById('video');
var button = document.getElementById('button');
var allow = document.getElementById('allow');
var context = canvas.getContext('2d');
var videoStreamUrl = false;
// функция которая будет выполнена при нажатии на кнопку захвата кадра
var captureMe = function () {
if (!videoStreamUrl) alert('То-ли вы не нажали "разрешить" в верху окна, то-ли что-то не так с вашим видео стримом')
// переворачиваем canvas зеркально по горизонтали (см. описание внизу статьи)
context.translate(canvas.width, 0);
context.scale(-1, 1);
// отрисовываем на канвасе текущий кадр видео
context.drawImage(video, 0, 0, video.width, video.height);
// получаем data: url изображения c canvas
var base64dataUrl = canvas.toDataURL('image/png');
context.setTransform(1, 0, 0, 1, 0, 0); // убираем все кастомные трансформации canvas
// на этом этапе можно спокойно отправить base64dataUrl на сервер и сохранить его там как файл (ну или типа того)
// но мы добавим эти тестовые снимки в наш пример:
var img = new Image();
img.src = base64dataUrl;
window.document.body.appendChild(img);
}
button.addEventListener('click', captureMe);
// navigator.getUserMedia и window.URL.createObjectURL (смутные времена браузерных противоречий 2012)
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
window.URL.createObjectURL = window.URL.createObjectURL || window.URL.webkitCreateObjectURL || window.URL.mozCreateObjectURL || window.URL.msCreateObjectURL;
// запрашиваем разрешение на доступ к поточному видео камеры
navigator.getUserMedia({video: true}, function (stream) {
// разрешение от пользователя получено
// скрываем подсказку
allow.style.display = "none";
// получаем url поточного видео
videoStreamUrl = window.URL.createObjectURL(stream);
// устанавливаем как источник для video
video.src = videoStreamUrl;
}, function () {
console.log('что-то не так с видеостримом или пользователь запретил его использовать :P');
});
};
</script>
CSS
video{
transform: scaleX(-1);
-o-transform: scaleX(-1);
-ms-transform: scaleX(-1);
-moz-transform: scaleX(-1);
-webkit-transform: scaleX(-1);
}
Зеркальное отображение при съемке
В примере выше мы делали захват изображений с зеркальным отображением по горизонтали. Зачем, спросите вы. Иногда можно встретить такие задачи. Это особенно актуально, когда вам нужно точно спозиционировать свое изображение по отношению к фрейму или окружающим предметам. Например, поместить свое лицо в заданную область для сканирования, совместить с предустановленной маской и т.п. В этом случае для пользователя будет удобнее, если изображение, получаемое с камеры, отображается на мониторе зеркально (по горизонтали).
Как мы этого достигли:
Во-первых, мы сделали css transform для video
CSS
video{
transform: scaleX(-1);
-o-transform: scaleX(-1);
-ms-transform: scaleX(-1);
-moz-transform: scaleX(-1);
-webkit-transform: scaleX(-1);
}
Во-вторых, повернули изображение на canvas таким же образом
JS
// переворачиваем canvas зеркально по горизонтали
context.translate(canvas.width, 0);
context.scale(-1, 1);
Если вам не нужно зеркальное отображение, просто удалите эту часть js и css
Удачи! Жду вопросов и поправок в комментариях.
как раз вчера клиент просил такую фичу и я думал, что придется оборачивать приложение в phonegap для снабжения его большей свободой :( — А тут очень кстати твой пост! Супер!
Будьте осторожны с поддержкой браузеров, эта штука пока очень сырая :(
http://caniuse.com/stream
Добрый день, подскажите как отправить base64dataUrl на сервер?
Мы сейчас на проекте обсуждаем альтернативы нативному iOS приложению, которое нам
пока не удалось сделать достаточно стабильным. Т.к. есть разработчики которые
делают веб-приложение, то рассматриваем альтернативы типа phonegap или appcelerator.
Но ни у кого нет опыта работы с ними. Есть понимание, что простые вещи там можно
сделать, а вот запись видео/фото/аудио, отправка на сервер да так, чтобы это
работало стабильно… мы не знаем.
Может есть опыт и знание этих платформ и можете подсказать, возможно ли там такое
реализовать?
Так получилось, что последнее время мы делаем мини приложения для http://urturn.com у которого есть phonegap based ios app. Мы используем нативную objective C часть для захвата с камеры, а в webview (web часть) только для интерфейсов и всей пост обработки (canvas, svg, разные стикеры, эффекты и тп). Сразу хочу сказать, работать в ios uiwebview с phonegap — это кошмар. Очень много ограничений, нужно следить за памятью, дебажить очень сложно + сотни непонятных багов сходных по уровню магии с ie6. Если Вы хотите сделать приложеие с хорошим быстрым юзер-интерфейсом, обработкой видео или аудио или даже просто фото и все это для IOS.. лучше сделать его нативым (( Я думаю что apple еще долго будет искуственно тормозить развитие web-based приложений, и это связано в основном с политикой компании. Что касается android, firefoxOS, blackberryOS, TizenOS.. то через несколько лет, все перейдут (если уже не перешли) к web-based приложениям. Но это уже совсем другая история :)
ковыряюсь с программаой.
на ноуте все работает, на смартфоне — нет.
как разрешить на смартфоне использование камеры? у меня самсунг GT-S6810 с андроидом 4.1.2
как браузеры стоят хром и мозила 5.0
эта страничка открвается, но нету диалога(или скорее я не могу его найти) о том, что есть запрос на использование камеры.
подскажите, где почитать
спасибо заранее
К сожалению, ничего пока не получится. На данный момент (08.2013) ни один мобильный браузер толком не поддерживает getUserMedia API.
Подробнее тут http://caniuse.com/#search=getusermedia
chrome для андроид теперь поддерживает getUserMedia (03.2014)
Немного не по теме, но близко. Нужен захват «видео» из окна браузера. Пользователь работает с корпоративным сайтом и для саппорта очень бы помогло увидеть то, что видит пользователь. Может быть подскажите в какую сторону копать и возможно ли вообще такое?
посмотрите скриншаринг с использованием webRTC (но это пока очень на ранней стадии, только в хроме с включеным флагом)http://stackoverflow.com/questions/17542384/accomplish-screen-sharing-using-webrtc
Другое решение — написать расширение для браузера. Там точно можно делать скриншоты и отправлять их куда вам надо ;)
Пробую скопировать код, всё отрабатывает, но при отправке на сервер и base64_decode получаю чёрную картинку… Что может быть не так?
перед отправкой на сервер, попробуйте вставить base64 url в img.
и посмотрите, как это выглядит, дейсвительно ли вы отправляете не черную картинку. Если все ок, ищите проблемы по пути передачи или декодирования. Конкретнее, к сожалению, ничего не посоветую.
ошибка тут
var base64dataUrl = canvas.toDataURL(‘image/png’);
если подставлять параметры то получается ошибка https://pp.vk.me/c623927/v623927444/1eae4/Dvb4PN_cGlc.jpg просто исправте на
var base64dataUrl = canvas.toDataURL();
Замечательно! Как раз искал варианты для вызова камеры со смартфона из HTML+JS
Подскажите, пожалуйста! При сохранении переданного изображения BASE64 на сервере сохраняется неверный формат, который не отображается. Клиент:
Спасибо за статью. Тестировал Вашу программу на firefox и хроме под android — всё работает. Скажите подалуйста, как получить управление фокусировкой и другими настройками камеры?
сапасибо за статью. с видео все получилось и в мобильных браузерах работает.
а как можно сделать что бы аудио записывалось. ну там, например 5с после нажатия кнопки. как мне потом этот stream в файл аудио запихнуть. может подскажите?
ну или с видео: что бы не просто скриншот брался, а тоже скажем 5с видео сохранялось в файл.
Отличная штука. Осталось решить, как лучше «убить» видеозахват, когда он более не нужен на странице.
А это очень просто:
Повесить обработчик на кнопку или куда-то ещё, и прописать:
navigator.getUserMedia({video: false})
Или:
videoStreamUrl = false
Подскажите, как получить доступ к основной камере мобильного телефона? по умолчанию включается фронтальная камера
И второй вопрос, можно ли разрешить использование камеры по умолчанию, а не спрашивать каждый раз пользователя об этом?
C начала 2016 г. ваша демка перестала работать в Chrome, в Mozille работает, в чем может быть проблема?
As of Chrome 47, the getUserMedia API cannot be called from insecure origins.
Открывайте ссылку по https в Chrome.
Спасибо за подробное описание. Надеюсь этой темой Вы занимаетесь и за прошедшие годы стали ассом. Чтобы смотреть себя в браузере много где теперь написано. Но никак не найду как можно между двумя и более людьми видеопоказ устроить. Типа один показывает, а несколько смотрят. На флэше с RED5 сделал, но скоро обещают что его не будет. Хочется на новом HTML5, а никак. Может поможете или направите в полезное место? Нашел только тех кто через свой сервер делает. А хочется независимо сделать на своем.
Вам нужно смотреть в сторону webrtc
https://habrahabr.ru/post/198632/
https://habrahabr.ru/post/255833/
Уже спрашивали в этом чате, но ответа, к сожалению, не нашел, может кто-то уже решил данную проблему.
Подскажите, пожалуйста, как получить доступ к основной камере мобильного телефона в хроме? По умолчанию включается фронтальная камера, а в опере предоставляется возможность выбора камеры. Необходимо сделать, чтобы всегда включалась основная (задняя) камера или, на крайний случай, был выбор, как в опере.
Спасибо.
I genuinely enjoy looking att on this site, it has got wonderful content.
I just like the valuable information you supply for
your articles. I will bookmark your blig and take a look at again right here regularly.
I’m rather certain I will be told plenty of new stuff right
here! Best of luck for the following!