Clipchamp API: the “Blob” output option

This article explains the purpose and use of the Blob output option that is available in the Enterprise plans of the Clipchamp API. We illustrate when to favour the Blob output option over our “pre-canned” video upload options, such as the inbuilt capability to have us upload your users’ videos to your AWS S3 or Microsoft Azure accounts.

What is a Blob and what does the Blob output option do?

“Blob” is an acronym that stands for “Binary Large OBject”. In Javascript, a Blob  is a data type that represents an opaque handle to an unstructured, typically large chunk of data, such as the binary data that makes up a video file. The Javascript Blob API is available in all modern browsers.

You can think of an instance of Blob as a file handle that may represent some in-memory data, binary data received from XMLHttpRequest , data that is persistently stored on the client’s file system using the IndexedDB or FileWriter APIs. Blobs may even be views onto other Blob instances. For instance, you can create a “wrapper Blob” from other Blob instances like so:

Internally, the Clipchamp API uses Blobs extensively to abstract from browser-specific techniques to store output video files including videos recorded with the API’s JavaScript webcam input option or videos converted and compressed with the API. With the “Blob” output option, we make a client-side delivery of output videos available as part of our Javascript API. Using the Blob output option is confined to scenarios where using our inbuilt video upload options is not feasible. These include:

  • Your application needs to perform some custom client side post-processing steps after output video data has become available. For instance, you may want to embed the output video in an HTML5 video player and play it to the user before uploading it to your backend server.
  • You cannot use any of our (steadily growing list of) inbuilt upload targets for regulatory (legal) reasons, technical obstacles, or cost considerations and store the uploaded videos on your own servers instead.

Generally, we recommend to consider using the inbuilt upload targets before opting for the Blob output. This does not only save you time and effort to code the upload to your own servers yourself. It will also make you benefit from all the robustness that we have built into the upload protocol, including retry mechanisms in sketchy network conditions and robust security protocols to safeguard your videos from malicious third parties while uploading.

How to use the Blob output option?

In order to use the Blob output option, you need to subscribe to the Enterprise plan of the Clipchamp API. Please contact info@clipchamp.com to discuss your specific requirements. Using the Blob output option essentially requires you to adjust the way you invoke the Clipchamp API in two ways:

  1. Use 'blob'  as the value of the output parameter.
  2. Provide a callback function in the onVideoCreated  parameter.

Using the Blob output option would thus follow this pattern:

In the example above, we assume you use jQuery in conjunction with the Clipchamp API and choose to use the Clipchamp-styled button, which we inject into the DOM (inside the wrapper element that is selected with the jQuery selector). Naturally, using the Blob output option is not confined to this use of the Clipchamp API.

That is, you can use the Blob output option without jQuery or when using the “custom button” flavour of our API (see CUSTOM BUTTON API on that page). The Clipchamp API will call the onVideoCreated  callback with the output video, which is an instance of Blob . In the following, we will describe 3 ways how to process that blob inside the onVideoCreated callback:

Synchronous processing (discouraged!)

The simple-most, albeit discouraged way to implement the onVideoCreated  callback function is to process outputVideoBlob  only synchronously. Doing so requires you to finish up all use of the output video synchronously, such that when your implementation of onVideoCreated  returns control to the Clipchamp API, we can immediately destroy the outputVideoBlob  object and delete its underlying persistent storage.

A synchronous implementation of onVideoCreated  is strongly discouraged because in JavaScript, few things can be done synchronously. For instance, outside of a Worker, you cannot even deeply copy a Blob  object into another Blob object synchronously. What you may be able to do is performing a synchronous XMLHttpRequest  where you send the outputVideoBlob to your backend server:

However, performing synchronous HTTP requests is deprecated in most browsers and for good reason: a synchronous operation blocks the UI thread, which Javascript shares with the rendering process. Our strong advice is thus, not to implement onVideoCreated  as a synchronous function, but use one of the following two asynchronous implementations instead.

Using callbacks

The most straightforward way to make onVideoCreated  asynchronous is to add a number of callback parameters that you need to asynchronously invoke to signal the successful (or unsuccessful) completion of handling the outputVideoBlob  in your code. For instance, the asynchronous counterpart of a simple video upload functionality could be implemented like so:

Notice how we added two parameters to the signature on onVideoCreated : doneCallback  and failCallback . Once you add them to the function signature, the Clipchamp API will be smart enough to pass a function to each. Your code then needs to either invoke the doneCallback  or failCallback , depending on whether or not your post-processing of outputVideoBlob was successful (or unsuccessful).

When your post-processing merely comprises of asynchronously uploading the video to a some HTTP(S) endpoint of yours, you should tie the success of that uploading operation to invoking doneCallback  or failCallback. While doing so, you are free to delay invoking doneCallback  until the complete post-processing operation is finally complete. Similarly, you only need to call failCallback  if it has ultimately failed.

For instance, you could implement a simple chunking upload protocol based on HTTP Content-Range  request headers, where you split outputVideoBlob into smaller chunks and send each one in a separate HTTP request (provided that your server can handle chunked uploads):

Let’s unpack this slightly more complex implementation of the onVideoCreated function. For the sake of better modularity, it defines two nested functions:

  • uploadSingleChunk  (asynchronously) sends a POST request with a 1 MB chunk to a HTTPS endoint. To signal the fragment of outputVideoBlob  that is being sent with this request, we set the Content-Range  header to the corresponding byte interval. Notice that the upper value in the bytes=...  range is inclusive.
  • uploadNextChunk  recursively traverses over outputVideoBlob , slicing out 1 MB chunks that it passes to uploadSingleChunk . If uploadSingleChunk  succeeds, it recursively invokes uploadNextChunk  with the next chunk offset. Otherwise, it retries sending the current chunk after one second. If it fails another time, we invoke the (global) failCallback . Once the offset has exceeded the size of outputVideoBlob , we invoke the (global) doneCallback .

In reality, a retry policy of chunked uploads would be even more robust with an exponential timely backoff strategy.

Using promises

Promises often constitute a superior programming model, replacing callbacks with a (stateful) concept where an asynchronous function returns a promise object. That promise object allows to register callbacks that get invoked when the promise is “resolved” or “rejected”, i.e., the asynchronous function has succeeded or failed.

The Clipchamp API allows you to use promises instead of callbacks, supporting both the upcoming Promise A+ standard and jQuery’s “deferred” objects. In either case, your implementation of onVideoCreated needs to return a promise object and can then (asynchronously) resolve or reject that promise. The following example uses Promise A+, which is part of the ECMAScript 6 standard

The beauty of promises does not stop there, but includes the notion of being “chainable”. In fact, much of jQuery’s utility functions use their “deferred” implementation. That includes jQuery’s AJAX functions, which provide a convenience wrapper around XMLHttpRequest :

Notice how we package outputVideoBlob  into a FormData  instance, which makes sure jQuery uses a multipart/form-data  encoding.

Signalling progress

Besides signalling the success or failure of your asynchronous post-processing of the outputVideoBlob , you can optionally signal the progress of your processing step to the Clipchamp API as a percentage value. We will use that value to display a progress bar and calculate a timely estimate for the remaining duration before completion. To do so, you can either add a third notifyCallback  to the signature of onVideoCreated  or use the progress reporting capability of your promise object – note that not all promise implementations support progress reporting, jQuery promises do though:

Unlike the doneCallback  or failCallback , the notifyCallback  can be invoked multiple times. You should make sure to pass increasing percentage values such as to make sure that the progress bar only ever moves forward. The same is true for invoking the notify function of the jQuery promise. In order to signal the progress of a file upload using the XMLHttpRequest  API, you can do the following: