AccessMediaStream - camera direction

My current setup involves using an Android tablet and GetUserMedia to capture images in my program.

It seems that by default, GetUserMedia uses the front camera. How can I set the rear camera as the default instead?

Below is the code snippet I am using with GetUserMedia:

        navigator.getUserMedia({
            "audio": false,
            "video": {
                mandatory: {
                    minWidth: this.params.dest_width,
                    minHeight: this.params.dest_height,
                    //facingMode: "environment",
                },
            }
        }, 
        function(stream) {
            // Access granted, linking stream to video
            video.src = window.URL.createObjectURL( stream ) || stream;
            Webcam.stream = stream;
            Webcam.loaded = true;
            Webcam.live = true;
            Webcam.dispatch('load');
            Webcam.dispatch('live');
            Webcam.flip();
        },
        function(err) {
            return self.dispatch('error', "Could not access webcam.");
        });

I attempted to add facingMode in the "mandatory" section but it did not work as expected.

Your assistance in resolving this issue would be greatly appreciated.

Answer №1

Update: facingMode can now be found in Chrome for Android thanks to the adapter.js polyfill!

facingMode is currently not supported in Chrome for Android, but it works smoothly in Firefox for Android.

When implementing constraints, make sure to adhere to the standard guidelines: (you can use this https fiddle for Chrome):

var gum = mode => 
  navigator.mediaDevices.getUserMedia({video: {facingMode: {exact: mode}}})
  .then(stream => (video.srcObject = stream))
  .catch(e => log(e));

var stop = () => video.srcObject && video.srcObject.getTracks().forEach(t => t.stop());

var log = msg => div.innerHTML += msg + "<br>";
<button onclick="stop();gum('user')">Front</button>
<button onclick="stop();gum('environment')">Back</button>
<div id="div"></div><br>
<video id="video" height="320" autoplay></video>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

The { exact: } notation indicates that the constraint is mandatory, and failure may occur if the user lacks the appropriate camera. Omitting it makes the constraint optional, which in Firefox for Android only alters the default choice in the camera selection during permission prompts.

Answer №2

After studying Peter's code () closely, I devised a solution to access the rear camera:

function handleSuccess(stream) {
  window.stream = stream; // allowing access to browser console
  video.srcObject = stream;
}

function handleError(error) {
  console.log('navigator.getUserMedia error: ', error);
}

var DEVICES = [];
var final = null;
navigator.mediaDevices.enumerateDevices()
    .then(function(devices) {

        var arrayLength = devices.length;
        for (var i = 0; i < arrayLength; i++)
        {
            var tempDevice = devices[i];
            
            // Picking only video input devices (cameras) and checking if they match the desired facing mode
            // Assigning device found to "final"
            if (tempDevice.kind == "videoinput")
            {
                DEVICES.push(tempDevice);
                if(tempDevice.facingMode == "environment" ||tempDevice.label.indexOf("facing back")>=0 )
                    {final = tempDevice;}
            }
        }

        var totalCameras = DEVICES.length;
        
        // If no suitable camera is found, select the last one by default
        if(final == null)
        {
            //console.log("no suitable camera, getting the last one");
            final = DEVICES[totalCameras-1];
        };

        // Defining constraints and calling getUserMedia with the final selected device
        var constraints = {
        audio: false, 
        video: {
            deviceId: {exact: final.deviceId}
            }
        };

        navigator.mediaDevices.getUserMedia(constraints).
        then(handleSuccess).catch(handleError);

    })
    .catch(function(err) {
        console.log(err.name + ": " + err.message);
});

Answer №3

When deploying our web application to Android using Cordova, I encountered various challenges in accessing the rear camera. After trying multiple solutions, I finally found success with the following code snippet:

constraints = {
    audio: false,
    video: {
        width: 400,
        height: 300,
        deviceId: deviceId ? {exact: deviceId} : undefined
    }
};

To retrieve the deviceId, I utilized the following method:

navigator.mediaDevices.enumerateDevices()
    .then(function(devices) {
        // devices is an array of available audio and video inputs. The deviceId property was crucial for switching cameras.
    })
    .catch(function(err) {
        console.log(err.name + ": " + error.message);
});

I made a conscious decision not to rely on a Cordova plugin so that transitioning away from Cordova in the future would be less burdensome.

Answer №4

Here's a nifty code snippet that might come in handy:

let isFront = false;
document.getElementById('toggle-button').onclick = function() { isFront = !isFront; };
let videoOptions = { facingMode: (isFront ? "user" : "environment") };

This should do the trick for you.

Answer №5

After updating to Chrome version 52, I encountered issues with the adapter.js solutions not working as expected. To solve this problem, I decided to enumerate devices first and came up with a solution that involves flipping the camera and displaying the video on the screen. Although there may be alternative methods to achieve this, I found it necessary to stop the track and obtain a new stream in my implementation.

let Video = function() {
    let cameras = [];
    let currCameraIndex = 0;
    let constraints = {
        audio: true,
        video: {
          deviceId: { exact: "" }
        }
      };
    let videoCanvas = $('video#gum');


    this.initialize = function() {
      return enumerateDevices()
        .then(startVideo);
    };

    this.flipCamera = function() {
      currCameraIndex += 1; 
      if (currCameraIndex >= cameras.length) {
        currCameraIndex = 0;
      }

      if (window.stream) {
        window.stream.getVideoTracks()[0].stop();
      }
      return startVideo();
    };

    function enumerateDevices() {
      return navigator.mediaDevices.enumerateDevices()
        .then(function(devices) {
          devices.forEach(function(device) {
            console.log(device);
            if (device.kind === "videoinput") {
              cameras.push(device.deviceId);
            }
          });
          console.log(cameras);
        });
    }

    function startVideo() {
      constraints.video.deviceId.exact = cameras[currCameraIndex];
      return navigator.mediaDevices.getUserMedia(constraints)
        .then(handleSuccess).catch(handleError);
    }

    function handleSuccess(stream) {
      videoCanvas[0].srcObject = stream;
      window.stream = stream;
    }

    function handleError(error) {
      alert(error);
    }
};

Answer №6

For optimal rear camera functionality:

navigator.mediaDevices.getUserMedia({
video: {facingMode: "environment",
 height:{<heightValueHere>},
 width : {<widthValueHere>} 
}
})
.then(function(stream){
window.stream = stream;
video.srcObject = stream;

})

Answer №7

My technique for utilizing webcam.js involves calling LoadWebcam()

async function LoadWebcam () { 
var i
var frontdev 
var backdev
const tempStream = await navigator.mediaDevices.getUserMedia({video:true})
const devices = await navigator.mediaDevices.enumerateDevices()
//Searching for the back camera device among available video inputs
devices.forEach(function(device) {
    if (device.kind === 'videoinput') {
        if( device.label && device.label.length > 0 ) {
          if( device.label.toLowerCase().indexOf( 'back' ) >= 0 ) 
            backdev = device.deviceId
          else if( device.label.toLowerCase().indexOf( 'front' ) >= 0 )
            frontdev = device.deviceId
        }
    }
})
//Stopping temporary stream
const tracks = tempStream.getTracks()
if( tracks ) 
  for( let t = 0; t < tracks.length; t++ ) tracks[t].stop()
//Configuring and loading the webcam 
Webcam.set({
    width: 320,
    height: 240,
    image_format: 'png',
    jpeg_quality: 90,
    flip_horiz: true,
    constraints: {
    video: true,
        deviceId: {exact: backdev }
    }
});
Webcam.attach( '#my_camera' )}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Evaluate a program to identify prime numbers

I am currently working on a JavaScript program that utilizes recursion to determine whether an input is a prime number or not. Within my code, I've defined the isPrime function. The base cases are set to return false when x==1 and true for x==2, cons ...

Combining selected boxes through merging

Looking to create a simple webpage with the following requirements: There should be 10 rows and 3 boxes in each row. If I select 2 or more boxes or drag a box, they should merge together. For example, if my initial screen looks like this: and then I se ...

What is the best way to divide data prior to uploading it?

I am currently working on updating a function that sends data to a server, and I need to modify it so that it can upload the data in chunks. The original implementation of the function is as follows: private async updateDatasource(variableName: strin ...

Arrange the object's key-value pairs in ng-repeat by their values

I'm completely new to AngularJS and I am working with an API that returns key-value pairs related to different sports. $scope.sports = { 1: "Soccer", 2: "Tennis", 3: "Basketball" ... }; My challenge is sorting these items by sport name: <ul> ...

Select2 using AJAX: chosen option disappears upon receiving AJAX response

Despite going through numerous questions and answers, the issue persists. Here is an excerpt of the code in question: <div class="col-md-2"> <label for="wh_location">{{ __('reports.warehouse_movement.location') ...

Issues with visuals in jQuery.animate

I have nearly finished implementing a slide down drawer using jQuery. The functionality I am working on involves expanding the drawer downwards to reveal its content when the handle labeled "show" is clicked, and then sliding the drawer back up when the ha ...

Oops! Looks like there was an error. The text strings need to be displayed within a <Text> component in the BottomTabBar. This occurred at line 132 in the

My app includes a bottomTab Navigation feature, but I encountered an error: Error: Text strings must be rendered within a <Text> component. This error is located at: in BottomTabBar (at SceneView.tsx:132) in StaticContainer in StaticCont ...

How can I safeguard my HTML and CSS content from being altered using tools similar to Firebug?

Is there a method to deter the alteration of HTML and CSS components on a webpage using tools similar to Firebug? I have noticed that certain users are changing values in hidden fields and modifying content embedded within div or span tags for their perso ...

Create a shape using a series of points without allowing any overlap between the lines

JS fiddle There is an array of coordinates that gets populated by mouse clicks on a canvas. var pointsArray = []; Each mouse click pushes x and y values into this array using a click event. pointsArray.push({x: xVal, y: yVal}); The script iterates thr ...

Can anyone explain to me how to render attributes of a tag in Vue? I'm curious about how v-for interacts with HTML

<ul> <span class="tabs" :class="{ activeTab: selectedTab === tab }" v-for="(tab, index) in tabs" @click="selectedTab = tab" :key="tab"> {{ in ...

Frontend experiencing issues with Laravel Echo Listener functionality

I have recently developed a new event: <?php namespace App\Events; use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PresenceChannel; use Illuminate&bs ...

Improving form handling with Vuex: Ensuring state is only updated after pressing the submit button

I am currently working on developing a form that pulls data from a Vuex store, allowing users to update the form fields and then submit when they are ready. Most tutorials I have seen use v-model with computed get() and set() to retrieve values from the s ...

Is it possible to display a combination of images and text data using JQUERY/AJAX, when the data is sent as objects or arrays?

I'm struggling to figure out how to handle an object or array sent from a server that contains binary picture and text data using JQUERY/AJAX Here is the server-side setup: const url= require('url'), express = require('express&ap ...

When utilizing "reques" in Node.js code, the parameter response.timings may be found to be undefined

The code I created in node.js is giving me trouble - for some reason, response.timing is showing up as undefined. Any idea what could be causing this issue? const request = require("request"); request.get({ time : true, url : 'https://www.bbc.com ...

Unable to see Bootstrap 5.2 Modals in action with documentation demo

Here is an example that I copied and pasted from the documentation on https://getbootstrap.com/docs/5.2/components/modal/: <!-- Button trigger modal --> <button type="button" class="btn btn-primary" data-bs-toggle="modal&q ...

Creating a responsive Google map within a div element: A step-by-step guide

I am experiencing difficulties with implementing a responsive Google map on my webpage. To achieve a mobile-first and responsive design, I am utilizing Google Map API v3 along with Bootstrap 3 CSS. My objective is to obtain user addresses either through th ...

Tips for modifying date format in Angular 8

My datepicker for a date column is displaying the incorrect date format after submission. I am looking to change this format to the correct one. I am working with bsConfig bootstrap in Angular 8, but I am unsure of how to modify the date format. The back ...

Tips for choosing a single row in a table using a checkbox

I need help with a table that has multiple rows and four columns. One column is for checkboxes, while the other three are select boxes set to read-only. I want users to be able to edit only one row at a time by checking the checkbox in the first column. If ...

Group HTML Tables According to Specific Attributes

Let's cut to the chase. My table is functioning well, printing all the necessary information without any issues. However, I'm facing a challenge when it comes to grouping the data rows under Program 1 together. Instead of having Program 1 print, ...

The utilization of 'ref' with React Styled Components is proving to be ineffective

Using refs in Styled Components has been tricky for me. When I attempt to access them in my class methods as shown below, I encounter the error message: Edit.js:42 Uncaught TypeError: this.....contains is not a function constructor(props) { .... ...