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
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
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.