Five Video Features Developers No Longer Need to Build From Scratch
Tags: programming, video, javascript, code
Published: 2021-10-07 01:19:59

At a roundtable chat I recently shared with three software developers, we talked about the overwhelming participation in social media among Millennials and Gen Zs. That led to a deep technical conversation on what’s required to build and scale social apps, with everyone agreeing that the most challenging issues were time and scalability. 

With respect to time, the key questions raised by many developers and company founders would center around how long it takes to do the following:

- Go to market.
- Develop video capabilities on top of the existing product features.
- Build a Vine or TikTok of tomorrow.

This post shows you how to efficiently create video features with Cloudinary. You’ll be amazed at how productive you’ll become.

## Upload

The first video feature is always to enable your audience to upload videos—one by one or several at a time—to your app.  You can do so by integrating Cloudinary’s upload widget, which offers a skinnable UI for uploads from many data sources into your codebase. The integration takes only a few blocks of code:

```html
<button id="upload_widget" class="cloudinary-button">Upload files</button>

<script src="https://upload-widget.cloudinary.com/global/all.js" type="text/javascript"></script>  

<script type="text/javascript">  
var myWidget = cloudinary.createUploadWidget({
  cloudName: 'my_cloud_name', 
  uploadPreset: 'my_preset'}, (error, result) => { 
    if (!error && result && result.event === "success") { 
      console.log('Done! Here is the image info: ', result.info); 
    }
  }
)

document.getElementById("upload_widget").addEventListener("click", function(){
    myWidget.open();
  }, false);
</script>

```
_index.html_

## Compression and Optimization

As technology advances, the size of videos on devices grows exponentially. All that rich content has led to challenges, however, especially in loading speed. But of course, your audience wants the best of two worlds: watch high-quality videos that are streamed with less data along with fast playback.

Cloudinary arms you with compression and optimization techniques. For example, reducing the quality (`q`) of an uploaded MP4 video named `dog` to 50 results in a file size of **1.1 MB** compared to the original size of **9.8 MB**.

_*Before compression:*_
 [https://res.cloudinary.com/demo/video/upload/dog.mp4](https://res.cloudinary.com/demo/video/upload/dog.mp4)

_*After compression:*_ [https://res.cloudinary.com/demo/video/upload/q_50/dog.mp4](https://res.cloudinary.com/demo/video/upload/dog.mp4)

You can set the `q` parameter, which stands for quality transformation, to a value of between 0 and 100.
 
Alternatively, set `q` to `auto` (`q_auto`) for automatic quality encoding. Here are the options:
- `q_auto`: Strike the optimal balance between file size and visual quality. By default, this setting is the same as `q_auto:good`.
- `q_auto:best`: Adopt a less aggressive algorithm, which generates bigger files with potentially higher visual quality.
- `q_auto:good`: Ensure a relatively small file size with high visual quality, e.g., for stock-media sites that display high-quality videos.
- `q_auto:eco`: Adopt a more aggressive algorithm, which results in smaller files of slightly lower visual quality, e.g., for popular sites and social networks with heavy traffic.
- `q_auto:low`: Adopt the most aggressive algorithm, which results in the smallest files of low visual quality, e.g., for sites that link to high-quality videos through thumbnail preview-videos.

## Streaming

The COVID-19 pandemic has led to a boom in remote activities worldwide. Live streaming of video through Instagram and the like is a key contributor. To quickly enable live streaming to your app, look no further than Cloudinary, whose end-to-end solution for streaming video supports both WebRTC and RTMP. What’s more, the output of on-the-fly adaptive-bitrate streaming through a dedicated JavaScript library features effects and transformations.

Here’s the HTML and JavaScript code:

```html
<link href="./styles.css" rel="stylesheet" type="text/css">
<script src="https://unpkg.com/@cloudinary/js-streaming/dist/js-streaming.js"></script>

<div class="container wrapper">
    <h1>Example of Live Streaming With Cloudinary</h1>
    <div class="video-wrapper">
        <video class="video" id="video" autoPlay muted="muted" playsInline></video>
    </div>
    <div class="center">
        <div class="center-text">
            <button id="viewbtn" onclick="view();">Show camera</button>
            <button id="hidebtn" onclick="hide();">Hide camera</button>
        </div>
        <div class="center-text">
            <button id="initbtn" onclick="initialize();">Initialize stream</button>
            <button disabled id="startbtn" onclick="start();">Start stream</button>
            <button disabled id="stopbtn" onclick="stop();">Stop stream</button>
        </div>

        <div class="ui">
            <p>Status: <span id="status">Click Initialize stream to begin</span></p>
            <p>Public ID: <span id="publicid"></span></p>
            <p>File URL: <a id="file_url" target="_blank"></a></p>
            <p>Stream URL: <a id="stream_url" target="_blank"></a></p>
        </div>
    </div>
</div>
<script src="./index.js"></script>
```
_index.html_

```js
const {initLiveStream, attachCamera, detachCamera} = cloudinaryJsStreaming;
const CLOUD_NAME = '<your-cloud-name>';
const UPLOAD_PRESET = '<your-upload-preset>';
let liveStream, publicId, url;

function setText(id, text) {
  document.getElementById(id).innerHTML = text;
}

function setStatus(status) {
  setText("status", status);
}

function toggleButton(id, enabled) {
  document.getElementById(id).disabled = !enabled;
}

function toggleBtns(init = false, start = false, stop = false) {
  toggleButton("initbtn", init);
  toggleButton("startbtn", start);
  toggleButton("stopbtn", stop);
}

function setUrl(url) {
  const fileUrl = url + '.mp4';
  const streamUrl = url + '.m3u8';

  const file_link = document.getElementById('file_url');
  const stream_link = document.getElementById('stream_url');

  file_link.href = fileUrl;
  file_link.innerText = fileUrl;
  stream_link.href = streamUrl;
  stream_link.innerText = streamUrl;
}

function view(){
  attachCamera(document.getElementById("video")).then(c=>{
    console.log(c);
  })
}

function hide(){
  detachCamera(document.getElementById("video")).then(c=>{
    console.log(c);
  })
}

function start() {
  setStatus("starting...");
  toggleBtns();
  liveStream.start(publicId);
}

function stop() {
  setStatus("stopping...");
  toggleBtns();
  liveStream.stop();
}

// Call initLiveStream with the configuration parameters:
function initialize() {
  setStatus("initializing...");
  toggleBtns();

  initLiveStream({
    cloudName: CLOUD_NAME,
    uploadPreset: UPLOAD_PRESET,
    debug: "all",
    hlsTarget: true,
    fileTarget: true,
    events: {
      start: function (args) {
        setStatus("started");
        document.getElementById("video").className = "video recording";
        toggleBtns(false, false, true);
      },
      stop: function (args) {
        setStatus("stopped");
        document.getElementById("video").className = "video";
        toggleBtns(true, false, false);
      },
      error: function (error) {
        setStatus("error: " + error);
        toggleBtns(true, false, false);
      },
      local_stream: function (stream) {
        setStatus("local stream");
        // Attach the stream to a video element:
        liveStream.attach(document.getElementById("video"), stream);
      }
    }
  }).then(result => {
    // keep handle to instance to start/stop streaming
    liveStream = result;

    // Extract the public ID and URL from the result (publish the URL for the stream):
    publicId = result.response.public_id;
    url = 'https://res.cloudinary.com/'+CLOUD_NAME+'/video/upload/' + publicId;

    setStatus("initialized");
    setText("publicid", publicId);
    setUrl(url);

    toggleBtns(false, true, false);
  });
}
``` 
_index.js_

Copy the [styles.css file from GitHub](https://gist.github.com/unicodeveloper/22b58d26f15a054d588beeecb3bedc05).

## Transformations

As illustrated by the footage in Instagram, Snapchat, and TikTok, you can transform video in several ways. Cloudinary offers many tools and techniques for doing that, notably the following:

**Convert videos to animated GIFs** by changing the file extension of the returned URL to `.gif`. Try it out with this [video](https://res.cloudinary.com/demo/video/upload/dog.mp4).

- Convert video to audio by setting the file format (or extension) to one of the [supported audio formats](https://cloudinary.com/documentation/audio_transformations#supported_audio_formats). See it for yourself: Convert the MP4 file above to an MP3 file by changing the file extension.

**Add text overlays to video** with the `text` property of the overlay parameter ( `l_text:` in URLs), followed by the font name and size (separated with an underscore), a colon, and the text string to display. For example, to overlay the text string "Sample Video" in Arial font with a size of 40 pixels, code it this way:`l_text:arial_40:Sample Video`.
[https://res.cloudinary.com/demo/video/upload/l_text:arial_60:Cool%20Video/eo_5.0,fl_layer_apply,g_south,so_2.0,y_80/dog.mp4](https://res.cloudinary.com/demo/video/upload/l_text:arial_60:Cool%20Video/eo_5.0,fl_layer_apply,g_south,so_2.0,y_80/dog.mp4)
- **Add image overlays to video** by adding the overlay parameter (`l` in URLs) and the public ID of a previously uploaded PNG image (e.g., `l_watermark`) for an image with the public ID `watermark`. You can specify the dimension and position of the overlay with the width, height, x, y, and gravity parameters as you do for images. For details, see the post *[Adding Watermarks, Credits, Badges and Text Overlays to Images](https://cloudinary.com/blog/adding_watermarks_credits_badges_and_text_overlays_to_images)*.

Furthermore, you can specify when to display the overlay by combining the three offset parameters. For details, see the documentation on [trimming videos](https://cloudinary.com/documentation/video_manipulation_and_delivery#trimming_videos).

You can also [further transform](https://cloudinary.com/documentation/image_transformations#transformation_types) an overlay like any other image uploaded to Cloudinary. An example is to add an overlay of a PNG image called `cloudinary_icon_white` to the video named `dog.mp4` and display the overlay between the 6.5- and 10-second mark. Convert the overlay to a watermark by reducing the opacity to 50 with the `o` parameter and intensifying the brightness to 100 with the `e_brightness` effect.

[https://res.cloudinary.com/demo/video/upload/l_cloudinary_icon_white/o_50/e_brightness:100/eo_10.0,fl_layer_apply,so_6.5/dog.mp4](https://res.cloudinary.com/demo/video/upload/l_cloudinary_icon_white/o_50/e_brightness:100/eo_10.0,fl_layer_apply,so_6.5/dog.mp4)

- **Add other videos as overlays** with the overlay-video parameter (`l_video:` in URLs) and the public ID of a previously uploaded video (e.g., `l_video:dog` for a video with the public ID `dog`). Specify the dimension and position of the video overlay with the width, height, x, y, and gravity parameters as you do for images. See the [related documentation](https://cloudinary.com/documentation/video_manipulation_and_delivery#adding_image_overlays) for details. 

To specify when to display the video overlay, combine the three offset parameters. For reference, see the documentation on [trimming videos](https://cloudinary.com/documentation/video_manipulation_and_delivery#trimming_videos). You can [further transform](https://cloudinary.com/documentation/transformation_reference) the overlay like any other video uploaded to Cloudinary.

Try it out yourself: Add a video overlay named `dog` to the same video, also named `dog`, and display the video overlay between the 4.5- and 8-second mark. Rotate the overlay by 90 degrees, set with a gravity of 'east' and scaled to a width of 200 pixels.

[https://res.cloudinary.com/demo/video/upload/l_video:dog/c_scale,w_200/a_90/eo_8.0,fl_layer_apply,g_east,so_4.5/dog.mp4](https://res.cloudinary.com/demo/video/upload/l_video:dog/c_scale,w_200/a_90/eo_8.0,fl_layer_apply,g_east,so_4.5/dog.mp4)

## Concatenation

Joining multiple videos together to form a single video is a common approach for fun and for instructional talks. The simplest way to concatenate small-sized clips is to set these two parameters:

- The overlay-video parameter (`l_video:` in URLs), which specifies the name of another uploaded video on Cloudinary.
- The splice-flag parameter (`fl_splice` in URLs), which specifies that the video be concatenated onto the container video—not added as an overlay.

For a demo, set the video named `dog` and the one named `kitten_fighting` to a width of 300 pixels and a height of 200 pixels.

[https://res.cloudinary.com/demo/video/upload/c_fill,h_200,w_300/fl_splice,l_video:dog/c_fill,h_200,w_300/fl_layer_apply/kitten_fighting.mp4](https://res.cloudinary.com/demo/video/upload/c_fill,h_200,w_300/fl_splice,l_video:dog/c_fill,h_200,w_300/fl_layer_apply/kitten_fighting.mp4)

**Note:** You can customize the transitions between videos. An example:
 ​​[https://res.cloudinary.com/demo/video/upload/du_5.0/c_scale,h_200,w_300/l_video:dog/c_scale,h_200,w_300/du_5.0/e_transition,l_video:transition1/fl_layer_apply/fl_layer_apply/kitten_fighting.mp4](https://res.cloudinary.com/demo/video/upload/du_5.0/c_scale,h_200,w_300/l_video:dog/c_scale,h_200,w_300/du_5.0/e_transition,l_video:transition1/fl_layer_apply/fl_layer_apply/kitten_fighting.mp4)

The `e_transition` parameter specifies that the video overlay  `l_video:transition1` act as a transition between the base and second video. 

## Final Thoughts

To attain speed and peace of mind, do leverage effective and efficient tools to handle mundane or repetitive tasks at scale. You can then focus on brainstorming business logic and building features and apps that require creative talent.

For more ins and outs of Cloudinary’s video features, see the [documentation](https://cloudinary.com/documentation/video_manipulation_and_delivery).