Cloudinary Blog

An Open-Source Interface for Editing Videos With Cloudinary

A New, Open-Source Tool for Performing Simple Video-Editing Tasks With Cloudinary

Cloudinary offers powerful APIs for uploading, managing, transforming, and delivering images and videos, enabling developers to treat media as code and to capitalize on media’s full potential. However, performing simple editing tasks with APIs and SDKs might be too overwhelming for nondevelopers, who might prefer UI-based capabilities instead.

Examples of simple video-editing tasks are trimming videos based on time offsets, merging videos, adding text or image overlays to videos, etc. Currently, those capabilities are not part of Cloudinary’s digital asset management (DAM) toolset. To perform those tasks, nondevelopers must construct delivery URLs, such as the one below, which concatenates two clipped videos with an image at the start and another at the end:

Ruby:
Copy to clipboard
cl_video_tag("pramod-vid-demo/telecope_video", :transformation=>[
  {:duration=>"3", :end_offset=>"5", :height=>800, :width=>1200, :crop=>"fill"},
  {:duration=>"3", :flags=>"splice", :height=>800, :overlay=>"pramod-vid-demo:Thank%20you", :width=>1200},
  {:flags=>"layer_apply"},
  {:duration=>"3", :end_offset=>"5", :flags=>"splice", :height=>800, :overlay=>"video:pramod-vid-demo:microscope_video", :width=>1200, :crop=>"fill"},
  {:flags=>"layer_apply", :start_offset=>"0"},
  {:duration=>"3", :flags=>"splice", :height=>800, :overlay=>"pramod-vid-demo:Microscope", :width=>1200},
  {:flags=>"layer_apply", :start_offset=>"0"}
  ])
PHP v1:
Copy to clipboard
cl_video_tag("pramod-vid-demo/telecope_video", array("transformation"=>array(
  array("duration"=>"3", "end_offset"=>"5", "height"=>800, "width"=>1200, "crop"=>"fill"),
  array("duration"=>"3", "flags"=>"splice", "height"=>800, "overlay"=>"pramod-vid-demo:Thank%20you", "width"=>1200),
  array("flags"=>"layer_apply"),
  array("duration"=>"3", "end_offset"=>"5", "flags"=>"splice", "height"=>800, "overlay"=>"video:pramod-vid-demo:microscope_video", "width"=>1200, "crop"=>"fill"),
  array("flags"=>"layer_apply", "start_offset"=>"0"),
  array("duration"=>"3", "flags"=>"splice", "height"=>800, "overlay"=>"pramod-vid-demo:Microscope", "width"=>1200),
  array("flags"=>"layer_apply", "start_offset"=>"0")
  )))
PHP v2:
Copy to clipboard
(new VideoTag('pramod-vid-demo/telecope_video.mp4'))
  ->videoEdit(VideoEdit::trim()->endOffset(5)->duration(3))
  ->resize(Resize::fill()->width(1200)->height(800))
  ->videoEdit(
      VideoEdit::concatenate(Concatenate::imageSource('pramod-vid-demo/Thank you')
        ->transformation((new ImageTransformation())
          ->resize(Resize::scale()->width(1200)->height(800))))
      ->duration(3))
    ->videoEdit(
        VideoEdit::concatenate(Concatenate::videoSource('pramod-vid-demo/microscope_video')
          ->transformation((new VideoTransformation())
            ->videoEdit(VideoEdit::trim()->endOffset(5))
            ->resize(Resize::fill()->width(1200)->height(800))))
        ->prepend()->duration(3))
          ->videoEdit(
              VideoEdit::concatenate(Concatenate::imageSource('pramod-vid-demo/Microscope')
                ->transformation((new ImageTransformation())
                  ->resize(Resize::scale()->width(1200)->height(800))))
              ->prepend()->duration(3)
          
        
          );
Python:
Copy to clipboard
CloudinaryVideo("pramod-vid-demo/telecope_video").video(transformation=[
  {'duration': "3", 'end_offset': "5", 'height': 800, 'width': 1200, 'crop': "fill"},
  {'duration': "3", 'flags': "splice", 'height': 800, 'overlay': "pramod-vid-demo:Thank%20you", 'width': 1200},
  {'flags': "layer_apply"},
  {'duration': "3", 'end_offset': "5", 'flags': "splice", 'height': 800, 'overlay': "video:pramod-vid-demo:microscope_video", 'width': 1200, 'crop': "fill"},
  {'flags': "layer_apply", 'start_offset': "0"},
  {'duration': "3", 'flags': "splice", 'height': 800, 'overlay': "pramod-vid-demo:Microscope", 'width': 1200},
  {'flags': "layer_apply", 'start_offset': "0"}
  ])
Node.js:
Copy to clipboard
cloudinary.video("pramod-vid-demo/telecope_video", {transformation: [
  {duration: "3", end_offset: "5", height: 800, width: 1200, crop: "fill"},
  {duration: "3", flags: "splice", height: 800, overlay: "pramod-vid-demo:Thank%20you", width: 1200},
  {flags: "layer_apply"},
  {duration: "3", end_offset: "5", flags: "splice", height: 800, overlay: "video:pramod-vid-demo:microscope_video", width: 1200, crop: "fill"},
  {flags: "layer_apply", start_offset: "0"},
  {duration: "3", flags: "splice", height: 800, overlay: "pramod-vid-demo:Microscope", width: 1200},
  {flags: "layer_apply", start_offset: "0"}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .duration("3").endOffset("5").height(800).width(1200).crop("fill").chain()
  .duration("3").flags("splice").height(800).overlay(new Layer().publicId("pramod-vid-demo:Thank%20you")).width(1200).chain()
  .flags("layer_apply").chain()
  .duration("3").endOffset("5").flags("splice").height(800).overlay(new Layer().publicId("video:pramod-vid-demo:microscope_video")).width(1200).crop("fill").chain()
  .flags("layer_apply").startOffset("0").chain()
  .duration("3").flags("splice").height(800).overlay(new Layer().publicId("pramod-vid-demo:Microscope")).width(1200).chain()
  .flags("layer_apply").startOffset("0")).videoTag("pramod-vid-demo/telecope_video");
JS:
Copy to clipboard
cloudinary.videoTag('pramod-vid-demo/telecope_video', {transformation: [
  {duration: "3", endOffset: "5", height: 800, width: 1200, crop: "fill"},
  {duration: "3", flags: "splice", height: 800, overlay: new cloudinary.Layer().publicId("pramod-vid-demo:Thank%20you"), width: 1200},
  {flags: "layer_apply"},
  {duration: "3", endOffset: "5", flags: "splice", height: 800, overlay: new cloudinary.Layer().publicId("video:pramod-vid-demo:microscope_video"), width: 1200, crop: "fill"},
  {flags: "layer_apply", startOffset: "0"},
  {duration: "3", flags: "splice", height: 800, overlay: new cloudinary.Layer().publicId("pramod-vid-demo:Microscope"), width: 1200},
  {flags: "layer_apply", startOffset: "0"}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.video("pramod-vid-demo/telecope_video", {transformation: [
  {duration: "3", end_offset: "5", height: 800, width: 1200, crop: "fill"},
  {duration: "3", flags: "splice", height: 800, overlay: new cloudinary.Layer().publicId("pramod-vid-demo:Thank%20you"), width: 1200},
  {flags: "layer_apply"},
  {duration: "3", end_offset: "5", flags: "splice", height: 800, overlay: new cloudinary.Layer().publicId("video:pramod-vid-demo:microscope_video"), width: 1200, crop: "fill"},
  {flags: "layer_apply", start_offset: "0"},
  {duration: "3", flags: "splice", height: 800, overlay: new cloudinary.Layer().publicId("pramod-vid-demo:Microscope"), width: 1200},
  {flags: "layer_apply", start_offset: "0"}
  ]})
React:
Copy to clipboard
<Video publicId="pramod-vid-demo/telecope_video" >
  <Transformation duration="3" endOffset="5" height="800" width="1200" crop="fill" />
  <Transformation duration="3" flags="splice" height="800" overlay="pramod-vid-demo:Thank%20you" width="1200" />
  <Transformation flags="layer_apply" />
  <Transformation duration="3" endOffset="5" flags="splice" height="800" overlay="video:pramod-vid-demo:microscope_video" width="1200" crop="fill" />
  <Transformation flags="layer_apply" startOffset="0" />
  <Transformation duration="3" flags="splice" height="800" overlay="pramod-vid-demo:Microscope" width="1200" />
  <Transformation flags="layer_apply" startOffset="0" />
</Video>
Vue.js:
Copy to clipboard
<cld-video publicId="pramod-vid-demo/telecope_video" >
  <cld-transformation duration="3" endOffset="5" height="800" width="1200" crop="fill" />
  <cld-transformation duration="3" flags="splice" height="800" :overlay="pramod-vid-demo:Thank%20you" width="1200" />
  <cld-transformation flags="layer_apply" />
  <cld-transformation duration="3" endOffset="5" flags="splice" height="800" :overlay="video:pramod-vid-demo:microscope_video" width="1200" crop="fill" />
  <cld-transformation flags="layer_apply" startOffset="0" />
  <cld-transformation duration="3" flags="splice" height="800" :overlay="pramod-vid-demo:Microscope" width="1200" />
  <cld-transformation flags="layer_apply" startOffset="0" />
</cld-video>
Angular:
Copy to clipboard
<cl-video public-id="pramod-vid-demo/telecope_video" >
  <cl-transformation duration="3" end-offset="5" height="800" width="1200" crop="fill">
  </cl-transformation>
  <cl-transformation duration="3" flags="splice" height="800" overlay="pramod-vid-demo:Thank%20you" width="1200">
  </cl-transformation>
  <cl-transformation flags="layer_apply">
  </cl-transformation>
  <cl-transformation duration="3" end-offset="5" flags="splice" height="800" overlay="video:pramod-vid-demo:microscope_video" width="1200" crop="fill">
  </cl-transformation>
  <cl-transformation flags="layer_apply" start-offset="0">
  </cl-transformation>
  <cl-transformation duration="3" flags="splice" height="800" overlay="pramod-vid-demo:Microscope" width="1200">
  </cl-transformation>
  <cl-transformation flags="layer_apply" start-offset="0">
  </cl-transformation>
</cl-video>
.NET:
Copy to clipboard
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Duration("3").EndOffset("5").Height(800).Width(1200).Crop("fill").Chain()
  .Duration("3").Flags("splice").Height(800).Overlay(new Layer().PublicId("pramod-vid-demo:Thank%20you")).Width(1200).Chain()
  .Flags("layer_apply").Chain()
  .Duration("3").EndOffset("5").Flags("splice").Height(800).Overlay(new Layer().PublicId("video:pramod-vid-demo:microscope_video")).Width(1200).Crop("fill").Chain()
  .Flags("layer_apply").StartOffset("0").Chain()
  .Duration("3").Flags("splice").Height(800).Overlay(new Layer().PublicId("pramod-vid-demo:Microscope")).Width(1200).Chain()
  .Flags("layer_apply").StartOffset("0")).BuildVideoTag("pramod-vid-demo/telecope_video")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .duration("3").endOffset("5").height(800).width(1200).crop("fill").chain()
  .duration("3").flags("splice").height(800).overlay(new Layer().publicId("pramod-vid-demo:Thank%20you")).width(1200).chain()
  .flags("layer_apply").chain()
  .duration("3").endOffset("5").flags("splice").height(800).overlay(new Layer().publicId("video:pramod-vid-demo:microscope_video")).width(1200).crop("fill").chain()
  .flags("layer_apply").startOffset("0").chain()
  .duration("3").flags("splice").height(800).overlay(new Layer().publicId("pramod-vid-demo:Microscope")).width(1200).chain()
  .flags("layer_apply").startOffset("0")).resourceType("video").generate("pramod-vid-demo/telecope_video.mp4");
iOS:
Copy to clipboard
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setDuration("3").setEndOffset("5").setHeight(800).setWidth(1200).setCrop("fill").chain()
  .setDuration("3").setFlags("splice").setHeight(800).setOverlay("pramod-vid-demo:Thank%20you").setWidth(1200).chain()
  .setFlags("layer_apply").chain()
  .setDuration("3").setEndOffset("5").setFlags("splice").setHeight(800).setOverlay("video:pramod-vid-demo:microscope_video").setWidth(1200).setCrop("fill").chain()
  .setFlags("layer_apply").setStartOffset("0").chain()
  .setDuration("3").setFlags("splice").setHeight(800).setOverlay("pramod-vid-demo:Microscope").setWidth(1200).chain()
  .setFlags("layer_apply").setStartOffset("0")).generate("pramod-vid-demo/telecope_video.mp4")

As the number of video clips for trimming or merging increases, the complexity involved in manually building delivery URLs also intensifies. As a remedy, we recently built a simple tool that uses Cloudinary’s transformation APIs behind the scenes via our JavaScript SDK to help you quickly perform these two editing tasks:

  • Trim videos by specifying the start time and the end time.
  • Join multiple videos.

You can also do the following with this new tool:

  • Rearrange the order of the videos.
  • Add images to a video for display for x seconds.
  • Add a global text overlay or have it overridden for specific video clips.
  • Choose the font, color, and size of the text overlay.
  • Specify the gravity, i.e., the position of the text in the video.
  • Add an image and specify its size as an overlay.
  • Specify the image’s gravity, i.e., its position in the video.
  • Adjust the image’s brightness, contrast, saturation, gamma, and vignette.
  • Make the video transparent or untransparent (if supported by the browser).

The sections below describe how to install and use the tool.

Installing the Tool

This tool is a front-end-only app written in HTML and JS with no server required. Download the code to your local machine. For testing, you can use the hosted demo.

Using the Tool

Let’s take an example of a student’s science homework. Say, the required images and videos are already in DAM storage and tagged as ‘my_homework’. Check out the entire collection here.

Select the Media

The student can search for videos manually from his Cloudinary account’s Media Library or under the Search by Tag option. He can add images to a video under Search by Tag, but not from the Media Library.

Note
Feel free to fork the source code and add capabilities, e.g., one that enables selection of images from the Media Library also.

The video below shows you how to search for videos and images based on the tag my_homework.

Trim Videos and Add Images for Video Stitching

To trim videos and add images for video stitching, the student would take these steps:

  1. Specify the start and end offset to clip the video that is active in the video player.
  2. Select images from the image-search results and add them for video stitching.
  3. Drag and drop the videos to arrange them in the correct order.

See the video below for a demo.

Enable Text Overlay

The student can either enable a global text overlay for the entire video or add text overlays to individual videos or images. He can also configure the text font, size, color, and gravity, i.e., the position of the text overlay in the video, such as northwest, center, etc., and adjust the position by specifying x-y offsets.

The video below shows you how to add a date as the text overlay at the bottom-right corner of a video.

Enable Image Overlay

You can add a logo or any image to video output by choosing the image from prior image-search results or from the Media Library. Additionally, you can configure the image size and gravity, i.e., the position of the image overlay in the video.

The demo below shows you how to add the Cloudinary logo as an overlay to our concatenated video, resize the logo, and add it as a transparent image.

Here are more examples:

  • Demo 1: Merge an image and two trimmed videos, displaying the image in the first two seconds.
  • Demo 2: Merge two clipped videos, rearrange their order, add a text overlay, and adjust the brightness.
  • Demo 3: Merge three clipped videos, add two images in between the videos, and then add an image overlay.

Summing It Up

The features in this simple video-editing tool are a subset of the robust capabilities that Cloudinary offers for video editing. We plan to add more features to the Cloudinary DAM UI in the near future so that you can transform videos within that UI. Until then, we’ll incorporate more common video-transformation features as part of the above tool.

Again, you are welcome to clone and modify the code, create personalized versions for your use cases and apps, and send us pull requests if your additions are worth sharing. Above all, feel free to suggest enhancements for the tool. We’d appreciate your insight.

Recent Blog Posts

New for DAM: Media Library Extension for Chrome

By Sharon Yelenik
A New Media Library Chrome Extension for Cloudinary DAM

With the introduction of the Media Library Extension, a Chrome-browser add-on that streamlines the access to, search for, and management of images and videos, Cloudinary offers yet another effective tool for its Digital Asset Management (DAM) solution. Let’s have a look at how most teams are currently working with media assets and how the new add-on not only boosts efficiency, but also renders the process a pleasure to work with.

Read more
New Features Supercharge Cloudinary’s Digital Asset Management Solution.

Today, I’m thrilled to announce the launch of Apps for Digital Asset Management and a Media Library Extension for the Chrome browser, which enables easy, flexible integration with all web-based applications in addition to making asset discovery more robust and accessible to all.

Read more
Scale and Automate Workflows With Modern Digital Asset Management Systems

With building, growing, and maintaining a strong digital presence being a top priority for all brands, high-quality visual content is paramount. In fact, consumers are 40 times more likely to share visual content on social networks than on other forums. Plus, a recent study from Wyzowl found that 84% of consumers made purchase decisions after watching a video, which explains why many brands are adding more and more visual media to their sites.

Read more
Speed Up Your Website With No Code Through Cloudinary’s Media Optimizer

As website and mobile apps rely more on visual media to create engaging user experiences, delivering strong web and app performance becomes more challenging for developers. The faster your site, the more time visitors would spend on it. Conversely, the slower the site, the higher the bounce rate, and the lower Google ranks it in SEO.

Read more
Bizzabo Holds Virtual and Simulive Events and Delivers VOD

While facing the pandemic-induced setbacks to its live-events business in the past two years, our customer and event innovator Bizzabo decided to reshape its offering into a digital-first Event Experience OS that fosters human connections and generates excitement. Toward that end, Bizzabo turned to Cloudinary for support of high-performance, visual events for large audiences to replace or augment live shows.

Read more