Generating Video Preview Clips

Creating a dynamic and engaging animated video preview (as opposed to a static image) can have a lot of benefits:

  • Improves the ability to captures a user’s attention for the content
  • More clearly demonstrates that there is video content available
  • Provides several preview clips, allowing the user to decide if the video is relevant pre-click

Compare two different preview options to see which is more eye-catching and engaging:

Static Image Preview Dynamic Video Preview

Here’s the basics of how this is created in Cloudinary:

Ruby:
cl_video_tag("MLB2", :transformation=>[
  {:width=>400, :duration=>"12", :crop=>"scale"},
  {:overlay=>"video:MLB2", :start_offset=>"2", :end_offset=>"6"},
  {:start_offset=>"0", :flags=>["layer_apply", "splice"], :width=>400, :crop=>"scale"},
  {:overlay=>"video:MLB2", :start_offset=>"20", :end_offset=>"24"},
  {:start_offset=>"4", :flags=>["layer_apply", "splice"], :width=>400, :crop=>"scale"},
  {:overlay=>"video:MLB2", :start_offset=>"31", :end_offset=>"35"},
  {:start_offset=>"8", :flags=>["layer_apply", "splice"], :width=>400, :crop=>"scale"},
  {:audio_codec=>"none"}
  ])
PHP:
cl_video_tag("MLB2", array("transformation"=>array(
  array("width"=>400, "duration"=>"12", "crop"=>"scale"),
  array("overlay"=>"video:MLB2", "start_offset"=>"2", "end_offset"=>"6"),
  array("start_offset"=>"0", "flags"=>array("layer_apply", "splice"), "width"=>400, "crop"=>"scale"),
  array("overlay"=>"video:MLB2", "start_offset"=>"20", "end_offset"=>"24"),
  array("start_offset"=>"4", "flags"=>array("layer_apply", "splice"), "width"=>400, "crop"=>"scale"),
  array("overlay"=>"video:MLB2", "start_offset"=>"31", "end_offset"=>"35"),
  array("start_offset"=>"8", "flags"=>array("layer_apply", "splice"), "width"=>400, "crop"=>"scale"),
  array("audio_codec"=>"none")
  )))
Python:
CloudinaryVideo("MLB2").video(transformation=[
  {"width": 400, "duration": "12", "crop": "scale"},
  {"overlay": "video:MLB2", "start_offset": "2", "end_offset": "6"},
  {"start_offset": "0", "flags": ["layer_apply", "splice"], "width": 400, "crop": "scale"},
  {"overlay": "video:MLB2", "start_offset": "20", "end_offset": "24"},
  {"start_offset": "4", "flags": ["layer_apply", "splice"], "width": 400, "crop": "scale"},
  {"overlay": "video:MLB2", "start_offset": "31", "end_offset": "35"},
  {"start_offset": "8", "flags": ["layer_apply", "splice"], "width": 400, "crop": "scale"},
  {"audio_codec": "none"}
  ])
Node.js:
cloudinary.video("MLB2", {transformation: [
  {width: 400, duration: "12", crop: "scale"},
  {overlay: "video:MLB2", start_offset: "2", end_offset: "6"},
  {start_offset: "0", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:MLB2", start_offset: "20", end_offset: "24"},
  {start_offset: "4", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:MLB2", start_offset: "31", end_offset: "35"},
  {start_offset: "8", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {audio_codec: "none"}
  ]})
Java:
cloudinary.url().transformation(new Transformation()
  .width(400).duration("12").crop("scale").chain()
  .overlay("video:MLB2").startOffset("2").endOffset("6").chain()
  .startOffset("0").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay("video:MLB2").startOffset("20").endOffset("24").chain()
  .startOffset("4").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay("video:MLB2").startOffset("31").endOffset("35").chain()
  .startOffset("8").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .audioCodec("none")).videoTag("MLB2");
JS:
cloudinary.videoTag('MLB2', {transformation: [
  {width: 400, duration: "12", crop: "scale"},
  {overlay: "video:MLB2", startOffset: "2", endOffset: "6"},
  {startOffset: "0", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:MLB2", startOffset: "20", endOffset: "24"},
  {startOffset: "4", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:MLB2", startOffset: "31", endOffset: "35"},
  {startOffset: "8", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {audioCodec: "none"}
  ]}).toHtml();
jQuery:
$.cloudinary.video("MLB2", {transformation: [
  {width: 400, duration: "12", crop: "scale"},
  {overlay: "video:MLB2", start_offset: "2", end_offset: "6"},
  {start_offset: "0", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:MLB2", start_offset: "20", end_offset: "24"},
  {start_offset: "4", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: "video:MLB2", start_offset: "31", end_offset: "35"},
  {start_offset: "8", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {audio_codec: "none"}
  ]})
React:
<Video publicId="MLB2" >
  <Transformation width="400" duration="12" crop="scale" />
  <Transformation overlay="video:MLB2" startOffset="2" endOffset="6" />
  <Transformation startOffset="0" flags={["layer_apply", "splice"]} width="400" crop="scale" />
  <Transformation overlay="video:MLB2" startOffset="20" endOffset="24" />
  <Transformation startOffset="4" flags={["layer_apply", "splice"]} width="400" crop="scale" />
  <Transformation overlay="video:MLB2" startOffset="31" endOffset="35" />
  <Transformation startOffset="8" flags={["layer_apply", "splice"]} width="400" crop="scale" />
  <Transformation audioCodec="none" />
</Video>
Angular:
<cl-video public-id="MLB2" >
  <cl-transformation width="400" duration="12" crop="scale">
  </cl-transformation>
  <cl-transformation overlay="video:MLB2" start-offset="2" end-offset="6">
  </cl-transformation>
  <cl-transformation start-offset="0" flags={{["layer_apply", "splice"]}} width="400" crop="scale">
  </cl-transformation>
  <cl-transformation overlay="video:MLB2" start-offset="20" end-offset="24">
  </cl-transformation>
  <cl-transformation start-offset="4" flags={{["layer_apply", "splice"]}} width="400" crop="scale">
  </cl-transformation>
  <cl-transformation overlay="video:MLB2" start-offset="31" end-offset="35">
  </cl-transformation>
  <cl-transformation start-offset="8" flags={{["layer_apply", "splice"]}} width="400" crop="scale">
  </cl-transformation>
  <cl-transformation audio-codec="none">
  </cl-transformation>
</cl-video>
.Net:
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Width(400).Duration("12").Crop("scale").Chain()
  .Overlay("video:MLB2").StartOffset("2").EndOffset("6").Chain()
  .StartOffset("0").Flags("layer_apply", "splice").Width(400).Crop("scale").Chain()
  .Overlay("video:MLB2").StartOffset("20").EndOffset("24").Chain()
  .StartOffset("4").Flags("layer_apply", "splice").Width(400).Crop("scale").Chain()
  .Overlay("video:MLB2").StartOffset("31").EndOffset("35").Chain()
  .StartOffset("8").Flags("layer_apply", "splice").Width(400).Crop("scale").Chain()
  .AudioCodec("none")).BuildVideoTag("MLB2")
Android:
MediaManager.get().url().transformation(new Transformation()
  .width(400).duration("12").crop("scale").chain()
  .overlay("video:MLB2").startOffset("2").endOffset("6").chain()
  .startOffset("0").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay("video:MLB2").startOffset("20").endOffset("24").chain()
  .startOffset("4").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay("video:MLB2").startOffset("31").endOffset("35").chain()
  .startOffset("8").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .audioCodec("none")).resourceType("video").generate("MLB2.mp4");
iOS:
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setWidth(400).setDuration("12").setCrop("scale").chain()
  .setOverlay("video:MLB2").setStartOffset("2").setEndOffset("6").chain()
  .setStartOffset("0").setFlags("layer_apply", "splice").setWidth(400).setCrop("scale").chain()
  .setOverlay("video:MLB2").setStartOffset("20").setEndOffset("24").chain()
  .setStartOffset("4").setFlags("layer_apply", "splice").setWidth(400).setCrop("scale").chain()
  .setOverlay("video:MLB2").setStartOffset("31").setEndOffset("35").chain()
  .setStartOffset("8").setFlags("layer_apply", "splice").setWidth(400).setCrop("scale").chain()
  .setAudioCodec("none")).generate("MLB2.mp4")

  • Upload a video
  • Set your total duration for the preview video you want to create
  • Layer on additional copies of the video with the corresponding beginning/end of each clip
  • Set the desired dimensions of the preview video
  • Remove the audio channel to save on page weight

And that’s it!

Some other options:

  • Add a quick fade between preview clips
  • Add a text or image overlay explicitly telling people to click to play the full video
  • Use the upload response from the main video to capture total video length, and then generate the preview clip’s start/stop timing.

by Josh Slivken