Enhance video quality with Dolby

Emma Alder

According to one of the leading companies specialized in market and consumer data, statista; the global film industry is more than a 42 billion U.S. dollar business. This projection has brought about the invention of new software, jobs, and specialized personnel to help improve the quality of videos and audio within movies.

In this post, we will discuss how to achieve better video sound quality using Dolby, Cloudinary, and Next.js. At the end of this tutorial, we will learn how to upload video to Cloudinary, process the audio with Dolby, and then re-upload the enhanced video to Cloudinary.

By way of introduction, Dolby is an API platform for transforming media and communications. It offers sets of reach APIs for enhancing, analyzing, diagnosing, and analyzing media data.

Next.js is a React-based front-end development framework that enables functionalities like server-side rendering, static site generation, file-system routing (with no need to manually configure react-router-dom), and API endpoints for backend features.

Cloudinary is a platform on which you can quickly and easily upload, store, manage, transform, and deliver images and videos for websites and apps. The platform also offers a vast collection of SDKs for frontend frameworks and libraries.

Sandbox

We completed this project in a Codesandbox, and you can “fork” it to run the code. Ensure you update the Sandbox with your Cloudinary and Dolby API keys before using it. Also, disable CORS in your browser, preferably in Safari.

1<CodeSandbox id="laughing-cdn-4mvfo"/>

Prerequisites

The next steps in this post require JavaScript and React.js experience. Experience with Next.js isn’t a requirement, but it’s nice to have.

We also need the following:

Getting Started

We need to create a Next.js starter project by navigating to the desired directory and running the command below in our terminal:

1npx create-next-app video-enhancer && cd video-enhancer

This command creates a Next.js project called video enhancer and navigates into the project directory.

We proceed to install the required dependencies with:

1npm install react-helmet

react-helmet is a library that takes plain HTML tags and adds them to the <head/> element of a web page. It will help us avoid the Reference error: Window is not Defined error when using client-side only packages in Next.js.

Setting up Cloudinary Upload Widget

With the project dependencies installed, we can now set up our application to use the Cloudinary Upload Widget. To use the Cloudinary Upload Widget in our application, we need to include the script from a CDN in our application using react-helmet, a package we installed earlier. Add the script from a CDN to index.js file in pages folder to use Cloudinary Upload Widget:

1import { Helmet } from "react-helmet"
2 export default function IndexPage() {
3 return (
4 <div>
5 <Helmet>
6 <script src="https://upload-widget.cloudinary.com/global/all.js" />
7 </Helmet>
8 <button>Upload Video</button>
9 <form>
10 <input
11 type="text"
12 required
13 disabled
14 />
15 <button>Enhance Audio</button>
16 </form>
17 </div>
18 );
19 }

Next, we need to start a development server using the command below:

1npm run dev

Next.js will start a development server on http://localhost:3000.

With our application up and running, we can leverage Next.js CSS Module support to style our page. First, we need to create a components folder in project root directory and, in that folder, create a Style.module.css file.

Next, we need to add the code snippet as shown below:

1.upload {
2 height: 30px;
3 color: white;
4 font-size: 14px;
5 background-color: green;
6 border: none;
7 }
8
9 .input {
10 display: block;
11 height: 30px;
12 border-radius: 5px;
13 width: 80%;
14 margin-bottom: 20px;
15 }
16
17 .button {
18 height: 30px;
19 color: white;
20 font-size: 14px;
21 background-color: rgb(22, 22, 177);
22 border: none;
23 }

With that done, we can update index.js file with the styles created and configure Cloudinary Upload Widget to upload videos to Cloudinary. We also include state variables to handle state for upload and enhancement of videos.

1import { Helmet } from "react-helmet";
2 import { useState } from "react"; //add
3 import Style from "../components/Style.module.css";
4
5 export default function IndexPage() {
6 const [urlLink, setUrlLink] = useState(null); //add
7
8 //add
9 const openWidget = () => {
10 window.cloudinary
11 .createUploadWidget(
12 {
13 cloudName: <REPLACE WITH YOUR CLOUDNAME>,
14 uploadPreset: <REPLACE WITH YOUR UPLOADPRESET>
15 },
16 (error, result) => {
17 if (!error && result && result.event === "success") {
18 setUrlLink(result.info.url);
19 }
20 }
21 )
22 .open();
23 };
24
25 return (
26 <div>
27 <Helmet>
28 <script src="https://upload-widget.cloudinary.com/global/all.js" />
29 </Helmet>
30 {!urlLink && (
31 <button className={Style.upload} onClick={() => openWidget()}>
32 Upload Video
33 </button>
34 )}
35 {urlLink && (
36 <form>
37 <input
38 className={Style.input}
39 type="text"
40 disabled
41 placeholder="enter video url"
42 value={urlLink}
43 onChange={(e) => setUrlLink(e.target.value)}
44 />
45 <button className={Style.button}>Enhance Audio</button>
46 </form>
47 )}
48 </div>
49 );
50 }

<!— Is cloud name intentionally suppose to have special characters ? COMMENT-WILLIAM: No those are just dummy values. —>

The Cloudinary Upload Widget also configures cloudName and uploadPreset. The cloudName is the name of our Cloudinary account while uploadPreset is a parameter that enables us to centrally define a set of asset upload options instead of specifying them in each upload call.

Find out more about Cloudinary Upload Widget here.

With this, we can now test the application by uploading video, get the URL, and then populate our form input field with the URL.

Integrating Dolby Media Processing APIs

Setup a Developer Account

To get started, we need to create an account with Dolby. Creating an account is completely free.

In the summary view, click ADD NEW APP, enter video-enhancer as the app name and then click on CREATE

In the Applications section, click on the LINK ICON to reveal the API Key for **the video-enhancer app we created.

Integrating Dolby with Next.js

Setup Environment Variable To integrate Dolby into our app, we need to include the API Key **generated above **into the application. In the project directory, we will create a next.config.js file and add the code snippet

<!— Would it be more safe to use a .env ? —>

1module.exports = {
2 env: {
3 customKey: <REPLACE WITH OUR API KEY>
4 }
5 };

Typically, you want to have this environment variable in a private .env file. You can look up how to do this with Dotenv

Enhancing our Uploaded Video Sound Quality To enhance video sound, Dolby provides us with three APIs to work with:

  • An API to make a media enhancement request. This API takes in input URL (video to be enhanced), output URL (for downloading enhanced video), and returns a job_id
    • [https://api.dolby.com/media/enhance](https://api.dolby.com/media/enhance)
  • An API to check the status of uploaded video
    • [https://api.dolby.com/media/enhance?job_id=<Our job_id comes here>](https://api.dolby.com/media/enhance)
  • An API to download enhanced media
    • [https://api.dolby.com/media/output](https://api.dolby.com/media/output).

First, in pages/index.js, we need to create states to store required variables

<!— Is this code snippet to be added in pages>index.js ? —>

1import { useState } from "react";
2 import { Helmet } from "react-helmet";
3 import Style from "../components/Style.module.css";
4
5 export default function IndexPage() {
6 const [urlLink, setUrlLink] = useState(null);
7 //add
8 const [cloudName] = useState("dtgbzmpca");
9 const [uploadPreset] = useState("tca2j0ee");
10 const [dolbyURL] = useState("dlb://out/video-enhanced.mp4");
11 const [uploadURL] = useState("https://api.dolby.com/media/enhance");
12 const [downloadURL] = useState("https://api.dolby.com/media/output");
13 const [cloudinaryURL] = useState(
14 `https://api.cloudinary.com/v1_1/${cloudName}/auto/upload`
15 );
16
17 const openWidget = () => {
18 //Cloudinary upload widget code goes here
19 };
20
21 return (
22 <div>
23 {\* JSX goes here*\}
24 </div>
25 )
26 }

Next, we need to create a function that gets the returned video URL on upload to Cloudinary, sends the URL to Dolby for enhancement, checks enhanced videos' status periodically, gets the downloadable link of enhanced video, and then uploads the enhanced video to Cloudinary.

Polling in Computer Science Before creating the function to handle uploads, we must understand what Polling is. Polling is the continuous checking of other programs or devices by one program or device to see what state they are in, usually to see whether they are still connected or want to communicate. We need to periodically check the status of our video before initiating a download. In this post, we will use a while loop and nested fetch API to achieve this.

We also have methods like Event Emitter and Webhooks to achieve this exact purpose.

https://gist.github.com/Mr-Malomz/a8193124c00ab02c574b3d03257450c7

https://gist.github.com/Mr-Malomz/a8193124c00ab02c574b3d03257450c7

In the gist above, we created an handleSubmit function, prevented the default form behaviour and options (optionRequest, optionCheck, and optionDownload) as second parameters for making API calls. We also included the API key we generated from Dolby as part of the header. The optionRequest takes in a request body object of input and output. The input key takes the urlLink returned by the Cloudinary Upload Widget, and the output takes in URL - dolbyURL that Dolby can write.

Find out more about how Dolby processes Media Input and Output here.

We can also modify the request body to include content and audio object to improve the quality of the video. In this post, we won’t change any of the above and automatically let Dolby take care of the processing.

Next, we created a wait function to set a delay of 2 seconds when running the while loop and a state variable as conditions to stop the while loop.

Next, we made the first API call to Dolby to enhance the returned video URL, created a while loop using the state variable as a condition and called the wait function asynchronously. Then, we used the returned job_id response from the API call to periodically (2 seconds interval) make another API call to check the status of the video and update the state variable with the current status. Next, we checked for when the video status is successful, got the downloadable URL from Dolby, and then uploaded the enhanced video to Cloudinary.

PS: We need to disable CORS on the browser to test the application as Dolby expects downloading of the enhanced video to be a server-side operation. An alternative is to write the Dolby enhance function in a serverless function.

Finally, we need to include the handleSubmit function in our form and test the application by uploading the video to Cloudinary and enhancing with Dolby. We can check the browser console to see the log of the various operations.

To test the video outputs, we can log in to our Cloudinary account, navigate to the Media Library tab, and play both original video and enhanced video to see audio quality differences.

Here's a Google drive link to a video of the final build. https://drive.google.com/file/d/1uSKZvH6B58t8DKiNd6hgbKuxH77BS3y-/view?usp=sharing

Conclusion

This post discussed how to enhance video sound quality using the Dolby API platform. Try out different videos and content types to see how robust the Dolby platform is.

You may find these resources useful:

Emma Alder

Technical Writer at Hackmamba.io

Technical writer at Hackmamba.io