This is an example of how you could write a service that on-the-fly generates a preview image or video from an HLS stream. Before we start, why would you need this type of service? One use case is that you want to add basic metadata for a web page containing video and you want that metadata to include a poster image or preview video. For example:
<html> <head> <title>Video Page</title> <script src="https://unpkg.com/@firstname.lastname@example.org/dist/web-player.component.js"></script> </head> <body> <eyevinn-video source="https://demo.vc.eyevinn.technology/channels/eyevinn/master.m3u8" muted="true" autoplay="true"></eyevinn-video> </body> </html>
It would be nice to have a poster when sharing this web page in social media. You can add that by adding the open graph tag
og:image with a URL to an image. And here is where this service becomes relevant. It will on request generate an image from the HLS in question and you could use it this way by adding this metadata tag to the header.
<meta property="og:url" content="https://hlspreview.cdn.eyevinn.technology/image?u=https%3A%2F%2Fdemo.vc.eyevinn.technology%2Fchannels%2Fdemo%2Fmaster.m3u8" />
A live example below: https://hlspreview.cdn.eyevinn.technology/image?u=https%3A%2F%2Fdemo.vc.eyevinn.technology%2Fchannels%2Fdemo%2Fmaster.m3u8
As you can see a very neat way of obtaining a poster image of an HLS stream.
How does it work?
The source code for this service is available on GitHub and released under open source so you are welcome to use and contribute to it.
It is a micro service written in NodeJS and uses ffmpeg for the video processing. It provides two endpoints
/video who both takes two query parameters
pos where the second one is optional. The parameter
u contains the urlencoded URL to the HLS stream.
Once this endpoint is requested it fetches and parses the HLS.
const m3u = await fetchAndParseHLS(searchParams.get("u"));
then it fetches the media chunk closes to the value of parameter
pos (in seconds). If not provided it will assume the first media chunk.
const segmentUrl = findSegmentAtPosition(m3u, pos).get("uri");
The URL to the media chunk is then passed to a function that renders a PNG from this media chunk.
const data = await renderPngFromTS(segmentUrl);
It returns a binary buffer containing the image data. This binary data is in response to the client request with the
Content-Type set to
To process the media chunk we use ffmpeg:
ffmpeg -y -i <media-chunk-url> -ss 1 -t 1 -f mjpeg <outputfile-path>.png
The outputfile name is generated based on an md5 hash of the media chunk url. We then read the file and store the content in a buffer.
const data = readFileSync(outputFilePath);
This micro service is also available as a public container if you want to use it directly.
docker run --rm -p 8000:8000 eyevinntechnology/hlspreview:<version>
To make this service scale we use cache directives and place a CDN in front. Important when configuring the CDN property is to make sure to include the query parameters in the cache key and part of identifying the cached resource. In this example we set an max-age of 3600 seconds (1 hour) in the response, which would offload this service for all requests for the very same image to be generated. In this example setup we are running the container on AWS ECS using an AWS ELB to access it and AWS Cloudfront as CDN. A setup that could easily be replicated to another cloud infrastructure as it does not contain any AWS specific functions.
Hope you found this interesting and inspiring. Let me know if you have any questions or thoughts. You find me on Twitter in addition to here.
About Eyevinn Technology
Eyevinn Technology is an independent consultant firm specialized in video and streaming. Independent in a way that we are not commercially tied to any platform or technology vendor.
At Eyevinn, every software developer consultant has a dedicated budget reserved for open source development and contribution to the open source community. This give us room for innovation, team building and personal competence development. And also gives us as a company a way to contribute back to the open source community.
Want to know more about Eyevinn and how it is to work here. Contact us at email@example.com!
Top comments (1)
awesome this is what i was looking for. can i use this live service for open source projects? does it have any limit?