Render Me This: Video Thumbnails in Alfresco 3.3

Alfresco has undergone quite a few changes under the hood in version 3.3, including refactoring of the ThumbnailService to make use of the RenditionService, which I had to explore in a recent deep dive to get video working for the thumbnails extension. This is obviously a subject dear to your heart as well or you would have moved on by now.

Alfresco 3.1.

Let’s take a look at how things worked back in the old days, before 3.2 (fuzzy 2009 dream sequence begins…)

You most likely kicked things off with a thumbnail generating URL which would hit a ScriptNode.createThumbnail method which looked up the thumbnailDefinition and called the ThumbnailService with the TransformationOptions contained in the definition.

The ThumbnailService then told the ContentService to perform the transformation which looked up the ContentTransformer from the TransformerRegistry and executed transformer.transform which usually delegated to a RuntimeExec object to perform the actual command line transformation.

If we were to visualize the key elements of that stack for a synchronous video thumbnail creation it would look something like:

  • org.alfresco.repo.jscript.ScriptNode.createThumbnail
    • org.alfresco.repo.thumbnail.ThumbnailRegistry.getThumbnailDefinition (loads TransformationOptions)
    • org.alfresco.repo.thumbnail.ThumbnailServiceImpl.createThumbnail
      • org.alfresco.repo.content.ContentServiceImpl.transform
        • org.alfresco.repo.content.transform.ContentTransformerRegistry.getTransformer
        • org.alfresco.repo.content.transform.ContentTransformer.transform
          • TempFileProvider.createTempFile
          • org.alfresco.util.exec.RuntimeExec.execute
            • ffmpeg …

Well now, that’s not so bad.

Alfresco 3.3.

These Alfresco people don’t mess around. If it’s determined that refactoring should happen, it happens, real damn quick, even if it’s huge. To that end subsystems were rolled out in 3.2 and the RenditionService was introduced in 3.3.

Subsystems. Certain content transformers, like ImageMagick, have been refactored as a subsystem, which is cool. Read the wiki page to get the full story but in short it’s a much more flexible architecture.

The ffmpeg video transformer contained in the latest release of the thumbnails extension follows this precedence and has been refactored as a subsystem, so there.

RenditionService. I wouldn’t say I hate it, but this package should be wary of eating crackers in bed, or maybe I’m just not familiar enough with it yet.

The new rendition service utilizes RenditionDefinitions which require that any TransformationOptions be ‘serialized’ into a parameter map, which are then reassembled into TransformationOptions objects before being passed to the ContentTransformer. I suppose this is done to make it easier to do things like hand renditions off to another server in a cluster, but it’s a bit of a pain in the ass for developers.

So, back to our synchronous video thumbnail creation scenario (deep breath), the ThumbnailService now creates a RenditionDefinition which it passes to the RenditionService which wraps things up in a PerformRenditionActionExecuter that gets passed to the ActionService. The PerformRenditionActionExecuter calls the ActionService again which loads the RenderingEngine from the spring ApplicationContext. A RenderingEngine is itself an ActionExecuter so the ActionService calls execute which calls render which proceeds to rebuild the TransformationOptions object needed by the ContentService to get the proper ContentTransformer so transformer.transform can use a RuntimeExec object to perform the actual command line transformation.

The key elements of our pseudo stack/method trace would look like:

  • org.alfresco.repo.jscript.ScriptNode.createThumbnail
    • org.alfresco.repo.thumbnail.ThumbnailRegistry.getThumbnailDefinition (loads TransformationOptions)
    • org.alfresco.repo.thumbnail.ThumbnailServiceImpl.createThumbnail
      • org.alfresco.repo.thumbnail.ThumbnailServiceImpl.createRenditionDefinition
        • org.alfresco.repo.thumbnail.ThumbnailRegistry.getThumbnailRenditionConvertor().convert(transformationOptions, assocDetails) <- this serializes the transformationOptions into a parameter map
      • org.alfresco.repo.rendition.RenditionServiceImpl.render
        • org.alfresco.repo.rendition.RenditionServiceImpl.createAndExecuteRenditionAction
          • org.alfresco.repo.action.ActionServiceImpl.createAction(PerformRenditionActionExecuter.NAME)
          • set the renditionDefintion on performRenditionAction
          • org.alfresco.repo.action.ActionServiceImpl.executeAction
            • org.alfresco.repo.action.ActionServiceImpl.directActionExecution
              • load ActionExecuter from applicationContext
              • org.alfresco.repo.rendition.executer.ImageRenderingEngine.execute
                • org.alfresco.repo.rendition.executer.ImageRenderingEngine.render
                  • org.alfresco.repo.rendition.executer.ImageRenderingEngine.getTransformationOptions <- rebuilds parameter map into TransformationOptions objects
                  • org.alfresco.repo.content.ContentServiceImpl.transform
                    • org.alfresco.repo.content.transform.ContentTransformerRegistry.getTransformer
                    • org.alfresco.repo.content.transform.ProxyContentTransformer.transform <- subsystems
                      • org.alfresco.repo.content.transform.ContentTransformerWorker.transform
                        • TempFileProvider.createTempFile
                        • org.alfresco.util.exec.RuntimeExec.execute
                          • ffmpeg …

that’s a spicy meatball!

A while ago we submitted an issue to Alfresco suggesting TransformationOptions which contain distinct target AND source options so that one could for example specify that all ‘doclib’ thumbnails be of max-width X and max-height Y (the type of target options currently available) and furthermore, if it’s a document take page 1 (or maybe you need a different page in your deployment) or if it’s a video take 1 frame starting 0.5 seconds in, or if it’s a layered image file take the second layer, etc. (a list of source options).

Alas, this concept of SourceTargetTransformationOptions hasn’t yet been embraced by the Alfresco team but is used by the video transformer in the thumbnails extension which made refactoring for renditions even more difficult, but you’re not here to listen to me bitch and moan, so I’ll just say that it’s done and seems to be working fine.

So, there you have it, renditions and subsystems as they relate to video thumbnails. Hit me up with any questions or things I’ve missed.

2 thoughts on “Render Me This: Video Thumbnails in Alfresco 3.3

  1. I’m trying to reconcile what you wrote with what I’ve seen in the
    thumbnail definition context file. From looking at the context file
    it looks as though I can only create a single “doclib” thumbnail
    definition and that definition uses a single transformer (I’m not talking about complex transformations in this case). doclib was the one that was defined
    OOTB and it uses Imagemagick. It seemed like I could not then create
    a doclib thumbnail definition that also used FFmpeg for video since it
    would be a duplicate definition of doclib. If this was true, then in
    Share document library I was going to have to modify the javascript to
    pick up a separate thumbnail type (e.g., a newly defined videothumnail) if
    the mimetype was video. Anyway, I was pleasantly surprised that
    thumbnails just magically appeared in Share with no additional work on
    my part once the Thumbnail Extension was installed. Is that what you were referring to regarding the need for SourceTargetTranformation and is this what you coded around in the thumbnail extension?

    1. You’re exactly right Steve.

      The thumbnails extension replaces the built-in doclib and imgpreview thumbnail definitions with definitions that call on the SourceTargetImageTransformationOptions which allows for specifying source options for each source mimetype. The transformer itself isn’t specified in the thumbnail definition, just the source options, then at thumbnail creation time the transformers are polled to see if they know how to handle the options and source and target mimetypes.

      With those SourceTargetTransformationOptions in place the standard thumbnail creation mechanisms can be used for generation including the thumbnail webscript URL that Share uses to create the thumbnails.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s