Suppose, you are having a web application that has the feature to open a camera. For a Laptop or desktop machine, it is fine to access the one camera you are having. What if you are accessing the same web app on mobile or tablet, wouldn't it be cool to access both front and rear cameras. In this blog, we are going to create an Ember component using which will have features to access both Front and Rear cameras.
Let's build one!! ๐ท
- First of all, I am assuming you have one running ember application. If not create one
ember new my-camera-access
. - Navigate to your project
cd my-camera-access
. - I like to use ember-modifier, so let's install
ember-modifier
by runningember install ember-modifier
in your terminal. - Go to
app/templates/application.hbs
and remove ember generated boilerplate HTML code. Just leave{{outlet}}
{{outlet}}
- Run,
ember server
and your application will run atlocalhost:4200
. You can see a blank page. - Now, we are ready to add
dual-camera
component.
Creating dual-camera component:
- Run the
ember g component dual-camera
command in your terminal. - This will generate
app/components/dual-camera.hbs
. In the latest Ember version, it may skip the componentjs
class. You can add one by runningember generate component-class dual-camera
. This will addapp/components/dual-camera.js
. - Let's add some dummy code in the view file of the component.
<h1> Camera Test</h1>
- Now, to render the component we will place the camera component in
application.hbs
.<DualCamera /> {{outlet}}
- Now, on the web app you can see the text
Camera Test
.
Accessing camera and adding video-tag ๐ฅ
- Before working on accessing front/rear camera logic, we have to understand how the camera is accessed and how we can display the video captured by the camera.
- In HTML5 there is MediaDevices API which provides access to the camera.
- With this API we can provide video feeds to the browser to display video streams.
- We use
mediaDevices.getUserMedia
method to access the video feeds from the camera and play it in the browser. getUserMedia
method prompts the user for permission to access the camera. You can see Allow/Block options.- When the user selects "Allows" its returns a Promise that resolves to a media stream. The device access is blocked if the user clicks the "Block" button.
navigator.mediaDevices.getUserMedia({video: true}). //we will add other options later.
- The process of accessing the camera permission is achieved with the above line.
- As we discussed earlier it returns video feeds as a promise. This video feeds needs to be played somewhere.
- So, we are going to add the
video
tag in our component view i.eapp/components/dual-camera.hbs
.<video autoplay id="video-player"></video>
- We will add some styling to the video tag to make it a little large in size.
- For now, it is just video tag with
autoplay
property. It still does not have video streams. - We will add this data fetching logic in
did-insert
hook of theglimmer
component which will be called fromdid-insert
modifier in the video.<video autoplay id="video-player" {{did-insert this.onRender}}></video>
did-insert
will callonRender
action withvideo
tag as the parameter.
@action
onRender(videoPlayer) {
videoPlayer.play();
this.video = videoPlayer; // we are maintaining `videoPlayer` instance in the class to use it later.
this.initializeCamera();
}
- As soon as the view is inserted in the DOM,
onRender
method will be called, which will have access to the video tag. We can use it to play the stream. - But if you notice, we still haven't provided a video stream it is just a video tag.
Providing video stream to the video tag
- As discussed earlier, after allowing the permission to access the video. It returns video feeds as a promise.
- let's add this permission code in
initializeCamera
method.async initializeCamera() { ...... ...... const videoStream= await navigator.mediaDevices.getUserMedia(this.videoOpts); this.videoStream = videoStream; this.video.srcObject = videoStream; }
- As you can see
getUserMedia
returns stream which is assigned tovideo.srcObject
.video.srcObject
is nothing butvideo
player instance. - This will start displaying video on the web app.
Accessing Rear camera
- With the above implementation, we can access the front camera. How to access the rear camera?
- It's very easy, the options we provide to
getUserMedia
need to passfacingMode
options with a value ofenvironment
by default its value isuser
. - We will add one button in the view which will change the camera view.
<button {{action this.changeCamera}}>Change</button>
- We will add
changeCamera
action to change the camera view.@action changeCamera() { this.useFrontCamera = !this.useFrontCamera; this.initializeCamera(); }
- We are maintaining a boolean value of
useFrontCamera
to initialize the camera withfacingMode
options ofuser
andenvironment
. Something like below,async initializeCamera() { const cameraType = this.useFrontCamera ? "user" : "environment"; this.videoOpts.video.facingMode = cameraType; ...... ...... ...... }
Final Implementation of the javascript code is below
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
export default class DualCameraComponent extends Component {
@tracked videoStream = "";
@tracked useFrontCamera = true;
@tracked videoOpts = {
video: {
width: {
min: 1280,
ideal: 1920,
max: 2560
},
height: {
min: 720,
ideal: 1080,
max: 1440
}
}
};
async initializeCamera() {
const cameraType = this.useFrontCamera ? "user" : "environment";
this.videoOpts.video.facingMode = cameraType;
const videoStream = await navigator.mediaDevices.getUserMedia(this.videoOpts);
this.videoStream = videoStream;
this.video.srcObject = videoStream;
}
@action
onRender(videoPlayer) {
videoPlayer.play();
this.video = videoPlayer;
this.initializeCamera();
}
@action
changeCamera() {
this.useFrontCamera = !this.useFrontCamera;
this.initializeCamera();
}
}
I hope you like this easy implementation of accessing the front and rear cameras in the Ember application. If you have any questions then please comment below.