From e761edf5ecd1260237766bb7b7b2583e933d5ffb Mon Sep 17 00:00:00 2001 From: Mr-Z-2697 <74594146+Mr-Z-2697@users.noreply.github.com> Date: Mon, 21 Sep 2026 22:05:54 +0800 Subject: [PATCH] Recon file fixes - Fix outPicPos calculation for Y4M recon The extra parentheses make the entire calculation happen in uint32 and then cast to uint64, resulting in file being overwritten in the 4GiB + header limit. - Fix down Y4M recon shift path `pic.bitDepth` is the received bit depth and will be identical to the internal bit depth, `bitDepth` is the requested bit depth. `inputDepth` was the original input bit depth, but the actual pixel depth may be changed depending on the internal bit depth, so it doesn't matter in this case. - Fix YUV recon bit depth handling In a multilib build if the "base lib" is 8bit, the HIGH_BIT_DEPTH macro is not defined, and the high bit depth output is broken. Also add down shift warning. - Remove now unused sourceBitDepth/inputDepth --- source/output/output.cpp | 6 +-- source/output/output.h | 2 +- source/output/y4m.cpp | 50 ++++++--------------- source/output/y4m.h | 4 +- source/output/yuv.cpp | 95 +++++++++++++++++++++------------------- source/output/yuv.h | 4 +- source/x265cli.cpp | 7 ++- 7 files changed, 75 insertions(+), 93 deletions(-) diff --git a/source/output/output.cpp b/source/output/output.cpp index 7a5151987..e0bc2e214 100644 --- a/source/output/output.cpp +++ b/source/output/output.cpp @@ -30,14 +30,14 @@ using namespace X265_NS; -ReconFile* ReconFile::open(const char *fname, int width, int height, uint32_t bitdepth, uint32_t fpsNum, uint32_t fpsDenom, int csp, int sourceBitDepth) +ReconFile* ReconFile::open(const char *fname, int width, int height, uint32_t bitdepth, uint32_t fpsNum, uint32_t fpsDenom, int csp) { const char * s = strrchr(fname, '.'); if (s && !strcmp(s, ".y4m")) - return new Y4MOutput(fname, width, height, bitdepth, fpsNum, fpsDenom, csp, sourceBitDepth); + return new Y4MOutput(fname, width, height, bitdepth, fpsNum, fpsDenom, csp); else - return new YUVOutput(fname, width, height, bitdepth, csp, sourceBitDepth); + return new YUVOutput(fname, width, height, bitdepth, csp); } OutputFile* OutputFile::open(const char *fname, InputFileInfo& inputInfo) diff --git a/source/output/output.h b/source/output/output.h index 6fee4f223..ac61d8a90 100644 --- a/source/output/output.h +++ b/source/output/output.h @@ -42,7 +42,7 @@ class ReconFile ReconFile() {} static ReconFile* open(const char *fname, int width, int height, uint32_t bitdepth, - uint32_t fpsNum, uint32_t fpsDenom, int csp, int sourceBitDepth); + uint32_t fpsNum, uint32_t fpsDenom, int csp); virtual bool isFail() const = 0; diff --git a/source/output/y4m.cpp b/source/output/y4m.cpp index 91b410f57..235b1ee13 100644 --- a/source/output/y4m.cpp +++ b/source/output/y4m.cpp @@ -28,13 +28,12 @@ using namespace X265_NS; using namespace std; -Y4MOutput::Y4MOutput(const char* filename, int w, int h, uint32_t bitdepth, uint32_t fpsNum, uint32_t fpsDenom, int csp, int inputdepth) +Y4MOutput::Y4MOutput(const char* filename, int w, int h, uint32_t bitdepth, uint32_t fpsNum, uint32_t fpsDenom, int csp) : width(w) , height(h) , bitDepth(bitdepth) , colorSpace(csp) , frameSize(0) - , inputDepth(inputdepth) { ofs.open(filename, ios::binary | ios::out); buf = new char[width]; @@ -54,7 +53,7 @@ Y4MOutput::Y4MOutput(const char* filename, int w, int h, uint32_t bitdepth, uint } for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) - frameSize += (uint32_t)((width >> x265_cli_csps[colorSpace].width[i]) * (height >> x265_cli_csps[colorSpace].height[i])); + frameSize += static_cast(width >> x265_cli_csps[colorSpace].width[i]) * (height >> x265_cli_csps[colorSpace].height[i]); } Y4MOutput::~Y4MOutput() @@ -66,35 +65,29 @@ Y4MOutput::~Y4MOutput() bool Y4MOutput::writePicture(const x265_picture& pic) { std::ofstream::pos_type outPicPos = header; - if (pic.bitDepth > 8) - outPicPos += (uint64_t)(pic.poc * (6 + frameSize * 2)); + if (bitDepth > 8) + outPicPos += static_cast(pic.poc) * (6 + frameSize * 2); else - outPicPos += (uint64_t)pic.poc * (6 + frameSize); + outPicPos += static_cast(pic.poc) * (6 + frameSize); ofs.seekp(outPicPos); ofs << "FRAME\n"; - if (inputDepth > 8) - { - if (pic.bitDepth == 8 && pic.poc == 0) - x265_log(NULL, X265_LOG_WARNING, "y4m: down-shifting reconstructed pixels to 8 bits\n"); - } - X265_CHECK(pic.colorSpace == colorSpace, "invalid chroma subsampling\n"); - if (inputDepth > 8)//if HIGH_BIT_DEPTH + if (pic.bitDepth > 8) { - if (pic.bitDepth == 8) + if (bitDepth == 8) { - // encoder gave us short pixels, downshift, then write - X265_CHECK(pic.bitDepth == 8, "invalid bit depth\n"); int shift = pic.bitDepth - 8; + if (pic.poc == 0) + x265_log(NULL, X265_LOG_WARNING, "y4m: down-shifting reconstructed pixels to 8 bits\n"); for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) { - char *src = (char*)pic.planes[i]; + uint16_t *src = reinterpret_cast(pic.planes[i]); for (int h = 0; h < height >> x265_cli_csps[colorSpace].height[i]; h++) { for (int w = 0; w < width >> x265_cli_csps[colorSpace].width[i]; w++) - buf[w] = (char)(src[w] >> shift); + buf[w] = static_cast(src[w] >> shift); ofs.write(buf, width >> x265_cli_csps[colorSpace].width[i]); src += pic.stride[i] / sizeof(*src); @@ -103,37 +96,22 @@ bool Y4MOutput::writePicture(const x265_picture& pic) } else { - X265_CHECK(pic.bitDepth > 8, "invalid bit depth\n"); for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) { - uint16_t *src = (uint16_t*)pic.planes[i]; + uint16_t *src = reinterpret_cast(pic.planes[i]); for (int h = 0; h < (height * 1) >> x265_cli_csps[colorSpace].height[i]; h++) { - ofs.write((const char*)src, (width * 2) >> x265_cli_csps[colorSpace].width[i]); + ofs.write(reinterpret_cast(src), (width * 2) >> x265_cli_csps[colorSpace].width[i]); src += pic.stride[i] / sizeof(*src); } } } } - else if (inputDepth == 8 && pic.bitDepth > 8) - { - X265_CHECK(pic.bitDepth > 8, "invalid bit depth\n"); - for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) - { - uint16_t* src = (uint16_t*)pic.planes[i]; - for (int h = 0; h < (height * 1) >> x265_cli_csps[colorSpace].height[i]; h++) - { - ofs.write((const char*)src, (width * 2) >> x265_cli_csps[colorSpace].width[i]); - src += pic.stride[i] / sizeof(*src); - } - } - } else { - X265_CHECK(pic.bitDepth == 8, "invalid bit depth\n"); for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) { - char *src = (char*)pic.planes[i]; + char *src = reinterpret_cast(pic.planes[i]); for (int h = 0; h < height >> x265_cli_csps[colorSpace].height[i]; h++) { ofs.write(src, width >> x265_cli_csps[colorSpace].width[i]); diff --git a/source/output/y4m.h b/source/output/y4m.h index 5aaf05994..809570d67 100644 --- a/source/output/y4m.h +++ b/source/output/y4m.h @@ -44,8 +44,6 @@ class Y4MOutput : public ReconFile uint32_t frameSize; - int inputDepth; - std::ofstream ofs; std::ofstream::pos_type header; @@ -56,7 +54,7 @@ class Y4MOutput : public ReconFile public: - Y4MOutput(const char *filename, int width, int height, uint32_t bitdepth, uint32_t fpsNum, uint32_t fpsDenom, int csp, int inputDepth); + Y4MOutput(const char *filename, int width, int height, uint32_t bitdepth, uint32_t fpsNum, uint32_t fpsDenom, int csp); virtual ~Y4MOutput(); diff --git a/source/output/yuv.cpp b/source/output/yuv.cpp index b13dc4096..805b6ff95 100644 --- a/source/output/yuv.cpp +++ b/source/output/yuv.cpp @@ -28,19 +28,18 @@ using namespace X265_NS; using namespace std; -YUVOutput::YUVOutput(const char *filename, int w, int h, uint32_t d, int csp, int inputdepth) +YUVOutput::YUVOutput(const char *filename, int w, int h, uint32_t d, int csp) : width(w) , height(h) , depth(d) , colorSpace(csp) , frameSize(0) - , inputDepth(inputdepth) { ofs.open(filename, ios::binary | ios::out); buf = new char[width]; for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) - frameSize += (uint32_t)((width >> x265_cli_csps[colorSpace].width[i]) * (height >> x265_cli_csps[colorSpace].height[i])); + frameSize += static_cast(width >> x265_cli_csps[colorSpace].width[i]) * (height >> x265_cli_csps[colorSpace].height[i]); } YUVOutput::~YUVOutput() @@ -55,51 +54,55 @@ bool YUVOutput::writePicture(const x265_picture& pic) fileOffset *= frameSize; X265_CHECK(pic.colorSpace == colorSpace, "invalid chroma subsampling\n"); - X265_CHECK(pic.bitDepth == (int)depth, "invalid bit depth\n"); -#if HIGH_BIT_DEPTH - if (depth == 8) - { - int shift = pic.bitDepth - 8; - ofs.seekp((std::streamoff)fileOffset); - for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) - { - uint16_t *src = (uint16_t*)pic.planes[i]; - for (int h = 0; h < height >> x265_cli_csps[colorSpace].height[i]; h++) - { - for (int w = 0; w < width >> x265_cli_csps[colorSpace].width[i]; w++) - buf[w] = (char)(src[w] >> shift); + if (pic.bitDepth > 8) + { + if (depth == 8) + { + int shift = pic.bitDepth - 8; + if (pic.poc == 0) + x265_log(NULL, X265_LOG_WARNING, "yuv: down-shifting reconstructed pixels to 8 bits\n"); + ofs.seekp(static_cast(fileOffset)); + for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) + { + uint16_t *src = reinterpret_cast(pic.planes[i]); + for (int h = 0; h < height >> x265_cli_csps[colorSpace].height[i]; h++) + { + for (int w = 0; w < width >> x265_cli_csps[colorSpace].width[i]; w++) + buf[w] = static_cast(src[w] >> shift); - ofs.write(buf, width >> x265_cli_csps[colorSpace].width[i]); - src += pic.stride[i] / sizeof(*src); - } - } - } - else - { - ofs.seekp((std::streamoff)(fileOffset * 2)); - for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) - { - uint16_t *src = (uint16_t*)pic.planes[i]; - for (int h = 0; h < height >> x265_cli_csps[colorSpace].height[i]; h++) - { - ofs.write((const char*)src, (width * 2) >> x265_cli_csps[colorSpace].width[i]); - src += pic.stride[i] / sizeof(*src); - } - } - } -#else - ofs.seekp((std::streamoff)fileOffset); - for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) - { - char *src = (char*)pic.planes[i]; - for (int h = 0; h < height >> x265_cli_csps[colorSpace].height[i]; h++) - { - ofs.write(src, width >> x265_cli_csps[colorSpace].width[i]); - src += pic.stride[i] / sizeof(*src); - } - } -#endif + ofs.write(buf, width >> x265_cli_csps[colorSpace].width[i]); + src += pic.stride[i] / sizeof(*src); + } + } + } + else + { + ofs.seekp(static_cast(fileOffset * 2)); + for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) + { + uint16_t *src = reinterpret_cast(pic.planes[i]); + for (int h = 0; h < height >> x265_cli_csps[colorSpace].height[i]; h++) + { + ofs.write(reinterpret_cast(src), (width * 2) >> x265_cli_csps[colorSpace].width[i]); + src += pic.stride[i] / sizeof(*src); + } + } + } + } + else + { + ofs.seekp(static_cast(fileOffset)); + for (int i = 0; i < x265_cli_csps[colorSpace].planes; i++) + { + char *src = reinterpret_cast(pic.planes[i]); + for (int h = 0; h < height >> x265_cli_csps[colorSpace].height[i]; h++) + { + ofs.write(src, width >> x265_cli_csps[colorSpace].width[i]); + src += pic.stride[i] / sizeof(*src); + } + } + } return true; } diff --git a/source/output/yuv.h b/source/output/yuv.h index c70c480f0..6b01b4e5f 100644 --- a/source/output/yuv.h +++ b/source/output/yuv.h @@ -46,15 +46,13 @@ class YUVOutput : public ReconFile uint32_t frameSize; - int inputDepth; - char *buf; std::ofstream ofs; public: - YUVOutput(const char *filename, int width, int height, uint32_t bitdepth, int csp, int inputDepth); + YUVOutput(const char *filename, int width, int height, uint32_t bitdepth, int csp); virtual ~YUVOutput(); diff --git a/source/x265cli.cpp b/source/x265cli.cpp index b8d314332..0b1a2b63c 100755 --- a/source/x265cli.cpp +++ b/source/x265cli.cpp @@ -1041,6 +1041,11 @@ namespace X265_NS { { if (reconFileBitDepth == 0) reconFileBitDepth = param->internalBitDepth; + else if (reconFileBitDepth != param->internalBitDepth && reconFileBitDepth != 8) + { + x265_log(param, X265_LOG_ERROR, "unsupported output-depth and recon-depth combination\n"); + return true; + } #if ENABLE_ALPHA || ENABLE_MULTIVIEW if (param->bEnableAlpha || param->numViews > 1) { @@ -1058,7 +1063,7 @@ namespace X265_NS { for (int i = 0; i < param->numLayers; i++) { this->recon[i] = ReconFile::open(reconfn[i], param->sourceWidth, param->sourceHeight, reconFileBitDepth, - param->fpsNum, param->fpsDenom, param->internalCsp, param->sourceBitDepth); + param->fpsNum, param->fpsDenom, param->internalCsp); if (this->recon[i]->isFail()) { x265_log(param, X265_LOG_WARNING, "unable to write reconstructed outputs file\n");