Cloudinary Blog

Easily Generating Video Preview Clips with Cloudinary

How to Generate Video Preview Clips

Before deciding whether to watch a movie, you would likely check out its reviews and ratings on sites such as Rotten Tomatoes, IMDB, or Metacritic. You’re not alone. Online reviews figure prominently as a factor that influences viewers’ decisions on which movies to see. In addition, filmmakers always produce trailers to be shown as previews that showcase the highlights of their movies in the hope of stirring a buzz and anticipation for the debut.

Toward that end, suppose you as an app developer are tasked with generating a preview clip for a playlist of videos. Do take advantage of Cloudinary, a cloud-based, end-to-end solution for uploading, storing, transforming, optimizing, and delivering images and videos, with which you can manage media by way of a simple process. You can then focus on your primary tasks.

The Process

In this article, I’ll show you how to create video preview clips in two simple steps with Cloudinary.

Step 1: Upload the Video

In the console, click the Media Library tab and then click My File in the pane that opens. Drag and drop the video file to the pane.

Alternatively, click Browse in the My File pane and select and open the video file in your file system.

Upload

Tip: Embed the upload widget in your app to enable quick video upload from multiple channels.

Step 2: Build the Clip

Animated previews for any videos, including films, are often eye-catching and captivating. Because time is of the essence, you might want to produce multiple previews with different themes for various audiences.

The following procedure creates an approximately four-and-a-half-minute-long clip from a video, which stars a bunny.

Ruby:
cl_video_tag("bb_bunny")
PHP:
cl_video_tag("bb_bunny")
Python:
CloudinaryVideo("bb_bunny").video()
Node.js:
cloudinary.video("bb_bunny")
Java:
cloudinary.url().videoTag("bb_bunny");
JS:
cloudinary.videoTag('bb_bunny').toHtml();
jQuery:
$.cloudinary.video("bb_bunny")
React:
<Video publicId="bb_bunny" >

</Video>
Angular:
<cl-video public-id="bb_bunny" >

</cl-video>
.Net:
cloudinary.Api.UrlVideoUp.BuildVideoTag("bb_bunny")
Android:
MediaManager.get().url().resourceType("video").generate("bb_bunny.mp4");
iOS:
cloudinary.createUrl().setResourceType("video").generate("bb_bunny.mp4")

  1. Specify the duration (in seconds) of the preview video, for example, du_20.
  2. Specify the desired dimension (in pixels) of the preview video, for example w_400.
  3. Specify the first video section (so for start_offset) and the last one (eo for end_offset).
  4. Assign a name (public_id) for the videos to be concatenated with the overlay video parameter l_video.
  5. Activate the flag fl_layer_apply, which concatenates a section of the video on to another video by means of the offset parameters.
  6. Set splice so that Cloudinary concatenates the video section instead of adding it as an overlay.

Afterwards, perform the above six steps for the other sections of the video that contain the remaining scenes of the preview video. No overlays are necessary. It’s a cinch.

There you have it: a 20-second preview video:

Ruby:
cl_video_tag("bb_bunny", :transformation=>[
  {:width=>400, :duration=>"20", :crop=>"scale"},
  {:overlay=>"video:bb_bunny", :start_offset=>"3", :end_offset=>"7"},
  {:start_offset=>"0", :flags=>["layer_apply", "splice"], :width=>400, :crop=>"scale"},
  {:overlay=>"video:bb_bunny", :start_offset=>"25", :end_offset=>"30"},
  {:start_offset=>"4", :flags=>["layer_apply", "splice"], :width=>400, :crop=>"scale"},
  {:overlay=>"video:bb_bunny", :start_offset=>"240", :end_offset=>"280"},
  {:start_offset=>"8", :flags=>["layer_apply", "splice"], :width=>400, :crop=>"scale"}
  ])
PHP:
cl_video_tag("bb_bunny", array("transformation"=>array(
  array("width"=>400, "duration"=>"20", "crop"=>"scale"),
  array("overlay"=>"video:bb_bunny", "start_offset"=>"3", "end_offset"=>"7"),
  array("start_offset"=>"0", "flags"=>array("layer_apply", "splice"), "width"=>400, "crop"=>"scale"),
  array("overlay"=>"video:bb_bunny", "start_offset"=>"25", "end_offset"=>"30"),
  array("start_offset"=>"4", "flags"=>array("layer_apply", "splice"), "width"=>400, "crop"=>"scale"),
  array("overlay"=>"video:bb_bunny", "start_offset"=>"240", "end_offset"=>"280"),
  array("start_offset"=>"8", "flags"=>array("layer_apply", "splice"), "width"=>400, "crop"=>"scale")
  )))
Python:
CloudinaryVideo("bb_bunny").video(transformation=[
  {"width": 400, "duration": "20", "crop": "scale"},
  {"overlay": "video:bb_bunny", "start_offset": "3", "end_offset": "7"},
  {"start_offset": "0", "flags": ["layer_apply", "splice"], "width": 400, "crop": "scale"},
  {"overlay": "video:bb_bunny", "start_offset": "25", "end_offset": "30"},
  {"start_offset": "4", "flags": ["layer_apply", "splice"], "width": 400, "crop": "scale"},
  {"overlay": "video:bb_bunny", "start_offset": "240", "end_offset": "280"},
  {"start_offset": "8", "flags": ["layer_apply", "splice"], "width": 400, "crop": "scale"}
  ])
Node.js:
cloudinary.video("bb_bunny", {transformation: [
  {width: 400, duration: "20", crop: "scale"},
  {overlay: "video:bb_bunny", start_offset: "3", end_offset: "7"},
  {start_offset: "0", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:bb_bunny", start_offset: "25", end_offset: "30"},
  {start_offset: "4", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:bb_bunny", start_offset: "240", end_offset: "280"},
  {start_offset: "8", flags: ["layer_apply", "splice"], width: 400, crop: "scale"}
  ]})
Java:
cloudinary.url().transformation(new Transformation()
  .width(400).duration("20").crop("scale").chain()
  .overlay("video:bb_bunny").startOffset("3").endOffset("7").chain()
  .startOffset("0").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay("video:bb_bunny").startOffset("25").endOffset("30").chain()
  .startOffset("4").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay("video:bb_bunny").startOffset("240").endOffset("280").chain()
  .startOffset("8").flags("layer_apply", "splice").width(400).crop("scale")).videoTag("bb_bunny");
JS:
cloudinary.videoTag('bb_bunny', {transformation: [
  {width: 400, duration: "20", crop: "scale"},
  {overlay: "video:bb_bunny", startOffset: "3", endOffset: "7"},
  {startOffset: "0", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:bb_bunny", startOffset: "25", endOffset: "30"},
  {startOffset: "4", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:bb_bunny", startOffset: "240", endOffset: "280"},
  {startOffset: "8", flags: ["layer_apply", "splice"], width: 400, crop: "scale"}
  ]}).toHtml();
jQuery:
$.cloudinary.video("bb_bunny", {transformation: [
  {width: 400, duration: "20", crop: "scale"},
  {overlay: "video:bb_bunny", start_offset: "3", end_offset: "7"},
  {start_offset: "0", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:bb_bunny", start_offset: "25", end_offset: "30"},
  {start_offset: "4", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:bb_bunny", start_offset: "240", end_offset: "280"},
  {start_offset: "8", flags: ["layer_apply", "splice"], width: 400, crop: "scale"}
  ]})
React:
<Video publicId="bb_bunny" >
  <Transformation width="400" duration="20" crop="scale" />
  <Transformation overlay="video:bb_bunny" startOffset="3" endOffset="7" />
  <Transformation startOffset="0" flags={["layer_apply", "splice"]} width="400" crop="scale" />
  <Transformation overlay="video:bb_bunny" startOffset="25" endOffset="30" />
  <Transformation startOffset="4" flags={["layer_apply", "splice"]} width="400" crop="scale" />
  <Transformation overlay="video:bb_bunny" startOffset="240" endOffset="280" />
  <Transformation startOffset="8" flags={["layer_apply", "splice"]} width="400" crop="scale" />
</Video>
Angular:
<cl-video public-id="bb_bunny" >
  <cl-transformation width="400" duration="20" crop="scale">
  </cl-transformation>
  <cl-transformation overlay="video:bb_bunny" start-offset="3" end-offset="7">
  </cl-transformation>
  <cl-transformation start-offset="0" flags={{["layer_apply", "splice"]}} width="400" crop="scale">
  </cl-transformation>
  <cl-transformation overlay="video:bb_bunny" start-offset="25" end-offset="30">
  </cl-transformation>
  <cl-transformation start-offset="4" flags={{["layer_apply", "splice"]}} width="400" crop="scale">
  </cl-transformation>
  <cl-transformation overlay="video:bb_bunny" start-offset="240" end-offset="280">
  </cl-transformation>
  <cl-transformation start-offset="8" flags={{["layer_apply", "splice"]}} width="400" crop="scale">
  </cl-transformation>
</cl-video>
.Net:
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Width(400).Duration("20").Crop("scale").Chain()
  .Overlay("video:bb_bunny").StartOffset("3").EndOffset("7").Chain()
  .StartOffset("0").Flags("layer_apply", "splice").Width(400).Crop("scale").Chain()
  .Overlay("video:bb_bunny").StartOffset("25").EndOffset("30").Chain()
  .StartOffset("4").Flags("layer_apply", "splice").Width(400).Crop("scale").Chain()
  .Overlay("video:bb_bunny").StartOffset("240").EndOffset("280").Chain()
  .StartOffset("8").Flags("layer_apply", "splice").Width(400).Crop("scale")).BuildVideoTag("bb_bunny")
Android:
MediaManager.get().url().transformation(new Transformation()
  .width(400).duration("20").crop("scale").chain()
  .overlay("video:bb_bunny").startOffset("3").endOffset("7").chain()
  .startOffset("0").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay("video:bb_bunny").startOffset("25").endOffset("30").chain()
  .startOffset("4").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay("video:bb_bunny").startOffset("240").endOffset("280").chain()
  .startOffset("8").flags("layer_apply", "splice").width(400).crop("scale")).resourceType("video").generate("bb_bunny.mp4");
iOS:
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setWidth(400).setDuration("20").setCrop("scale").chain()
  .setOverlay("video:bb_bunny").setStartOffset("3").setEndOffset("7").chain()
  .setStartOffset("0").setFlags("layer_apply", "splice").setWidth(400).setCrop("scale").chain()
  .setOverlay("video:bb_bunny").setStartOffset("25").setEndOffset("30").chain()
  .setStartOffset("4").setFlags("layer_apply", "splice").setWidth(400).setCrop("scale").chain()
  .setOverlay("video:bb_bunny").setStartOffset("240").setEndOffset("280").chain()
  .setStartOffset("8").setFlags("layer_apply", "splice").setWidth(400).setCrop("scale")).generate("bb_bunny.mp4")
, complete with shots that highlight the fetching parts of the video.

Bonus Step: Remove the Audio

Depending on the context in which the preview video is shown, the associated audio might not apply. In that case, remove the audio by adding the ac_none parameter to the URL, like this:

https://res.cloudinary.com/demo/video/upload/w_400,du_72/l_video:bb_bunny,so_3,eo_7/so_0,fl_layer_apply.splice,w_400/l_video:bb_bunny,so_25,eo_30/so_4,fl_layer_apply.splice,w_400/l_video:bb_bunny,so_240,eo_290/so_8,fl_layer_apply.splice,w_400/ac_none/w_400/bb_bunny.mp4

A Cinch Indeed

As promised, the process calls for no coding at all. You could, however, polish up the preview clip, as follows:

  • Add text or an image overlay with a UI tip, such as “Click to play the full preview.”

  • Add an image to the end of the video with a suggestion or catchy message, for example, “Coming soon to a cinema near you.”

  • Add a quick flash between sections as a hint on what’s coming up in the clip!

Note
Videos spliced together must share the same width and height. To achieve that uniformity, set the size-transformation parameters.

Conclusion

For simplicity, this tutorial employs URLs to illustrate the Cloudinary capabilities in question. Do check out Cloudinary’s many useful libraries:

PHP, Ruby, Ruby, JavaScript, iOS, Android, and others.

For details on trimming videos, check out the Trimming Videos section of the Cloudinary documentation.

Again, creating video preview clips with Cloudinary is painless, intuitive, and efficient. Have a try!

Recent Blog Posts

Integrating Cloudinary with Forestry’s Media Library

At Forestry, we believe that there is a bright future for static HTML sites built with tools like Jekyll and Hugo. These tools can create sites that run well, and are easy to host and maintain, because they don’t require any server-side code.

Read more
Video Optimization With the HTML5 <video> Player

Lack of experience and compression knowhow can cause significant user-experience problems. For instance, on a major retail site, I recently ran into a 48 MB video-hero banner. Pulling out the video and encoding it as an H.264 MP4 reduces the size to 1.9 MB. So, despite the desire for more video content, developers have not yet caught up to best practices. How do we get the best of both worlds without creating a disaster like the one above?

Read more
Build a Facial Emotion Recognition Based Video Suggestion App

Developers are always looking for new and creative ways to deliver content that resonates with the way users feel. Often using the latest technical innovations the market has to offer such as Artificial Intelligence (AI) and Machine Learning (ML). What better way to demonstrate innovative uses of these technology in a consumer market than capturing expressions from your users and then serving content based on that expression!

Read more
Improve Customer Data Protection with GDPR Implementation

TL;DR

Yay! We've done it! Gold-Star for us! We've talked with all the people, made all the changes, paid all the lawyers and checked all the boxes. GDPR? ✅Done!

Not so fast. Of course, conforming to the GDPR regulations introduced in Europe is just the beginning. This is a process and a state of mind that must become part of our long-term cultural ethos.

Read more
Magento Image and Video Optimization

As the number of channels and devices continues to grow, it is becoming much more challenging to deliver an optimal visual experience. On an eCommerce site, engagement and conversions are critical. Factors such as page load time strongly influence search engine rankings, shopping experiences, conversion rates and, ultimately, your revenue. An optimized visual experience positively affects conversion rates. But it also can introduce resource bottlenecks, as every image and video needs to be delivered in the most efficient format, quality and resolution, based on the viewing device.

Read more