From cf342133cd758e6603726f29a3e88b24f690d909 Mon Sep 17 00:00:00 2001 From: Claudiu Lataretu Date: Wed, 17 Jun 2026 16:48:57 +0300 Subject: [PATCH] fix video thumbnail generation for limited-range YUV videos Signed-off-by: Claudiu Lataretu --- .../job-services/thumbnails/nft.thumbnail.service.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/queue.worker/nft.worker/queue/job-services/thumbnails/nft.thumbnail.service.ts b/src/queue.worker/nft.worker/queue/job-services/thumbnails/nft.thumbnail.service.ts index 711580387..d92d0fdbc 100644 --- a/src/queue.worker/nft.worker/queue/job-services/thumbnails/nft.thumbnail.service.ts +++ b/src/queue.worker/nft.worker/queue/job-services/thumbnails/nft.thumbnail.service.ts @@ -117,8 +117,14 @@ export class NftThumbnailService { private async extractScreenshotFromVideo(buffer: Buffer, nftIdentifier: string): Promise { // we try to extract frames at 0, 10, 30 seconds, and we take the frame that has the biggest size // (i.e. the bigger the size, the more "crisp" an image should be, since it contains more details) + // + // Screenshots are written as PNG (RGB) rather than JPEG on purpose: the MJPEG/JPEG encoder + // (strict since ffmpeg 8.0) rejects limited-range ("tv") YUV videos with "Non full-range YUV + // is non-standard ..." and fails to open the encoder (-22). PNG has no such range constraint, + // so it works for every video format. The final JPEG thumbnail is produced downstream by sharp + // in extractThumbnailFromImage, so the intermediate format does not affect the output. const frames = [0, 10, 30]; - const filePaths = frames.map(x => path.join(this.apiConfigService.getTempUrl(), `${nftIdentifier}.screenshot.${x}.jpg`)); + const filePaths = frames.map(x => path.join(this.apiConfigService.getTempUrl(), `${nftIdentifier}.screenshot.${x}.png`)); const videoPath = path.join(this.apiConfigService.getTempUrl(), nftIdentifier); await FileUtils.writeFile(buffer, videoPath);