Nuxtjs video format converter

Eugene Musebe

Introduction

In an increasingly video-dependent world, the need for ensuring video format compatibility is increasing. In this video, we explore how we can programmatically change the video format.

Codesandbox

The final project can be viewed on Codesandbox.

You can find the full source code on my Github repository.

Prerequisites

To follow along in this tutorial. Basic knowledge on HTML, JavaScript, and CSS is required. VueJs knowledge will be helpful but it is not a hard requirement.

Setup

Nuxt.Js project

We are going to use the create-nuxt-app utility. To use it, make sure you have installed yarn, npx (included by default with npm v5.2+), or npm (v6.1+).

Open the terminal in your working directory of choice and run the following command:

1yarn create nuxt-app nuxtjs-video-format-converter

The above command will result in a series of setup questions. Here are our recommended defaults:

Project name: nuxtjs-video-format-converter

Programming language: JavaScript

Package manager: Yarn

UI framework: Tailwind CSS

Nuxt.js modules: N/A

Linting tools: N/A

Testing framework: None

Rendering mode: Universal (SSR / SSG)

Deployment target: Server (Node.js hosting)

Development tools: N/A

What is your Github username? Eugene Musebe

Version control system: Git

You may now enter the project and run it:

1cd nuxtjs-video-format-converter
2
3yarn dev

@nuxtjs/cloudinary

Cloudinary is a media management platform geared at allowing developers to unleash their full potential. We are going to set up the recommended @nuxtjs/cloudinary plugin.

Run the following command in the project folder:

1yarn add @nuxtjs/cloudinary
2# OR
3npm install @nuxtjs/cloudinary

Add @nuxtjs/cloudinary as a module in the modules section in the nuxt.config.js file:

1// nuxt.config.js
2export default {
3 ...
4 modules: [
5 '@nuxtjs/cloudinary'
6 ]
7 ...
8}

To configure our Cloudinary instance, add a cloudinary section in the nuxt.config.js file:

1// nuxt.config.js
2export default {
3 cloudinary: {
4 cloudName: process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,
5 secure: true,
6 useComponent: true
7 }
8}

The above piece of code refers to our environmental variables. These are values that are set in the code's environment as they are dependent on the environment in which the code is deployed. They can also be used to store sensitive values. Let's create our .env file:

1touch .env

After creation, we can now set our environmental variable:

1NUXT_ENV_CLOUDINARY_CLOUD_NAME=secret-cloud-name

Uploading video

In order to convert the video, we are first going to upload it to Cloudinary. This is because the video format conversion is all done on Cloudinary's platform.

Let us create the HTML form that will be used for file selection. As visible below, we ensure that only videos are uploaded.

1<!-- pages/index.vue -->
2<form @submit.prevent="submit">
3 ...
4 <input type="file" name="video" id="video" accept="video/*" v-on:change="handleFile" required />
5 ...
6 <div>
7 <p v-if="uploading">Uploading...</p>
8 <div v-else>
9 <button type="reset">Reset</button>
10 <button type="submit">Save</button>
11 </div>
12 </div>
13 ...
14</form>

Once the video has been selected, we trigger the handleFile method. In this method, we are going to store the selected file in our state.

1// pages/index.vue
2export default{
3 data(){
4 return {
5 uploadVideo: null,
6 cloudinaryVideo: null,
7 uploading: false
8 }
9 },
10 methods: {
11 async handleFile(e){
12 this.uploadVideo = e.target.files[0];
13 },
14 async readData(f) {
15 return new Promise((resolve) => {
16 const reader = new FileReader();
17 reader.onloadend = () => resolve(reader.result);
18 reader.readAsDataURL(f);
19 });
20 },
21 async submit() {
22 this.uploading = true;
23 const videoData = await this.readData(this.uploadVideo);
24 this.cloudinaryVideo = await this.$cloudinary.upload(videoData, {
25 upload_preset: "default-preset",
26 folder: "nuxtjs-video-format-converter",
27 });
28 this.uploading = false;
29 ...
30 },
31 }
32}

Once the form is submitted, we prevent submission and send then handle the event ourselves. We use the readData method to create a FileReader instance and get the file data. We then send this data to Cloudinary for storage. We specify the folder to be used for storage as well as an upload preset. This is a set of configurations to be followed when processing the file upload.

To create an upload preset, open the Add Upload Preset page. We are then going to use the following settings:

Name: default-preset

Mode: unsigned

Unique filename: true

Delivery type: upload

Access mode: public

Once the upload is complete, we store the video in the `Cloudinary video local state variable.

Converting video formats

Since we are using Cloudinary to convert video formats, we first need to understand which video output formats are supported. We can easily understand this by checking the Supported video formats section in the documentation. We are now going to add the video formats to the form above so that our users can select the format they want to download their video in.

1<!-- pages/index.vue -->
2<select
3 id="format"
4 name="format"
5 v-model="format"
6 required
7>
8 <option
9 v-for="format in formats"
10 :key="format.value"
11 :value="format.value"
12 >
13 {{ format.text }}
14 </option>
15</select>

The formats variable in the state is an array of all the supported output formats:

1// pages/index.vue
2export default {
3 data(){
4 return {
5 ...
6 format: null,
7 convertedUrl: null,
8 formats: [
9 { text: "FLV (Flash Video)", value: "flv" },
10 { text: "HLS adaptive streaming", value: "m3u8" },
11 { text: "MPEG-2 Transport Stream (ts)", value: "ts" },
12 { text: "MPEG-2 Transport Stream (m2ts)", value: "m2ts" },
13 { text: "MPEG-2 Transport Stream (mts)", value: "mts" },
14 { text: "MOV", value: "mov" },
15 { text: "MKV (Matroska Multimedia Container)", value: "mkv" },
16 { text: "MP4", value: "mp4" },
17 { text: "MPEG-DASH adaptive streaming ", value: "mpd" },
18 { text: "OGV (Ogg Video)", value: "ogv" },
19 { text: "WebM", value: "webm" },
20 ],
21 ...
22 };
23 }
24 ...
25}

Once the user selects their format of choice, we generate the converted URL once the upload is complete:

1// pages/index.vue
2export default {
3 ...
4 methods:{
5 ...
6 async submit(){
7 ...
8 this.uploading = false;
9 this.convertedUrl = this.$cloudinary.video.url(
10 this.cloudinaryVideo.public_id,
11 { format: this.format }
12 );
13 }
14 }
15}

We will use the cld-video component to display the convered video as well as use the convertedUrl to enable video download:

1<!-- pages/index.vue -->
2<div v-if="convertedUrl">
3 <h1>Video convertion complete</h1>
4 <p>
5 Here is a preview of your converted video. Use the button below to
6 download
7 </p>
8 <cld-video
9 controls="true"
10 :public-id="cloudinaryVideo.public_id"
11 :format="format"
12 >
13 </cld-video>
14 <a
15 target="_blank"
16 :href="convertedUrl"
17 >
18 Download
19 </a>
20 </div>

Conclusion

In the above tutorial, we learn how to convert video formats programmatically. This information is very useful for optimizing our video content when building intensive applications. Feel free to review the entire video transformation documentation to learn what else is possible.

Eugene Musebe

Software Developer

I’m a full-stack software developer, content creator, and tech community builder based in Nairobi, Kenya. I am addicted to learning new technologies and loves working with like-minded people.