Skip to main content

Timestamps in Panda videos

The following is a post explaining how to use timestamps in Panda using our API. Interested in having this feature added to the web interface? Request beta access

article-2539097-1AA6876200000578-761_634x485In Panda, it’s easy to setup the encoding pipeline with presets developed by our team – with just a few clicks, it’s possible to configure profiles for the most popular audio and video formats on the web. With that comes some caveats, such as limiting how much you can configure.

FFmpeg and corepack-3

You might have already stumbled across a chapter in our documentation titled “FFmpeg Neckbeard”. It describes how you can create encoding profiles by specifying the whole FFmpeg command by yourself, which means that everything that our FFmpeg can do is available. We’ve recently added the FreeType library to corepack-3 (it’s the newest stack we have), and that made a few new things possible. One of them is adding timestamps to videos. This can be done through FFmpeg’s “drawtext” filter.

Play time

Okay, so let’s create a new profile that, besides doing some typical transcoding, adds a small timestamp in the top-left corner. The filter that does this can be configured by passing the below argument to FFmpeg:

-vf "drawtext=fontfile=/usr/fonts/FreeSans.ttf:timecode='00:00:00:00':r=25:x=5:y=5:fontcolor=black"

The “drawtext” filter takes a few arguments that tell FFmpeg how the timestamp should be rendered, the full list is available in FFmpeg’s documentation. And, as you can see, it needs a font. The example above uses “FreeSans.ttf” – it’s one of the fonts from the GNU FreeFont library, and the whole collection is available in /usr/fonts/ directory, so the following values of “fontfile” will work on Panda:

/usr/fonts/FreeMono.ttf
/usr/fonts/FreeMonoBold.ttf
/usr/fonts/FreeMonoBoldOblique.ttf
/usr/fonts/FreeMonoOblique.ttf
/usr/fonts/FreeSans.ttf
/usr/fonts/FreeSansBold.ttf
/usr/fonts/FreeSansBoldOblique.ttf
/usr/fonts/FreeSansOblique.ttf
/usr/fonts/FreeSerif.ttf
/usr/fonts/FreeSerifBold.ttf
/usr/fonts/FreeSerifBoldItalic.ttf
/usr/fonts/FreeSerifItalic.ttf

Now we can apply this knowledge to a profile in Panda. There are plenty of examples of creating new profiles in “FFmpeg Neckbeard”, and basically adding a timestamp is as simple as adding the filter argument to the command. The important thing is that you use corepack-3 – “drawtext” will not work with older stacks. That’s how this would look like in Ruby:

require 'panda'

Panda.configure do
  access_key "your_access_key_123"
  secret_key "your_secret_key_42"
  cloud_id "id_of_the_target_pand_cloud"
  api_host "api.pandastream.com"
end

drawtext_args_map = {
  :fontfile => "/usr/fonts/FreeSans.ttf",
  :timecode => "'00\:00\:00\:00'", # timestamp offset
  :r => "25", # FPS of the timestamp, for 1:1 ratio it should be equal to the FPS of input videos
  😡 => "5", # x and y specify position of the timestamp
  :y => "5",
  :fontcolor => "black",
}

drawtext_args = drawtext_args_map.to_a.map { |k, v| "#{k}=#{v}" }.join(":")

Panda::Profile.create!({
  :stack => "corepack-3",
  :name => "timestamped_videos_v2",
  :width => 480,
  :height => 320,
  :video_bitrate => 500,
  :audio_bitrate => 128,
  :extname => ".mp4",
  :command => "ffmpeg -i $input_file$ -threads 0 -c:a libfaac" 
              " -c:v libx264 -preset medium $audio_sample_rate$" 
              " $video_bitrate$ $audio_bitrate$ $fps$ $filters$" 
              " -vf "drawtext=#{drawtext_args}" -y $output_file$"
})

The result (the original video is on pandastream.com):

That is nice, but we can do better. The timestamp could be more visible and in a better position – by using different “drawtext” switches we can add a background to the timestamp and place it near the bottom, centered. Using drawtext’s built-in variables we can even do this independently from video’s dimensions. The following does exactly that:

drawtext_args_map = {
  :fontfile => "/usr/fonts/FreeSans.ttf",
  :timecode => "'00\:00\:00\:00'",
  :r => "25",
  😡 => "(w-tw)/2", # w - width, tw - text width
  :y => "h-(2*lh)", # h - height, lh - line height
  :fontcolor => "white",
  :fontsize => "18",
  :box => "1",
  :boxcolor => "black@1", # 1 means opaque
  :borderw => "5",
  :bordercolor => "black@1"
}

And the final result:

If you have any questions on this subject, send a note to support@copper.io. We’re happy to help.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.