From f7a668355537c31786f1e3a6cc400542945573df Mon Sep 17 00:00:00 2001 From: Chema Gonzalez Date: Mon, 26 May 2025 12:08:22 -0700 Subject: [PATCH 1/2] Fix support for y4m color spaces Add support for the following Y4M color spaces produced by ffmpeg: * 422 * 420 * 420jpeg * 420mpeg2 * 420paldv * 422 * 444 * mono * 411 * 420p10 * 422p10 * 444p10 * mono10 * 420p12 * 422p12 * 444p12 * mono12 * 420p14 * 422p14 * 444p14 * 420p16 * 422p16 * 444p16 * mono16 Unsupported spaces: * 444alpha * 420p9 * 422p9 * 444p9 * mono9 Tested: * opened a 400 image. --- .../src/playlistitem/playlistItemRawFile.cpp | 129 ++++++++++++------ 1 file changed, 90 insertions(+), 39 deletions(-) diff --git a/YUViewLib/src/playlistitem/playlistItemRawFile.cpp b/YUViewLib/src/playlistitem/playlistItemRawFile.cpp index 0cc974027..eae4876e9 100644 --- a/YUViewLib/src/playlistitem/playlistItemRawFile.cpp +++ b/YUViewLib/src/playlistitem/playlistItemRawFile.cpp @@ -320,50 +320,101 @@ bool playlistItemRawFile::parseY4MFile() } else if (parameterIndicator == 'C') { - // Get 3 bytes and check them - auto formatName = rawData.mid(offset, 3); - offset += 3; - - // The YUV format. By default, YUV420 is setup. - // TDOO: What is the difference between these two formats? - // 'C420' = 4:2:0 with coincident chroma planes - // 'C420jpeg' = 4:2 : 0 with biaxially - displaced chroma planes - // 'C420paldv' = 4 : 2 : 0 with vertically - displaced chroma planes + // get the full word + int space_index = rawData.indexOf(' ', offset); + auto formatName = rawData.mid(offset, space_index - offset); + offset = space_index; + unsigned bitsPerSample = 8; auto subsampling = video::yuv::Subsampling::YUV_420; - if (formatName == "422") + if ((formatName == "420") || + // 'C420' = 4:2:0 with coincident chroma planes + (formatName == "420jpeg") || + // 'C420jpeg' = 4:2 : 0 with biaxially - displaced chroma planes + (formatName == "420mpeg2") || + (formatName == "420paldv")) { + // 'C420paldv' = 4 : 2 : 0 with vertically - displaced chroma planes + bitsPerSample = 8; + subsampling = video::yuv::Subsampling::YUV_420; + + } else if (formatName == "422") { + bitsPerSample = 8; subsampling = video::yuv::Subsampling::YUV_422; - else if (formatName == "444") + + } else if (formatName == "444") { + bitsPerSample = 8; subsampling = video::yuv::Subsampling::YUV_444; - unsigned bitsPerSample = 8; + } else if (formatName == "mono") { + bitsPerSample = 8; + subsampling = video::yuv::Subsampling::YUV_400; - if (rawData.at(offset) == 'p') - { - offset++; - if (rawData.at(offset) == '1') - { - offset++; - if (rawData.at(offset) == '0') - { - bitsPerSample = 10; - offset++; - } - else if (rawData.at(offset) == '2') - { - bitsPerSample = 12; - offset++; - } - else if (rawData.at(offset) == '4') - { - bitsPerSample = 14; - offset++; - } - else if (rawData.at(offset) == '6') - { - bitsPerSample = 16; - offset++; - } - } + } else if (formatName == "411") { + bitsPerSample = 8; + subsampling = video::yuv::Subsampling::YUV_411; + + // 10-bit components + } else if (formatName == "420p10") { + bitsPerSample = 10; + subsampling = video::yuv::Subsampling::YUV_420; + + } else if (formatName == "422p10") { + bitsPerSample = 10; + subsampling = video::yuv::Subsampling::YUV_422; + + } else if (formatName == "444p10") { + bitsPerSample = 10; + subsampling = video::yuv::Subsampling::YUV_444; + + } else if (formatName == "mono10") { + bitsPerSample = 10; + subsampling = video::yuv::Subsampling::YUV_400; + + // 12-bit components + } else if (formatName == "420p12") { + bitsPerSample = 12; + subsampling = video::yuv::Subsampling::YUV_420; + + } else if (formatName == "422p12") { + bitsPerSample = 12; + subsampling = video::yuv::Subsampling::YUV_422; + + } else if (formatName == "444p12") { + bitsPerSample = 12; + subsampling = video::yuv::Subsampling::YUV_444; + + } else if (formatName == "mono12") { + bitsPerSample = 12; + subsampling = video::yuv::Subsampling::YUV_400; + + // 14-bit components + } else if (formatName == "420p14") { + bitsPerSample = 14; + subsampling = video::yuv::Subsampling::YUV_420; + + } else if (formatName == "422p14") { + bitsPerSample = 14; + subsampling = video::yuv::Subsampling::YUV_422; + + } else if (formatName == "444p14") { + bitsPerSample = 14; + subsampling = video::yuv::Subsampling::YUV_444; + + // 16-bit components + } else if (formatName == "420p16") { + bitsPerSample = 16; + subsampling = video::yuv::Subsampling::YUV_420; + + } else if (formatName == "422p16") { + bitsPerSample = 16; + subsampling = video::yuv::Subsampling::YUV_422; + + } else if (formatName == "444p16") { + bitsPerSample = 16; + subsampling = video::yuv::Subsampling::YUV_444; + + } else if (formatName == "mono16") { + bitsPerSample = 16; + subsampling = video::yuv::Subsampling::YUV_400; } format = video::yuv::PixelFormatYUV(subsampling, bitsPerSample); From 63a91b0ee09db365022fb621e65daf8ca87db282 Mon Sep 17 00:00:00 2001 From: Chema Gonzalez Date: Sun, 1 Jun 2025 20:20:24 -0700 Subject: [PATCH 2/2] Fix support for y4m files with odd dimensions This fixes the Y4M parser, though yuview eventually refused to read the file. Error before: "Error parsing the Y4M header: Could not locate the next 'FRAME' indicator". Note that the parser cannot deal correctly with the odd-dimensions. Error after: "With the given settings, the YUV data can not be converted to RGB: The item width 9 must be divisible by the horizontal subsampling factor 2. The item height 9 must be divisible by the horizontal subsampling factor 2." Now the problem is that yuview does not seem to support odd dimensions for subsampled files. --- YUViewLib/src/playlistitem/playlistItemRawFile.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/YUViewLib/src/playlistitem/playlistItemRawFile.cpp b/YUViewLib/src/playlistitem/playlistItemRawFile.cpp index eae4876e9..678b51494 100644 --- a/YUViewLib/src/playlistitem/playlistItemRawFile.cpp +++ b/YUViewLib/src/playlistitem/playlistItemRawFile.cpp @@ -447,11 +447,13 @@ bool playlistItemRawFile::parseY4MFile() // parameters is also terminated by 0x0A. // The offset in bytes to the next frame - auto stride = width * height * 3 / 2; + auto ypixels = width * height; + auto cpixels = ((width + 1) / 2) * ((height + 1) / 2); if (format.getSubsampling() == video::yuv::Subsampling::YUV_422) - stride = width * height * 2; + cpixels = ((width + 1) / 2) * height; else if (format.getSubsampling() == video::yuv::Subsampling::YUV_444) - stride = width * height * 3; + cpixels = width * height; + auto stride = ypixels + 2 * cpixels; if (format.getBitsPerSample() > 8) stride *= 2;