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
MLB

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(new Layer().publicId("video:MLB2")).startOffset("2").endOffset("6").chain()
  .startOffset("0").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay(new Layer().publicId("video:MLB2")).startOffset("20").endOffset("24").chain()
  .startOffset("4").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay(new Layer().publicId("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: new cloudinary.Layer().publicId("video:MLB2"), startOffset: "2", endOffset: "6"},
  {startOffset: "0", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: new cloudinary.Layer().publicId("video:MLB2"), startOffset: "20", endOffset: "24"},
  {startOffset: "4", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: new cloudinary.Layer().publicId("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: new cloudinary.Layer().publicId("video:MLB2"), start_offset: "2", end_offset: "6"},
  {start_offset: "0", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: new cloudinary.Layer().publicId("video:MLB2"), start_offset: "20", end_offset: "24"},
  {start_offset: "4", flags: ["layer_apply", "splice"], width: 400, crop: "scale"},
  {overlay: new cloudinary.Layer().publicId("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(new Layer().PublicId("video:MLB2")).StartOffset("2").EndOffset("6").Chain()
  .StartOffset("0").Flags("layer_apply", "splice").Width(400).Crop("scale").Chain()
  .Overlay(new Layer().PublicId("video:MLB2")).StartOffset("20").EndOffset("24").Chain()
  .StartOffset("4").Flags("layer_apply", "splice").Width(400).Crop("scale").Chain()
  .Overlay(new Layer().PublicId("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(new Layer().publicId("video:MLB2")).startOffset("2").endOffset("6").chain()
  .startOffset("0").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay(new Layer().publicId("video:MLB2")).startOffset("20").endOffset("24").chain()
  .startOffset("4").flags("layer_apply", "splice").width(400).crop("scale").chain()
  .overlay(new Layer().publicId("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